麻烦纹理 VBO

Posted

技术标签:

【中文标题】麻烦纹理 VBO【英文标题】:Trouble Texturing VBO 【发布时间】:2014-09-20 19:30:44 【问题描述】:

似乎我在我的游戏中纹理化 VBO 时遇到了一些问题。 VBO 本身似乎渲染得很好,我什至可以相应地切换面。然而,当我尝试添加纹理时,一切看起来都是歪斜的,有些纹理甚至出现在错误的面上。当我使用 VAO 时一切正常,所以我现在不知道为什么纹理突然不起作用。

这是一张图片:

这里是相关的数据:

private static uint frontFaceHandle;
        private static uint backFaceHandle;
        private static uint leftFaceHandle;
        private static uint rightFaceHandle;
        private static uint topFaceHandle;
        private static uint bottomFaceHandle;


        private static uint indexBufferId;
        private static uint colorBufferId;
        private static uint texCoordBufferId;

        private static float[] textureCoordData = 
            0, 1,
            1, 1,
            1, 0,
            0, 0,
        ;

        private static ushort[] indices = 
            0, 1, 3,
            0, 3, 2
        ;

        private static float[] colorData = 
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
        ;

        private static float[] frontFaceVert = 
            -1.0f, -1.0f, -1.0f,
            -1.0f, -1.0f, 1.0f,
            -1.0f, 1.0f, -1.0f,
            -1.0f, 1.0f, 1.0f
        ;

        private static float[] backFaceVert = 
            1.0f, -1.0f, 1.0f,
            1.0f, -1.0f, -1.0f,
            1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, -1.0f,
        ;

        private static float[] leftFaceVert = 
            1.0f, -1.0f, -1.0f,
            -1.0f, -1.0f, -1.0f,
            1.0f, 1.0f, -1.0f,
            -1.0f, 1.0f, -1.0f,
        ;

        private static float[] rightFaceVert = 
            -1.0f, -1.0f, 1.0f,
            1.0f, -1.0f, 1.0f,
            -1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f,
        ;

        private static float[] topFaceVert = 
            -1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f,
            -1.0f, 1.0f, -1.0f,
            1.0f, 1.0f, -1.0f,
        ;

        private static float[] bottomFaceVert = 
            -1.0f, -1.0f, -1.0f,
            1.0f, -1.0f, -1.0f,
            -1.0f, -1.0f, 1.0f,
            1.0f, -1.0f, 1.0f,
        ;

我上传数据的方式:

static Voxel() 
            /**
             * Front Face
             */
            GL.GenBuffers( 1 , out frontFaceHandle );
            GL.BindBuffer( BufferTarget.ArrayBuffer , frontFaceHandle );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )( frontFaceVert.Length * sizeof( float ) ) ,
                frontFaceVert ,
                BufferUsageHint.StaticDraw );
            /**
             * Back Face
             */
            GL.GenBuffers( 1 , out backFaceHandle );
            GL.BindBuffer( BufferTarget.ArrayBuffer , backFaceHandle );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )( backFaceVert.Length * sizeof( float ) ) ,
                backFaceVert ,
                BufferUsageHint.StaticDraw );
            /**
             * Left Face
             */
            GL.GenBuffers( 1 , out leftFaceHandle );
            GL.BindBuffer( BufferTarget.ArrayBuffer , leftFaceHandle );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )( leftFaceVert.Length * sizeof( float ) ) ,
                leftFaceVert ,
                BufferUsageHint.StaticDraw );
            /**
             * Right Face
             */
            GL.GenBuffers( 1 , out rightFaceHandle );
            GL.BindBuffer( BufferTarget.ArrayBuffer , rightFaceHandle );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )( rightFaceVert.Length * sizeof( float ) ) ,
                rightFaceVert ,
                BufferUsageHint.StaticDraw );
            /**
             * Top Face
             */
            GL.GenBuffers( 1 , out topFaceHandle );
            GL.BindBuffer( BufferTarget.ArrayBuffer , topFaceHandle );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )( topFaceVert.Length * sizeof( float ) ) ,
                topFaceVert ,
                BufferUsageHint.StaticDraw );
            /**
             * Bottom Face
             */
            GL.GenBuffers( 1 , out bottomFaceHandle );
            GL.BindBuffer( BufferTarget.ArrayBuffer , bottomFaceHandle );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )( bottomFaceVert.Length * sizeof( float ) ) ,
                bottomFaceVert ,
                BufferUsageHint.StaticDraw );
            /**
             * Texture Buffer
             */
            GL.GenBuffers( 1 , out texCoordBufferId );
            GL.BindBuffer( BufferTarget.ArrayBuffer , texCoordBufferId );
            GL.BufferData( BufferTarget.ArrayBuffer , ( IntPtr )( textureCoordData.Length * sizeof( float ) ) , textureCoordData , BufferUsageHint.StaticDraw );

            /**
             * Index Buffer
             */
            GL.GenBuffers( 1 , out indexBufferId );
            GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
            GL.BufferData(
                BufferTarget.ElementArrayBuffer ,
                ( IntPtr )( indices.Length * sizeof( ushort ) ) ,
                indices ,
                BufferUsageHint.StaticDraw );
            /**
             * Color buffer (This Remains unused for now
             */
            GL.GenBuffers( 1 , out colorBufferId );
            GL.BindBuffer( BufferTarget.ArrayBuffer , colorBufferId );
            GL.BufferData(
                BufferTarget.ArrayBuffer ,
                ( IntPtr )colorData.Length ,
                colorData ,
                BufferUsageHint.StaticDraw );
        

以及我绘制立方体的方式(每个面都是一个单独的 vbo):

public void Render( FirstPersonCameraWidget gameCamera ) 
            GL.Translate( Location.X , Location.Y , Location.Z );
            GL.Enable( EnableCap.Texture2D );
            GL.EnableClientState( ArrayCap.VertexArray );
            GL.EnableClientState( ArrayCap.TextureCoordArray );
            if( ShowFrontFace ) 

                GL.BindBuffer( BufferTarget.ArrayBuffer , frontFaceHandle );
                GL.BindBuffer( BufferTarget.TextureBuffer , texCoordBufferId );
                GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
                GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );
                GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );
                GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.FrontFace.GetID() );
                GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );
            
            if( ShowBackFace ) 
                GL.BindBuffer( BufferTarget.ArrayBuffer , backFaceHandle );
                GL.BindBuffer( BufferTarget.TextureBuffer , texCoordBufferId );
                GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
                GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );
                GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );
                GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.BackFace.GetID() );
                GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );
            
            if( ShowLeftFace ) 
                GL.BindBuffer( BufferTarget.ArrayBuffer , leftFaceHandle );
                GL.BindBuffer( BufferTarget.TextureBuffer , texCoordBufferId );
                GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
                GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );
                GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );
                GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.LeftFace.GetID() );
                GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );
            
            if( ShowRightFace ) 
                GL.BindBuffer( BufferTarget.ArrayBuffer , rightFaceHandle );
                GL.BindBuffer( BufferTarget.TextureBuffer , texCoordBufferId );
                GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
                GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );
                GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );
                GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.RightFace.GetID() );
                GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );
            
            if( ShowTopFace ) 
                GL.BindBuffer( BufferTarget.ArrayBuffer , topFaceHandle );
                GL.BindBuffer( BufferTarget.TextureBuffer , texCoordBufferId );
                GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
                GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );
                GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );
                GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.TopFace.GetID() );
                GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );
            
            if( ShowBottomFace ) 
                GL.BindBuffer( BufferTarget.ArrayBuffer , bottomFaceHandle );
                GL.BindBuffer( BufferTarget.TextureBuffer , texCoordBufferId );
                GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
                GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );
                GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );
                GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.BottomFace.GetID() );
                GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );
            
            GL.Translate( -Location.X , -Location.Y , -Location.Z );
        

希望有人能发现我做错了什么。

更新:根据@Andom M. Coleman 的建议,我已经修复了代码并且它有效,但是立方体仍然略微倾斜。

【问题讨论】:

【参考方案1】:

您为纹理坐标数组和位置数组使用不同的 VBO,对吗?这些东西没有离散的绑定位置,您的代码实际上应该如下所示:

        if( ShowFrontFace ) 
            GL.BindBuffer( BufferTarget.ArrayBuffer , frontFaceHandle );
            GL.VertexPointer( 3 , VertexPointerType.Float , 0 , IntPtr.Zero );

            // ArrayBuffer!
            GL.BindBuffer( BufferTarget.ArrayBuffer , texCoordBufferId ); 
            GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );

            GL.BindTexture( TextureTarget.Texture2D , TextureAtlas.FrontFace.GetID() );

            GL.BindBuffer( BufferTarget.ElementArrayBuffer , indexBufferId );
            GL.DrawElements( PrimitiveType.Triangles , 6 , DrawElementsType.UnsignedShort , IntPtr.Zero );

注意:BufferTarget.TextureBuffer实际上是针对缓冲区对象(Texture Buffer Objects)的完全不同用途。

对于顶点缓冲区,您将始终将它们绑定到 BufferTarget.ArrayBuffer,然后下一个 gl___CoordPointer (...) 调用将与当前绑定的内容相关。

在您的原始代码中,由于 BufferTarget.ArrayBuffer 仅设置一次,因此您的纹理坐标指针实际上来自与您的顶点位置相同的数据集。这显然不是你想要的行为。


其实,如果你想花哨,你可以把纹理指针的规范拉出分支,因为它是不变的。每次绘制立方体时,只需执行以下一次

            GL.BindBuffer     ( BufferTarget.ArrayBuffer , texCoordBufferId     ); 
            GL.TexCoordPointer( 2 , TexCoordPointerType.Float , 0 , IntPtr.Zero );

【讨论】:

我肯定会这样做,但是,您知道为什么我的纹理仍然略微倾斜吗?是我的纹理坐标吗? 是的,从你的顶点位置设置的方式来看,我认为你的坐标实际上应该是:0,0 0,1 1,0 1,1。 那些坐标将所有东西都翻转到它的一边,但至少现在我知道它是纹理坐标。感谢您的帮助;现在接受作为答案。 正确的纹理坐标是:private static float[] textureCoordData = 0, 1, 1, 1, 0, 0, 1, 0 ;

以上是关于麻烦纹理 VBO的主要内容,如果未能解决你的问题,请参考以下文章

对 VBO 中的特定三角形使用不同的纹理

使用 VAO/VBO 进行 OpenGL 模型/纹理渲染

使用 VBO 的纹理绑定无法正常工作

Android OpenGL ES2 一个 VBO 的许多纹理

lwjgl 纹理多重绑定到一个 VBO

使用 VBO/IBO 的 OpenGL 纹理三角形