Vertex Buffer vs. DrawPrimitiveUP (DirectX 9.0)

Started by
15 comments, last by Tar 14 years, 6 months ago
Hello, In my application vertex information is stored in a collection "shapes" which I load to a vertex buffer (m_vb) every frame. The procedure looks like that: m_vb->Lock(0, 0, (void**)&v, 0); UINT nv = 0; for (UINT i=0; i<shapes.size(); i++) { // copy information about vertices from shape to m_vb using memcpy() } m_vb->Unlock(); It looks to me that there is some redundancy. Why I would keep two copies of the vertices: one in the "shapes" collection and another one in the vertex buffer. Moreover, data in vertex buffer is overridden with every frame and the entire vertex buffer is locked during that time. Some people here suggested using DrawPrimitiveUP instead of loading data to the vertex buffer every frame. But I read in MSDN documentation that "DrawPrimitiveUP is intended for use in applications that are unable to store their vertex data in vertex buffers". I'm able to store data in the vertex buffer - it just seems to be not very efficient. Additionally, DrawPrimitiveUP is gone in DirectX 10. If I ever wanted to port my application to DirectX 10 I would have to get rid of DrawPrimitiveUP anyway. I would stick to the vertex buffer but I don't know what technique to use in order to make it more efficient: to minimize locking, to reduce duplication of data etc. The procedure I'm using right now was taken from the Frank Luna's book "Introduction to 3D Game Programming". I thought it would be efficient as it comes from the book. Maybe it is and I just miss something here. Any suggestions are very welcome. Thanks Tar I'm using DirectX 9.0c and C++
Advertisement
Do you change the data every frame, so that your shape changes its appearance, in a way that can't be expressed through matrix transformations?
If that is the case, then you must update the vertex buffer data, and memcpy is probably the best way to do that. If your vertex data is static then you don't need to memcpy it more than once.
Thanks Erik for your reply.

I change my vertex information every frame using standard transformations: rotation, translation, scaling. It means vertex information changes with every frame - it's not static.

Thanks for your assurance that memcpy is the most efficient way to load my buffer with data.

Tar
Then it should most definitely be static, unless I'm missing some crucial detail. Those transformations are usually applied by the hardware, using IDirect3DDevice9::SetTransform. Updating a vertex buffer every frame is very unusual, as you can move/scale/rotate your objects without updating the vertices.
Quote:vertex information changes with every frame - it's not static.

I think what Erik was getting at is, if the entire buffer undergoes the same transformation, the buffer can remain static and the world transform set each frame.

Certainly if each vertex is operated on separately, the data must be reloaded following recalculation.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Thanks for the replies.

I change vertex data for every shape independently. It means there are as many different world transformations as the shapes.

This is the tranformation code called every frame for each shape (dt is the time difference between two frames):

void CShape::UpdateWorld(float dt)
{
// determine the scale factor
if (tmpScale < 1.0f) tmpScale += dt * 5.0f;
if (tmpScale > 1.0f) tmpScale = 1.0f;

// Build the scale matrix.
D3DXMATRIX S;
D3DXMatrixScaling(&S, tmpScale, tmpScale, tmpScale);

// Build the translation matrix.
D3DXMATRIX T;
D3DXMatrixTranslation(&T, cp.x, cp.y, cp.z); // cp - center point of the shape

// Update the rotation angle and build the rotation matrix.
D3DXMATRIX RotZ;
D3DXMatrixIdentity(&RotZ);

angle += dt * rs; // apply the rotation speed rs
if (angle >= 2.0f*D3DX_PI) angle = 0.0f; // reset angle to zero when angle reaches 2*PI
D3DXMatrixRotationZ(&RotZ, angle);

// Update the world matrix by combining the transformations.
m_World = S * RotZ * T;
}

It seems I have to load the vertex buffer with every frame, doesn't it?

Buckeye: I didn't quite grasp your explanation:
"the buffer can remain static and the world transform set each frame".

Does it mean I do not touch the vertex buffer data at all? If so, how to apply the world transormation? How would Direct3D know the vertices in the buffer are transformed?

Thanks,
Tar
What about creating a dynamic vertex buffer? MSDN on dynamic vertex buffer. Not a good idea?
I think I got it!

You mean I could use code like that:

g_Device->SetStreamSource(0, m_vb, 0, sizeof(VertexFormat));
g_Device->SetTransform(D3DTS_WORLD, &m_WorldTransformation);

in order to apply a world tranformation to ALL vertices in my vertex buffer.
Right?

Tar
Dynamic buffers? hmm... I need to think about it.

Currently, I provide the D3DUSAGE_WRITEONLY flag in CreateVertexBuffer(). It seems to be efficient enough.
Quote:Original post by Tar
I think I got it!

You mean I could use code like that:

g_Device->SetStreamSource(0, m_vb, 0, sizeof(VertexFormat));
g_Device->SetTransform(D3DTS_WORLD, &m_WorldTransformation);

in order to apply a world tranformation to ALL vertices in my vertex buffer.
Right?

Tar


Yes this is correct, don't change the vertex buffer.

This topic is closed to new replies.

Advertisement