OpenGL texture rendering - only upper left pixel is displayed

358 Views Asked by At

I working with C# and OpenTK. Currently I only want to map a texture on a triangle. It seems to be working but on nearest texture filter, the whole triangle is only colored with the upper left pixel color of the bmp image and if I set the texture filter to linear the triangle shows still only one color, but it seems whether it is now mixed with the other pixels. Can someone find the error in the code ?

protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            GL.Enable(EnableCap.Texture2D);
            GL.ClearColor(0.5F, 0.5F, 0.5F, 1.0F);

            int vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);
            int fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);

            string vertexShaderSource = @"#version 400
                                            layout(location = 0) in vec3 position;
                                            layout(location = 1) in vec2 uv;
                                            out vec2 texture_uv;
                                            void main()
                                            {
                                                gl_Position = vec4(inPosition.xyz, 1);
                                                texture_uv = uv;
                                            }";
            string fragmentShaderSource = @"#version 400
                                            in vec2 texture_uv;
                                            out vec3 outColor;
                                            uniform sampler2D uniSampler;
                                            void main()
                                            {
                                                outColor = texture( uniSampler, texture_uv ).rgb;
                                            }";

            GL.ShaderSource(vertexShaderHandle, vertexShaderSource);
            GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);

            GL.CompileShader(vertexShaderHandle);
            GL.CompileShader(fragmentShaderHandle);

            prgHandle = GL.CreateProgram();
            GL.AttachShader(prgHandle, vertexShaderHandle);
            GL.AttachShader(prgHandle, fragmentShaderHandle);
            GL.LinkProgram(prgHandle);

            GL.DetachShader(prgHandle, vertexShaderHandle);
            GL.DetachShader(prgHandle, fragmentShaderHandle);
            GL.DeleteShader(vertexShaderHandle);
            GL.DeleteShader(fragmentShaderHandle);

            uniSamplerLoc = GL.GetUniformLocation(prgHandle, "uniSampler");

            texHandle = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D, texHandle);
            Bitmap bmp = new Bitmap("C:/Users/Michael/Desktop/Test.bmp");
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmpData.Width, bmpData.Height, 0,
            OpenTK.Graphics.OpenGL4.PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0);

            bmp.UnlockBits(bmpData);

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);

            vaoHandle = GL.GenVertexArray();
            GL.BindVertexArray(vaoHandle);

            vboHandle = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle);
            float[] bufferData = {  0.5F, 1, 0, 1, 1, 
                                    0, 0, 0, 0, 0, 
                                    1, 0, 0, 1, 0 };
            GL.BufferData<float>(BufferTarget.ArrayBuffer, (IntPtr) (15 * sizeof(float)), bufferData, BufferUsageHint.StaticDraw);

            GL.EnableVertexAttribArray(0);
            GL.EnableVertexAttribArray(1);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0);
            GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));
        }
        protected override void OnUnload(EventArgs e)
        {
            base.OnUnload(e);

            GL.DeleteTexture(texHandle);
            GL.DeleteProgram(prgHandle);
            GL.DeleteBuffer(vboHandle);
            GL.DeleteVertexArray(vaoHandle);
        }
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);

            GL.Clear(ClearBufferMask.ColorBufferBit);
            GL.UseProgram(prgHandle);
            GL.Uniform1(uniSamplerLoc, texHandle);
            GL.BindVertexArray(vaoHandle);
            GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

            SwapBuffers();
        }

EDIT:

I tried this:

protected override void OnRenderFrame(FrameEventArgs e)
{
    base.OnRenderFrame(e);

    GL.Clear(ClearBufferMask.ColorBufferBit);
    GL.UseProgram(prgHandle);

    GL.BindVertexArray(vaoHandle);

    GL.ActiveTexture(TextureUnit.Texture3);
    GL.BindTexture(TextureTarget.Texture2D, texHandle);
    GL.Uniform1(uniSamplerLoc, 3);

    GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

    SwapBuffers();
}

But nothing changed :(

1

There are 1 best solutions below

1
On

The value of a sampler uniform variable needs to be the texture unit it should sample from. In your code, it is set to the texture name (aka texture id, aka texture handle) instead:

GL.Uniform1(uniSamplerLoc, texHandle);

The texture unit can be set with ActiveTexture(). When glBindTexture() is called, the value of the currently active texture unit determines which unit the texture is bound to. The default for the active texture unit is 0. So if you never called ActiveTexture(), the uniform should be set as:

GL.Uniform1(uniSamplerLoc, 0);

Just as a heads-up, another related source of errors is that the value of the uniform is a 0-based index of the texture unit, while the glActiveTexture() call takes an enum starting with GL_TEXTURE0. For example with the C bindings (not sure how exactly this looks with C# and OpenTK, but it should be similar enough), this would bind a texture to texture unit 3, and set a uniform sampler variable to use it:

glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texId);
glUniform1i(texUniformLoc, 3);

Note how GL_TEXTURE3 is used in the argument for glActiveTexture(), but a plain 3 in glUniform1i().