Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing world, view and projection matrices to shader in Direct3D

I'm going through all the MS tutorials on DirectX and I've noticed that they are always passing World, View and Projection matrices to the technique and then multiplying them in the vertex shader.

Is there a reason to do that rather than multiply the matrices before drawing and then pass a single WVP matrix to the shader? This way the matrices would be multiplied once per frame instead of once per vertex, right?

Thanks in advance.

Edit: updated with sample code

MS tutorials:

matrix World;
matrix View;
matrix Projection;

struct VS_INPUT
{
    float4 Pos : POSITION;
    float4 Color : COLOR;
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
};

PS_INPUT VS( VS_INPUT input )
{
    VS_OUTPUT output;
    output.Pos = mul( input.Pos, World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Color = input.Color;

    return output;
}

Why not this way:

matrix WVP;

struct VS_INPUT
{
    float4 Pos : POSITION;
    float4 Color : COLOR;
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
};

PS_INPUT VS( VS_INPUT input )
{
    VS_OUTPUT output;
    output.Pos = mul( input.Pos, WVP );  
    output.Color = input.Color;

    return output;
}
like image 779
jaho Avatar asked Feb 19 '23 09:02

jaho


2 Answers

In this example your suggestion of pre-multiplying the world, view and projection matrices makes sense and would be more efficient. I'm not sure why the tutorials keep them separate for this simple example.

Sometimes it makes sense to keep them separate (or keep the world matrix separate and have a combined view-projection matrix). Sometimes you might want to do your lighting in world space rather than object space for example so you'd want access to the world space vertex position in the vertex shader. If you're doing some kind of instancing you might want to keep the world space matrix separate as well as pointed out by DeadMG. In many cases though you will want to combine them as you suggest.

like image 170
mattnewport Avatar answered Feb 20 '23 23:02

mattnewport


Because the World matrix changes for each object. If you passed the WVP matrix to the shader, you would have to change that matrix every time you re-draw- very inefficient, and you'd be multiplying it out on the CPU which would also be very slow. On the other hand, you can send all the world matrices to the GPU at once in a hardware instancing buffer, and then multiply them all out on the GPU, which is really nothing on the scale of a modern GPU, and then issue one Draw call.

In short, when you add hardware instancing, then doing it in the shader is vastly more efficient.

like image 39
Puppy Avatar answered Feb 20 '23 22:02

Puppy