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
Basic bullet movement patterns in 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
OpenGL 4 with OpenTK in C# Part 15: Object picking by mouse

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.

All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link on social media, not required but appreciated! :)

21 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
  5. Maybe mod _time by 2 * Math.PI in case of double overflow when the program runs for a long while.

    Just some trivia for thought. :)

    ReplyDelete
    Replies
    1. Hmm.. Wouldn't that take quite a while? :)
      Given that _time is per second and double has the approximate range ±5.0 × 10^−324 to ±1.7 × 10^308
      See documentation https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/double

      Delete
  6. Hello, thanks you for your great tutorials, they are really helpful.

    I am having problems recreating this particular bit in my code.
    I am running Lubuntu with mono, as the machine i am using is rather old .
    The graphics chip support OpenGL 2.1 so i think the problem might be because of that.
    I can see the dot in the middle of the window, however i am failing to reproduce the movement and color change. My code does correlate with the code on your github page.
    The program does not complain about anything. Any help would be appreciated.

    best regards.

    ReplyDelete
    Replies
    1. Hi there, sorry for the late reply. I think that you need a newer graphics chip to fully use these tutorials as they target OpenGL 4.5 and up, i.e. many of the API calls that are used do not work on older hardware. Please refer to the following wikipedia article for information on how the versions of GLSL and OpenGL work together: https://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions

      Delete
  7. Hello, great tutorial but I have a question.

    For some reason if I use the variable defined in "layout (location = 0)" the point don't show. It works if I change that to layout (location = 1) and layout (location = 2).

    Did you have an idea what may causing this?

    Thanks

    ReplyDelete
    Replies
    1. Hi there, sorry for the late reply.
      Little bit unsure, I would check that the C# code binds the variables correctly as a starter.. I.e. GL.VertexAttrib4(1, position); And that you are using the correct overload of the API call. VertexAttrib4 for a Vector4 and VertexAttrib1 for a float for example.. Hope this helps!

      Delete
    2. Hi. same problem here. I retyped passing fuction to GL.VertexAttrib1(0, (float)_time); to get proper float overload, but this did not help. Furthermore, when I change code on shader side only just to "load" from any other location ( = 5 for example), it shows fixed color, but for 0 it shows none square (or transparent).

      Delete
  8. Found out the hard way my little Potato of a computer can't handle some of the code in the tutorial. Just wondering what sections of code would need to be replaced with what for getting this usable for those of us on older graphics cards? I know OpenTK has several versions it can target even now so it might just be a matter of figuring out what lib of the OpenTK graaphics lib to use.

    ReplyDelete
    Replies
    1. Hi there! My tutorials focus on the OpenGL API version 4. There are a lot of resources describing previous openGL versions elsewhere on the internet. Just that when I started out with v4, there was no other tutorial, hence this series.

      Delete
  9. I am trying to learn a little about modern Opengl, I am grateful to use csharp, but I wonder if these classes use the modern Opengl concept?

    ReplyDelete
    Replies
    1. Hi there!
      Yes, this guide uses the opengl 4+ way of doing things.

      Delete
  10. I really, really love you! This is my second tutorial and it is answering all my major question so far.

    ReplyDelete