Sign in to follow this  

Display Lists, other ways to speed up code

This topic is 3627 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I've recently been working on a new game project (a full 3D space shooter/adventure game) and I've been noticing some relative slowness in the engine... As of right now, the program draws one 3D model of ~500 vertices and 20,000 "stars" in the starfield (they are rendered way out in the distance as small untextured quads). I have just put the starfield drawing code into a display list and yielded a boost of ~8 to 10 fps so i'm getting around 45fps at the moment. I have a single point light and some ambient light being applied to the 3D model (only one model at the moment for testing of ship control code). Are there any good ways to boost execution speed? My Dev Machine Specs: Thinkpad T61 2.0 Ghz Core 2 Duo 1GB DDR2 Intel Integrated Graphics

Share this post


Link to post
Share on other sites
Quote:
20,000 "stars" in the starfield (they are rendered way out in the distance as small untextured quads).


Is that 20,000 individual draw calls or a single draw call with 20,000 quads?

If it's 20,000 individual draw calls, that's likely to be what's sapping your performance. Each draw call has a CPU overhead inside the graphics API and the device driver for the GPU. Depending on the driver (AFAIK, OpenGL isn't my main area), each entry in the display list can still equate to an individual draw. Each time you recreate the display list there is also CPU overhead (to translate from the generic OpenGL command into the hardware specific command).

But that's still a guess - the only way to know for sure is to profile your application with both a CPU and a GPU profiler to find where the bottlenecks are.

Share this post


Link to post
Share on other sites
Wow, I really should have noticed that earlier. It was 20,000 different draw calls each one with a glColor4d() call. I just changed it into one draw call with one glColor4d() call for a speed boost of about 10fps. Its not pretty consistent around 60fps (which means a system with a reasonable graphics card will probably get far more -- I'll test on my desktop and check).

Thanks a lot for that suggestion. I probably never would have noticed that myself. Any other suggestions?

Share this post


Link to post
Share on other sites
Quote:
Original post by medevilenemy
As of right now, the program draws one 3D model of ~500 vertices and 20,000 "stars" in the starfield (they are rendered way out in the distance as small untextured quads).

If they are rendered "way out in the distance" then why not just use a texture? Or is the distance not big enough that the stars effectively form a background? Then perhaps it would make sense to draw a map with stars very far out and only render 10% as quads?

Share this post


Link to post
Share on other sites
I've thought about that, but for that to actually work (if I'm imagining this right) the starfield would actually need to be a huge textured sphere in order to get a proper view of the starfield (I have a 6dof camera). Also, I wanted to capture that really nice "twinkling" of the stars as you move and turn, which my current method provides. I may at some point switch over to a textured system if I decide to make the starfield more complex (nebulae and such) as those would require some rather complex particle effects to look good if rendered dynamically. Thanks for the suggestion, though.

Share this post


Link to post
Share on other sites
Quote:
Original post by medevilenemy
Wow, Just for anyone who doubts the value of a proper vid card over integrated graphics:

Execution Speed on Dev Machine: ~60fps


Have you ruled out vsync?

Share this post


Link to post
Share on other sites
Why didn't you use glPoint? If they're far away it could work well, and it's gonna be 3 less calls... Or you can use triangles too, it's only 1 call less but it's free, and if they're small you won't notice any difference.

If you plan using extensions, take a look on vertex arrays, they are way faster. And you can try the point sprite extension too, it's only 1 call (glpoint) and you get a full textured quad ;)

Share this post


Link to post
Share on other sites
RESULTS: With triangles instead of quads, framerate is up to ~65fps with the ship in the camera scene, and ~75 with the ship out of the scene.

[EDIT:] Could someone perhaps post a link to a reference for glPoint? I can't seem to find it.

Share this post


Link to post
Share on other sites
Glpoint is not the way to go because the size of the points is always == GL_POINT_SIZE. the point sprite extension,however, is perfect for this purpose, as would be a display list of GL_QUADS. You could have glPoints for the further away stars, and depending on their proximity you could render them in increasing complexity.


>1 light year away: GL_POINTS
0.3 light years away: textured tris
<0.1 light year away: textured ball of burning gas.
10,000km away: animated ball of burning gas with solar flares.

< diameter of star: very close fog plane in colour of star, flashes of burning gas, very bright ambient light.

What you could do is change GL_POINT_SIZE for each star you render. But, the points will be square on screen.

Because objects far away take an aparrently long time to move closer, you could create a new display list one every 30ms, with the scale i mentioned above.

You could also draw the stars at 1/64 of their actual distance, and vary the size and the color to simulate the distance. Don't forget to move them 1/64 of the speed to compensate. That way, you could shrink the view frustum and use a smaller depth buffer for a further speed boost.

Share this post


Link to post
Share on other sites
judging by that description, I think i'll stick with what I am using. I currently have a display list of triangles (with one call to glBegin(GL_TRIANGLES);) All of the "stars" are drawn on a unit sphere that has simply been expanded to astronomical size. Thanks anyway! With everyone's help, I've still managed to practically double the framerate. I'm still taking a drop of about ~10 fps whenever the ship model is in the camera scene, so I guess its time to start finding ways to make model drawing faster.

My models are in OBJ format with pre-calculated normals, with one texture applied to each model. Ambient light and one diffuse point-light is then applied.

Share this post


Link to post
Share on other sites
The glPoint works this way:
glBegin(GL_POINTS);
glVertex3fv(position);
glEnd();

but they've the problem shotgunnutter says, I didn't remember it. Maybe if you try adjusting it, it could work, but the problem is that there are sizes supported by some graphic cards, and sizes unsupported (it depends on the implementation).

You can look at the begining if the graphic card support the range of point sizes that you're going to use, if they're supported great!, if not, you could stay with triangles :P

Share this post


Link to post
Share on other sites
You could have impressive performance boosts by using Vertex Buffer Objects (VBOs), which are an OpenGL extension which is VERY common on graphics card, I'm sure you'd have no problem on geforce 3 series graphics card.

For VBOs, look here or on NeHe.

If you don't want to mess around with extensions (you should though), you can batch your vertices in an array, and use glVertexPointer combined with glDrawArrays (or glDrawElements, or glDrawRangeElements) to render them. This should be a little bit faster then using display list, but nowhere as fast as VBOs.

If you were using DirectX8, DirectX9, DirectX10, or OpenGl3 (maybe I'm mistaking for OGL3), you'd be pretty much forced to use VBO-equivalent functionality, so why not get used to it right now?

Share this post


Link to post
Share on other sites
Yeah VBO are best, but arrays are quite better than standard ogl calls. And they're supported by the "standard" OpenGL 1.1, so you could look for them without the hassle of initializing extensions.

Share this post


Link to post
Share on other sites
How would I apply that to my model drawing routine? (The drawing function is below)


void DrawObj(ObjModel dat, int img, float x, float y, float z) // Draw the actual object
{
int i;
int j;
glColor4d(0.0, 0.0, 0.0, 1.0);
//glEnable(GL_LIGHTING);
glBindTexture(GL_TEXTURE_2D, img);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
glBegin(GL_TRIANGLES);
for(i=0; i<dat.NumTriangle; i++)
{
for(j=0; j<3; j++)
{
glNormal3d(dat.NormalArray[dat.TriangleArray[i].Normal[j]].X+x, dat.NormalArray[dat.TriangleArray[i].Normal[j]].Y+y, dat.NormalArray[dat.TriangleArray[i].Normal[j]].Z+z);
if(dat.NumTexCoord > 0)
glTexCoord2f(dat.TexCoordArray[dat.TriangleArray[i].TexCoord[j]].U, dat.TexCoordArray[dat.TriangleArray[i].TexCoord[j]].V);
//glNormal3d(dat.VertexArray[dat.TriangleArray[i].Vertex[j]].X+x, dat.VertexArray[dat.TriangleArray[i].Vertex[j]].Y+y, dat.VertexArray[dat.TriangleArray[i].Vertex[j]].Z+z);
//glNormal3d(dat.NormalArray[dat.TriangleArray[i].Vertex[j]].X+x, dat.NormalArray[dat.TriangleArray[i].Vertex[j]].Y+y, dat.NormalArray[dat.TriangleArray[i].Vertex[j]].Z+z);
glVertex3d(dat.VertexArray[dat.TriangleArray[i].Vertex[j]].X+x, dat.VertexArray[dat.TriangleArray[i].Vertex[j]].Y+y, dat.VertexArray[dat.TriangleArray[i].Vertex[j]].Z+z);
}
}
glEnd();
glDisable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//glDisable(GL_LIGHTING);
}




[EDIT:] For my starfield, I'm going to stick with triangles for now. I don't see any particularly compelling reason to use anything else at the moment.

[Edited by - medevilenemy on December 4, 2007 8:41:50 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Istarion
The glPoint works this way:
glBegin(GL_POINTS);
glVertex3fv(position);
glEnd();

but they've the problem shotgunnutter says, I didn't remember it. Maybe if you try adjusting it, it could work, but the problem is that there are sizes supported by some graphic cards, and sizes unsupported (it depends on the implementation).

You can look at the begining if the graphic card support the range of point sizes that you're going to use, if they're supported great!, if not, you could stay with triangles :P


The problem with GL_POINTS is that, regardless of the point's distance from the camera, they are always a fixed size. so, if you have some points spaced out over a wide area you see separate points, but move away and you start to see a single large mass. You can change their size, but that simply exaggerates this effect.

What you can do is, in code, dynamically change GL_POINT_SIZE depending on a point's distance from the camera. That way, you can artificially make them change size as they move further away. You can calculate what size they should be using pythagorus.

Share this post


Link to post
Share on other sites
Ouch, I didn't remember that too. Well you can change the size every time you are going to draw a point, and you can sort them before to make less OGL calls. However, 20.000 distance calculations aren't much?? I'm not sure...

Well to use vertex arrays you have to replace all your drawing code, they work quite different. Here are two good links to use vertex arrays:
NeHe example:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=45
OpenGL Specification:
http://www.cs.rit.edu/~ncs/Courses/570/UserGuide/OpenGLonWin-15.html

but basically, all you have to do is a three step routine:
1. Activate the array(s).
2. Load data into the array(s).
3. Draw the array.

Since you're using textures and normals, you will need 3 arrays, one for every different data. So you activate these three arrays, load them with data, and then execute the drawing command, pretty straightforward isn't it? :P

Share this post


Link to post
Share on other sites
Alright, I've done some research, and Vertex Arrays/Vertex Buffers seem to be a good solution for me (thanks for the solution, its a great idea), however I can't seem to find any tutorials or suggestions regarding their use for multiple objects (I will have numerous 3D models in each scene) Is it possible/practical to manage that? If so, how would I do that?

[EDIT: Better Explanation] What I mean is that all the examples I have seen create a buffers/arrays for a single shape which is defined in-code. What I have are a variable number of shapes which are loaded into arrays. each model, once loaded, occupies a object containing an array each for vertex coords, tex coords, and normals. What I seem to need to be able to do is create a VBO/VA (don't know what method is best) for each model upon load, and somehow modify my drawing function above to draw the VBO/VA. Therein lies my problem, as there don't seem to be any examples of something like that.

Share this post


Link to post
Share on other sites
Are you sending GL commands even for stars that are not currently visible (ie behind you)? Using a scene graph or similar culling methods can reduce drastically the amount of data to be sent to the graphics card, and greatly improve the performances.

Share this post


Link to post
Share on other sites
In your draw function...


void DrawObj(ObjModel dat, int img, float x, float y, float z);


...Assuming that this is a fairly complex class with all of the model data in it. It should most definitely be passed by reference. The way you currently have it it is copying all of the data to another location every time you call the function. Try something like this:


void DrawObj(const ObjModel &dat, int img, float x, float y, float z);


The "const" is just to promise that you won't change the data.

Depending on the size of your model... this will speed it up.

Share this post


Link to post
Share on other sites

This topic is 3627 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this