0
\$\begingroup\$

I'm working on shadow mapping. Part of the implementation involves drawing 3D models to a depth buffer with recommended 16-bit depth. To that end, I'm first creating a render target as follows:

new RenderTarget2D(graphicsDevice, width, height, false, SurfaceFormat.HalfSingle, DepthFormat.Depth16)

My HLSL shader is shown below.

#define VShaderModel vs_4_0_level_9_1
#define PShaderModel ps_4_0_level_9_1

matrix World;
matrix LightProjection;

struct MapVOutput
{
    float4 Position : SV_Position;
    float Depth : Depth;
};

MapVOutput MapVShader(in float4 position : SV_Position)
{
    MapVOutput output;
    output.Position = mul(position, mul(World, LightProjection));
    output.Depth = output.Position;

    return output;
}

float MapPShader(MapVOutput input) : Depth
{
    return input.Depth;
}

technique CreateShadowMap
{
    pass Pass0
    {
        VertexShader = compile VShaderModel MapVShader();
        PixelShader = compile PShaderModel MapPShader();
    }
};

The idea is to render the scene from the light's perspective (using the LightProjection matrix) and store depth information only. However, trying to compile this shader gives the following error:

pixel shader must minimally write all four components of SV_Target0

Note that the shader currently uses vs_4_0_level_9_1 and ps_4_0_level_9_1 to compile. I've tried changing those to simply vs_4_0 and ps_4_0, which lets the shader compile, but causes an error to be thrown during runtime (with a cryptic error message).

Given all this, I have several questions I'm hoping to understand.

  1. To generate a shadow map, I only need to store 16-bit depth information. Is SurfaceFormat.HalfSingle the correct format to use for this purpose?
  2. I only need to store 16 bits, but the pixel shader function writes a float (32 bits). How can I write only 16 bits to the render target? If I write a float, is the value properly truncated anyway?
  3. I've looked at existing shadow map samples and noticed that the Depth value in MapVOutput uses the TEXCOORD0 semantic rather than `DEPTH'. Is DEPTH the correct semantic to use on this variable?
  4. How do I resolve the HLSL error listed above without simply returning a color? Google hasn't given me useful answers so far, and switching compiler versions seems to introduce other problems.

Thank you.

\$\endgroup\$
1
\$\begingroup\$

First of all, I am not very familiar with monogame specifically, but what I say apply to DirectX 11, which I expect Monogame is using under the hood.

Now, for most cases, you don't need to expicitly write to a depth buffer from a pixel shader. Just enabling depth writes in the depth stencil state and setting a depth buffer before rendering should already enable depth buffering. For drawing shadow maps, you shouldn't even be setting a rendertarget by the way. Which means, that the pixel shader should return nothing, you should just declare it as void return type, or don't even set a pixel shader. You should only set a pixel shader in this case if you want alpha testing, so the shader would discard or clip based on the surface texture alpha and return nothing. When you finished rendering your depth buffer, you can just bind that as a readable texture for other shaders to sample from.

There are cases when you want to explicitly output depth from the pixel shader, for example with cube map shadows where you want to output the distance from light to pixel instead of the native depth alue. For that, you can use the SV_DEPTH semantic in DX11 (there are also SV_DEPTHGREATEREQUAL and SV_DEPTHLESSEQUAL for conservative depth output). If you specify the output as SV_DEPTH, you are expected to return a float. There are performance implications with this technique though, so try to avoid it if possible.

In your case, DepthFormat.Depth16 looks fine, as it is a 16 bit unorm integer format. You still write your shaders as float return type if you want to export depth with SV_DEPTH semantic.

For your TEXCOORD question, the only reserved and meaningful semantic names are the ones starting with SV_ (system value). Any other semantic names can be just whatever. Their only use is probably with shader reflections, where they can be queried from the application for custom shader management logic.

\$\endgroup\$
  • \$\begingroup\$ Great. Thanks very much for the answer. My questions were pretty lengthy, so that helps clear things up a bit. I think I'll wait another day or so to see if I can get clarification on my other issues, and then I'll likely mark this as accepted. \$\endgroup\$ – Grimelios Oct 21 '17 at 16:52

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.