PDA

View Full Version : Vertex Transform vs SetTransform(D3DTS_WORLD..



cronodragon
06-11-2006, 05:45 AM
I would like to have some advice on this.

I was transforming each vertex of my meshes in DirectX 9 before using DrawPrimitive. I thought that was the common method to rotate, translate and scale meshes. Then I found that instead, I could use SetTransform(D3DTS_WORLD... saving the processing to transform each vertex.

Now I'm thinking on an optimization method, in which I could sort the meshes by texture, shaders, etc, and then make a large vertex buffer to store several transformed meshes that share those elements. That way I could draw a batch of meshes in one go with DrawPrimitive. The problem of that is that I have to return to the old method of transforming each vertex, instead of using the World transform.

Then what's optimal? Drawing several buffers transformed fastly with the World matrix, or drawing a large buffer containing vertices transformed one by one?

chronozphere
06-11-2006, 02:47 PM
Hmm.... :think:

I am currently transforming my vertices using D3DXVec3Transform wich works fine. :)
I dont know what method is faster.. The idea of Changing the world transformation matrix never occured in me.

If changing the world matrix seems to be faster then you could do the following:
>>Put all the data in a large vertexbuffer
>>Split the data in different objects/meshes, each with their own world transformation matrix.
>>Every time you render, you set the world matrix for a specific object/mesh and then render it.
After that you set the world matrix for the next one .. and render that one as well. In this way you could render all your data from a single Vertexbuffer and use the world matrix.

I didn't test this, so i dont know wheter it is possible, but it seems ok to me. :)

Good luck ;)

BTW: Using indexbuffers is also a good way to improve preformance.. At least it occupies less Video-Ram. Maybe you should consider using DrawIndexedPrimitive instead of DrawPrimitive. :)

cronodragon
06-11-2006, 03:45 PM
You are right, I forgot it's possible to split the drawing with DrawPrimitive's parameters. :mrgreen:


I am currently transforming my vertices using D3DXVec3Transform wich works fine. Smile
I dont know what method is faster.. The idea of Changing the world transformation matrix never occured in me.

Yes, it's faster. Because your don't have to do that operation of multiplying by the transformation matrix each vertex. But the trick only works for position and normals, not for texture coordinates. I kept half of my transformation code to update U,V. I realized transforming the World matrix would work from watching code about animation skinning. I tried it with the camera, lights and relative transformations, and it seems to work correctly in every case. They also use D3DTS_WORLDMATRIX(index), but I still don't understand what is it for... maybe it's for saving the state of the World matrix while crawling the skinning tree.


BTW: Using indexbuffers is also a good way to improve preformance.. At least it occupies less Video-Ram. Maybe you should consider using DrawIndexedPrimitive instead of DrawPrimitive. Smile

Good advice, but I can't use it because I need more control over the texture coordinates.

chronozphere
06-11-2006, 04:51 PM
Yes, it's faster. Because your don't have to do that operation of multiplying by the transformation matrix each vertex.

Hmm... i doubt it. I think that the per vertex transformation must be done anyway. The only difference is: doing it Internally in D3D or do it yourself. I dont understand why the World matrix method is faster. :?
If you noticed any speed increases , those probably only exist due the fact that the D3D implementation works faster than that one you wrote.

I am not completely sure about this.. the above is my own conclusion. :)


But the trick only works for position and normals, not for texture coordinates.

I dont understand why you want to transform the U,V coordinates. This is not nessecary when you preform ordinary translations, rotations etc.
The only reason why i think you should change these coords, is animation and things like that. :)



Good advice, but I can't use it because I need more control over the texture coordinates.

Sorry but i dont understand why you have more control over vertex-coords when using DrawPrimitive instead of DrawIndexedPrimitive.
The only difference between these two is the way the vertex data is interpreted.
Even with an indexbuffer, you can still use vertex-coords the same way as before :)

cronodragon
06-11-2006, 05:05 PM
Well, I'm not willing to sell the method, I think everyone should experiment make their own conclusions. I'm just sharing that I found the World transformation to be faster and it fits my needs. To test the speed of that transformation I loaded two 3D models and rotated them, one realtive to the other. The I switched the World transformation off, and you might not believe me, but instead of going faster, it went slower without the World transformation. Maybe because without the transformation both models ended at the same position, increasing the Z comparissons. Anyway, the World transformation doesn't consume significant time, and I'm sure the time wasted by the vertex transformation loop is proportional to the number of vertex. So, I'm keeping with the World transform. On the other hand, that's the method to transform skinning bones. If I find I'm wrong I have no problem on switching back to per vertex transform :D


I dont understand why you want to transform the U,V coordinates. This is not nessecary when you preform ordinary translations, rotations etc.
The only reason why i think you should change these coords, is animation and things like that. Smile

Exactly! It's a feature available in my engine. 8) And I'm using tiled textures, there is no way to use them with Indexed primitives.

chronozphere
06-11-2006, 06:07 PM
To test the speed of that transformation I loaded two 3D models and rotated them, one realtive to the other. The I switched the World transformation off, and you might not believe me, but instead of going faster, it went slower without the World transformation. Maybe because without the transformation both models ended at the same position, increasing the Z comparissons.

Okay.. You tested it.. Great :razz:. I will try the world-transformation method too. :)

Good luck ;)

cronodragon
06-11-2006, 07:12 PM
Great! :D Please post your results.

By the way, do you know what's the largest size for a vertex buffer? I can't find that information, and I need it to make the batch primitives.

chronozphere
06-11-2006, 07:41 PM
of course.. I will post my results :razz:

No i dont know that for sure..:( but i think this is limited to the available ammount of video-memory.
Since there is no good way of retrieving the ammount of available memory, i think you must pick a maximum yourself e.g 250.000 vertices.
This maximum will influence the ammount of video-ram required for your game. 8)
I do know for sure that it cant be bigger than 2^32 vertices ,because that's the highest value an vertex-index can have, but i think you already knew that. BTW: 2^32 seems big enough to me. :)

If a were you i should ask this on the MSDN forums or take a look at the list of device-capabilities. ;)

chronozphere
06-11-2006, 09:10 PM
Okay.. i did some tests and i agree that using the world-matrix gives a small speed increase :razz:

I render 12 cubes, each at a different position.
I have a 500Mhz Pentium III with a Geforce 2 MX/MX 400.

FPS:
Without worldmatrix transforms: approx 117
With worldmatrix transforms: approx 124

It was hard to get these values because the fps sometimes jumped form 125 tot 108. So these value's are not very reliable.

Maybe i must calculate the approx fps for every 20 secs. This might give a better view on this. :)

I also like to know your test results ;)

cronodragon
06-11-2006, 11:34 PM
I think the higher benefit is when rendering more complex geometry, I'll make some tests on that.

By the way, I started working on my optimization method, hope to get good results. :D

alexione
07-11-2006, 12:18 PM
The main reason why method which uses WORLD transformation is faster is that more job is done on GPU, not on CPU. That is one thing you should always keep in mind when making rendering engine - do as much of work as you can on GPU!

Also, you should keep CPU/GPU traffic as low as possible (that is one of reasons why indexed primitives are faster), so it's faster to send to GPU "render this vertex buffer" (assuming vertex buffer is created in DEFAULT or MANAGED pool) instead of "render this vertex buffer UP" (when you have to send all the data to GPU).



hey also use D3DTS_WORLDMATRIX(index), but I still don't understand what is it for...

It is used for skeletal animation. You first need to setup bones in your mesh and define WeightMap for each bone. After that, you set WorldMatrix for each bone (up to 256), and you let GPU to do the job :)


And, don't forget - test, test, test! ;)

Best regards!

Clootie
07-11-2006, 04:06 PM
Generally if you draw less than 100 triangles with each DrawIndexedPrimitive call - it's better to pre-transform vertices on CPU to single vertex bufer and draw these several objects later with single DIP call. And this border value (of 100 vertices) tends to increase with increasing perfromance of GPU's.

So in you case (drawing cube consisting of 12 triangles) it should be better if you transform vertices of many cubes on CPU and later draw them with one call to Draw{Indexed}Primitive.

PS. This will not help if your box cover almost significant part of screen - in that case your application wil be limited by fillrate of pixelShader and Vertex transform perfromance does not matter in this case.

cronodragon
08-11-2006, 05:42 AM
Thanks for the explanations ppl, now I'm sure that's the right method to transform vertices.


I am currently transforming my vertices using D3DXVec3Transform wich works fine. :)

I was checking this post again, and found out that you use D3DXVec3Transform(). I use D3DXVec3TransformCoord() which returns a TD3DVector3, the other one returns a TD3DVector4. Is there a difference more than the returned type? Maybe I'm lossing soemthing on the operation. :?

chronozphere
08-11-2006, 10:08 PM
I was checking this post again, and found out that you use D3DXVec3Transform(). I use D3DXVec3TransformCoord() which returns a TD3DVector3, the other one returns a TD3DVector4. Is there a difference more than the returned type? Maybe I'm lossing soemthing on the operation. Confused

Oh..great tip :) I used the D3DXVec3Transform and after retrieving the TD3DVector4, i converted it to a normal vector, wich is inefficient.

I will use the D3DXVec3TransformCoord() from now on. :D