forked from dexyfex/CodeWalker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShadowmap.hlsli
250 lines (200 loc) · 9.4 KB
/
Shadowmap.hlsli
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#include "Common.hlsli"
//Texture2DArray<float> Depthmap : register(t1);
//SamplerState DepthmapSS : register(s1);
Texture2D Depthmap : register(t1);
SamplerComparisonState DepthmapSS : register(s1);
cbuffer ShadowmapVars : register(b1)
{
float4 CamScenePos; //in shadow scene coords
float4x4 CamSceneView;
float4x4 LightView;
float4 LightDir;
float4 CascadeOffsets[16];
float4 CascadeScales[16];
float4 CascadeDepths[16]; //in scene eye space
int CascadeCount;
int CascadeVisual;
int PCFLoopStart;
int PCFLoopEnd;
float BorderPaddingMin;
float BorderPaddingMax;
float Bias;
float BlurBetweenCascades;
float CascadeCountInv;
float TexelSize;
float TexelSizeX;
float ShadowMaxDistance; //2000 or so
};
float ShadowmapSceneDepth(float3 camRelPos, out float4 lspos)
{
float4 scenePos = float4(camRelPos + CamScenePos.xyz, 1.0);
lspos = mul(scenePos, LightView);
return mul(scenePos, CamSceneView).z;
}
//--------------------------------------------------------------------------------------
// Use PCF to sample the depth map and return a percent lit value.
//--------------------------------------------------------------------------------------
void ShadowmapCalculatePCFPercentLit(in float4 vShadowTexCoord,
in float fRightTexelDepthDelta,
in float fUpTexelDepthDelta,
in float fBlurRowSize,
in float fCascade,
out float fPercentLit
)
{
fPercentLit = 0.0f;
// This loop could be unrolled, and texture immediate offsets could be used if the kernel size were fixed.
// This would be performance improvment.
for (int x = PCFLoopStart; x < PCFLoopEnd; ++x)
{
for (int y = PCFLoopStart; y < PCFLoopEnd; ++y)
{
float depthcompare = vShadowTexCoord.z;
// A very simple solution to the depth bias problems of PCF is to use an offset.
// Unfortunately, too much offset can lead to Peter-panning (shadows near the base of object disappear )
// Too little offset can lead to shadow acne ( objects that should not be in shadow are partially self shadowed ).
depthcompare -= Bias;
//depthcompare += Bias;
// Compare the transformed pixel depth to the depth read from the map.
//fPercentLit += Depthmap.SampleLevel(DepthmapSS,
fPercentLit += Depthmap.SampleCmpLevelZero(DepthmapSS,
float2(
vShadowTexCoord.x + (((float)x) * TexelSizeX),
vShadowTexCoord.y + (((float)y) * TexelSize)//,
), depthcompare);
//fCascade
//), 0).r > depthcompare ? 1.0 : 0.0;// , depthcompare);//== 1.0)?1:0;//
}
}
fPercentLit /= (float)fBlurRowSize;
}
//--------------------------------------------------------------------------------------
// Calculate amount to blend between two cascades and the band where blending will occure.
//--------------------------------------------------------------------------------------
void ShadowmapCalculateBlendAmountForMap(in float4 vShadowMapTextureCoord,
in out float fCurrentPixelsBlendBandLocation,
out float fBlendBetweenCascadesAmount)
{
// Calcaulte the blend band for the map based selection.
float2 distanceToOne = float2 (1.0f - vShadowMapTextureCoord.x, 1.0f - vShadowMapTextureCoord.y);
fCurrentPixelsBlendBandLocation = min(vShadowMapTextureCoord.x, vShadowMapTextureCoord.y);
float fCurrentPixelsBlendBandLocation2 = min(distanceToOne.x, distanceToOne.y);
fCurrentPixelsBlendBandLocation =
min(fCurrentPixelsBlendBandLocation, fCurrentPixelsBlendBandLocation2);
fBlendBetweenCascadesAmount = BlurBetweenCascades != 0.0 ?
(fCurrentPixelsBlendBandLocation / BlurBetweenCascades) : 0.0;
}
static const float4 vCascadeColorsMultiplier[8] =
{
float4 (1.5f, 0.0f, 0.0f, 1.0f),
float4 (0.0f, 1.5f, 0.0f, 1.0f),
float4 (0.0f, 0.0f, 5.5f, 1.0f),
float4 (1.5f, 0.0f, 5.5f, 1.0f),
float4 (1.5f, 1.5f, 0.0f, 1.0f),
float4 (1.0f, 1.0f, 1.0f, 1.0f),
float4 (0.0f, 1.0f, 5.5f, 1.0f),
float4 (0.5f, 3.5f, 0.75f, 1.0f)
};
void ShadowComputeCoordinatesTransform(in int iCascadeIndex, inout float4 vShadowTexCoord)
{
//transform X coord for current cascade.
vShadowTexCoord.x *= CascadeCountInv;// m_fShadowPartitionSize; // precomputed (float)iCascadeIndex / (float)CASCADE_CNT
vShadowTexCoord.x += (CascadeCountInv*(float)iCascadeIndex);// (m_fShadowPartitionSize * (float)iCascadeIndex);
}
float ShadowAmount(float4 shadowcoord, float shadowdepth)//, inout float4 colour)
{
float4 vShadowMapTextureCoord = 0.0f;
float4 vShadowMapTextureCoord_blend = 0.0f;
float4 vVisualizeCascadeColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
float fPercentLit = 0.0f;
float fPercentLit_blend = 0.0f;
float fUpTextDepthWeight = 0;
float fRightTextDepthWeight = 0;
float fUpTextDepthWeight_blend = 0;
float fRightTextDepthWeight_blend = 0;
int iBlurRowSize = PCFLoopEnd - PCFLoopStart;
iBlurRowSize *= iBlurRowSize;
float fBlurRowSize = (float)iBlurRowSize;
int iCascadeFound = 0;
int iNextCascadeIndex = 1;
// The interval based selection technique compares the pixel's depth against the frustum's cascade divisions.
float fCurrentPixelDepth = shadowdepth;
// This for loop is not necessary when the frustum is uniformaly divided and interval based selection is used.
// In this case fCurrentPixelDepth could be used as an array lookup into the correct frustum.
int iCurrentCascadeIndex = 0;
float4 vShadowMapTextureCoordViewSpace = shadowcoord;
if (CascadeCount == 1)
{
vShadowMapTextureCoord = vShadowMapTextureCoordViewSpace * CascadeScales[0];
vShadowMapTextureCoord += CascadeOffsets[0];
}
if (CascadeCount > 1) {
for (int iCascadeIndex = 0; iCascadeIndex < CascadeCount && iCascadeFound == 0; ++iCascadeIndex)
{
vShadowMapTextureCoord = vShadowMapTextureCoordViewSpace * CascadeScales[iCascadeIndex];
vShadowMapTextureCoord += CascadeOffsets[iCascadeIndex];
if (min(vShadowMapTextureCoord.x, vShadowMapTextureCoord.y) > BorderPaddingMin
&& max(vShadowMapTextureCoord.x, vShadowMapTextureCoord.y) < BorderPaddingMax)
{
iCurrentCascadeIndex = iCascadeIndex;
iCascadeFound = 1;
}
}
}
if (iCascadeFound == 0 || vShadowMapTextureCoord.z>=1)
{
//colour = float4(0.1, 0.3, 1.0, 0.5);
return 1.0; //out of range!
}
else
{
ShadowComputeCoordinatesTransform(iCurrentCascadeIndex, vShadowMapTextureCoord);
vVisualizeCascadeColor = vCascadeColorsMultiplier[iCurrentCascadeIndex];
//colour = vVisualizeCascadeColor;
// Repeat texcoord calculations for the next cascade.
// The next cascade index is used for blurring between maps.
iNextCascadeIndex = min(CascadeCount - 1, iCurrentCascadeIndex + 1);
float fBlendBetweenCascadesAmount = 1.0f;
float fCurrentPixelsBlendBandLocation = 1.0f;
ShadowmapCalculateBlendAmountForMap(vShadowMapTextureCoord, fCurrentPixelsBlendBandLocation, fBlendBetweenCascadesAmount);
ShadowmapCalculatePCFPercentLit(vShadowMapTextureCoord, fRightTextDepthWeight, fUpTextDepthWeight, fBlurRowSize, (float)iCurrentCascadeIndex, fPercentLit);
if (CascadeCount > 1)
{
if (fCurrentPixelsBlendBandLocation < BlurBetweenCascades)
{ // the current pixel is within the blend band.
// Repeat texcoord calculations for the next cascade.
// The next cascade index is used for blurring between maps.
vShadowMapTextureCoord_blend = vShadowMapTextureCoordViewSpace * CascadeScales[iNextCascadeIndex];
vShadowMapTextureCoord_blend += CascadeOffsets[iNextCascadeIndex];
ShadowComputeCoordinatesTransform(iNextCascadeIndex, vShadowMapTextureCoord_blend);
// We repeat the calcuation for the next cascade layer, when blending between maps.
if (fCurrentPixelsBlendBandLocation < BlurBetweenCascades)
{
// the current pixel is within the blend band.
ShadowmapCalculatePCFPercentLit(vShadowMapTextureCoord_blend, fRightTextDepthWeight_blend, fUpTextDepthWeight_blend, fBlurRowSize, (float)iNextCascadeIndex, fPercentLit_blend);
fPercentLit = lerp(fPercentLit_blend, fPercentLit, fBlendBetweenCascadesAmount);
// Blend the two calculated shadows by the blend amount.
}
}
}
return fPercentLit;
}
}
float3 FullLighting(float3 diff, float3 spec, float3 norm, float4 vc0, uniform ShaderGlobalLightParams globalLights, uint enableShadows, float shadowdepth, float4 shadowcoord)
{
float lf = saturate(dot(norm, globalLights.LightDir.xyz));
float shadowlit = 1.0;
if (enableShadows == 1)
{
//float shadowdepth = input.Shadows.x;// *0.000001;
if (abs(shadowdepth) < ShadowMaxDistance)//2km
{
//float4 shadowcoord = input.LightShadow;
//float4 shadowcolour = (float4)1;
shadowlit = ShadowAmount(shadowcoord, shadowdepth);// , shadowcolour);
}
}
lf *= shadowlit;
float3 speclit = spec*shadowlit;
return GlobalLighting(diff, norm, vc0, lf, globalLights) + speclit;
}