Results 1 to 4 of 4

Thread: textures and VBOs

  1. #1
    Junior Member Newbie
    Join Date
    Jun 2005
    Posts
    19

    textures and VBOs

    Hi.

    I'm trying to use a 2D texture to color a terrain. The geometry (triangle strips) and texture coordinates are stored in VBOs and drawing is achieved using glVertexPointer, glTexCoordPointer, and glDrawArrays.

    I'm running into a peculiar problem: when I render all strips the first ??? of strips are colored (e.g. texture mapped) correctly and the remaining are munged. To verify that the coordinates are correctly specified in the coordinate buffer, I've rendered different portions of the terrain (e.g. the first 50 strips, the next 50 strips, the last 50 strips) and these strips appear to render correctly. Here are some snapshots of those tests:

    http://asheridan.net/FullRendering.png
    http://asheridan.net/FirstFifty.png
    http://asheridan.net/NextFifty.png
    http://asheridan.net/LastFifty.png

    The code is below. It is written in Java. The populateBuffers() method populates the buffers (java.nio.Buffer instances) with geometry, texture coordinates, and texture image data. The initialize(GL) method puts those buffers in VBOs and creates the texture. Finally, the drawTerrain(GL) method does the drawing. The colorBuffer isn't being used (because we are using the texture for colors), so please disregard that buffer.

    Since the constructor specified classes aren't shown here: the Data class determines the z-coordinate for a given x,y on the terrain and the ColorMap class determines the color for a give z-coordinate.

    Any thoughts? Am I setting up my texture coordinate buffer incorrectly?

    Thanks,
    Andrew

    Code :
     
    import java.awt.Color;
     
    import java.nio.Buffer;
    import java.nio.ByteBuffer;
    import java.nio.FloatBuffer;
     
    import net.java.games.jogl.GL;
     
    final class VertexBufferTerrain // package private!
      implements Terrain
    {
      // CONSTRUCTORS
      //
     
      public VertexBufferTerrain( final Data imageData, final ColorMap colorMap )
      {
        this.data = imageData;
        this.colors = colorMap;
     
        // RxTBD: we probably only need one array for the buffer IDs, but this
        // is more clear so I'm keeping it for now.
        this.vertexBufferID = new int[1];
        this.colorBufferID = new int[1];
        this.texCoordBufferID = new int[1];
     
        int numStrips = imageData.getHeight() - 1;
        int numDegenerateVerticesPerStrip = 4;
        int numVerticesPerStrip = 
          2*imageData.getWidth() + numDegenerateVerticesPerStrip;
     
        this.numVertices = numVerticesPerStrip*numStrips;    
     
        int bufferCapacity = (numVertices*3);
        this.vertexBuffer = FloatBuffer.allocate( bufferCapacity );
        this.colorBuffer = ByteBuffer.allocate( bufferCapacity );
        this.texCoordBuffer = FloatBuffer.allocate( bufferCapacity );
     
        // The texture buffer needs a width and height that are the next power
        // of two greater than the max of the width and the height of the
        // image.
        //
        // RxTBD: width and height can be independent...
        textureBufferSize = 
          lumeniq.util.math.MathUtils.findNextPowerOfTwo( 
            Math.max( imageData.getWidth(), imageData.getHeight() ) );
        this.textureBuffer = 
          ByteBuffer.allocateDirect( textureBufferSize*textureBufferSize );
     
        populateBuffers();
      }
     
      // METHODS
      //
     
      private void populateBuffers()
      {
        int width = data.getWidth();
        int height = data.getHeight();
        int numStrips = height - 1;
     
        // the coordinates for the top left corner of the terrain
        final float xStart = -width/2f;
        final float yStart = height/2f;
     
        // each triangle strip has a top and bottom y (duh!).
        int topImageY = 0;
        int bottomImageY = 0;
     
        // reuse these...
        float dataValue = 0f;
        Color color = Color.BLACK;
        float xCoord = 0f;
        float yCoord = 0f;
        final float texCoordDenominator = textureBufferSize-1;
     
        for( int strip = 0; strip < numStrips; ++strip )
        {
          topImageY = strip;
          bottomImageY = strip+1;
     
          // start with a degenerate...
          dataValue = data.getValue( 0, bottomImageY );
          degenerate( xStart, yStart-bottomImageY, dataValue, Color.BLUE, 
                      0, bottomImageY/texCoordDenominator );
     
          for( int x = 0; x < width; ++x )
          {
            xCoord = x+xStart; 
            yCoord = yStart-bottomImageY;
            dataValue = data.getValue( x, bottomImageY );
            color = colors.getColor( dataValue );
            vertex( xCoord, yCoord, dataValue, color, 
                    x/texCoordDenominator, bottomImageY/texCoordDenominator );
     
            yCoord = yStart-topImageY;
            dataValue = data.getValue( x, topImageY );
            color = colors.getColor( dataValue );
            vertex( xCoord, yCoord, dataValue, color,
                    x/texCoordDenominator, topImageY/texCoordDenominator );
          }
     
          // end with a degenerate...
          degenerate( xCoord, yCoord, dataValue, Color.BLUE, 
                      (width-1)/texCoordDenominator, 
                      topImageY/texCoordDenominator );
        }
     
        // fill the textureBuffer with the colors...
        for( int y = 0; y < height; ++y )
        {
          for( int x = 0; x < width; ++x )
          {
            textureBuffer.put( 
              (byte)colors.getColor( data.getValue( x, y ) ).getRed() );
          }
     
          // fill the remainder of this row in the textureBuffer with 0s...
          for( int i = 0; i < textureBufferSize - width; ++i )
            textureBuffer.put( (byte)0 );
        }
      }
     
      private void vertex( float x, float y, float z, Color color, 
                           float textureX, float textureY )
      {
        vertexBuffer.put( x );
        vertexBuffer.put( y );
        vertexBuffer.put( z );
        colorBuffer.put( (byte)color.getRed() );
        colorBuffer.put( (byte)color.getGreen() );
        colorBuffer.put( (byte)color.getBlue() );    
        texCoordBuffer.put( textureX );
        texCoordBuffer.put( textureY );
      }
     
      private void degenerate( float x, float y, float z, Color color,
                               float textureX, float textureY )
      {
        vertex( x,y,z,color, textureX, textureY );
        vertex( x,y,z,color, textureX, textureY );
      }
     
      public void initialize( final GL gl )
      {
        gl.glEnableClientState( GL.GL_VERTEX_ARRAY );
        //gl.glEnableClientState( GL.GL_COLOR_ARRAY );
        gl.glEnableClientState( GL.GL_TEXTURE_COORD_ARRAY );
     
        if( vertexBuffer != null )
        {
          // generate and bind the buffer
          //
          // 1) get the buffer ID
          gl.glGenBuffers( 1, vertexBufferID ); 
     
          // 2) bind the buffer (e.g. make it the active buffer).
          gl.glBindBuffer( GL.GL_ARRAY_BUFFER, vertexBufferID[0] ); 
     
          // load the data into the buffer...
          gl.glBufferData( 
            GL.GL_ARRAY_BUFFER, 
            vertexBuffer.capacity()*4, 
            vertexBuffer.array(), 
            GL.GL_STATIC_DRAW );
     
          // we don't need the geometry anymore... it's on the graphics card
          vertexBuffer.clear();
          vertexBuffer = null;
        }
     
        if( colorBuffer != null )
        {
          // generate and bind the buffer
          //
          // 1) get the buffer ID
          gl.glGenBuffers( 1, colorBufferID ); 
     
          // 2) bind the buffer (e.g. make it the active buffer).
          gl.glBindBuffer( GL.GL_ARRAY_BUFFER, colorBufferID[0] ); 
     
          // load the data into the buffer...
          gl.glBufferData( 
            GL.GL_ARRAY_BUFFER, 
            colorBuffer.capacity(), 
            colorBuffer.array(), 
            GL.GL_STATIC_DRAW );
     
          // we don't need the colors anymore... 
          colorBuffer.clear();
          colorBuffer = null;
        }
     
        if( texCoordBuffer != null )
        {
          // texture stuph...
          int numTextures = 1;
          textureID = new int[numTextures];
          gl.glGenTextures( numTextures, textureID );
          gl.glBindTexture( GL.GL_TEXTURE_2D, textureID[0] );
     
          // RxTBD: asheridan: are these correct?
          gl.glTexParameteri( 
            GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE );
          gl.glTexParameteri( 
            GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE );
     
          gl.glTexParameteri( 
            GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR );
          gl.glTexParameteri( 
            GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR );
     
          // now, specify the friggin' texture...
          gl.glTexImage2D( 
            GL.GL_TEXTURE_2D, 
            0, // not mipmapping
            1, // only one color component in the texture
            textureBufferSize,
            textureBufferSize,
            0, // no border
            GL.GL_LUMINANCE, //replicates single value across RGB, alpha is 1
            GL.GL_UNSIGNED_BYTE, // textureBuffer has unsigned byte values...
            textureBuffer
            );
     
          // generate and bind the buffer
          //
          // 1) get the buffer ID
          gl.glGenBuffers( 1, texCoordBufferID ); 
     
          // 2) bind the buffer (e.g. make it the active buffer).
          gl.glBindBuffer( GL.GL_ARRAY_BUFFER, texCoordBufferID[0] ); 
     
          // load the data into the buffer...
          gl.glBufferData( 
            GL.GL_ARRAY_BUFFER, 
            texCoordBuffer.capacity(), 
            texCoordBuffer.array(), 
            GL.GL_STATIC_DRAW );
     
          // we don't need the coords anymore... 
          texCoordBuffer.clear();
          texCoordBuffer = null;
        }
      }
     
      public void shutdown( final GL gl )
      {
        gl.glDeleteBuffers( GL.GL_ARRAY_BUFFER, vertexBufferID );
        gl.glDeleteBuffers( GL.GL_ARRAY_BUFFER, colorBufferID );
        gl.glDeleteBuffers( GL.GL_ARRAY_BUFFER, texCoordBufferID );
      }
     
      public void drawTerrain( final GL gl )
      {
        gl.glEnable( GL.GL_TEXTURE_2D );
        gl.glTexEnvf( GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE );
     
        gl.glActiveTexture( GL.GL_TEXTURE0 );
        gl.glBindTexture( GL.GL_TEXTURE_2D, textureID[0] );
     
     
        gl.glBindBuffer( GL.GL_ARRAY_BUFFER, vertexBufferID[0] );
        gl.glVertexPointer( 
          3,           // num floats in a vertex (x,y,z)
          GL.GL_FLOAT, // the data type
          0,           // the stride between verteces in the array
          null         // this would be the vertex array, if using those...
          );
     
    //     gl.glBindBuffer( GL.GL_ARRAY_BUFFER, colorBufferID[0] );
    //     gl.glColorPointer(
    //       3,                   // num color components
    //       GL.GL_UNSIGNED_BYTE, // data type
    //       0,                   // the stride
    //       null                 // this would be the color array, if not using VBOs
    //       );
     
        gl.glBindBuffer( GL.GL_ARRAY_BUFFER, texCoordBufferID[0] );
        gl.glTexCoordPointer(
          2,
          GL.GL_FLOAT,
          0,
          null // the pointer is the currently bound buffer...
          );
     
        // now, do the drawing...
        gl.glDrawArrays( GL.GL_TRIANGLE_STRIP, 0, numVertices );
     
        //JoglUtils.checkError( "drawTerrain", gl, null );
     
        gl.glDisable( GL.GL_TEXTURE_2D );
      }
     
     
      // ATTRIBUTES
      //
     
      private final Data data;
      private final ColorMap colors;
     
      /** 
       * The total number of vertices, including degenerates (used to separate
       * triangle strips).
       */
      private final int numVertices;
     
      // RxTBD: we probably only need one array for the buffer IDs.
      private final int[] vertexBufferID;
      private final int[] colorBufferID;
      private final int[] texCoordBufferID;
     
     
      private FloatBuffer vertexBuffer;
      private ByteBuffer colorBuffer;
      private FloatBuffer texCoordBuffer;
     
      /** 
       * This buffer will be the next power of two greater than the max of the
       * width and the height of the image.
       */
      private ByteBuffer textureBuffer;
     
      /** 
       * The width and the height of the texture buffer (the next power of two
       * greater than the max of the image width and height). 
       */
      private final int textureBufferSize;
     
      /** The ID (or "name", in OpenGL terms) of the texture. */
      private int[] textureID;
     
      // STATICS
      //
    }

  2. #2
    Guest

    Re: textures and VBOs

    gl.glBufferData( GL.GL_ARRAY_BUFFER, texCoordBuffer.capacity(), texCoordBuffer.array(), GL.GL_STATIC_DRAW );
    You do realize that the size parameter is in machine units (bytes). I don't know what capacity() returns (number of elements?).

    And make sure your texcoords make sense with your wrap. CLAMP_TO_EDGE will clamp (s,t) to [1/(2n), 1 - 1/(2n)].

    Hlz

  3. #3
    Junior Member Newbie
    Join Date
    Jun 2005
    Posts
    19

    Re: textures and VBOs

    Thank you! texCoordBuffer.capacity() was returning the number of floats. Simply multiplying this by 4 fixed my problem.

    I'll have to attribute this to a copy and paste error on my part Notice I was correctly specifying the size param for the vertexBuffer, but forgot to add this to the texCoordBuffer...

    Thanks for finding my bug...

    Andrew

  4. #4
    Guest

    Re: textures and VBOs

    My pleasure.

    Made me forget about my own bugs for a moment

    Hlz

Similar Threads

  1. Defining textures for VBOs
    By Bhoot123 in forum OpenGL: Basic Coding
    Replies: 2
    Last Post: 08-26-2018, 10:50 PM
  2. How many VAOs/VBOs/textures to use?
    By BenFoppa in forum OpenGL: Basic Coding
    Replies: 0
    Last Post: 08-18-2014, 05:40 PM
  3. ES2 and VBOs
    By birdcage in forum OpenGL ES
    Replies: 2
    Last Post: 01-04-2011, 11:25 AM
  4. VBOs without the V.
    By Fred T.J. in forum OpenGL: Basic Coding
    Replies: 5
    Last Post: 12-08-2008, 04:39 AM
  5. VBOs and ATI
    By Leadwerks in forum OpenGL: Advanced Coding
    Replies: 35
    Last Post: 04-07-2008, 06:57 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean