Pixel Shaders, Output Merger & Blending
Integer render targets need uint4/int4 outputs.
17.1 Outputs
Integer render targets need uint4/int4 outputs.
// Single render target
float4 PS(VSOut i) : SV_Target { return float4(1, 0, 0, 1); }
// Multiple render targets (G-buffer)
struct GBufferOut
{
float4 albedo : SV_Target0; // RGBA8_UNORM_SRGB
float4 normal : SV_Target1; // RGB10A2_UNORM
float2 material : SV_Target2; // RG8_UNORM: roughness, metallic
};
GBufferOut GBufferPS(VSOut i)
{
GBufferOut o;
o.albedo = float4(0.8, 0.2, 0.2, 1);
o.normal = float4(normalize(i.normalW) * 0.5 + 0.5, 0);
o.material = float2(0.4, 0.0);
return o;
}17.2 Discard, clip & alpha testing
Discarding disables some early-depth optimizations; prefer alpha-to-coverage with MSAA for foliage, or a depth prepass.
Texture2D gTex : register(t0);
SamplerState gSamp : register(s0);
float4 AlphaTestPS(VSOut i) : SV_Target
{
float4 c = gTex.Sample(gSamp, i.uv);
clip(c.a - 0.5); // discard when alpha < 0.5
return c;
}17.3 Depth output & early-Z
Writing SV_Depth disables early depth testing. If you only push depth one way, use SV_DepthGreaterEqual/SV_DepthLessEqual. [earlydepthstencil] forces early-Z even when the PS writes UAVs:
RWStructuredBuffer<uint> gVisible : register(u1);
[earlydepthstencil]
float4 VisibilityPS(float4 pos : SV_Position, nointerpolation uint id : OBJECT_ID) : SV_Target
{
gVisible[id] = 1; // only executed for pixels passing the depth test
return 0;
}17.4 Blending (host state)
Blending is fixed-function, configured in D3D12_BLEND_DESC/D3D11_BLEND_DESC:
Dual-source (SV_Target0 + SV_Target1) Premultiplied alpha (return float4(color * alpha, alpha);) composes correctly with filtering and mipmaps.
17.5 Visual debugging with color
Output intermediate values to see them: return float4(N * 0.5 + 0.5, 1); (normals), return float4(i.uv, 0, 1); (UVs), return float4(frac(i.posW), 1); (world position), heatmaps for counts or costs.