4
votes

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;
}
4

4 Answers

5
votes

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.

3
votes

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.

0
votes

I think each matrix can change in each frame. Unless you view in the same way for some, the view might change if you position your camera view in other angle or coordinates to observe the world/objects.

0
votes

This way the matrices would be multiplied once per frame instead of once per vertex, right?

The term "per frame" does not make sense here, Why we call it vertex shader? because it is a per-vertex process, so no matter where you multiply the 3 matrix into a single one(outside or inside the shader), each vertex should apply to this single matrix before drawing. and GPU is a better choice for such task, such as vector/matrix calculation and other graphics processing.