I'm rendering in forward mode my scene with its depth buffer and because I'm using animated characters I'm plannig to find a way to use multiple rendertargets to do the directional shadow pass at the same time using a geometry shader. The reason for this is also that I have arranged my shadowmap size to be the same as the screen size. Moreover I'm doing "transparent colored shadows" inspired from here that requires for my needs an extra color channel and an additional depth information. The effect is cool but has some impact on the performance so doing the animation only once should be interesting. So my plan is :

with geometry shader:

send to RTV0+Depth0 the scene

send to RTV1+RTV2+Depth1 shadow colored(RTV1)+additional depth layer(RTV2) and regular shadowmap (depth1)

currently I have these two rendering made in two passes (scene then shadows).

I have already used depthmap cube for pointlight shadow so I wonder if we can use 2Darray depth with multiple targets.

If using 2DARRAY depth with 2Darray rendertarget is possible I'm wondering how this must be arranged. Do we need the number of slices for the target 2Darray to match the number of slice for the depth 2DArray or is it possible to use less depth buffer than the number of rendertarget? Or can the number of target per depth not be the same? Is the device managing this automatically and how?


1 Answer 1


Still learning a global answer to my question is yes we can render in 2DArray n targets with a 2Darray n depthstencil and the device knows that RTVn must be linked to DSVn.

Below I present how I proceeded for my application to btain a scene with colored shadow in one pass.

Create 2DArray RTV0 with array=2 for colors (scene/shadow) (RGBA format)
From RTV0 texture create RTV1 from array=0 (scene colors)
From RTV0 texture create RTV2 from array=1 (shadow colors) and its SRV2

Create 2DArray DSV0 with array=2 for depths (scene/shadows) (R16/32 format)
From DSV0 texture create DSV1 from arrayslice=0 (scene depth)
From DSV0 texture create SRV1 from arrayslice=1 (shadow depth)

Create 2D RTV3 for depth of colored shadow (R16/32 format) and its SRV3

Set viewproj0 in shader to SceneViewProjection for RTVIndex 0;
Set viewproj1 in shader to LightViewProjection for RTVIndex 1;
Clear RTV0 to white, DSV0 to 1, RTV3 to 1

//************** Scene opaque pass
//in the shader the object on RTVIndex0 are colored and those on RTVIndex1 are drawn white, the result is no object visible on a white background in RTVIndex1 but array 1 of DSV0 is filled
SetRenderTargets(1, RTV0, DSV0);
SetShaderOpaque; //use the geometry shader below
SetBlendState(Opaque); //SRC COLOR/ZERO/ADD

//************** Scene alpha pass add only alpha object in the scene
SetRenderTargets(1, RTV1, DSV1);
RenderAlpha;//cull None

//************** Shadow color pass
//renders only transparent objet in the shadow view color/depth surfaces. I disable depthstencil here as depth is written to a color RTV3 but a dedicated depthbuffer can be used instead. The point is that we are sure that the object will be visible if in shadow scene
Set viewproj0 in shader to LightViewProjection
SetBlendState(ShadowColor)//RTV2 Alpha blending SRC_ALPHA/INVALPHA ADD//RTV3 ONE/ONE MIN
SetShaderShadowAlpha; //write color in RTV2 and depth in RTV3
ID3D11RenderTargetView* pRT2;
pRT[0] = RTV2 //shadow colors
pRT1 = RTV3;//shadow depth;
SetRenderTargets(2, pRT, NULL);
RenderAlpha ;// cull None

After copying the Scene (from RTV0 array=0 that gives SRV0) to the main buffer with a simple blitting pixel shader, the result is in the picture below.

enter image description here

All opaque objects are rendered once and only transparent ones must be rendered twice. I have to search more to render everything only once.

Everything is prepared in one batch and I first used a deferred shadow rendering. But as shown in the left picture shadows behind transparent object are missing due to the reconstructed depth from DSV0 scene depth. Storing the depth buffer before rendering the transparent object for later comparison during deferred shadowing can solve this but I did not try.

I finaly used forward rendering. We need to store SRV1, SRV2 and SRV3 SRVs to 3 additional resources to allow writing to their original RTVs during forward rendering. On my system rendering with a pixel shader from SRV1-3 to their copies is more efficient (125FPS) than using copysubresource (100FPS). Using a multirendertarget setting works also but less efficiently than a separate rendering. Finally I also tested a rolling method with two duplicates of surfaces RTV0/DSV0/RTV3, one serving as resource for the other and vice versa. This is the faster method (200FPS) as no copy is required for SRV1/2/3. The price is to have duplicated surfaces.

Below I added only the geometry and final shadowing shader, other are classical. No lighting is done.

The geometry shader. The major interest for doing this is to have matrix skinning for animated characters in the vertex shader outputing GS_INPUT struct, avoiding calculating them twice.

void GS_Array2D( triangle GS_INPUT input[3], inout, TriangleStream<PS_ARRAY2D_IN> Map2DStream )
    PS_ARRAY2D_IN output;
    output.RTIndex = 0;//scene target
    int v;
    for( v = 0; v < 3; v++ ) )//this gives a back culling for objects in scene
        output.Pos = mul( input[v].Pos, ViewProjection);
        output.Col = input[v].Col;
        output.Tex = input[v].Tex;
        Map2DStream.Append( output );
    output.RTIndex = 1; // light view target,
    for( v = 2; v >-1; v-- )//this gives a front culling for objects as shadows
        output.Pos = mul( input[v].Pos, LightViewProjection );
        output.Col = input[v].Col;
        output.Tex = input[v].Tex;
        Map2DStream.Append( output );

In the final pixel shader
for RTVIndex 0 set colors normally
for RTVIndex1 set opaque object to white, alpha 0 and normal colors for transparent ones with alpha =1. Alpha channel can be used later as a mask.

Below is the pixel shader valid for a single shadow color but adaptable to more

// LightViewProjection = LightView x LightProjection x TexOffset. TexOffset includes 0.5 shift used for translating to texture coordinate

float4 dPS = mul(worldpos, LightViewProjection);
float3 Color = SRV1.Sample(samPoint, Input.Tex);
float2 Depth;
Depth.x = SRV1.Sample(samClamp, dPS.xy).r+0.0005f;//includes Z bias
Depth.y = SRV3.Sample(samClamp, dPS.xy).r+0.0005f;
float2 DZH = float2(dPS.z, 0);
DZH = (Depth.x<DZH.x)?float2(Depth.x,1):DZH;
DZH = ((Depth.y<DZH.x)&&(DZH.x==dPS.z))?float2(Depth.y,2):DZH;
float Shadow = (DZH.y==1)?0:1; 
if ( DZH.y==2)
    float4 RGBA = SRV2.Sample(samClamp, dPS.xy);
return float4(Color*Shadow,1);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .