PDA

View Full Version : Render geometry mesh of 3,4,5+ vertices per face



Narann
10-18-2011, 01:36 AM
Real title: Best efficient way to render geometry mesh of 3,4,5+ vertices per faces?

Hi OpenGL community!

I'm working on a way to render geometry objects in the most efficient way (some are very big). I've found some ways.

I deal with VBOs (GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER)

Notice that geometry indices are stored "by face". I need to go through each face to find his indices (like many 3d modeler actually).


glMultiDrawElements
The first one was using glMultiDrawElements. I made an array of indices (with repeated indices as it is stored by face) and a array of "cout" (4,4,4,4,3,5,4,4...etc).

But after some investigates, I had discover that using glMultiDrawElements was like to do a CPU loop of glDrawElements, which is most easy to write actually (is that true? glMultiDrawElements is not done in hardware?)

Example: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=296001&page=1 and http://www.opengl.org/registry/specs/EXT/multi_draw_arrays.txt we can read:

It has the "same effect" as:


for(i=0; i<primcount; i++) {
if (*(count+i)>0) DrawElements(mode, *(count+i), type, *(indices+i));
}

By "same effect" this mean "in the GPU"? Or really in the CPU code execution? I don't understand actually...

This seems logical as the array of index array is never put in the GPU but why create/use a glFunction to do what CPU can do easely? This is the point I don't understand...

Three time render
So I'd start to draw my geometry in three time:

Three arrays (each containing indices of his type):
indexTriArray (3 indices each) indexQuadArray (4 indices each) indexPolyArray with his countPolyArray (indices are stored in countPolyArray)
Then two glDrawElements and one glMultiDrawElements:
glDrawElements to render all GL_TRIANGLES (indexTriArray) glDrawElements to render all GL_QUAD (indexQuadArray) glMultiDrawElements to render the GL_POLYGONS (indexPolyArray and countPolyArray)
Is this way is more efficient that the first one?


glPrimitiveRestartIndex
The last way seems to be glPrimitiveRestartIndex but I'm not sure this is adapted to in my specific case because I have very changing indices number per primitive.


What do you think?
Maybe I've missed something and there is a more efficient way to do that.

I'm sure anyone that know OpenGL enough already had to deal with that.

Any idea?

Thanks in advance and have a good day! :)

aqnuep
10-18-2011, 02:23 AM
I'm sure anyone that know OpenGL enough already had to deal with that.

I don't think so as this is not a usual use case. Most renderers simply use triangle lists, triangle strips, or in case tessellation is used they use fixed size patches.

What you want to achieve is not supported by current hardware, at least not with the fixed function indexed primitive fetching.

However, you can possibly do it in OpenGL by implementing your own vertex pulling. That means that you simply don't use indexed primitive drawing but feed somehow your customized indices as integer vertex attributes and then you fetch the actual vertices and their attributes from a buffer texture.

mhagain
10-18-2011, 02:59 AM
It would be possible to draw this mesh with a single glDrawElements (GL_TRIANGLES, ... call, provided you set up your indices correctly. That's most likely to offer the best performance on PC hardware.

tksuoran
10-18-2011, 03:00 AM
Simply triangulate your mesh. If your faces are convex (they typically are) then doing fan or strip triangulation is easy.

If you want best efficiency, you should do vertex cache optimization after triangulating the mesh. For example: Linear-Speed Vertex Cache Optimisation (http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html)

Once you have triangulated (and optimized) mesh, you can draw it with a single glDrawElements() - assuming there is no multiple materials that would require to split to multiple draw calls.

Narann
10-18-2011, 03:13 AM
Thanks for answers! :)


I don't think so as this is not a usual use case. Most renderers simply use triangle lists, triangle strips, or in case tessellation is used they use fixed size patches.
Yeah, 3D modelers are not very usual but each one of them have this kind of problem.


However, you can possibly do it in OpenGL by implementing your own vertex pulling.
By "implementing your own vertex pulling", you mean in the GPU side? Is this possible?
If you talk about CPU side, glMultiDrawElements is done for that no?


feed somehow your customized indices as integer vertex attributes and then you fetch the actual vertices and their attributes from a buffer texture.
I think I understand but I'd never done that before (OpenGL noob).

Have you any implementation examples? (I never deal with buffer texture before but what you said seems to be very interesting actually).

Thanks in advance! :)

Narann
10-18-2011, 03:19 AM
@mhagain, @tksuoran

Thanks for answers and link!

This is true, your way is good rendering a shaded geometry but the prob is mainly to draw the wireframe (Sorry, I did not mention that).

Maybe there is a more common specific way to render correct wireframes.

aqnuep
10-18-2011, 03:56 AM
Yeah, 3D modelers are not very usual but each one of them have this kind of problem.

3D modellers usually still use immediate mode not indexed primitives. You can do the same, but then don't be surprised if you get very awful performance.



However, you can possibly do it in OpenGL by implementing your own vertex pulling.
By "implementing your own vertex pulling", you mean in the GPU side? Is this possible?
If you talk about CPU side, glMultiDrawElements is done for that no?
Of course you can do it on the GPU side. Current hardware knows much more than just drawing simple meshes with textures.




feed somehow your customized indices as integer vertex attributes and then you fetch the actual vertices and their attributes from a buffer texture.
I think I understand but I'd never done that before (OpenGL noob).

Have you any implementation examples? (I never deal with buffer texture before but what you said seems to be very interesting actually).
I don't know any examples published using programmable vertex pulling, but if you get familiar with buffer textures and vertex shader texture fetches I think you can figure it out. There will be at least one published next summer in a book that I don't want to name here ;)

Anyway, if you can go with the triangulation approach proposed by the others, I would rather go with that as it is better performance-wise.

Narann
10-18-2011, 04:10 AM
@aqnuep
Thanks for answers.

You talk about OpenGLInsight? ^^

About triangulation, the problem still remain with wireframe... :(

Narann
10-18-2011, 05:40 AM
After a couple of investigates, I found this (geometry shaders at the end):

http://cirl.missouri.edu/gpu/glsl_lessons/glsl_geometry_shader/index.html
http://www.opengl.org/wiki/Geometry_Shader_Examples

From what I understand, I put indices count array in the GPU as an uniform buffer texture and use a geometry shader to create myself primitives (with EmitVertex() and EndPrimitive()).

Am I write? Or completely wrong? :p

Thanks in advance. :)

tksuoran
10-18-2011, 07:59 AM
Geometry shaders are not needed here, and they are only going to make performance worse.

Generate different index buffers for filled faces and for wireframe. You can still reuse the vertex buffer, unless you reorder vertices in the order indices use them.

You can draw wireframe with GL_LINES with suitably generated index buffer. Collect all unique edges from your faces. So if edge A,B exists, you do need need to add edge B, A.

Narann
10-18-2011, 08:30 AM
Ok thanks. So forget about shader.

For wireframes I use a custom index buffer generate using the condition "if edge AB exists, continue".

For filled face (not sure strip triangle could work, I had to try), I can use my "three time render" method (once for GL_TRIANGLES, once for GL_QUADS, once for GL_POLYGONS) or use the link you give to me (I have to understand it first).

Thanks a lot! I will have to work on that! :)