0
\$\begingroup\$

I have posted this question on StackOverflow and was directed here, so I'll just copy the question:

I am attempting to improvise some sort of hardware instancing in my game. I wish to draw multiple trees with only one Draw Call.

So far, I have set up a class which holds the model, texture, and an array of Matrices. Each matrix corresponds to a location of one tree in the game world.

I have determined to use 50 copies of object as hard coded limit within my class and my shader.

I am sure that the matrices generated are correct ones. Using Basic effect with multiple draw calls and switching out World matrices between them does yield in correct number of trees on their correct locations.

I have tried a shot-in-the dark approach:

float4x4 View;
float4x4 Projection;
float4x4 World[50];

...

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output[50];

    for (int i=0; i<50; i++)
    {
        float4 worldPosition = mul(input.Position, World[i]);
        float4 viewPosition = mul(worldPosition, View);
        output[i].Position = mul(viewPosition, Projection);
        output[i].texCoord = input.texCoord;

        return output[i];
    }

}

To my surprise, this actually did compile, and to even greater surprise, didn't melt my GPU.

To not so big of a surprise, this draws only one tree, the first one, as the loop ends as soon as it hits the "return" keyword as any sane mind would expect it to.

I have tried my google-fu skills with googling this kind of problem, but majority of the results deal with C++ code (I'm using C# + XNA), and their approach to the problem is basically to collect all needed model's vertices and forward all that, as one huge model drawn with one World matrix position.

Is there a reliable way to draw one model using an array of World matrices on a shader, or must I collect all vertex data and batch it that way?

P.S. I am attempting to toy around with nested structures, like these:

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 texCoord : TEXCOORD0;
};

struct VSOUT
{
    VertexShaderOutput output[50];
};

VSOUT VertexShaderFunction(VertexShaderInput input)
{
    VSOUT output;

    for (int i=0; i<50; i++)
    {
        float4 worldPosition = mul(input.Position, World[i]);
        float4 viewPosition = mul(worldPosition, View);
        output.output[i].Position = mul(viewPosition, Projection);
        output.output[i].texCoord = input.texCoord;

    }

    return output;
}

But, of course, as the loop gets unrolled, the very next instance of Output gives an overlapping semantic error. I am pretty sure there are no POSITION50 and TEXCOORD50 semantics :p So, how would I go about solving this problem?

Thank you in advance!

\$\endgroup\$
0
\$\begingroup\$

Just as the vertices can stream through the GPU pipeline to be modified per the shaders you write when calling Draw, so can the 50 world matrices be streamed through the pipeline at the same time. So you set up 2 streams, one for the vertices that repeats itself each time a new matrix from the other stream goes through.

Check out how that is done in Xna in this sample: http://xbox.create.msdn.com/en-US/education/catalog/sample/mesh_instancing

\$\endgroup\$
  • \$\begingroup\$ I've already checked out that example, but my problem with Microsoft's examples is always the impossibly unreadable code, it's always seperated through 15 classes and 100 different Methods, instead of one normally written piece of code. I will try to study it the best I can But, bottom line, it IS possible to draw multiple 3D objects using one Draw call? \$\endgroup\$ – Eudaimonium Feb 21 '14 at 17:12
  • \$\begingroup\$ yes, very possible and common. Study the sample to groc the gist of the concept and implement it any way you want. \$\endgroup\$ – Steve H Feb 21 '14 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.