kevink's picture

Create uniform shader blocks

Hi everybody,

I´m new to opentk and I try using uniform blocks in the GLControl.
The question is also on stackoverflow. But it is still not working.

I try to rewrite an example of the "OpenGL Shading Language Cookbook".
The source can be found here:
Source

File: scenebasic_uniformblock.cpp

Compiling and linking is successfull.

My source in the initializing function looks now:

// Get the index of the uniform block			
var blockIndex = GL.GetUniformBlockIndex(programId, "BlobSettings");
 
// Store data within the buffer at the appropriate offsets
var blockBuffer = new BlobSettings
{
	OuterColor = new Vector4(1.0f, 0.0f, 0.0f, 0.0f),
	InnerColor = new Vector4(1.0f, 1.0f, 0.75f, 1.0f),
	InnerRadius = 0.25f,
	OuterRadius = 0.45f
};  					
 
 // Create the buffer object and copy the data
int uboHandle;
GL.GenBuffers(1, out uboHandle);
GL.BindBuffer(BufferTarget.UniformBuffer, uboHandle);
 
GL.BufferData(
	BufferTarget.UniformBuffer, 
	(IntPtr)BlobSettings.Size, 
	ref blockBuffer, BufferUsageHint.DynamicDraw);			
 
// Bind the buffer object to the uniform block
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 1, uboHandle);
 
// We don't need this if we specify the binding within the shader
GL.UniformBlockBinding(programId, blockIndex, 0);				
 
// Clear Color
GL.ClearColor(Color.Black);
GL.Enable(EnableCap.DepthTest);
 
// Create buffer objects
var vertexBufferObjectHandles = new int[2];
GL.GenBuffers(2, vertexBufferObjectHandles);
 
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObjectHandles[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_vertdata.Length * sizeof(float)), _vertdata, BufferUsageHint.StaticDraw);
 
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObjectHandles[1]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_tcData.Length * sizeof(float)), _tcData, BufferUsageHint.StaticDraw);
 
// Create VAO
GL.GenVertexArrays(1, out _vao);
GL.BindVertexArray(_vao);
 
GL.EnableVertexAttribArray(0);
GL.EnableVertexAttribArray(1);
 
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObjectHandles[0]);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
 
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObjectHandles[1]);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 0, 0);
 
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

The BlobSettings Type is a struct of:

public struct BlobSettings
{
	public Vector4 InnerColor;
	public Vector4 OuterColor;
	public float InnerRadius;
	public float OuterRadius;
 
	public static readonly int Size = BlittableValueType<BlobSettings>.Stride;
}

And the paint Method:

glControl1.MakeCurrent();
 
// Clear Color Buffer and Depth Buffer
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
GL.BindVertexArray(_vao);
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
 
GL.Flush();
glControl1.SwapBuffers();

The full source of my projekt can be found:
Full Source of Project

All I got is a black Screen. If I change the Fragment shader to

FragColor = mix(innerC, outerC, smoothstep(0.25, 0.45, dist));

I got a working Image.

So I think there is a Problem with setting the uniform block data.

Does anyone know where the problem is?

Thank you very much!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

I'll take a look into this as soon as I get some time.

kevink's picture

That would be very nice. Thank you very much.

the Fiddler's picture

I am having some trouble getting this project to work on my system.

First thing I tried was to replace OpenTK.dll with a debug version. This uncovered an OpenGL error at GL.UseProgram, so I added some code to check for compile/link status of the shaders.

            GL.GetShader(vertexShaderId, ShaderParameter.CompileStatus, out status);
            if (status == 0)
            {
                throw new Exception(
                    GL.GetShaderInfoLog(vertexShaderId));
            }
 
            GL.GetShader(fragmentShaderId, ShaderParameter.CompileStatus, out status);
            if (status == 0)
            {
                throw new Exception(
                    GL.GetShaderInfoLog(fragmentShaderId));
            }
 
            GL.GetProgram(programId, GetProgramParameterName.LinkStatus, out status);
            if (status == 0)
            {
                throw new Exception(
                    GL.GetProgramInfoLog(programId));
            }

On my system, it appears that the fragment shader is failing to compile: explicit uniform location requires OpenGL 4.3, so you need to bump your shader to #version 430.

My system only supports OpenGL 4.1, so I removed the explicit location. However, the fragment shader still fails to compile for me, but with no error message this time.

I would suggest the following:

  • Use a debug version of OpenTK.dll for testing. This will throw an exception as soon as an OpenGL error is detected, which is very helpful during development.
  • Run your shaders through the reference GLSL compiler to ensure they are correct.
  • Use layout(std140, binding = 1) to specify the binding location for the uniform block.
  • Try layout(std430) to see if it makes a difference. (From my reading of the spec, std140 should match the default C# packing rules, but I might be wrong.)

I'll try to see if I have any system with better OpenGL support to test on.

maxwills's picture

Where can I find a "debug version of OpenTK.dll". I've seen this advice a couple of times. Sounds great, but I have no idea where to get that dll.

the Fiddler's picture

You can use OpenTK.sln to compile a debug build of OpenTK.dll. Additional instructions here: http://www.opentk.com/doc/install

You can download the source code from https://github.com/opentk/opentk/releases. The source is also included in the installation package from sourceforge.

kevink's picture

Hi,

sorry I extracted this project from a bigger one.

After setting the shader sources I forgot to compile the shaders:

So adding this

GL.CompileShader(vertexShaderId);
and
GL.CompileShader(fragmentShaderId);

after
GL.CompileShader(...)

result in no shader errors.

The current source can be found here:

With
"Use layout(std140, binding = 1) to specify the binding location for the uniform block."
I get a System.AccessViolationException.

With
"Try layout(std430) to see if it makes a difference. (From my reading of the spec, std140 should match the default C# packing rules, but I might be wrong.)"
I get a ERROR: 0:12: '' : layout std430 is only allowed for buffer

Tomorrow I will test the code on another machine. Then I can say it has something to do with my GPU.

kevink's picture

On an nvidia quadro 2000 I cant it also get working.

Same issues.