Thursday, January 26, 2017

OpenGL 4 with OpenTK in C# Part 3: Passing data to shaders



In this post we will look passing data from your application code to the shaders using OpenTK.

This is part 3 of my series on OpenGL4 with OpenTK.
For other posts in this series:
OpenGL 4 with OpenTK in C# Part 1: Initialize the GameWindow
OpenGL 4 with OpenTK in C# Part 2: Compiling shaders and linking them
OpenGL 4 with OpenTK in C# Part 3: Passing data to shaders
OpenGL 4 with OpenTK in C# Part 4: Refactoring and adding error handling
OpenGL 4 with OpenTK in C# Part 5: Buffers and Triangle
OpenGL 4 with OpenTK in C# Part 6: Rotations and Movement of objects
OpenGL 4 with OpenTK in C# Part 7: Vectors and Matrices
OpenGL 4 with OpenTK in C# Part 8: Drawing multiple objects
OpenGL 4 with OpenTK in C# Part 9: Texturing
OpenGL 4 with OpenTK in C# Part 10: Asteroid Invaders
OpenGL 4 with OpenTK in C# Part 11: Mipmap
OpenGL 4 with OpenTK in C# Part 12: Basic Moveable Camera
OpenGL 4 with OpenTK in C# Part 13: IcoSphere
OpenGL 4 with OpenTK in C# Part 14: Basic Text

As stated in the previous post, I am in no way an expert in OpenGL. I write these posts as a way to learn, if you want to have all the theory behind why things are done in a certain way I recommend reading OpenGL SuperBible, Seventh Edition :)
This part will build upon the game window and shaders from the previous post.

Defining in parameters to our Vertex Shader

For starters a reminder of our OnRenderFrame method from the previous posts. Added _time to hold total time elapsed as OpenTK seems to be giving the delta time only in the FrameEventArgs.
private double _time;
protected override void OnRenderFrame(FrameEventArgs e)
{
    _time += e.Time;
    Title = $"{_title}: (Vsync: {VSync}) FPS: {1f / e.Time:0}";
    Color4 backColor;
    backColor.A = 1.0f;
    backColor.R = 0.1f;
    backColor.G = 0.1f;
    backColor.B = 0.3f;
    GL.ClearColor(backColor);
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    GL.UseProgram(_program);

    // add shader attributes here

    GL.DrawArrays(PrimitiveType.Points, 0, 1);
    GL.PointSize(10);
    SwapBuffers();
}

Float parameter

So, lets modify our vertex shader to take a parameter, time in this case and calculate a color and forward it to the fragment shader. I.e. out parameter of vertex shader matches the in parameter of fragment shader.

Vertex Shader
#version 440 core

layout (location = 0) in float time;
out vec4 frag_color;

void main(void)
{
 gl_Position = vec4( 0.25, -0.25,  0.5,  1.0);
 frag_color = vec4(sin(time) * 0.5 + 0.5, cos(time) * 0.5 + 0.5, 0.0, 0.0);
}

Fragment Shader
#version 440 core

in vec4 frag_color;
out vec4 color;

void main(void)
{
 color = frag_color;
}

And in our OnRenderFrame we add the following to pass along our float time to the shader.
    // add shader attributes here
    GL.VertexAttrib1(0, _time);

This should result in the vertex blending in color over time. Key here is that the first parameter of GL.VertexAttrib1 should match the location definition in our shader.


Vector4 parameter

Vertex Shader
Here we add a new in attribute, position that is a vec4. And we just set the gl_Position to whatever value is supplied by our game code.
#version 440 core

layout (location = 0) in float time;
layout (location = 1) in vec4 position;
out vec4 frag_color;

void main(void)
{
 gl_Position = position;
 frag_color = vec4(sin(time) * 0.5 + 0.5, cos(time) * 0.5 + 0.5, 0.0, 0.0);
}

And in our OnRenderFrame we add the following

    Vector4 position;
    position.X = (float)Math.Sin(_time) * 0.5f;
    position.Y = (float)Math.Cos(_time) * 0.5f;
    position.Z = 0.0f;
    position.W = 1.0f;
    GL.VertexAttrib4(1, position);

See that the location definition and the first parameter of the GL.VertexAttrib4 match.

This should give an output similar to the picture below (or watch at https://youtu.be/na_96BMN-EA), The dot should be moving on an elliptical path around the center of the window and it should still be changing colors as it moves.

There are a lot of overload versions for the GL.VertexAttrib function. I guess so that we can pass through all that we could possibly need. Just look around and see what overload to use that matches your needs. Head over to the OpenGL API documentation for a full list, and check your Intellisense to figure out what OpenTK overload to use.


Hope this helps someone out there :)
Thanks for reading. Here's another video of 2 of our cats fighting to lighten up your day.

Until next time: Work to Live, Don’t Live to Work

9 comments:

  1. After making this changes I don't see the point any more.
    I saw the static one in the previous post.
    Can you please give the complete code so far?

    ReplyDelete
    Replies
    1. Hi there!
      Thank you for your comment, thanks to you I've now created my first GitHub repository. It contains the code at the end of part 4 of this series.
      https://github.com/eowind/dreamstatecoding
      Hope that you sort out the issue, if you find that I've missed to add something in the article please let me know :)

      Delete
    2. I had similar situation under intel graphics and openGL 4.0.0. After changing on Nvidia and openGL 4.4.0 program normally works.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. I pasted your code as you recommended but during running method CompileShader info variable is equal "no errors.\n" and
    if (!string.IsNullOrWhiteSpace(info))
    throw new Exception($"CompileShader {type} had errors: {info}");
    return shader;
    throw exception. Why you use !string.IsNullOrWhiteSpace?

    ReplyDelete
    Replies
    1. Hi there,
      old habit to use just that method to check, if info contains anything we got an error or a warning and want to quit here. If it is empty, null or just blanks then we assume that everything went OK. I.e. it has no content :)

      Delete
    2. Ah. should probably have read a bit more indepth. so your opengl version reports No errors in the info. Ill probably just change it to info logging and no exceptions in later tutorial. I did not think of that as my machine just returns empty string.

      Delete
  4. Previous comment is done under Inter graphics. Under Intel my computer is using OpenGL 4.0.0 so I changed version in your code on 4 0 0. Also I removed ! from if statement conditions and program have normally run but I have got static blue screen (no point, no movement).
    Then, I changed graphic card on nvidia. Now OpenGL is 4.4.0 so I changed code again and also I have to put ! in if statements, because variable info is now equal "". After this modification program normally work. Point is running and changing color.

    ReplyDelete
    Replies
    1. Thank you for your comments,
      I had similar issue, I found a way to trigger the application to use Nvidia as default in http://dreamstatecoding.blogspot.se/2017/01/opentk-glcompileshader.html
      Now my driver reports opengl 4.5 on nvidia (updated drivers) and later posts require that..

      Delete