Search code examples
imageopengl2dopentk

Simplest way to display a simple image in OpenGL (OpenTK)?


I have to following code:

    public void BeginDraw()
    {
        if(bufferMaterial != null)
        {
            bufferMaterial.Textures[0].Surface.BindFramebuffer();
            beganDraw = true;
        }
    }
    public void EndDraw()
    {
        if (beganDraw)
        {
            beganDraw = false;
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
            if (bufferMaterial != null)
            {
                GL.BindBuffer(BufferTarget.ArrayBuffer, screenMesh.VBO);
                GL.BindVertexArray(VAO);
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, screenMesh.VEO);
                bufferMaterial.Use();
                screenMesh.ApplyDrawHints(bufferMaterial.Shader);
                GL.DrawElements(PrimitiveType.Triangles, 2, DrawElementsType.UnsignedInt, 0);
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
                GL.BindVertexArray(0);
                GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
                GL.UseProgram(0);
            }
        }
    }

Between those two I draw my scene, so the image should be drawn to bufferMaterial.Textures[0].Surface.

Now the "screenMesh" is created like this:

        screenMesh = new Mesh();
        screenMesh.SetVertices(new float[] {
            0,0,
            1,0,
            1,1,
            0,1
        });
        screenMesh.SetIndices(new uint[] {
            0,3,2,
            0,1,2
        });
        screenMesh.SetDrawHints(new VertexObjectDrawHint("pos", 2, 2, 0));

-> 2 components, stride of 2, 0 offset

The shader looks like this:

++++++++
Screenbuffer
++++++++

[Shader vertexScreen]
#version 150 core

in vec2 pos;
uniform float _time;
uniform sampler2D tex;
void main() {
    gl_Position = vec4(pos, -1, 1);
}
[Shader fragmentScreen]
#version 150 core
#define PI 3.1415926535897932384626433832795

out vec4 outColor;
uniform float _time;
uniform sampler2D tex;
//texture2D(tex, 
void main() {
    outColor = vec4(1,1,1,1);
}

Now, I would expect this to draw a white rectangle to the screen, but the screen stays black. I played around with the indices of the screenMesh a little so the might be off, but they were never visible...

I don't need any projection matrix with a shader like this right ?

Mesh class: http://pastebin.com/PcwEYqGH

Edit: Okay, the buffer is rendered now, but I still need to get the depth buffer working! The surface creation code looks like this:

public void Create(int width, int height, SurfaceFormat format)
    {
        Width = width;
        Height = height;
        textureHandle = GL.GenTexture();
        //bind texture
        GL.BindTexture(TextureTarget.Texture2D, textureHandle);
        Log.Error("Bound Texture: " + GL.GetError());
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)format.WrapMode);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)format.WrapMode);

        Log.Error("Created Texture Parameters: " + GL.GetError());
        GL.TexImage2D(TextureTarget.Texture2D, 0, format.InternalFormat, Width, Height, 0, format.PixelFormat, format.SourceType, format.Pixels);
        Log.Error("Created Image: " + GL.GetError());
        //unbind texture
        GL.BindTexture(TextureTarget.Texture2D, 0);
        //create depthbuffer
        if (format.DepthBuffer)
        {
            GL.GenRenderbuffers(1, out dbHandle);
            GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, dbHandle);
            GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent24, Width, Height);
        }

        //create fbo
        fboHandle = GL.GenFramebuffer();
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, fboHandle);
        GL.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, textureHandle, 0);
        if(format.DepthBuffer)
            GL.FramebufferRenderbuffer(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, dbHandle);
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
        Log.Error("Created Framebuffer: " + GL.GetError());

    }

And this is the code for binding it:

public void BindTexture(TextureUnit slot = TextureUnit.Texture0)
    {
        GL.ActiveTexture(slot);
        GL.BindTexture(TextureTarget.Texture2D, textureHandle);

    }
    public void BindFramebuffer()
    {
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, fboHandle);
    }

Yet if the depth buffer is enabled, the screen goes black again.

EDIT: Forgot to clear the depth buffer!


Solution

  • There is a problem in your draw call:

    GL.DrawElements(PrimitiveType.Triangles, 2, DrawElementsType.UnsignedInt, 0);
    

    The second argument is the number of indices used for rendering. With only 2 indices, that's not enough for a complete triangle. You have 6 indices in your index array, so it should be:

    GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
    

    Beyond that, I haven't been able to find code or documentation for the Mesh class you are using, so I can't tell if the vertex data stored in the mesh is set up correctly.