Skip to content

Commit ad5b22c

Browse files
committed
Add slang shaders for parallax mapping sample
1 parent e4b7bb1 commit ad5b22c

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
struct UBOScene
8+
{
9+
float4x4 projection;
10+
float4x4 view;
11+
float4x4 model;
12+
float4 lightPos;
13+
float4 cameraPos;
14+
};
15+
ConstantBuffer<UBOScene> uboScene;
16+
17+
Sampler2D samplerColorMap;
18+
Sampler2D samplerNormalHeightMap;
19+
20+
struct UBOParams
21+
{
22+
float heightScale;
23+
float parallaxBias;
24+
float numLayers;
25+
int mappingMode;
26+
};
27+
ConstantBuffer<UBOParams> uboParams;
28+
29+
struct VSInput
30+
{
31+
float3 Pos;
32+
float2 UV;
33+
float3 Normal;
34+
float4 Tangent;
35+
};
36+
37+
struct VSOutput
38+
{
39+
float4 Pos : SV_POSITION;
40+
float2 UV;
41+
float3 TangentLightPos;
42+
float3 TangentViewPos;
43+
float3 TangentFragPos;
44+
};
45+
46+
float2 parallaxMapping(float2 uv, float3 viewDir)
47+
{
48+
float height = 1.0 - samplerNormalHeightMap.SampleLevel(uv, 0.0).a;
49+
float2 p = viewDir.xy * (height * (uboParams.heightScale * 0.5) + uboParams.parallaxBias) / viewDir.z;
50+
return uv - p;
51+
}
52+
53+
float2 steepParallaxMapping(float2 uv, float3 viewDir)
54+
{
55+
float layerDepth = 1.0 / uboParams.numLayers;
56+
float currLayerDepth = 0.0;
57+
float2 deltaUV = viewDir.xy * uboParams.heightScale / (viewDir.z * uboParams.numLayers);
58+
float2 currUV = uv;
59+
float height = 1.0 - samplerNormalHeightMap.SampleLevel(currUV, 0.0).a;
60+
for (int i = 0; i < uboParams.numLayers; i++) {
61+
currLayerDepth += layerDepth;
62+
currUV -= deltaUV;
63+
height = 1.0 - samplerNormalHeightMap.SampleLevel(currUV, 0.0).a;
64+
if (height < currLayerDepth) {
65+
break;
66+
}
67+
}
68+
return currUV;
69+
}
70+
71+
float2 parallaxOcclusionMapping(float2 uv, float3 viewDir)
72+
{
73+
float layerDepth = 1.0 / uboParams.numLayers;
74+
float currLayerDepth = 0.0;
75+
float2 deltaUV = viewDir.xy * uboParams.heightScale / (viewDir.z * uboParams.numLayers);
76+
float2 currUV = uv;
77+
float height = 1.0 - samplerNormalHeightMap.SampleLevel(currUV, 0.0).a;
78+
for (int i = 0; i < uboParams.numLayers; i++) {
79+
currLayerDepth += layerDepth;
80+
currUV -= deltaUV;
81+
height = 1.0 - samplerNormalHeightMap.SampleLevel(currUV, 0.0).a;
82+
if (height < currLayerDepth) {
83+
break;
84+
}
85+
}
86+
float2 prevUV = currUV + deltaUV;
87+
float nextDepth = height - currLayerDepth;
88+
float prevDepth = 1.0 - samplerNormalHeightMap.SampleLevel(prevUV, 0.0).a - currLayerDepth + layerDepth;
89+
return lerp(currUV, prevUV, nextDepth / (nextDepth - prevDepth));
90+
}
91+
92+
[shader("vertex")]
93+
94+
VSOutput vertexMain(VSInput input)
95+
{
96+
VSOutput output;
97+
output.Pos = mul(uboScene.projection, mul(uboScene.view, mul(uboScene.model, float4(input.Pos, 1.0f))));
98+
output.UV = input.UV;
99+
100+
float3 N = normalize(input.Normal);
101+
float3 T = normalize(input.Tangent.xyz);
102+
float3 B = normalize(cross(N, T));
103+
float3x3 TBN = float3x3(T, B, N);
104+
105+
output.TangentLightPos = mul(TBN, uboScene.lightPos.xyz);
106+
output.TangentViewPos = mul(TBN, uboScene.cameraPos.xyz);
107+
output.TangentFragPos = mul(TBN, mul(uboScene.model, float4(input.Pos, 1.0)).xyz);
108+
return output;
109+
}
110+
111+
[shader("fragment")]
112+
float4 fragmentMain(VSOutput input)
113+
{
114+
float3 V = normalize(input.TangentViewPos - input.TangentFragPos);
115+
float2 uv = input.UV;
116+
117+
if (uboParams.mappingMode == 0) {
118+
// Color only
119+
return samplerColorMap.Sample(input.UV);
120+
} else {
121+
switch (uboParams.mappingMode) {
122+
case 2:
123+
uv = parallaxMapping(input.UV, V);
124+
break;
125+
case 3:
126+
uv = steepParallaxMapping(input.UV, V);
127+
break;
128+
case 4:
129+
uv = parallaxOcclusionMapping(input.UV, V);
130+
break;
131+
}
132+
133+
// Discard fragments at texture border
134+
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
135+
clip(-1);
136+
}
137+
138+
float3 N = normalize(samplerNormalHeightMap.SampleLevel(uv, 0.0).rgb * 2.0 - 1.0);
139+
float3 L = normalize(input.TangentLightPos - input.TangentFragPos);
140+
float3 R = reflect(-L, N);
141+
float3 H = normalize(L + V);
142+
143+
float3 color = samplerColorMap.Sample(uv).rgb;
144+
float3 ambient = 0.2 * color;
145+
float3 diffuse = max(dot(L, N), 0.0) * color;
146+
float3 specular = float3(0.15, 0.15, 0.15) * pow(max(dot(N, H), 0.0), 32.0);
147+
148+
return float4(ambient + diffuse + specular, 1.0f);
149+
}
150+
}

0 commit comments

Comments
 (0)