PDA

View Full Version : Need advice about VBOs. See details please.



slavaklimov
06-23-2006, 03:14 PM
Hello everybody!
I need some advice. Here problem.
I have VBO contain several host meshes.
On the map I have multiple instances of each mesh.

Render pipeline

glBindBuffer(GL_ARRAY_BUFFER_ARB,..)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,..)
glEnableClientState(..)
glVertexPointer(..)
for(<each instance>){
glPushMatrix()
glMultMatrix(<instance matrix>)
glDrawRangeElements(<host corresponds instance range>)
glPopMatrix()
}
..

Now I need to use pre-computed vertices colors for each instance. So render data contains from
- constant data: host vertices buffer equals for each instance stored in VBO
- variable data: instance vertices colors buffer unique for each instance stored in system memory

So I need right way to mix constant and variable data. Approx count of instances ~20,000 (forest).

Thanks a lot.

k_szczech
06-23-2006, 07:02 PM
Perhaps instead of passing vertex colors you could put them into 2D texture.
For 32768 instances you need 256 x 128 texture.
You only need to change texture coordinate once per instance.

If you need separete colors for each vertex in a single instance of a mesh then you will have to add one more dimension to a texture:
32768 instances, 16 vertices each:
16 x 256 x 128 (3D texture).

The problem would be generating texture coordinates - you need to change X coordinate per-vertex, so you need a 1D texture coordinate array. In this case you will have to modify Y and Z coordinates on per-instance basis using texture matrix (I guess you modify modelview matrix per-instance).

If you can't use 3D texture for some reason then you can split your instances into groups:
16 groups, 2048 instances per group, 16 vertices per instance, so 16 2D textures, 16 x 2048 each.

Of course if you will use vertex shaders then everything will be much simplier, but you could run into performance problems with that large nuer of instances.

Another solution is to keep one vertex color array (common for all instances of the same object) and additoinally modulate instance by color fetched from texture (one texel per instance = one glTexCoord call per instance).

If you could write something more specific about your forest (why do you want separate vertex colors) then I could give you some specific solution.

slavaklimov
06-24-2006, 03:58 PM
I tried to use glBufferSubData() to modify VBO with vertices colors, but performance penalty reach 50%.

Same task I done before in directx. But dx have one feature - store different vertex attributes in different VBOs (in OpenGL terms).
Seems OpenGl have restruction - one VBO for all data. Or waybe not ?

To k_szczech: you mean to extract vertex colors from texture in vertex shader ?

Here some shots of my forest. I have approx 20 different tree meshes for 6,000 - 20,000 trees on the level. Precomputed vertex ligting fits pretty well. Maybe there are better solution for static lighting ?

http://www.geocities.com/slavaklimov_ua/f1.jpg
http://www.geocities.com/slavaklimov_ua/f2.jpg
http://www.geocities.com/slavaklimov_ua/f3.jpg

sqrt[-1]
06-24-2006, 05:54 PM
Yes you can use multiple VBOs for your vertex data, just make sure the appropiate VBO is bound before calling glVertexPointer(..) (or glColorPointer etc) .


Also make sure you recalculate the vertex data offsets for the new VBO arrangment.

k_szczech
06-24-2006, 07:11 PM
extract vertex colors from texture in vertex shaderInstead of modulating one texture by vertex color you can modulate it by another texture (multitexturing), and leave all vertex colors white.
Unfortunately that wouldn't be enough - you don't want all vertices in a mesh to have the same color, but you could combine both methods.
Instead of:
color = texture1 * vertex_color
you would have
color = texture1 * teture2 * vertex_color

So, all meshes of the same type could have identical vertex colors. Additional shading of entire mesh would come from texture2 (every mesh would have it's own texel in this texture).
You would only need to call glMultiTexCord once per mesh.
This is an approximation - obviously will not give as good results as having separate vertex colors.

No shader needed, except for the idea of storing every vertex color separately in the texture - this would require vertex shader with vertex texture fetch, but would let you specify color for every vertex.

slavaklimov
06-25-2006, 02:11 AM
Yes you can use multiple VBOs for your vertex data, just make sure the appropiate VBO is bound before calling glVertexPointer(..) (or glColorPointer etc) .

Also make sure you recalculate the vertex data offsets for the new VBO arrangment.
It's very interesting.
Did you mean something like this:

glBindBuffer ( GL_ARRAY_BUFFER, vbo_host_coords_and_texcoords );
glVertexPointer (...);
glTexCoordPointer (...);
for( <each instance> ){
glBindBuffer ( GL_ARRAY_BUFFER, vbo_instance_colors );
glColorPointer (..,0);
glDrawElements (...);
}Is it possible ??? How expensive is creation/switching 20,000 color VBOs ?

Or maybe this way:

glBindBuffer ( GL_ARRAY_BUFFER, vbo_host_coords_and_texcoords );
glVertexPointer (...);
glTexCoordPointer (...);
glBindBuffer ( GL_ARRAY_BUFFER, vbo_all_instances_colors );
for( <each instance> ){
glColorPointer (..,<instance colors offset>);
glDrawElements (...);
}?

k_szczech
06-25-2006, 04:07 AM
Why don't you try both and see what you get?

By the way - I've observed something about glDrawElements.
I was calling it once for large mesh (12k polygons but it was large in size), but then I subdivided this mesh into 64 parts (for BSP frustum culling).
So now I was calling glDrawElements 64 times per mesh (vertex and index arrays did not change - I was calling glDrawElements on different fragments of index array).
After applying BSP algorithm I've eliminatet more than 50% of sectors. Unfortunately calling glDrawElements once every 200 polygons was much slower for 50% of polygons than calling glDrawElements once for all polygons.
My final solution was to create temporary index array, and instead of calling glDrawElements for each sector I copied all indices for that sector into temporary index array. Then I just called glDrawArrays once for all sectors. It was much faster.
It's just a performance tip, but peraps you can make use of it.