Sign in to follow this  

Applying transformations to vertices?

This topic is 4746 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

Hey all, Is there a way to apply a transformation matrix to a list of vertices and get that list of vertices back with the result? Example: 1 (0, 0) 2 (1, 0) 3 (0, 1) 4 (1, 1) Then I apply a 90o rotation and end up with: 1 (1, 0) 2 (1, 1) 3 (0, 0) 4 (0, 1) (Hope I'm visualising that correctly) What I'm looking to do is optimize my 2D sprite cache by removing the need to sort by transformation after sorting by texture. Just fill up the cache with quads, sort by texture and render the whole-shebang. As of right now, I'm stuck doing this: 1. Add quad to rendering tree, sorted by texture. 2. Subsort each texture group by transformation. 3. Foreach texture : Foreach transformation : Add to Batch : Render Batch I'd really like to optimize tihs to: 1. Apply transformations to quad 2. Add quad to rendering tree, sorted by texture. 3. Foreach texture : Foreach transformation : Add to Batch : Render Batch It removes a sort from the process, which I feel will speed things up to allow more sprites on screen. Any ideas on how I can go about this? I'm using D3DXMatrixTransformation2D to compute the matrix if that makes any difference. Thanks in advance.

Share this post


Link to post
Share on other sites
I know of 2 ways, and I assume that you are storing the vertices in vertex buffers for both.

(1) - Lock the VB: IDirect3DVertexBuffer9::Lock()
- Transform the verts: Foreach vertex D3DXVec3TransformCoord()
- Unlock the VB: IDirect3DVertexBuffer9::Unlock()

(2) - Apply transformation: IDirect3DDevice9::SetTransform()
- Transform in HW to your VB: IDirect3DDevice9::ProcessVertices()

For a small number of vertices, method (1) is definetly faster. Since you only have 6 verts per sprite (3 verts per triangle, non-indexed), it might actually be better if each quad just stored the verts in an array (not a VB). Then, before rendering a batch, add all verts from the current batch into your global sprite vertex buffer. Finally, render with that VB.

ID3DXSprite does something quite similar, and it works very well.

Share this post


Link to post
Share on other sites
Setting a world transform is the standard way of transforming vertices.

For 2D sprites (or other quads) it's often better to software transform the vertices rather than do a seperate set transform and draw call for each quad, and store the result in a dynamic vertex buffer. This allows you to do one draw call per texture, or per VB size/4 quads.

Another alternative is shader based batching. Depending on you needs this may be useless, but here's how you go about it... So long as you're only rotating about one axis (for 2D this is perfect), and translating in 2D, you can get away with using one constant register per quad. In each vertex simply store a quad number (like a boneid... find a skinning shader sample in whatever shader language you use to see how to index constants by a value from the vertex data). It may be useful to store another 2 values as 0 or 1 to indicate left/right and top/bottom. Storing cos(angle), sin(angle), posx, posy, may be all you need, if all sprites use the same texture coordintes. You may go all out and use 2 registers, the second with u, v, width, height. Assuming you don't scale the textures, the second u and v can be worked out from the size of the quad. And if you're really in a pinch and want to use just 2 registers and get scaling as well, ditch the sin(angle), and store scaling there, and calculate the sin on the fly from the cos (ie: sqrt(1.0 - sin(x)*sin(x))). Calculate the new vertex positions based on the rotation (cos and sin), width, height, and scale. Calculate the uvs based on u, v, (left/right vertex flag)*width and (top/bottom vertex flag)*height, and a constant indicating texture size.

Share this post


Link to post
Share on other sites
Lock and unlock on a static buffer will kill your framerate. Lock and unlock on a dynamic buffer *can* be efficient if done correctly... ie: your buffer is larger than a single use size, you tend to lock with NOOVERWRITE and append data, and occasionally lock with DISCARD.

There is overhead to a dynamic buffer, but it's much less than the overhead of calling draw for each and every quad. Try to draw in batches of 100 or 200 quads or more at a time. This is the minimum size where the card can render at a good speed. If you need to render 800 quads with the same texture, you may find it optimal to render all 800 at once, or you may find it optimal to render 300, render 300 more, then render the final 200. This is because you can setup the data for the second set of quads while your card is busy rendering the first set. Doing work in parallel is what you're aiming for.

Share this post


Link to post
Share on other sites

This topic is 4746 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