Handling World Matrices

Started by
6 comments, last by Hodgman 12 years, 8 months ago
So I've been working away at some projects of mine and so far I've only come to rendering a few simple objects at a time like:


For each Object:
Update World Matrix
Send World Matrix to Vertex Shader
Draw Objects Vertex Data
End Loop


Pretty basic and it's probably the most common solution to rendering small projects but I've been wondering how this handles with large worlds with many objects I can tell already that there's going to be hundreds if not thousands of draw calls which is obviously not very efficient. So I came here to ask how you guys handle it. I've herd of a few ways of handling the draw calls but my main question is how to handle updating the world matrix? For example if i had a 16 cubes in one vertex buffer i would have to draw each 12 vertices separately and update the world matrix one by one. I thought of a few ways to handle this but i'm not too sure still:

Pre-computing it in a level editor:
This method would pre-compute all translations, rotations and scaling in the world editor and save the data into a separate file.

Pros:
Going to render fast as all data can just be done in 1(?) draw call.
Removes the task of multiplying all the data by the world matrix in a shader will obviously be a fair bit faster

Cons:
All objects would be static and wouldn't be able to update there position without manually editing the vertex data
File size would be huge.


Sending the world matrices as an array:

Pros:
Can again render all objects in a few draw calls

Cons:
Will be very memory heavy especially with lots of objects
Will probably have to be done in a few iterations due to memory
Hard to keep track in a vertex buffer on which data to apply the world matrix to

I can't see any of these being viable solutions, i'm probably under-estimating the processing power these days as i could use option 1 for all static and world data and then use the method i was using before to just update dynamic objects(physics props, npc's etc.)
Advertisement
Bump as it's nearly on the 2nd page o_O
I am far from being an expert in this type of stuff, but the way I understand is basically what you said in your last sentence.

Perhaps you can create a buffer object to batch vertices (using CPU time) to the GPU, then draw them when the buffer is full, cutting down on the amount of draw calls. I do not know the "sweet spot" between using CPU and minimizing draw calls, but this is the method used (I think) by the XNA Primitive Batch example. Also (having to do with XNA, but perhaps worth a read even if you are not) is this article.

I do know that you can run into "stitching" problems when using separate meshes and using a transform matrix to try and line them up - floating point inaccuracies can cause seams to appear where you would expect perfect joins. I know this, because I've recently had this happen in a project of mine, and now I am in the process of re-writing my level baking code...
Thanks for the reply! I thought i might have been over complicating things a bit i just needed some clarity on it :P Anyway I have another question now, i'm aware of some techniques for reducing draw calls, batching, instancing etc. but i'm not 100% on how the world matrix is applied to each object, hence the title for this thread. If your rendering a group of objects in one draw call then how does each object get translated, scaled, rotated? Back to my original example[color="#1C2837"] "if i had a 16 cubes in one vertex buffer i would have to draw each 12 vertices separately and update the world matrix one by one" with batching this would be done as:

[color="#1C2837"]
for each object until vertex buffer is full:
insert data into vertex buffer
end loop
Draw all 16 cubes


[color="#1C2837"]And what i'm not to sure is how these would get their world matrices applied to them? The only way i can see this working is if i did:

[color="#1C2837"][color="#000000"]
[color="#1C2837"]
or each object until vertex buffer is full:
insert data into vertex buffer
end loop


for each cube
Update World Matrix
Draw 1 cube
end loop

[color="#1C2837"][color="#1C2837"][color="#000000"]
[color="#1C2837"][color="#1C2837"][color="#000000"]But then wouldn't this just end up with lots and lots of draw calls?

So I've been working away at some projects of mine and so far I've only come to rendering a few simple objects at a time like
There's a few different processes going on in your example.
It's often better for performance to split things up so you're only doing one kind of operation at a time -- e.g. update all object's matrices, and then draw all objects.
For each active object:
Update World Matrix and bounding volume
For each active object
Determine visibility
For each visible object
Add to rendering queue
For each item in sorted rendering queue
Send World Matrix to Vertex Shader
Draw Objects Vertex Data

I've been wondering how this handles with large worlds with many objects I can tell already that there's going to be hundreds if not thousands of draw calls which is obviously not very efficient.[/quote]In my current engine, ~1000 draw calls takes ~1.5ms of CPU time. In other engines, I've seen 1000 draw calls take 10ms of CPU time... so it really depends on how you structure things.

Your 'pre-computation' method is common for static geometry, it's also known as baking/collapsing the transforms/matrices into the vertex data. Generally you end up with one draw-call per material (as different materials have different shader parameters, textures, shader programs, etc).

Your 'array' method is supported via instancing, and is commonly used the reduce the amount of draw-calls required when drawing many of the same object (e.g. a field of grass).

... instancing etc. but i'm not 100% on how the world matrix is applied to each object, hence the title for this thread. If your rendering a group of objects in one draw call then how does each object get translated, scaled, rotated?[/quote]With instancing, you have a VB containing the vertices for a single cube, and an another buffer containing 'N' matrices. You issue an instanced draw call, asking for the cube to be rendered 'N' times, and then the shaders for each object are passed a value from '0' to 'N-1'.

Back to my original example "if i had a 16 cubes in one vertex buffer i would have to draw each 12 vertices separately and update the world matrix one by one" with batching this would be done as:
[font="Courier New"]for each object until vertex buffer is full:
insert data into vertex buffer[/font][/quote]Why are there 12 verts in a cube? And you shouldn't be writing into a vertex buffer every frame -- the cubes should already be present in the buffer.

* If you were using instancing, there would only be a single cube in the buffer.
* If the cubes are static, there will be 16 of them in the buffer, pre-transformed.
* If the cubes are dynamic, then, yes, the 'standard' method would involve one draw-call per cube.
* If the cubes are dynamic and you want to draw them all in a single-draw call, then in their vertex data you would add another stream that contains an object-ID number. e.g. all the verts for the first cube would store the number 0 in this stream, the second cube's verts would store 1, etc... Then in the vertex shader, you can use this data as an array index into your array of transforms.

-snip-


Ah thanks for the reply, I understand want i need to do now. I just needed some clarity on how fast this method runs, i'm really under-estimating how long it takes to do this :P Thanks again for the replies!


and also

[color=#1C2837][size=2]Why are there 12 verts in a cube? And you shouldn't be writing into a vertex buffer every frame -- the cubes should already be present in the buffer.

[color="#1c2837"]My bad there's 12 polygons and 36 verts ;)

[quote name='Hodgman' timestamp='1313719496' post='4851028']
[color="#1C2837"]Why are there 12 verts in a cube? And you shouldn't be writing into a vertex buffer every frame -- the cubes should already be present in the buffer.

[color="#1c2837"]My bad there's 12 polygons and 36 verts ;)
[/quote]
With indexing, you could cut that down to 8 verts ;)
[quote name='Six222' timestamp='1313720182' post='4851032']My bad there's 12 polygons and 36 verts ;)
With indexing, you could cut that down to 8 verts ;)[/quote]Or 24 verts if normals aren't shared across face-edges ;)

This topic is closed to new replies.

Advertisement