DirectX 11 Pixel Shader What Is SV_POSITION?

Mike5050 picture Mike5050 · Oct 2, 2017 · Viewed 10.8k times · Source

I am learning HLSL for DirectX 11, and I was wondering what exactly is the SV_POSITION that is the output for a Vertex Shader, and the input for a Pixel Shader.

1: Is this x,y,z of every pixel on your screen, or of the object?

2: Why is it 4 32bit floats?

3: Do you need this System Variable for the vertex output?

Thank you!

Answer

Chuck Walbourn picture Chuck Walbourn · Oct 2, 2017

The vertex shader stage only has one required output: the position of the vertex. This value is then used by the fixed-function rasterizer to compute which pixels are being drawn and invoke the pixel shader for each one. That's what the system value semantic SV_Position indicates on the output of a vertex shader. A pixel shader doesn't actually need to take the pixel position as input, but it can if that is useful. The input layout must also have a position for the vertex shader which uses the SV_Position semantic as well.

A typically set up is:

  • Tnput layout describes the positions of the vertices in world space indicated as SV_Position. The input layout describes the format of the data.

For example:

D3D11_INPUT_ELEMENT_DESC layout[] =
{
    { "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
  • Vertex shader input receives that information from the input assembler as decoded by the input layout from the vertex buffer, optionally using an index buffer as well. Whatever format the position is in, typically it's converted to float for use by the shader.

  • The vertex shader has to produce the output vertex position, again indicated by SV_Position. This is the (x, y) position of the pixel in normalized coordinates in the range (-1, -1) to (1, 1). The z is the depth position (used for the depth buffer) in the normalized range 0 to 1.

For example:

float4 VS( float4 Pos : SV_Position ) : SV_Position
{
    return Pos;
}
  • The pixel shader can optionally take the position, but it doesn't have to. The (x,y) are in pixel coordinates. The vertex output ('clip space') is converted to pixels by using the viewport state that was provided in D3D11_VIEWPORT.

  • The pixel shader must produce a float4 result marked as SV_Target.

For example:

// We can omit the position
float4 PS() : SV_Target
{
    return float4( 1.0f, 1.0f, 0.0f, 1.0f );
}

// Or you can take it as input if that's helpful
float4 PS( float4 Pos : SV_Position ) : SV_Target
{
    return float4( 1.0f, 1.0f, 0.0f, 1.0f );
}

Technically the vertex shader doesn't have to take a position as input. With Shader Model 4.0 or better hardware, you can use the SV_VertexId to self-generate the corners of a quad in a vertex shader with code like the following which doesn't make use of any input layout, vertex buffer, or index buffer at all. It still has to produce an output position for the pixel shader of course.

VSInputTx VSQuad(uint vI : SV_VertexId)
{
    VSInputTx vout;

    float2 texcoord = float2(vI & 1, vI >> 1);
    vout.TexCoord = texcoord;

    vout.Position = float4((texcoord.x - 0.5f) * 2, -(texcoord.y - 0.5f) * 2, 0, 1);
    return vout;
}

Note that you can use the older Direct3D 9 POSITION semantic in pretty much any place that you can use the new SV_Position (or SV_POSITION) semantic. The only requirement is that you have to be consistent between the input layout and the vertex shader input. Otherwise it will fail to bind.

As you are new to DirectX, I recommend you take a look at the DirectX Tool Kit and in particular the built-in shader source.