代码之家  ›  专栏  ›  技术社区  ›  Mervin

OpenGL中2D投影和纹理的初学者问题

  •  0
  • Mervin  · 技术社区  · 11 年前

    最近我一直在尝试学习/使用OpenGL3+。我看过教程和示例,但我遇到了一堵墙,试图让纹理和2D投影毫无问题地工作。

    现在的目标是有一个函数,它可以用像素指定的位置(而不是[-1,1])在屏幕上绘制纹理四边形。

    为了可读性和测试,我用我目前所掌握的知识制作了一个新的barebones程序,它显示出几乎相同的问题。如果能帮上忙,我会很感激的,因为我开始变得秃头了。。

    当前代码显示的是乱码纹理,而不是图像本身(纹理为128x128px)。

    enter image description here

    [程序.cs]

    namespace OpenGLTester
    {
        static class Program
        {
            public static GameWindow window;
            public static String programDirectory = Directory.GetCurrentDirectory();
            public static int testTexture;
            public static int uniform_fragment_texture;
            public static int shaderProgram;
    
            [STAThread]
            static void Main()
            {
                window = new GameWindow(1024, 768, new GraphicsMode(new ColorFormat(8, 8, 8, 8), 0, 8), "OpenGLTester", GameWindowFlags.Default, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Default);
                GL.Viewport(new Size(1024,768));
    
                shaderProgram = GL.CreateProgram();
                int vertexShader = GL.CreateShader(ShaderType.VertexShader);
                int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
    
                GL.ShaderSource(vertexShader, File.ReadAllText(programDirectory + @"\vertex.vert"));
                GL.ShaderSource(fragmentShader, File.ReadAllText(programDirectory + @"\fragment.frag"));
    
                GL.CompileShader(vertexShader);
                GL.CompileShader(fragmentShader);
    
                GL.AttachShader(shaderProgram, vertexShader);
                GL.AttachShader(shaderProgram, fragmentShader);
                GL.LinkProgram(shaderProgram);
    
                if (GL.GetError() != ErrorCode.NoError) { System.Diagnostics.Debugger.Break(); }
    
                Console.WriteLine(GL.GetProgramInfoLog(shaderProgram));
    
                GL.UseProgram(shaderProgram);
    
                Matrix4 projectionMatrix = Matrix4.CreateOrthographic(1024, 768, 0, 1);
    
                GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "vertex_projection"), false, ref projectionMatrix);
    
                uniform_fragment_texture = GL.GetUniformLocation(shaderProgram, "fragment_texture");
    
                testTexture = loadTexture(programDirectory + @"\test.png");
    
                GL.Disable(EnableCap.DepthTest);
                GL.Disable(EnableCap.Lighting);
                GL.Enable(EnableCap.Blend);
                GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
    
                window.UpdateFrame += window_UpdateFrame;
                window.RenderFrame += window_RenderFrame;
                window.Resize += window_Resize;
    
                window.TargetRenderFrequency = 60;
                window.Run();
            }
    
            static void window_Resize(object sender, EventArgs e)
            {
                //Don't allow resizing for now.
                window.Size = new Size(1024, 768);
            }
    
            static void window_UpdateFrame(object sender, FrameEventArgs e)
            {
                ErrorCode currentError = GL.GetError();
                if (currentError != ErrorCode.NoError)
                {
                    Console.WriteLine(Enum.GetName(typeof(ErrorCode), currentError));
                    System.Diagnostics.Debugger.Break();
                }
            }
    
            static void window_RenderFrame(object sender, FrameEventArgs e)
            {
                GL.ClearColor(0, 0, 0, 0);
                GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
    
                //test texture is 128x128pixels.
                drawTexRect(100, 228, 100, 228, testTexture);
    
                window.SwapBuffers();
            }
    
            static int loadTexture(String filePath)
            {
                GL.Enable(EnableCap.Texture2D);
                int id = GL.GenTexture();
    
                GL.ActiveTexture(TextureUnit.Texture0);
                GL.BindTexture(TextureTarget.Texture2D, id);
    
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 0);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
    
                Bitmap bmp = new Bitmap(filePath);
                BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
                    OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, bmp_data.Scan0);
    
                bmp.UnlockBits(bmp_data);
                bmp.Dispose();
    
                return id;
            }
    
            static void drawTexRect(float top, float bottom, float left, float right, int texture)
            {
                //topLeft,bottomLeft,bottomRight,topRight
    
                float[] vertices = new float[] {
                   left, top, 0, 0,
                   left, bottom, 0, 1,
                   right, bottom, 1, 1,
                   right, top, 1, 0,
                };
    
                int buffer = GL.GenBuffer();
    
                GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
                GL.BufferData<float>(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
    
                //vec2 - screen position
                GL.EnableVertexAttribArray(0);
                GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4, 0);
    
                //vec2 - texture coordinates
                GL.EnableVertexAttribArray(1);
                GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4, 2 * sizeof(float));
    
                GL.Enable(EnableCap.Texture2D);
                GL.ActiveTexture(TextureUnit.Texture0);
                GL.BindTexture(TextureTarget.Texture2D, texture);
                GL.Uniform1(uniform_fragment_texture, 0);
    
                GL.DrawArrays(PrimitiveType.Quads, 0, 4);
                GL.DeleteBuffer(buffer);
            }
        }
    }
    

    [顶点.垂直]

    #version 330
    
    in vec2 vertex_position;
    in vec2 vertex_texturePosition;
    
    uniform mat4 vertex_projection;
    
    out vec2 fragment_texturePosition;
    
    void main()
    {
        gl_Position = vec4(vertex_position,0.0,1.0) * vertex_projection;
    
        fragment_texturePosition = vertex_texturePosition;
    }
    

    [碎片碎片]

    #version 330
    
    in vec2 fragment_texturePosition;
    
    uniform sampler2D fragment_texture;
    
    out vec4 output_color;
    
    void main()
    {
        output_color = texture(fragment_texture,fragment_texturePosition);
    }
    

    @j-p建议的更改后,仍然存在一个问题:

    enter image description here

    @j-p建议的纹理位置更改后:

    投影也是错误的,因为我预计它的位置是从左侧100像素,从顶部100像素,不知道我如何解决这个问题。。

    1 回复  |  直到 11 年前
        1
  •  2
  •   j-p    11 年前

    步幅参数以字节为单位:

    GL.EnableVertexAttribArray(0);
    GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);
    
    //vec2 - texture coordinates
    GL.EnableVertexAttribArray(1);
    GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));
    

    此外,windows argb位图对应的opengl像素格式是BGRA。( link )

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

    最后,应按如下方式调整纹理坐标:

            float[] vertices = new float[] {
               left, top, 0, 1,
               left, bottom, 0, 0,
               right, bottom, 1, 0,
               right, top, 1, 1
            };