Recommended Posts

In order to reduce the number render passes ive read that it may help to use instancing for repeatable types of objects. As in my application a lot of models are exact duplicates of each-other (which may only vary in scale) i think that this technique is pretty good.

Now my problem is that i didnt really understand how this works. Ive looked through the SDK-Sample but its a bit awkward they merged several different ways into one smaple/shader/project. So i didnt really get all the points of it.

It would be really nice if someone could give me some hints where to start, what the concept behind it is and maybe some simple examples with code.

Little summary what i plan:I have a class that handles caching of the same objects (they may be used bout 100 times in the same scene). From there id like to have a class that batch-renders all the instances of that object. The number of instances may vary depending on the players position and the instances may vary in size (that should be a pretty easy thing to do in the shader).

My ideas so far:I use the function ID3DXEffect9::SetVectorArray to set all the positions of the instances in the shader (and maybe another for the scales). I render an object that is aligned to the 0-point and move it for each instance.

Greetings and big thanksPlerion

0

Share this post

Link to post

Share on other sites

SM3.0-style hardware instancing (where you put the instance data in a second vertex stream) is preferable over shader constant instancing (where you put the instance data in an array of shader constants that you index into). It's more flexible, there's less overhead in locking a resource than in setting shader constants, you're not limited in the number of instances you can draw, the shader performance is better, and you don't have to modify the geometry you're rendering. The only reason to use shader constant instancing is if you're supporting SM2.0 GPU's.

Here's some basic steps you can go through to get instancing implemented:

1. Start with your vertex shader, and figure out exactly what data you need. Usually a world matrix is all you need at first. Add the instance data to your vertex shader inputs, and assign it a semantic you don't need (remember that a float4x4 will require 4 adjacent semantic slots). If you have a lot of instance data, it can help to declare the instance data in a separate struct. Like this:

2. Based on the instance data you need come up with a vertex declaration for your geometry that includes all of your geometry elements as well as the instance data elements. Make sure that you put the instance data elements in stream 1 instead of stream 0, and make sure that you start the offset at 0 again when you start listing them.

3. Simplest way to start things off at runtime is to just make a single large dynamic vertex buffer to use for your instance data. Pick some max number of instances and multiply it with the size of your instance data, and use that for the size. Make sure you put it in the Default pool, with the Dynamic and WriteOnly usage flags set.

4. Declare a struct in your app code that matches the layout of your instance data. So in my example above, give it a Matrix and Vector4. Then for any geometry you want instanced keep a List of that struct, and each frame remove all of the elements and then add in the instance data for each instance you want to render. Then when it's time to render all of those instances, lock your big dynamic VB and fill it with the instance data. This way the number of instances per frame can be dynamic.

5. After filling the vertex buffer, it's time to draw. First set stream 0 with your primary vertex buffer the same way you always would, and also set the indices (instanced geometry has to be indexed). Then set stream 1 with your instance data vertex buffer. Once you've done that, you need to specify how many instances you want to draw. This is done with the somewhat-cryptic SetStreamSourceFrequency method. What you do is you set the number of instances by specifying stream 0, the number of instances as the frequency, and IndexData as the source. Then you specify that stream 1 has instance data by calling it again with stream 1, 1 as the frequency, and InstanceData as the source. Then you just draw like your normally would. When you want to go back to non-instanced rendering, call ResetStreamSourceFrequency.

0

Share this post

Link to post

Share on other sites

Thank you for your explanation. I think the concept and also the basic usage is pretty clear, though sadly i cant see anything on the screen in my test project with just a cube that uses the following code:

I guess my problems could be either where i create the instance-data-buffer or with the vertex-declaration. But i dont really see what im doing wrong (used VertexFormat so far, so i dont know exactly if i understood the VertexElement/VertexDeclaration correct).