shadow_mapping.hlsl

src/5.advanced_lighting/3.1.shadow_mapping/shadow_mapping.hlsl · 87 lines

// Read matrices row by row, as rin stores them; mul(M, v) is then M * v.
#pragma pack_matrix(row_major)

cbuffer transforms : register(b0)
{
    float4x4 model;
    float4x4 normal_matrix;
    float4x4 view;
    float4x4 projection;
    float3 view_position;
};

struct vs_in
{
    float3 position : POSITION;
    float3 normal : NORMAL;
    float2 uv : TEXCOORD;
};

// Position and normal in world space, where the lighting is done.
struct vs_out
{
    float4 position : SV_Position;
    float3 world : WORLD;
    float3 normal : NORMAL;
    float2 uv : TEXCOORD;
};

vs_out vs_main(vs_in v)
{
    vs_out o;
    float4 world = mul(model, float4(v.position, 1.0));
    o.world = world.xyz;
    o.position = mul(projection, mul(view, world));
    o.normal = mul((float3x3)normal_matrix, v.normal);
    o.uv = v.uv;
    return o;
}

cbuffer shadow : register(b1)
{
    float4x4 light_space;
    float3 light_direction;  // where the sunlight travels
};

Texture2D albedo : register(t0);
Texture2D<float> shadow_map : register(t1);
SamplerState linear_wrap : register(s0);
SamplerComparisonState shadow_compare : register(s1);

// 1 lit, 0 shadowed, and between at the edges.
float lit_fraction(float3 world)
{
    float4 clip = mul(light_space, float4(world, 1.0));
    float3 ndc = clip.xyz / clip.w;
    // past the far end of the light's box: nothing there to cast a shadow
    if (ndc.z > 1.0) return 1.0;
    // clip space y is up, texture v is down
    float2 uv = float2(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);

    float w, h;
    shadow_map.GetDimensions(w, h);
    float2 texel = 1.0 / float2(w, h);
    float sum = 0.0;
    for (int y = -1; y <= 1; y++)
    {
        for (int x = -1; x <= 1; x++)
        {
            sum += shadow_map.SampleCmpLevelZero(shadow_compare, uv + float2(x, y) * texel, ndc.z);
        }
    }
    return sum / 9.0;
}

float4 ps_main(vs_out p) : SV_Target
{
    float3 color = albedo.Sample(linear_wrap, p.uv).rgb;
    float3 n = normalize(p.normal);
    float3 to_light = -light_direction;
    float3 to_eye = normalize(view_position - p.world);
    float3 halfway = normalize(to_light + to_eye);

    float diffuse = max(dot(n, to_light), 0.0);
    float spec = pow(max(dot(n, halfway), 0.0), 64.0);
    float lit = lit_fraction(p.world);
    return float4((0.15 + lit * (diffuse + 0.3 * spec)) * color, 1.0);
}
Part of rin-dx11, LearnOpenGL's lessons rewritten for Direct3D 11 and rin. Licensed CC BY-NC 4.0, after LearnOpenGL by Joey de Vries.