PDA

View Full Version : Creating Complex Objects at Initialization



Nuclear
05-20-2010, 10:04 AM
I'm trying to create a static randomized fractal landscape, with other objects which navigate around it. Currently the landscape is generated in the display function, and so has to be re-rendered in every frame, which is extremely inefficient, and prevents randomization. I tried to move the function to create the object so that it is called at initialization, and thus it will only be rendered once, however now the object isn't getting rendered at all. Is it only possible to render objects with the display function? Or am i doing something wrong? Cheers

Yomboprime
05-20-2010, 11:55 AM
How do you draw it? VAO, immediate mode...?

Nuclear
05-20-2010, 01:19 PM
I'm just using a recursive algorithm to create fractals and drawing polygons as i go along.

mhagain
05-20-2010, 02:22 PM
Yes, but "how"? glBegin/glEnd? glDrawArrays? glDrawElements? etc?

Nuclear
05-20-2010, 02:29 PM
glBegin/glEnd

mhagain
05-20-2010, 03:23 PM
There's your performance problem straight away then. For any significant amount of discrete polygons glBegin/glEnd are slow. I assume that you're using the GL_POLYGON primitive type from your mention of "polygons", and for textured/filled primitives this is the same as GL_TRIANGLE_FAN, which can be split out into it's individual triangles by taking vertexes in the order 0/1/2, 0/2/3, 0/3/4, etc.

You therefore need to switch it to an indexed triangle list. Building the geometry dynamically at runtime doesn't lend itself too well to VBOs (although they can be faster in certain cases even in this circumstance).

A rough algorithm would be:



- set up 2 big static buffers, one for vertexes and one for indexes (only do this once, not per frame!)
- set up vertex array pointers
- init numverts and numindexes to 0
- loop through all your surfaces; for each surface:
- check for overflow or state change and render then re-init numverts and numindexes if so
- copy in vertexes to the buffer for vertexes
- copy in indexes to the buffer for indexes
- increment numverts and numindexes by the appropriate amounts
- if numverts or numindexes > 0 draw anything left over
- take down vertex array pointers


Rendering is done via glDrawElements, and you should use 16-bit indexes in preference to 32-bit as they (1) are less data to send to the GPU, and (2) are more widely supported in hardware. This caps the sizes of your buffers at 65535 (hardware needs the other 1 for overhead).

Copying vertexes is straightforward enough, but indexes can be a little trickier. A loop like this should work:


for (int i = 2; i < numverts; i++)
{
indexes[numindexes++] = numverts;
indexes[numindexes++] = numverts + i - 1;
indexes[numindexes++] = numverts + i;
}

The number of indexes for each polygon is equal to (numverts - 2) * 3, by the way. You don't need to add this to your index counter if you use the numindexes++ method I've given above (it's also cleaner code).

OK, this looks like a lot of work but it won't disrupt your rendering loop too much. It may also seem counter-intuitive that more code runs faster, but that's the way things work with graphics.

There is lots more room for optimization here by the way, but this should be sufficient to get you started.

Nuclear
05-20-2010, 04:35 PM
Thanks alot, I'll give it a try tomorrow. Is there a reason why my current solution doesn't display at all when rendered at initialization?

mhagain
05-20-2010, 04:45 PM
Rendering needs to be done every frame unless you never call glClear or your SwapBuffers function basically. You can optimize to make that render every frame faster, and if your geometry is truly static (and you only use a single texture and never even do frustum culling) you could even get it down to one draw call to render your entire scene with all geometry stored on the GPU. But that's jumping way way ahead, you're better off sticking to learning how to render every frame as optimally as possible for now.