Search code examples
c#openglvbotexture-mappingopentk

Trouble Texturing VBO


It seems as though I am having some trouble with texturing VBOs in my game. The VBO itself, seems to render just fine, and I can even toggle the faces away accordingly. However, when I try to add textures everything looks skewed and some textures are even on the wrong face. Everything was working fine when I was using VAO's, so I am currently at a loss as to why the textures suddenly are not working.

Here is an image:

enter image description here

And here is the associated data:

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,
        };

The Way I upload the data:

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

And the way I draw the cube (Each face is a seperate 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 );
        }

Hoping someone can spot what I did wrong.

Update: I have fixed the code given the suggestion of @Andom M. Coleman and it worked, however the cube is still slightly skewed.

enter image description here


Solution

  • You are using different VBOs for your texture coordinate array and position array, correct? There are not discrete binding locations for those things, your code should actually look like this:

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

    NOTE: BufferTarget.TextureBuffer is actually for a completely different use of buffer objects (Texture Buffer Objects).

    For vertex buffers, you will always bind them to BufferTarget.ArrayBuffer and then the next gl___CoordPointer (...) call will be relative to whatever is currently bound there.

    In your original code, since BufferTarget.ArrayBuffer was only being set once, your texture coordinate pointer was actually coming from the same set of data as your vertex positions. That is obviously not the behavior you want.


    In fact, if you want to get fancy, you can pull the specification of the texture pointer out of the branch because it is invariant. Just do the following once each time you draw your cube:

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