Archived

This topic is now archived and is closed to further replies.

HanSoL0

Optimizing with Vertex Buffers

Recommended Posts

HanSoL0    1210
I''ve got a great playable demo of a multiplayer space combat game that looks good and runs at a silky-smooth 60 fps....as long as you''re running a P4 2.26GHz with 512MB RAM and a GeForce 3....not so great, obviously. I''ve been doing some research on how to get my framerate up on lower-end computers, and I found that it''s apparently not the smartest thing to have a separate vertex buffer for each object in your scene (20 starfighters plus about 800 asteroids). How would one concatenate all those individual vertex buffers from the .x files into one vertex buffer? And after you do that, how do you transform the individual objects independently of each other? Or am I completely misunderstanding and it _IS_ the best thing to do individual vertex buffers? Please help! Ryan Buhr Reactor Interactive, LLC. http://www.reactorinteractive.net

Share this post


Link to post
Share on other sites
Bilgates    128
I don''t have the answer to you question but, when you lock your vertexbuffer, can''t you specify the offset to start writing to you vertex buffer. That way, you can memcpy your second set of verticies after your first set. I don''t know how that''s going to affect transforming though (i''m a little behind in your talents... nice site BTW)

Share this post


Link to post
Share on other sites
masonium    118
if your asteroids, for example, are using the same class type, instead of having a vertexbuffer for each object you can have a static one for a class. Say your asteroid class looks something like this:


  
class CAsteroid
{
D3DXVECTOR3 position;
D3DXVECTOR3 velocity;

.....

IDirect3DVertexBuffer[8/9]* asteroidVB;
};


If every asteroid uses the same .x model, "asteroid.x" or the like, you can make the asteroidVB a static vertex buffer.


  
class CAsteroid
{
D3DXVECTOR3 position;
D3DXVECTOR3 velocity;

.....

static IDirect3DVertexBuffer[8/9]* asteroidVB;
static int numInstances;
};


The numInstances variable is so that you know how many CAsteroids you have initialized. Your constructor/initialization function and destructor can look something like this:


  
CAsteroid::CAsteroid(char* filename, ...)
{
...

if (numInstances == 0)
{
// whatever you use to initialize the VB

LoadMeshToVB(filename);
}

numInstances++;

...
}

CAsteroid::~CAsteroid()
{
...
numInstance--;
if (numInstance == 0)
{
asteroidVB->Release();
}

...
}


This way, you only load the data once and only need one copy of it, but all of your asteroids can access it for rendering. Using this, you save a lot of memory and you don''t have to change the stream source for every asteroid.

As for transforming each object, you can do something like this in your asteroid render function:


  
void CAsteroid::Render()
{
D3DXMATRIX trans;
D3DXMatrixTranslation(&trans, position.x, position.y, position.x);
DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numVertices, 0, numTrinagles);
}


hope this helps

''There''s something out there....something stupid...''
''I think I''m going to be ill. Is that a problem for you?''
''[You] overestimate my conscience by assuming that I have one.''
- Daria

Share this post


Link to post
Share on other sites
HanSoL0    1210
Right, thanks for the reply. I already do most of what you said. I only have one copy of each of about 10 asteroids and I just re-render more instances of each asteroid about 80 times or so. I''m not usin'' too much memory. I just want to reduce the number of DrawIndexedPrimitive() calls. Can this be done by putting all asteroid vertices into one vertex buffer, transforming individual groups of vertices, and rendering the whole vertex buffer with one call to DrawIndexedPrimitive()? Or am I thinking too far outside the box? Your help is much appreciated....

Ryan Buhr
Reactor Interactive, LLC.
www.reactorinteractive.net

Share this post


Link to post
Share on other sites
HanSoL0    1210
I just had a thought. What if I transformed the models individually every frame, and then ripped all the vertex buffers into one big one after all the transformations, and then draw the big VB with one call to DrawIndexedPrimitive()? Would there be a greater performance bonus to performing one VB lock and one call to DrawIndexedPrimitive() than to simply not lock any VBs, but call DrawIndexedPrimitive() 1000 times? In this case, would the individual transformations transfer to the final large vertex buffer?

Ryan Buhr
Reactor Interactive, LLC.
www.reactorinteractive.net

Share this post


Link to post
Share on other sites
masonium    118
The individual transformations would transfer, but I don''t think that the you would gain too much, if any speed. It''s a lot slower to transform a mesh in software probably than it is to make numerous calls ot DrawIndexedPrimitive. Besides, if your vertex buffer is too large that would also decrease the speed.

''There''s something out there....something stupid...''
''I think I''m going to be ill. Is that a problem for you?''
''[You] overestimate my conscience by assuming that I have one.''
- Daria

Share this post


Link to post
Share on other sites
masonium    118
if you''re not heavily dependent on mulitple lights based on the fixed-function pipeline, a vertex shader might increase your performance since all you''re doing is transforming the vertices. But I''m not completely sure about that...

''There''s something out there....something stupid...''
''I think I''m going to be ill. Is that a problem for you?''
''[You] overestimate my conscience by assuming that I have one.''
- Daria

Share this post


Link to post
Share on other sites
James Trotter    432
But if you really want better performance you should look into frustum culling and occlusion culling.
The idea of frustum culling is not to draw anything that isn''t inside your view frustum. Hence reducing the amount of calls to glDrawElements, or the equal DirectX command, (DrawIndexedPrimitive, I think...).
And with occlusion culling, you don''t draw anything that is behind anything else, and not visible to you.
If you implement both of these, I think you will get a much bigger performance-boost, than by just concatenating your vertex buffers.

Share this post


Link to post
Share on other sites
jorgander    180
my occlusion code runs something like this:

1. i have a bit array corresponsding to each triangle in the level (its an fps game). at the start of each frame, the whole array is set to zero (i.e. all triangles are turned off) with a call to memset.

2. i use an octree to turn on all bits in the bit array representing triangles that are 1) in the view frustum and 2) facing the camera.

3. i take all the visible triangles and use occluders to further minimize the visible list.

4. after the occlusion code is done, i rebuild the vertex buffer from the bit array and make a single call to glDrawArrays.

actually, i havent implemented step 3 yet but its in the works. this is only for the level; it doesnt account for API calls to draw other scene elements such as characters, weapons, explosions, etc.

i understand this doesnt really answer hansolo''s question since he was asking about combining buffers, i just thought it might give him or other people ideas about how to further increase framerate.

Share this post


Link to post
Share on other sites
Turbo_Pascal    122
quote:
Original post by HanSoL0
Right, thanks for the reply. I already do most of what you said. I only have one copy of each of about 10 asteroids and I just re-render more instances of each asteroid about 80 times or so. I''m not usin'' too much memory. I just want to reduce the number of DrawIndexedPrimitive() calls. Can this be done by putting all asteroid vertices into one vertex buffer, transforming individual groups of vertices, and rendering the whole vertex buffer with one call to DrawIndexedPrimitive()? Or am I thinking too far outside the box? Your help is much appreciated....

Ryan Buhr
Reactor Interactive, LLC.
www.reactorinteractive.net


I don''t known if using one big vertex buffer is better that using severlas smallers ones, i guess yes.

I understand that you need to draw severals objects, and each object need to be transfromed in the world (translated/rotated/scaled) using matrix, so ou transform the matrix and the call the vertex buffer, that for all objects.

Yes, YOU CAN transform each object your self and use a big vertex buffer to render all them.

the trick is this for each object that you are going to add to the big vertex buffer:

- transform the world matrix as you need for the object
- for each x,y,z vertex in your object transform it using the follow formula:

------------------------------------------
with matworld do
begin
xx:=(x*_11)+(y*_21)+(z*_31)+(1*_41);
yy:=(x*_12)+(y*_22)+(z*_32)+(1*_42);
zz:=(x*_13)+(y*_23)+(z*_33)+(1*_43);
end; //end matworld
------------------------------------------

(sorry about the pascal code)

x,y,z = are the original vertice in the object
_11,_21, _31 etc, are fields found in your "matworld" matrix,

xx,yy,zz = are your new transformed vertices as affected by the matworld matrix.

- now just add xx,yy,zz to the big vertex buffer.

that way you can have just one vertex buffer with severals different transformed object on in.

good luck,

tp.

Share this post


Link to post
Share on other sites