Skip to content

Commit afd3781

Browse files
committed
Add slang shader for omni-directional shadow mapping sample
1 parent 153aa3b commit afd3781

3 files changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
struct VSOutput
8+
{
9+
float4 Pos : SV_POSITION;
10+
float2 UV;
11+
};
12+
13+
struct UBO
14+
{
15+
float4x4 projection;
16+
float4x4 view;
17+
float4x4 model;
18+
};
19+
ConstantBuffer<UBO> ubo;
20+
21+
SamplerCube shadowCubeMapSampler;
22+
23+
[shader("vertex")]
24+
VSOutput vertexMain(uint VertexIndex: SV_VertexID)
25+
{
26+
VSOutput output;
27+
output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
28+
output.Pos = float4(output.UV.xy * 2.0f - 1.0f, 0.0f, 1.0f);
29+
return output;
30+
}
31+
32+
[shader("fragment")]
33+
float4 fragmentMain(VSOutput input)
34+
{
35+
float4 outFragColor = float4(0, 0, 0, 0);
36+
outFragColor.rgb = float3(0.05, 0.05, 0.05);
37+
38+
float3 samplePos = float3(0, 0, 0);
39+
40+
// Crude statement to visualize different cube map faces based on UV coordinates
41+
int x = int(floor(input.UV.x / 0.25f));
42+
int y = int(floor(input.UV.y / (1.0 / 3.0)));
43+
if (y == 1) {
44+
float2 uv = float2(input.UV.x * 4.0f, (input.UV.y - 1.0/3.0) * 3.0);
45+
uv = 2.0 * float2(uv.x - float(x) * 1.0, uv.y) - 1.0;
46+
switch (x) {
47+
case 0: // NEGATIVE_X
48+
samplePos = float3(-1.0f, uv.y, uv.x);
49+
break;
50+
case 1: // POSITIVE_Z
51+
samplePos = float3(uv.x, uv.y, 1.0f);
52+
break;
53+
case 2: // POSITIVE_X
54+
samplePos = float3(1.0, uv.y, -uv.x);
55+
break;
56+
case 3: // NEGATIVE_Z
57+
samplePos = float3(-uv.x, uv.y, -1.0f);
58+
break;
59+
}
60+
} else {
61+
if (x == 1) {
62+
float2 uv = float2((input.UV.x - 0.25) * 4.0, (input.UV.y - float(y) / 3.0) * 3.0);
63+
uv = 2.0 * uv - 1.0;
64+
switch (y) {
65+
case 0: // NEGATIVE_Y
66+
samplePos = float3(uv.x, -1.0f, uv.y);
67+
break;
68+
case 2: // POSITIVE_Y
69+
samplePos = float3(uv.x, 1.0f, -uv.y);
70+
break;
71+
}
72+
}
73+
}
74+
75+
if ((samplePos.x != 0.0f) && (samplePos.y != 0.0f)) {
76+
float dist = length(shadowCubeMapSampler.Sample(samplePos).xyz) * 0.005;
77+
outFragColor = float4(dist.xxx, 1.0);
78+
}
79+
return outFragColor;
80+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
struct VSInput
8+
{
9+
float3 Pos;
10+
};
11+
12+
struct VSOutput
13+
{
14+
float4 Pos : SV_POSITION;
15+
float4 WorldPos;
16+
float3 LightPos;
17+
};
18+
19+
struct UBO
20+
{
21+
float4x4 projection;
22+
float4x4 view;
23+
float4x4 model;
24+
float4 lightPos;
25+
};
26+
ConstantBuffer<UBO> ubo;
27+
28+
[shader("vertex")]
29+
VSOutput vertexMain(VSInput input, uniform float4x4 view)
30+
{
31+
VSOutput output;
32+
output.Pos = mul(ubo.projection, mul(view, mul(ubo.model, float4(input.Pos, 1.0))));
33+
34+
output.WorldPos = float4(input.Pos, 1.0);
35+
output.LightPos = ubo.lightPos.xyz;
36+
return output;
37+
}
38+
39+
[shader("fragment")]
40+
float fragmentMain(VSOutput input)
41+
{
42+
// Store distance to light as 32 bit float value
43+
float3 lightVec = input.WorldPos.xyz - input.LightPos;
44+
return length(lightVec);
45+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
struct VSInput
8+
{
9+
float3 Pos;
10+
float3 Color;
11+
float3 Normal;
12+
};
13+
14+
struct VSOutput
15+
{
16+
float4 Pos : SV_POSITION;
17+
float3 Normal;
18+
float3 Color;
19+
float3 EyePos;
20+
float3 LightVec;
21+
float3 WorldPos;
22+
float3 LightPos;
23+
};
24+
25+
struct UBO
26+
{
27+
float4x4 projection;
28+
float4x4 view;
29+
float4x4 model;
30+
float4 lightPos;
31+
};
32+
ConstantBuffer<UBO> ubo;
33+
34+
SamplerCube shadowCubeMapSampler;
35+
36+
#define EPSILON 0.15
37+
#define SHADOW_OPACITY 0.5
38+
39+
[shader("vertex")]
40+
VSOutput vertexMain(VSInput input)
41+
{
42+
VSOutput output;
43+
output.Color = input.Color;
44+
output.Normal = input.Normal;
45+
46+
output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0))));
47+
output.EyePos = mul(ubo.model, float4(input.Pos, 1.0f)).xyz;
48+
output.LightVec = normalize(ubo.lightPos.xyz - input.Pos.xyz);
49+
output.WorldPos = input.Pos;
50+
51+
output.LightPos = ubo.lightPos.xyz;
52+
return output;
53+
}
54+
55+
[shader("fragment")]
56+
float4 fragmentMain(VSOutput input)
57+
{
58+
// Lighting
59+
float3 N = normalize(input.Normal);
60+
float3 L = normalize(float3(1.0, 1.0, 1.0));
61+
62+
float3 Eye = normalize(-input.EyePos);
63+
float3 Reflected = normalize(reflect(-input.LightVec, input.Normal));
64+
65+
float4 IAmbient = float4(float3(0.05, 0.05, 0.05), 1.0);
66+
float4 IDiffuse = float4(1.0, 1.0, 1.0, 1.0) * max(dot(input.Normal, input.LightVec), 0.0);
67+
68+
float4 outFragColor = float4(IAmbient + IDiffuse * float4(input.Color, 1.0));
69+
70+
// Shadow
71+
float3 lightVec = input.WorldPos - input.LightPos;
72+
float sampledDist = shadowCubeMapSampler.Sample(lightVec).r;
73+
float dist = length(lightVec);
74+
75+
// Check if fragment is in shadow
76+
float shadow = (dist <= sampledDist + EPSILON) ? 1.0 : SHADOW_OPACITY;
77+
78+
outFragColor.rgb *= shadow;
79+
return outFragColor;
80+
}

0 commit comments

Comments
 (0)