Skip to main content
GameDev.net gamedev.net
🔒 Locked

Need help speeding up rendering time

Started by british Aug 10, 2007 at 11:50 AM 17 replies 3.9k views
Original Post
british
british
Hi, The problem I'm having is with a program I am writing view large models using OpenGL. I am using display lists, which already considerably improves rendering speeds, but I am still far from what I need. I am fairly new to 3D programming, but not programming in general. I don't know any techniques to increase rendering speed. Using a ~450,000 triangle model, I get about 30 fps (on a very powerful machine). I need to load models which exceed 1,500,000 triangles and would like to get to 60 fps. What else can I do to improve speed? Thanks!
shwasasin
shwasasin
With such high poly-counts, you're probably not going to get 60 FPS unless you have a darned good system. But in either case, you'll need to provide more information than what you currently have.

- What is the target machine (processor, graphics card) you want to run this on at 60 fps?
- What Platform/API/Compiler are you using?
- How are you storing/drawing your geometry?
Dancin_Fool
Dancin_Fool
Are you using VBO's for the vertex data?
rollo
rollo
Can you preprocess these models? If the whole one shows on screen at once you can run simplification algorithms on it that removes triangles where it wont make a big visual impact. If the whole model isnt visible you can do some spatial partitioning on it and make sure to only draw the visible chunks. It all depends on what type of data it is you have, so please give more information.
Ashkan
Ashkan
Have you considered optimizing your models for better vertex cache performance and less pixel overdraw? ATI Tootle is a good one to look into.
british
british
Thanks for all the help! Here are the answers to your questions and comments:

I'm not trying to run this on any particular system, but I would like it to run faster on at least my system. I'm compiling my code on Windows using GNU's GCC compiler (C++) and I'm using OpenGL.

The data I'm trying to display is actually a 3D organ obtained from a CT scan. I can't do much to modify the model before it is loaded into my program and it is loaded as one big mesh. (I don't know if this information is helpful at all.)

Triangles are stored in an array of my own structure called Triangle. This triangle structure holds the indexes of the three vertices of the particular triangle. The vertices are in turn stored in another structure which holds their coordinates and normals. I don't need materials and I do use lighting. I draw using:

glNormal3fv( m_pVertices[index].m_vertexNormal );
glVertex3fv( m_pVertices[index].m_coordinates );

This is done in a Display List, so I simply call the display list to render. I tried using vertex arrays and saw no difference in performance. I tried using VBOs and had some difficulty compiling my code; I kept getting library reference problems so I eventually gave up.

I am interested in what you guys mentioned at the end about preprocessing and vertex cache optimization. However, as I am still fairly new to this stuff, I'm not sure what you mean.

Thanks again for all the help guys!
SimonForsman
SimonForsman
Quote:
Original post by british
Thanks for all the help! Here are the answers to your questions and comments:

I'm not trying to run this on any particular system, but I would like it to run faster on at least my system. I'm compiling my code on Windows using GNU's GCC compiler (C++) and I'm using OpenGL.

The data I'm trying to display is actually a 3D organ obtained from a CT scan. I can't do much to modify the model before it is loaded into my program and it is loaded as one big mesh. (I don't know if this information is helpful at all.)

Triangles are stored in an array of my own structure called Triangle. This triangle structure holds the indexes of the three vertices of the particular triangle. The vertices are in turn stored in another structure which holds their coordinates and normals. I draw using:

glNormal3fv( m_pVertices[index].m_vertexNormal );
glVertex3fv( m_pVertices[index].m_coordinates );

This is done in a Display List, so I simply call the display list to render. I tried using vertex arrays and saw no difference in performance. I tried using VBOs and had some difficulty compiling my code; I kept getting library reference problems so I eventually gave up.

I am interested in what you guys mentioned at the end about preprocessing and vertex cache optimization. However, as I am still fairly new to this stuff, I'm not sure what you mean.

Thanks again for all the help guys!


You really shouldn't use glVertex... (immediate mode) as its slow as ....

Take a look at glDrawElement or GL_ARB_vertex_buffer_object
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
swiftcoder
swiftcoder
Quote:
Original post by british
Thanks for all the help! Here are the answers to your questions and comments:

I'm not trying to run this on any particular system, but I would like it to run faster on at least my system. I'm compiling my code on Windows using GNU's GCC compiler (C++) and I'm using OpenGL.

The data I'm trying to display is actually a 3D organ obtained from a CT scan. I can't do much to modify the model before it is loaded into my program and it is loaded as one big mesh. (I don't know if this information is helpful at all.)

Triangles are stored in an array of my own structure called Triangle. This triangle structure holds the indexes of the three vertices of the particular triangle. The vertices are in turn stored in another structure which holds their coordinates and normals. I don't need materials and I do use lighting. I draw using:

glNormal3fv( m_pVertices[index].m_vertexNormal );
glVertex3fv( m_pVertices[index].m_coordinates );

This is done in a Display List, so I simply call the display list to render. I tried using vertex arrays and saw no difference in performance. I tried using VBOs and had some difficulty compiling my code; I kept getting library reference problems so I eventually gave up.

I am interested in what you guys mentioned at the end about preprocessing and vertex cache optimization. However, as I am still fairly new to this stuff, I'm not sure what you mean.

Thanks again for all the help guys!


The most immediate method of getting a speed-up would be to go back to using vertex arrays, setup a separate array for the indices, and render using glDrawElements - make sure you are rendering as much of the model in a single call to glDrawElements as possible.

That will only provide a moderate speed-up, but it gets your vertex data in the right format for VBOs, and VBOs should be your next step. VBOs should be pretty straight forward, glGenBuffer() two buffers (one for vertex and normal data, the other for indices), glBindBuffer() and glBufferData() to set the size and upload the arrays into the buffer. When you go to render, glBindBuffer() both buffers, and then render as you would arrays, just using buffer offsets instead of pointers.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
shaderx
shaderx
how bad do you need to draw a 1.500.000 triangles model , if it's possible try to use a lower resolution mesh with normal mapping , it could be usefull also binding the texture for rendering is slow ,so make sure in case you use multiple textures to bind the texture then draw every triangle to that uses that texture so you only do it once per texture
Ashkan
Ashkan
OK, I'd try to shed some light on this since all that might seem daunting at first.

The method of rendering you're currently using is called immediate-mode rendering, where vertices are sent to the card one by one. The first problem with this method is that it involves a lot of API calls which makes for a lot of driver work and TENDS (can't say for sure since its tough to judge without precise profiling of the application) to make your application CPU-bound. As the name implies, the performance of a CPU-bound application is only affected by CPU speed. Generally you want to balance the load and keep both processors (CPU and GPU) synchronized, so one wouldn't starve to death. The second problem with immediate-mode rendering is the bus traffic caused by sending all the vertices each single frame. It would be great if we could just store our data somewhere and pass a pointer to it to the card, instead of sending all the data each frame. This is what the newer methods do, which significantly reduces bus traffic.

Another method to reduce bus traffic and more importantly to take advantage of the post-transform vertex cache is the use of triangle lists. You can NOT take advantage of post-transform vertex cache unless you send your data in form of indexed triangle lists. That's why you should almost always try to use triangle lists instead of sending your data in big vertex streams.

One last important issue is where you actually store your vertex and index data. For faster access you may store your buffers in VRAM or AGP memory instead of system memory.

So, to summarize, first convert your data to indexed triangle lists, store your vertices in VBOs and use some form of vertex cache optimization in case you're still not happy with the performance. You may then look into mesh simplification algorithms as a next step.

Good luck
british
british
OK, thanks a lot for the help! I converted to Indexed Vertex Arrays and I will try getting VBOs going. Your posts have helped a lot. I just have a little question about triangle lists. I googled them and I got the impression that they help when you are using several textures, but I am actually using NO textures. Is it still beneficial to use triangle lists?

Thanks!
PfhorSlayer
PfhorSlayer
The reason that indexed triangle lists are helpful is due to the GPU's post-transform vertex cache. Since you are using indices to specify which vertices make up each triangle ([0, 1, 2], [0, 2, 3], etc), the vertex cache can store the transformed vertices, so you don't need to transform the same vertex more than once. The cache is of limited size, of course, so yet another optimization step you can do is to re-arrange the triangles so that the same indices are used as close together as possible, to take advantage of the cache.
Ashkan
Ashkan
Yes it is beneficial. First of all using index buffers reduces bus traffic. A set of vertices alone can form a mesh, but for this to be applicable some vertices must be sent to the card more than once. Triangles usually share vertices. If a vertex is shared by n triangles and you're using an array of vertices alone to represent and render that mesh, that vertex must be sent n times. This is a waste of bandwidth since vertices suffer from post-depression obesity [wink]. They can get fat way too fast. Even if your vertices are composed of position and normal data alone we're talking about vertices that are 24 bytes in size.

Index buffers solve this problem by avoiding duplicate data to be sent to the card. Each new vertex is sent only once. All later references to that vertex uses an index. Indices are only 4 bytes in size so this is a huge saving.

Please note that this reduction in bus traffic doesn't necessarily translate to speed ups. If your application's current bottleneck is not located at this stage, this would result in no performance gains. PCIe allows for a maximum theoretical bandwidth of 4GB/s simultaneosly available to and from the GPU, so you might not hit this limit easily. The best way to optimize is to profile first so you would exactly know where the bottleneck is located, but that's another story...

As already pointed out, the more important advantage of using indexed triangle lists lies in the utilization of post-transform vertex cache. This is where the ordering of triangles plays an important role (each trio of indices represent a triangle).

Quote:

Indexed primitives have replaced strips and fans as the most common rendering primitive in graphics hardware today. When rendering each triangle, the vertices it uses must be processed (for example, transformed to screen space and lit in various ways) before rendering. Indexed rendering hardware typically uses a small cache of vertices to avoid re-processing vertices that are shared between recently-rendered triangles. Using a moderately-sized cache (anywhere between 12 and 24 vertices is common) reduces the load on the vertex processing pipeline far more than the older non-indexed strips and fans model – often halving the amount of work required per triangle.

However, the vertex cache relies on the ordering of the triangles to be optimised for its characteristics. If the triangles are sent in a random order, the vertices almost always miss the cache and there is no benefit obtained. If triangles are sent in clusters so that each triangle is close to previously-rendered triangles, it is more likely that more of its vertices are still in the cache.


The above paragraph is directly quoted from Tom Forsyth's Linear-Speed Vertex Cache Optimization. You might look into that for a more in-depth understanding of triangle re-ordering. ATI Tootle is an already written and tested library, if you don't want to get into details of implementing such a system.

british
british
Alright, I got some results! Using VBOs my framerate goes up to 60 when I'm inside the model (which is the main objective). It's still only 30 when I'm outside the model and the entire thing is on the screen.

I'm wondering though, at this point, is there a way to do a sort of quick render which somewhat reduces the quality of the model (which won't matter since it's much smaller when all the polygons are on the screen)?

Thanks again!
PfhorSlayer
PfhorSlayer
What you want there is an LOD scheme. When you're further away than some distance, render a lower-quality (that is, fewer triangles) version of the mesh. How exactly you calculate that lower-quality version is up to you. There are a number of libraries designed specifically for that purpose, but I couldn't tell you any off the top of my head. Google should know!
technomancer
technomancer
for mesh simplification and other mesh processing GTS is very good and open source :)
british
british
Just what I needed! Thanks again to all!
zedz
zedz
contary to what some ppl have mentioned.
VBOs are NOT gonna give u a speed up compared to DLs (it doesnt matter wether theyre made with immediate mode or not, since the driver takes the immediate mode calls + compiles them into a displaylist, which is no doubt how the driver writers consider it to be a near optimal solution of storing your data )

since the fps changes depending on how u view the model, i assume the number of pixels drawn is a problem
try making the screen smalleg 400x300. what fps do u get? is it much better than a normal sized window?

as someone mentioned look into LOD
also its normally good to break the model (esp if its big like yours are) into smaller chunks, < ~64,000 verts (u will have to do this anyway if the model consists of different materials)
Niwak
Niwak
Here are my 2 cents ;
- VBO should not give you any speed boost.
- The speed boost you had with glDrawElements is due to the fact that you are using indexed triangles instead of direct triangles. You can get this further using a vertex cache coherency optimization algorithm. The well known algorithm is the one's from Hoppe which is somewhat complicated to implement, Tom Forsyth's one is easier (but less optimal).
- Just in case, check that you did enable face culling and depth testing, check that your rendering surface is not unusual (no antialiasing, 8 bits per pixel).
- I'm not sure if it matters with display list, but it is usually well advised to provide data in an interleaved form, i.e. store your data with coords / normals interleaved and not with all coords somewhere and all normals elsewhere.
- Not sure if that will work, but I had a similar case where I had tons of vertices which resulted in less pixels (i.e. some tris where 1 pixel wide). In that situation, per-pixel lighting whould be more efficient. Here is a great resource for this
- As has already been said multiresolution meshes are a very good solution too.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.