OpenGL 纹理渲染 - 仅显示左上角像素

本文关键字:显示 左上角 像素 纹理 OpenGL | 更新日期: 2023-09-27 18:31:14

我使用 C# 和 OpenTK。目前我只想在三角形上映射纹理。它似乎正在工作,但在最近的纹理过滤器上,整个三角形仅与 bmp 图像的左上角像素颜色着色,如果我将纹理过滤器设置为线性三角形仍然只显示一种颜色,但似乎它现在是否与其他像素混合。有人可以在代码中找到错误吗?

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();
        }

编辑:

我试过这个:

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();
}

但没有任何改变:(

OpenGL 纹理渲染 - 仅显示左上角像素

采样

器均匀变量的值必须是它应该从中采样的纹理单位。在代码中,它设置为纹理名称(也称为纹理 id,也称为纹理句柄):

GL.Uniform1(uniSamplerLoc, texHandle);

纹理单元可以用ActiveTexture() .调用 glBindTexture() 时,当前活动纹理单元的值确定纹理绑定到哪个单元。活动纹理单元的默认值为 0。所以如果你从来没有叫过ActiveTexture(),制服应该设置为:

GL.Uniform1(uniSamplerLoc, 0);

作为提醒,另一个相关的错误来源是制服的值是从 0 开始的纹理单元索引,而 glActiveTexture() 调用采用以 GL_TEXTURE0 开头的枚举。例如,对于 C 绑定(不确定这与 C# 和 OpenTK 的确切效果如何,但它应该足够相似),这会将纹理绑定到纹理单元 3,并设置一个统一的采样器变量来使用它:

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

请注意GL_TEXTURE3glActiveTexture()的参数中是如何使用的,但在glUniform1i()中是一个普通的3