Search code examples
c#openglsharpgl

Vertex data is not drawn after DrawArrays call


Getting started using SharpGL after using other frameworks for OpenGL in C# I decided to start with the most simplest of examples to make sure I understood any syntax changes/niceties of SharpGL.

So I'm attempting to render a single solid coloured triangle which shouldn't be too difficult.

I have two Vertex Buffers, one that stores the points of the Triangle and the other that stores the colours at each of the points. These are built up like so (The points one is the same except it uses the points array):

var colorsVboArray = new uint[1];
openGl.GenBuffers(1, colorsVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
this.colorsPtr = GCHandle.Alloc(this.colors, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.colors.Length * Marshal.SizeOf<float>(), this.colorsPtr,
            OpenGL.GL_STATIC_DRAW);

These are then set with the correct attrib pointer and enabled:

openGl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.EnableVertexAttribArray(0);

But now when I draw using the call:

openGl.DrawArrays(OpenGL.GL_TRIANGLES, 0, 3);

I don't get anything on the screen. No exceptions, but the background is simply blank.

Naturally I presumed that there were compilation issues with my shaders, fortunately SharpGL gives me an easy way of checking and both the Vertex and Fragment shaders are showing as correctly compiled and linked.

Can anyone see why this code does not correctly display any objects, it's basically the same code that I've used before.

Full Source:

internal class Triangle
{
    private readonly float[] colors = new float[9];

    private readonly ShaderProgram program;

    private readonly float[] trianglePoints = 
    {
        0.0f,  0.5f,  0.0f,
        0.5f, -0.5f,  0.0f,
       -0.5f, -0.5f,  0.0f
    };

    private IntPtr colorsPtr;

    private IntPtr trianglePointsPtr;

    private readonly VertexBufferArray vertexBufferArray;

    public Triangle(OpenGL openGl, SolidColorBrush solidColorBrush)
    {

        for (var i = 0; i < this.colors.Length; i+=3)
        {
            this.colors[i] = solidColorBrush.Color.R / 255.0f;
            this.colors[i + 1] = solidColorBrush.Color.G / 255.0f;
            this.colors[i + 2] = solidColorBrush.Color.B / 255.0f;
        }

        this.vertexBufferArray = new VertexBufferArray();
        this.vertexBufferArray.Create(openGl);
        this.vertexBufferArray.Bind(openGl);

        var colorsVboArray = new uint[1];
        openGl.GenBuffers(1, colorsVboArray);
        openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
        this.colorsPtr = GCHandle.Alloc(this.colors, GCHandleType.Pinned).AddrOfPinnedObject();
        openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.colors.Length * Marshal.SizeOf<float>(), this.colorsPtr,
            OpenGL.GL_STATIC_DRAW);

        var triangleVboArray = new uint[1];
        openGl.GenBuffers(1, triangleVboArray);
        openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, triangleVboArray[0]);
        this.trianglePointsPtr = GCHandle.Alloc(this.trianglePoints, GCHandleType.Pinned).AddrOfPinnedObject();
        openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.trianglePoints.Length * Marshal.SizeOf<float>(), this.trianglePointsPtr,
            OpenGL.GL_STATIC_DRAW);

        openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,triangleVboArray[0]);
        openGl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
        openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
        openGl.VertexAttribPointer(1, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);

        openGl.EnableVertexAttribArray(0);
        openGl.EnableVertexAttribArray(1);

        var vertexShader = new VertexShader();
        vertexShader.CreateInContext(openGl);
        vertexShader.SetSource(new StreamReader(
                Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream(@"OpenGLTest.Shaders.Background.SolidColor.SolidColorVertex.glsl"))
            .ReadToEnd());
        vertexShader.Compile();

        var fragmentShader = new FragmentShader();
        fragmentShader.CreateInContext(openGl);
        fragmentShader.SetSource(new StreamReader(
                Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream(@"OpenGLTest.Shaders.Background.SolidColor.SolidColorFragment.glsl"))
            .ReadToEnd());
        fragmentShader.Compile();

        this.program = new ShaderProgram();
        this.program.CreateInContext(openGl);
        this.program.AttachShader(vertexShader);
        this.program.AttachShader(fragmentShader);
        this.program.Link();
    }

    public void Draw(OpenGL openGl)
    {
        this.program.Push(openGl, null);
        this.vertexBufferArray.Bind(openGl);
        openGl.DrawArrays(OpenGL.GL_TRIANGLES, 0, 3);
        this.program.Pop(openGl, null);
    }
}

Vertex Shader:

#version 430 core

layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_color;

out vec3 color;

void main()
{
    color = vertex_color;
    gl_Position = vec4(vertex_position, 1.0);
}

Fragment Shader:

#version 430 core

in vec3 colour;
out vec4 frag_colour;

void main () 
{
    frag_colour = vec4 (colour, 1.0);
}

Solution

  • Fixed this in the end fairly simply.

    I had previously reviewed the SharpGL code and had noted that GL_DEPTH_TEST had been enabled, so I had presumed that the GL_DEPTH_BUFFER_BIT had been correctly cleared and I didn't have to do this.

    After reviewing the Render code in SharpGL it turns out that this is not cleared by default but instead the onus is passed to the user to correctly clear the depth buffer.

    Therefore I needed a simple call to clear to fix this:

    this.openGl.Clear(OpenGL.GL_DEPTH_BUFFER_BIT);