Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: VBO problem

  1. #1
    Junior Member Newbie
    Join Date
    Apr 2007
    Posts
    12

    VBO problem

    Hi, i implemented vertex buffer objects for drawing an octree world, and i seems to work fine, but i have a question:

    when i init my program, i do something like this:
    Code :
    // bind and generate
    glGenBuffersARB( 1, &uiVBODataID);	
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, uiVBODataID );	
     
    // Load The Data	
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, octreeWorldNumberOfVerts*3*sizeof(float), pOctreeWorldVertices, GL_STREAM_DRAW_ARB );
    then, the code for the drawing the octree is something like this:
    Code :
    void COctree::DrawOctree(COctree *pOctreeNode)
    {	
    	if( pOctreeNode->IsSubdivided() )
    	{
    		// draw recursively all the nodes
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_LEFT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_LEFT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_RIGHT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_RIGHT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_LEFT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_LEFT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_RIGHT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_RIGHT_BACK] );
    	}
     
    	else
    	{
    	if( !pOctreeNode->m_pvVertices )
    		return;
     
     	glBindBufferARB( GL_ARRAY_BUFFER_ARB, uiVBODataID  );		
    	glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );	
    	glEnableClientState( GL_VERTEX_ARRAY );	
    	glDrawArrays( GL_TRIANGLES, 0, octreeWorldNumberOfVerts );	
    	glDisableClientState( GL_VERTEX_ARRAY );		
        }
    }
    Before using VBO, i used vertex arrays for doing it, and if i have more than one node (i.e the octree is subdivided), the framerate decreased a lot because it was drawing ALL the vertices while the octree was still subdivided.

    With VBO's it seems to be the same problem


    Because i have this problem, i tried to do what i had when i was using vertex arrays, and that was creating the necessary arrays for every subdivided node in my Init code, so then, when in every frame i call the draw function, it only drawed the vertex data that is in every node.

    I'm doing it like this:
    Code :
    void COctree::CreateVBOs(COctree *pOctreeNode, UINT uiVBOoffsetID)
    {
    	if( !pOctreeNode )
    		return;
     
    	if(  pOctreeNode->IsSubdivided() )
    	{
    	CreateVBOs( pOctreeNode->m_pOctreeNode[TOP_LEFT_FRONT ],uiVBOoffsetID );
    	CreateVBOs( pOctreeNode->m_pOctreeNode[TOP_LEFT_BACK  ],uiVBOoffsetID );
    	CreateVBOs( pOctreeNode->m_pOctreeNode[TOP_RIGHT_FRONT],uiVBOoffsetID );
    	CreateVBOs( pOctreeNode->m_pOctreeNode[TOP_RIGHT_BACK ],uiVBOoffsetID );
    	CreateVBOs(pOctreeNode->m_pOctreeNode[BOTT_LEFT_FRONT],uiVBOoffsetID  );
    	CreateVBOs( pOctreeNode->m_pOctreeNode[BOTT_LEFT_BACK],uiVBOoffsetID  );
    	CreateVBOs( pOctreeNode->m_pOctreeNode[BOTT_RIGHT_FRONT],uiVBOoffsetID);
    	CreateVBOs( pOctreeNode->m_pOctreeNode[BOTT_RIGHT_BACK],uiVBOoffsetID );
    	}
     
    	else
    	{
    	if( !pOctreeNode->m_pvVertices )
    		return;
     
    	// increase the VBO ID
    	pOctreeNode->m_uiVBODataID += uiVBOoffsetID;
     
    	// bind and generate
    	glGenBuffersARB( 1, &pOctreeNode->m_uiVBODataID);	
    	glBindBufferARB( GL_ARRAY_BUFFER_ARB, pOctreeNode->m_uiVBODataID );	
     
    	// Load The Data	
    	glBufferDataARB( GL_ARRAY_BUFFER_ARB,
                            pOctreeNode->GetTriangleCount()*sizeof(float),
    			pOctreeNode->m_pvVertices, GL_STREAM_DRAW_ARB );		
    	}
    }
    and then, when drawing:

    Code :
    if( pOctreeNode->IsSubdivided() )
    	{
    		// draw the nodes recursively
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_LEFT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_LEFT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_RIGHT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_RIGHT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_LEFT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_LEFT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_RIGHT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_RIGHT_BACK] );
    	}
     
    	else
    	{
             if( !pOctreeNode->m_pvVertices )
    		return;
              glBindBufferARB( GL_ARRAY_BUFFER_ARB, pOctreeNode->m_uiVBODataID  );
     
    	  glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );	
     
    	  glEnableClientState( GL_VERTEX_ARRAY );	
     
    	  glDrawArrays( GL_TRIANGLES, 0, pOctreeNode->m_TriangleCount/3 );	
     
    	  glDisableClientState( GL_VERTEX_ARRAY );
             }
    }
    But if i do that, it only draws some portions of the world, then...
    what am i doing wrong?

  2. #2
    Intern Contributor
    Join Date
    Feb 2005
    Posts
    90

    Re: VBO problem

    Hi,

    1. Don't create vbo each time while drawing.
    2. Use index array, update only this array for view culling/ordering

    Ido

  3. #3
    Advanced Member Frequent Contributor yooyo's Avatar
    Join Date
    Apr 2003
    Location
    Belgrade, Serbia
    Posts
    872

    Re: VBO problem

    1. Store all vertices in one VBO
    2. Split all faces into octree-nodes. Create one index buffer and store each octree-node faces set on this index buffer.
    3. Calculate boundary box or sphere for each octree-node.

    Code :
    IsNodeVisible checks boundary box or sphere against viewing frustum. 
    Result can be: 100% visible, partially visible and invisible. 
    100% visible node means that all it's child nodes are 100% visible too. 
    Partially visible nodes must check visibility for each child. Invisible 
    nodes are ignored.
     
    Each node contains bytes offset in index buffer, and number of faces in it.
     
     
    void DrawNode(node* root, int iVisible)
    {
     // parent node can be partially visible... in that case let check this child node
     if (iVisible == PARTIALY_VISIBLE)
       iVisible = IsNodeVisible(frustum, root);
     
     // if this child node not visible, nothing to draw
     if (iVisible == NOT_VISIBLE) return;
     
     if (IsLeaf(node))
     {
      // draw node
      glDrawArrays( GL_TRIANGLES, node->offset_in_indexbuffer, node->m_TriangleCount/3 );	
     }
     else
     {
      // roll recursion
      for (int i=0; i<8; i++)
       DrawNode(node->child[i], iVisible);
     }
    }
     
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, vertexVBO);	
    glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );	
    glEnableClientState( GL_VERTEX_ARRAY );
     
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexVBO);
     
    DrawNode(scene_root, PARTIALLY_VISIBLE);

  4. #4
    Junior Member Regular Contributor
    Join Date
    Dec 2000
    Location
    Madrid, Spain
    Posts
    136

    Re: VBO problem

    Originally posted by blackwind:
    Code :
    	  glDrawArrays( GL_TRIANGLES, 0, pOctreeNode->m_TriangleCount/3 );
    But if i do that, it only draws some portions of the world, then...
    what am i doing wrong?
    m_TriangleCount/3? Is it what you are trying to do? If m_TriangleCount means #of triangles you want to render, then it should be m_TriangleCount*3

    Hope this helps.

  5. #5
    Intern Newbie
    Join Date
    Sep 2006
    Posts
    37

    Re: VBO problem

    I think you can use only one VBO, an before you call DrawOctree do this:
    Code :
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, uiVBODataID  );		
    glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );	
    glEnableClientState( GL_VERTEX_ARRAY );	
    DrawOctree(octree->root())
    glDisableClientState( GL_VERTEX_ARRAY );
    Now you can call for each Leaf Node the subset of triangles you need using:
    Code :
    glDrawArrays( GL_TRIANGLES, pOctreeNode->firstVertex(), pOctreeNode->lastVertex() );
    So, you need to have on the VBO the triangles sorted by octree's nodes. If you don't want to repeat the vertexs, you need a double VBO.

  6. #6
    Junior Member Newbie
    Join Date
    Apr 2007
    Posts
    12

    Re: VBO problem

    Originally posted by Cab:
    m_TriangleCount/3? Is it what you are trying to do? If m_TriangleCount means #of triangles you want to render, then it should be m_TriangleCount*3

    Hope this helps. [/QB]
    Nop, unfurtonatelly thats not the problem.

    Originally posted by speed:
    I think you can use only one VBO, an before you call DrawOctree do this:
    Code :
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, uiVBODataID  );		
    glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );	
    glEnableClientState( GL_VERTEX_ARRAY );	
    DrawOctree(octree->root())
    glDisableClientState( GL_VERTEX_ARRAY );
    Now you can call for each Leaf Node the subset of triangles you need using:
    Code :
    glDrawArrays( GL_TRIANGLES, pOctreeNode->firstVertex(), pOctreeNode->lastVertex() );
    So, you need to have on the VBO the triangles sorted by octree's nodes. If you don't want to repeat the vertexs, you need a double VBO.
    I tried doing that something like this:

    Code :
    void COctree::DrawOctree(COctree *pOctreeNode)
    {
     
     
    	// checamos que existan datos del nodo
    	if( !pOctreeNode )
    		return;
     
             static int numTriangles = 0;	
             if( pOctreeNode->IsSubdivided() )
    	{
    		numTriangles += pOctreeNode->GetTriangleCount();
    		pOctreeNode->m_TriangleOffset += numTriangles;
    		// dibujamos recursivamente todos los nodos
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_LEFT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_LEFT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_RIGHT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[TOP_RIGHT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_LEFT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_LEFT_BACK] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_RIGHT_FRONT] );
    		DrawOctree( pOctreeNode->m_pOctreeNode[BOTTOM_RIGHT_BACK] );
    	}
     
    else
    	{
    glDrawArrays( GL_TRIANGLES, pOctreeNode->GetTriangleOffset(),pOctreeNode->GetTriangleCount()*3 );	
     
    }
    }
    but it doesnt work either.... what may be wrong?

    as for what Ido Ilan and yooyo said... i read about index arrays, and understand how call them with the opengl functios, but i dont undertand how can i create the indices? can you give me an example for doing that with my octree?

  7. #7
    Advanced Member Frequent Contributor yooyo's Avatar
    Join Date
    Apr 2003
    Location
    Belgrade, Serbia
    Posts
    872

    Re: VBO problem

    Imagine you have array of vertices.. v0... vN and array of triangles. Triangle is set of 3 indices in vertex array (ex. 0,1,2). Index buffer looks like:
    0,1,2, 0,1,3, 0,2,4, ...

    In octree, store all vertices in VBO and store indicies in IBO node by node. Usually, app will send to render whole node.

    Your code in first post is wrong. It send whole octree to render. It's better to send only visible nodes.

  8. #8
    Junior Member Newbie
    Join Date
    Apr 2007
    Posts
    12

    Re: VBO problem

    greetings,

    Originally posted by yooyo:
    Imagine you have array of vertices.. v0... vN and array of triangles. Triangle is set of 3 indices in vertex array (ex. 0,1,2). Index buffer looks like:
    0,1,2, 0,1,3, 0,2,4, ...

    In octree, store all vertices in VBO and store indicies in IBO node by node. Usually, app will send to render whole node.
    ok, i think i get it, but i have some question:

    so if i have this verts:
    verts[0] = {12,15,11}
    verts[1] = {12,5,12}

    i will have this indices:
    indices = {0,1,2,0,3,0}

    1.-is that correct?

    2.-whats the advantage of doing that? isnt that harder and more memory consumption for long meshes?

    3.- isnt it possible solving my problem the way that speed said?, i yes, then what could be wrong with my code? (the last i posted)

    Originally posted by yooyo:

    Your code in first post is wrong. It send whole octree to render. It's better to send only visible nodes.
    it isnt wrong hehe, i just cut down that code to keep the post simple and focus on the problem, it only draws the visbles nodes, but thanks for your advice.

  9. #9
    Advanced Member Frequent Contributor yooyo's Avatar
    Join Date
    Apr 2003
    Location
    Belgrade, Serbia
    Posts
    872

    Re: VBO problem

    Index buffers allows to "reuse" vertices in mesh. Difference between glDrawArrays and glDrawElements calls is in how they work.
    Imagine cube... It have 8 vertices and 12 triangles.
    - Using glDrawArrays VBO must have 36 vertices (3*12).
    Code :
    glDrawArrays(GL_TRIANGLES, 0, 36)
    - Using glDrawElements VBO must have 8 vertices and 12 triangles (36 indices).
    Code :
    // bind your vertex VBO
    ...
    // bind index buffer
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexVBO);
     
    glDrawElements(GL_TRIANGLES, 0, 36, GL_UNSIGNED_INT, OFSPTR(0));
    Anyway... in both cases same number of vertices will be transformed, but in case of indexed vertex buffer, memory footprint is smaller and (im not 100% sure in this) indexed vertex buffers can be more vertex-cache-friendly.

    Bottleneck in VBO can be pointer setup. glVertexPointer call is very expensive, and try to avoid to call it frequently. Bottleneck can be vertex memory aligment. Avoid odd offsets for vertex attributes.

    edit: typo

  10. #10
    Junior Member Newbie
    Join Date
    Apr 2007
    Posts
    12

    Re: VBO problem

    ok thank you ,but... so there isnt a way to it like speed said?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •