1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "BsRenderBeastPrerequisites.h" |
6 | #include "Utility/BsModule.h" |
7 | #include "Math/BsMatrix4.h" |
8 | #include "Math/BsConvexVolume.h" |
9 | #include "Renderer/BsParamBlocks.h" |
10 | #include "Renderer/BsRendererMaterial.h" |
11 | #include "Renderer/BsLight.h" |
12 | #include "Image/BsTextureAtlasLayout.h" |
13 | #include "BsRendererLight.h" |
14 | |
15 | namespace bs { namespace ct |
16 | { |
17 | struct FrameInfo; |
18 | class RendererLight; |
19 | class RendererScene; |
20 | struct ShadowInfo; |
21 | |
22 | /** @addtogroup RenderBeast |
23 | * @{ |
24 | */ |
25 | |
26 | BS_PARAM_BLOCK_BEGIN(ShadowParamsDef) |
27 | BS_PARAM_BLOCK_ENTRY(Matrix4, gMatViewProj) |
28 | BS_PARAM_BLOCK_ENTRY(Vector2, gNDCZToDeviceZ) |
29 | BS_PARAM_BLOCK_ENTRY(float, gDepthBias) |
30 | BS_PARAM_BLOCK_ENTRY(float, gInvDepthRange) |
31 | BS_PARAM_BLOCK_END |
32 | |
33 | extern ShadowParamsDef gShadowParamsDef; |
34 | |
35 | /** Material used for rendering a single face of a shadow map, while applying bias in the pixel shader. */ |
36 | class ShadowDepthNormalMat : public RendererMaterial<ShadowDepthNormalMat> |
37 | { |
38 | RMAT_DEF("ShadowDepthNormal.bsl" ); |
39 | |
40 | /** Helper method used for initializing variations of this material. */ |
41 | template<bool skinned, bool morph> |
42 | static const ShaderVariation& getVariation() |
43 | { |
44 | static ShaderVariation variation = ShaderVariation( |
45 | { |
46 | ShaderVariation::Param("SKINNED" , skinned), |
47 | ShaderVariation::Param("MORPH" , morph) |
48 | }); |
49 | |
50 | return variation; |
51 | } |
52 | |
53 | public: |
54 | ShadowDepthNormalMat() = default; |
55 | |
56 | /** Binds the material to the pipeline, ready to be used on subsequent draw calls. */ |
57 | void bind(const SPtr<GpuParamBlockBuffer>& shadowParams); |
58 | |
59 | /** Sets a new buffer that determines per-object properties. */ |
60 | void setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams); |
61 | |
62 | /** |
63 | * Returns the material variation matching the provided parameters. |
64 | * |
65 | * @param[in] skinned True if the shadow caster supports bone animation. |
66 | * @param[in] morph True if the shadow caster supports morph shape animation. |
67 | */ |
68 | static ShadowDepthNormalMat* getVariation(bool skinned, bool morph); |
69 | }; |
70 | |
71 | /** Material used for rendering a single face of a shadow map, without running the pixel shader. */ |
72 | class ShadowDepthNormalNoPSMat : public RendererMaterial<ShadowDepthNormalNoPSMat> |
73 | { |
74 | RMAT_DEF("ShadowDepthNormalNoPS.bsl" ); |
75 | |
76 | /** Helper method used for initializing variations of this material. */ |
77 | template<bool skinned, bool morph> |
78 | static const ShaderVariation& getVariation() |
79 | { |
80 | static ShaderVariation variation = ShaderVariation( |
81 | { |
82 | ShaderVariation::Param("SKINNED" , skinned), |
83 | ShaderVariation::Param("MORPH" , morph) |
84 | }); |
85 | |
86 | return variation; |
87 | } |
88 | |
89 | public: |
90 | ShadowDepthNormalNoPSMat(); |
91 | |
92 | /** Binds the material to the pipeline, ready to be used on subsequent draw calls. */ |
93 | void bind(const SPtr<GpuParamBlockBuffer>& shadowParams); |
94 | |
95 | /** Sets a new buffer that determines per-object properties. */ |
96 | void setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams); |
97 | |
98 | /** |
99 | * Returns the material variation matching the provided parameters. |
100 | * |
101 | * @param[in] skinned True if the shadow caster supports bone animation. |
102 | * @param[in] morph True if the shadow caster supports morph shape animation. |
103 | */ |
104 | static ShadowDepthNormalNoPSMat* getVariation(bool skinned, bool morph); |
105 | }; |
106 | |
107 | /** Material used for rendering a single face of a shadow map, for a directional light. */ |
108 | class ShadowDepthDirectionalMat : public RendererMaterial<ShadowDepthDirectionalMat> |
109 | { |
110 | RMAT_DEF("ShadowDepthDirectional.bsl" ); |
111 | |
112 | /** Helper method used for initializing variations of this material. */ |
113 | template<bool skinned, bool morph> |
114 | static const ShaderVariation& getVariation() |
115 | { |
116 | static ShaderVariation variation = ShaderVariation( |
117 | { |
118 | ShaderVariation::Param("SKINNED" , skinned), |
119 | ShaderVariation::Param("MORPH" , morph) |
120 | }); |
121 | |
122 | return variation; |
123 | } |
124 | public: |
125 | ShadowDepthDirectionalMat(); |
126 | |
127 | /** Binds the material to the pipeline, ready to be used on subsequent draw calls. */ |
128 | void bind(const SPtr<GpuParamBlockBuffer>& shadowParams); |
129 | |
130 | /** Sets a new buffer that determines per-object properties. */ |
131 | void setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams); |
132 | |
133 | /** |
134 | * Returns the material variation matching the provided parameters. |
135 | * |
136 | * @param[in] skinned True if the shadow caster supports bone animation. |
137 | * @param[in] morph True if the shadow caster supports morph shape animation. |
138 | */ |
139 | static ShadowDepthDirectionalMat* getVariation(bool skinned, bool morph); |
140 | }; |
141 | |
142 | BS_PARAM_BLOCK_BEGIN(ShadowCubeMatricesDef) |
143 | BS_PARAM_BLOCK_ENTRY_ARRAY(Matrix4, gFaceVPMatrices, 6) |
144 | BS_PARAM_BLOCK_END |
145 | |
146 | extern ShadowCubeMatricesDef gShadowCubeMatricesDef; |
147 | |
148 | BS_PARAM_BLOCK_BEGIN(ShadowCubeMasksDef) |
149 | BS_PARAM_BLOCK_ENTRY_ARRAY(int, gFaceMasks, 6) |
150 | BS_PARAM_BLOCK_END |
151 | |
152 | extern ShadowCubeMasksDef gShadowCubeMasksDef; |
153 | |
154 | /** Material used for rendering an omni directional cube shadow map. */ |
155 | class ShadowDepthCubeMat : public RendererMaterial<ShadowDepthCubeMat> |
156 | { |
157 | RMAT_DEF("ShadowDepthCube.bsl" ); |
158 | |
159 | /** Helper method used for initializing variations of this material. */ |
160 | template<bool skinned, bool morph> |
161 | static const ShaderVariation& getVariation() |
162 | { |
163 | static ShaderVariation variation = ShaderVariation( |
164 | { |
165 | ShaderVariation::Param("SKINNED" , skinned), |
166 | ShaderVariation::Param("MORPH" , morph) |
167 | }); |
168 | |
169 | return variation; |
170 | } |
171 | public: |
172 | ShadowDepthCubeMat(); |
173 | |
174 | /** Binds the material to the pipeline, ready to be used on subsequent draw calls. */ |
175 | void bind(const SPtr<GpuParamBlockBuffer>& shadowParams, const SPtr<GpuParamBlockBuffer>& shadowCubeParams); |
176 | |
177 | /** Sets a new buffer that determines per-object properties. */ |
178 | void setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams, |
179 | const SPtr<GpuParamBlockBuffer>& shadowCubeMasks); |
180 | |
181 | /** |
182 | * Returns the material variation matching the provided parameters. |
183 | * |
184 | * @param[in] skinned True if the shadow caster supports bone animation. |
185 | * @param[in] morph True if the shadow caster supports morph shape animation. |
186 | */ |
187 | static ShadowDepthCubeMat* getVariation(bool skinned, bool morph); |
188 | }; |
189 | |
190 | BS_PARAM_BLOCK_BEGIN(ShadowProjectVertParamsDef) |
191 | BS_PARAM_BLOCK_ENTRY(Vector4, gPositionAndScale) |
192 | BS_PARAM_BLOCK_END |
193 | |
194 | extern ShadowProjectVertParamsDef gShadowProjectVertParamsDef; |
195 | |
196 | /** Material used for populating the stencil buffer when projecting non-omnidirectional shadows. */ |
197 | class ShadowProjectStencilMat : public RendererMaterial<ShadowProjectStencilMat> |
198 | { |
199 | RMAT_DEF("ShadowProjectStencil.bsl" ); |
200 | |
201 | /** Helper method used for initializing variations of this material. */ |
202 | template<bool directional, bool useZFailStencil> |
203 | static const ShaderVariation& getVariation() |
204 | { |
205 | static ShaderVariation variation = ShaderVariation( |
206 | { |
207 | ShaderVariation::Param("NEEDS_TRANSFORM" , !directional), |
208 | ShaderVariation::Param("USE_ZFAIL_STENCIL" , useZFailStencil) |
209 | }); |
210 | |
211 | return variation; |
212 | }; |
213 | public: |
214 | ShadowProjectStencilMat(); |
215 | |
216 | /** Binds the material and its parameters to the pipeline. */ |
217 | void bind(const SPtr<GpuParamBlockBuffer>& perCamera); |
218 | |
219 | /** Returns the material variation matching the provided parameters. |
220 | * |
221 | * @param[in] directional Set to true if shadows from a directional light are being rendered. |
222 | * @param[in] useZFailStencil If true the material will use z-fail operation to modify the stencil buffer. If |
223 | * false z-pass will be used instead. Z-pass is a more performant alternative as it |
224 | * doesn't disable hi-z optimization, but it cannot handle the case when the viewer is |
225 | * inside the drawn geometry. |
226 | */ |
227 | static ShadowProjectStencilMat* getVariation(bool directional, bool useZFailStencil); |
228 | private: |
229 | SPtr<GpuParamBlockBuffer> mVertParams; |
230 | }; |
231 | |
232 | /** Common parameters used by the shadow projection materials. */ |
233 | struct ShadowProjectParams |
234 | { |
235 | ShadowProjectParams(const Light& light, const SPtr<Texture>& shadowMap, |
236 | const SPtr<GpuParamBlockBuffer>& shadowParams, const SPtr<GpuParamBlockBuffer>& perCameraParams, |
237 | GBufferTextures gbuffer) |
238 | : light(light), shadowMap(shadowMap), shadowParams(shadowParams), perCamera(perCameraParams), gbuffer(gbuffer) |
239 | { } |
240 | |
241 | /** Light which is casting the shadow. */ |
242 | const Light& light; |
243 | |
244 | /** Texture containing the shadow map. */ |
245 | const SPtr<Texture>& shadowMap; |
246 | |
247 | /** Parameter block containing parameters specific for shadow projection. */ |
248 | const SPtr<GpuParamBlockBuffer> shadowParams; |
249 | |
250 | /** Parameter block containing parameters specific to this view. */ |
251 | const SPtr<GpuParamBlockBuffer>& perCamera; |
252 | |
253 | /** Contains the GBuffer textures. */ |
254 | GBufferTextures gbuffer; |
255 | }; |
256 | |
257 | BS_PARAM_BLOCK_BEGIN(ShadowProjectParamsDef) |
258 | BS_PARAM_BLOCK_ENTRY(Matrix4, gMixedToShadowSpace) |
259 | BS_PARAM_BLOCK_ENTRY(Vector2, gShadowMapSize) |
260 | BS_PARAM_BLOCK_ENTRY(Vector2, gShadowMapSizeInv) |
261 | BS_PARAM_BLOCK_ENTRY(float, gSoftTransitionScale) |
262 | BS_PARAM_BLOCK_ENTRY(float, gFadePercent) |
263 | BS_PARAM_BLOCK_ENTRY(float, gFadePlaneDepth) |
264 | BS_PARAM_BLOCK_ENTRY(float, gInvFadePlaneRange) |
265 | BS_PARAM_BLOCK_ENTRY(float, gFace) |
266 | BS_PARAM_BLOCK_END |
267 | |
268 | extern ShadowProjectParamsDef gShadowProjectParamsDef; |
269 | |
270 | /** Material used for projecting depth into a shadow accumulation buffer for non-omnidirectional shadow maps. */ |
271 | class ShadowProjectMat : public RendererMaterial<ShadowProjectMat> |
272 | { |
273 | RMAT_DEF("ShadowProject.bsl" ); |
274 | |
275 | /** Helper method used for initializing variations of this material. */ |
276 | template<UINT32 quality, bool directional, bool MSAA> |
277 | static const ShaderVariation& getVariation() |
278 | { |
279 | static ShaderVariation variation = ShaderVariation( |
280 | { |
281 | ShaderVariation::Param("SHADOW_QUALITY" , quality), |
282 | ShaderVariation::Param("CASCADING" , directional), |
283 | ShaderVariation::Param("NEEDS_TRANSFORM" , !directional), |
284 | ShaderVariation::Param("MSAA_COUNT" , MSAA ? 2 : 1) |
285 | }); |
286 | |
287 | return variation; |
288 | }; |
289 | |
290 | public: |
291 | ShadowProjectMat(); |
292 | |
293 | /** Binds the material and its parameters to the pipeline. */ |
294 | void bind(const ShadowProjectParams& params); |
295 | |
296 | /** Returns the material variation matching the provided parameters. |
297 | * |
298 | * @param[in] quality Quality of the shadow filtering to use. In range [1, 4]. |
299 | * @param[in] directional True if rendering a shadow from a directional light. |
300 | * @param[in] MSAA True if the GBuffer contains per-sample data. |
301 | */ |
302 | static ShadowProjectMat* getVariation(UINT32 quality, bool directional, bool MSAA); |
303 | private: |
304 | SPtr<SamplerState> mSamplerState; |
305 | SPtr<GpuParamBlockBuffer> mVertParams; |
306 | |
307 | GBufferParams mGBufferParams; |
308 | |
309 | GpuParamTexture mShadowMapParam; |
310 | GpuParamSampState mShadowSamplerParam; |
311 | }; |
312 | |
313 | BS_PARAM_BLOCK_BEGIN(ShadowProjectOmniParamsDef) |
314 | BS_PARAM_BLOCK_ENTRY_ARRAY(Matrix4, gFaceVPMatrices, 6) |
315 | BS_PARAM_BLOCK_ENTRY(Vector4, gLightPosAndRadius) |
316 | BS_PARAM_BLOCK_ENTRY(float, gInvResolution) |
317 | BS_PARAM_BLOCK_ENTRY(float, gFadePercent) |
318 | BS_PARAM_BLOCK_ENTRY(float, gDepthBias) |
319 | BS_PARAM_BLOCK_END |
320 | |
321 | extern ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef; |
322 | |
323 | /** Material used for projecting depth into a shadow accumulation buffer for omnidirectional shadow maps. */ |
324 | class ShadowProjectOmniMat : public RendererMaterial<ShadowProjectOmniMat> |
325 | { |
326 | RMAT_DEF("ShadowProjectOmni.bsl" ); |
327 | |
328 | /** Helper method used for initializing variations of this material. */ |
329 | template<UINT32 quality, bool inside, bool MSAA> |
330 | static const ShaderVariation& getVariation() |
331 | { |
332 | static ShaderVariation variation = ShaderVariation( |
333 | { |
334 | ShaderVariation::Param("SHADOW_QUALITY" , quality), |
335 | ShaderVariation::Param("VIEWER_INSIDE_VOLUME" , inside), |
336 | ShaderVariation::Param("NEEDS_TRANSFORM" , true), |
337 | ShaderVariation::Param("MSAA_COUNT" , MSAA ? 2 : 1) |
338 | }); |
339 | |
340 | return variation; |
341 | }; |
342 | |
343 | public: |
344 | ShadowProjectOmniMat(); |
345 | |
346 | /** Binds the material and its parameters to the pipeline. */ |
347 | void bind(const ShadowProjectParams& params); |
348 | |
349 | /** Returns the material variation matching the provided parameters. |
350 | * |
351 | * @param[in] quality Quality of the shadow filtering to use. In range [1, 4]. |
352 | * @param[in] inside True if the viewer is inside the light volume. |
353 | * @param[in] MSAA True if the GBuffer contains per-sample data. |
354 | */ |
355 | static ShadowProjectOmniMat* getVariation(UINT32 quality, bool inside, bool MSAA); |
356 | private: |
357 | SPtr<SamplerState> mSamplerState; |
358 | SPtr<GpuParamBlockBuffer> mVertParams; |
359 | |
360 | GBufferParams mGBufferParams; |
361 | |
362 | GpuParamTexture mShadowMapParam; |
363 | GpuParamSampState mShadowSamplerParam; |
364 | }; |
365 | |
366 | /** Pixel format used for rendering and storing shadow maps. */ |
367 | const PixelFormat SHADOW_MAP_FORMAT = PF_D16; |
368 | |
369 | /** Information about a shadow cast from a single light. */ |
370 | struct ShadowInfo |
371 | { |
372 | /** Updates normalized area coordinates based on the non-normalized ones and the provided atlas size. */ |
373 | void updateNormArea(UINT32 atlasSize); |
374 | |
375 | UINT32 lightIdx; /**< Index of the light casting this shadow. */ |
376 | Rect2I area; /**< Area of the shadow map in pixels, relative to its source texture. */ |
377 | Rect2 normArea; /**< Normalized shadow map area in [0, 1] range. */ |
378 | UINT32 textureIdx; /**< Index of the texture the shadow map is stored in. */ |
379 | |
380 | float depthNear; /**< Distance to the near plane. */ |
381 | float depthFar; /**< Distance to the far plane. */ |
382 | float depthFade; /**< Distance to the plane at which to start fading out the shadows (only for CSM). */ |
383 | float fadeRange; /**< Distance from the fade plane to the far plane (only for CSM). */ |
384 | |
385 | float depthBias; /**< Bias used to reduce shadow acne. */ |
386 | float depthRange; /**< Length of the range covered by the shadow caster volume. */ |
387 | |
388 | UINT32 cascadeIdx; /**< Index of a cascade. Only relevant for CSM. */ |
389 | |
390 | /** View-projection matrix from the shadow casters point of view. */ |
391 | Matrix4 shadowVPTransform; |
392 | |
393 | /** View-projection matrix for each cubemap face, used for omni-directional shadows. */ |
394 | Matrix4 shadowVPTransforms[6]; |
395 | |
396 | /** Bounds of the geometry the shadow is being applied on. */ |
397 | Sphere subjectBounds; |
398 | |
399 | /** Determines the fade amount of the shadow, for each view in the scene. */ |
400 | SmallVector<float, 6> fadePerView; |
401 | }; |
402 | |
403 | /** |
404 | * Contains a texture that serves as an atlas for one or multiple shadow maps. Provides methods for inserting new maps |
405 | * in the atlas. |
406 | */ |
407 | class ShadowMapAtlas |
408 | { |
409 | public: |
410 | ShadowMapAtlas(UINT32 size); |
411 | |
412 | /** |
413 | * Registers a new map in the shadow map atlas. Returns true if the map fits in the atlas, or false otherwise. |
414 | * Resets the last used counter to zero. |
415 | */ |
416 | bool addMap(UINT32 size, Rect2I& area, UINT32 border = 4); |
417 | |
418 | /** Clears all shadow maps from the atlas. Increments the last used counter.*/ |
419 | void clear(); |
420 | |
421 | /** Checks have any maps been added to the atlas. */ |
422 | bool isEmpty() const; |
423 | |
424 | /** |
425 | * Returns the value of the last used counter. See addMap() and clear() for information on how the counter is |
426 | * incremented/decremented. |
427 | */ |
428 | UINT32 getLastUsedCounter() const { return mLastUsedCounter; } |
429 | |
430 | /** Returns the bindable atlas texture. */ |
431 | SPtr<Texture> getTexture() const; |
432 | |
433 | /** Returns the render target that allows you to render into the atlas. */ |
434 | SPtr<RenderTexture> getTarget() const; |
435 | |
436 | private: |
437 | SPtr<PooledRenderTexture> mAtlas; |
438 | |
439 | TextureAtlasLayout mLayout; |
440 | UINT32 mLastUsedCounter; |
441 | }; |
442 | |
443 | /** Contains common code for different shadow map types. */ |
444 | class ShadowMapBase |
445 | { |
446 | public: |
447 | ShadowMapBase(UINT32 size); |
448 | virtual ~ShadowMapBase() {} |
449 | |
450 | /** Returns the bindable shadow map texture. */ |
451 | SPtr<Texture> getTexture() const; |
452 | |
453 | /** Returns the size of a single face of the shadow map texture, in pixels. */ |
454 | UINT32 getSize() const { return mSize; } |
455 | |
456 | /** Makes the shadow map available for re-use and increments the counter returned by getLastUsedCounter(). */ |
457 | void clear() { mIsUsed = false; mLastUsedCounter++; } |
458 | |
459 | /** Marks the shadow map as used and resets the last used counter to zero. */ |
460 | void markAsUsed() { mIsUsed = true; mLastUsedCounter = 0; } |
461 | |
462 | /** Returns true if the object is storing a valid shadow map. */ |
463 | bool isUsed() const { return mIsUsed; } |
464 | |
465 | /** |
466 | * Returns the value of the last used counter. See incrementUseCounter() and markAsUsed() for information on how is |
467 | * the counter incremented/decremented. |
468 | */ |
469 | UINT32 getLastUsedCounter() const { return mLastUsedCounter; } |
470 | |
471 | protected: |
472 | SPtr<PooledRenderTexture> mShadowMap; |
473 | UINT32 mSize; |
474 | |
475 | bool mIsUsed; |
476 | UINT32 mLastUsedCounter; |
477 | }; |
478 | |
479 | /** Contains a cubemap for storing an omnidirectional cubemap. */ |
480 | class ShadowCubemap : public ShadowMapBase |
481 | { |
482 | public: |
483 | ShadowCubemap(UINT32 size); |
484 | |
485 | /** Returns a render target encompassing all six faces of the shadow cubemap. */ |
486 | SPtr<RenderTexture> getTarget() const; |
487 | }; |
488 | |
489 | /** Contains a texture required for rendering cascaded shadow maps. */ |
490 | class ShadowCascadedMap : public ShadowMapBase |
491 | { |
492 | public: |
493 | ShadowCascadedMap(UINT32 size, UINT32 numCascades); |
494 | |
495 | /** Returns the total number of cascades in the cascade shadow map. */ |
496 | UINT32 getNumCascades() const { return mNumCascades; } |
497 | |
498 | /** Returns a render target that allows rendering into a specific cascade of the cascaded shadow map. */ |
499 | SPtr<RenderTexture> getTarget(UINT32 cascadeIdx) const; |
500 | |
501 | /** Provides information about a shadow for the specified cascade. */ |
502 | void setShadowInfo(UINT32 cascadeIdx, const ShadowInfo& info) { mShadowInfos[cascadeIdx] = info; } |
503 | |
504 | /** @copydoc setShadowInfo */ |
505 | const ShadowInfo& getShadowInfo(UINT32 cascadeIdx) const { return mShadowInfos[cascadeIdx]; } |
506 | private: |
507 | UINT32 mNumCascades; |
508 | Vector<SPtr<RenderTexture>> mTargets; |
509 | Vector<ShadowInfo> mShadowInfos; |
510 | }; |
511 | |
512 | /** Provides functionality for rendering shadow maps. */ |
513 | class ShadowRendering |
514 | { |
515 | /** Contains information required for generating a shadow map for a specific light. */ |
516 | struct ShadowMapOptions |
517 | { |
518 | UINT32 lightIdx; |
519 | UINT32 mapSize; |
520 | SmallVector<float, 6> fadePercents; |
521 | }; |
522 | |
523 | /** Contains references to all shadows cast by a specific light. */ |
524 | struct LightShadows |
525 | { |
526 | UINT32 startIdx = 0; |
527 | UINT32 numShadows = 0; |
528 | }; |
529 | |
530 | /** Contains references to all shadows cast by a specific light, per view. */ |
531 | struct PerViewLightShadows |
532 | { |
533 | SmallVector<LightShadows, 6> viewShadows; |
534 | }; |
535 | public: |
536 | ShadowRendering(UINT32 shadowMapSize); |
537 | |
538 | /** For each visible shadow casting light, renders a shadow map from its point of view. */ |
539 | void renderShadowMaps(RendererScene& scene, const RendererViewGroup& viewGroup, const FrameInfo& frameInfo); |
540 | |
541 | /** |
542 | * Renders shadow occlusion values for the specified light, through the provided view, into the currently bound |
543 | * render target. The system uses shadow maps rendered by renderShadowMaps(). |
544 | */ |
545 | void renderShadowOcclusion(const RendererView& view, const RendererLight& light, GBufferTextures gbuffer) const; |
546 | |
547 | /** Changes the default shadow map size. Will cause all shadow maps to be rebuilt. */ |
548 | void setShadowMapSize(UINT32 size); |
549 | private: |
550 | /** Renders cascaded shadow maps for the provided directional light viewed from the provided view. */ |
551 | void renderCascadedShadowMaps(const RendererView& view, UINT32 lightIdx, RendererScene& scene, |
552 | const FrameInfo& frameInfo); |
553 | |
554 | /** Renders shadow maps for the provided spot light. */ |
555 | void renderSpotShadowMap(const RendererLight& light, const ShadowMapOptions& options, RendererScene& scene, |
556 | const FrameInfo& frameInfo); |
557 | |
558 | /** Renders shadow maps for the provided radial light. */ |
559 | void renderRadialShadowMap(const RendererLight& light, const ShadowMapOptions& options, RendererScene& scene, |
560 | const FrameInfo& frameInfo); |
561 | |
562 | /** |
563 | * Calculates optimal shadow map size, taking into account all views in the scene. Also calculates a fade value |
564 | * that can be used for fading out small shadow maps. |
565 | * |
566 | * @param[in] light Light for which to calculate the shadow map properties. Cannot be a directional light. |
567 | * @param[in] viewGroup All the views the shadow will (potentially) be seen through. |
568 | * @param[in] border Border to reduce the shadow map size by, in pixels. |
569 | * @param[out] size Optimal size of the shadow map, in pixels. |
570 | * @param[out] fadePercents Value in range [0, 1] determining how much should the shadow map be faded out. Each |
571 | * entry corresponds to a single view. |
572 | * @param[out] maxFadePercent Maximum value in the @p fadePercents array. |
573 | */ |
574 | void calcShadowMapProperties(const RendererLight& light, const RendererViewGroup& viewGroup, UINT32 border, |
575 | UINT32& size, SmallVector<float, 6>& fadePercents, float& maxFadePercent) const; |
576 | |
577 | /** |
578 | * Draws a mesh representing near and far planes at the provided coordinates. The mesh is constructed using |
579 | * normalized device coordinates and requires no perspective transform. Near plane will be drawn using front facing |
580 | * triangles, and the far plane will be drawn using back facing triangles. |
581 | * |
582 | * @param[in] near Location of the near plane, in NDC. |
583 | * @param[in] far Location of the far plane, in NDC. |
584 | * @param[in] drawNear If disabled, only the far plane will be drawn. |
585 | */ |
586 | void drawNearFarPlanes(float near, float far, bool drawNear = true) const; |
587 | |
588 | /** |
589 | * Draws a frustum mesh using the provided vertices as its corners. Corners should be in the order specified |
590 | * by AABox::Corner enum. |
591 | */ |
592 | void drawFrustum(const std::array<Vector3, 8>& corners) const; |
593 | |
594 | /** |
595 | * Calculates optimal shadow quality based on the quality set in the options and the actual shadow map resolution. |
596 | */ |
597 | static UINT32 getShadowQuality(UINT32 requestedQuality, UINT32 shadowMapResolution, UINT32 minAllowedQuality); |
598 | |
599 | /** |
600 | * Generates a frustum for a single cascade of a cascaded shadow map. Also outputs spherical bounds of the |
601 | * split view frustum. |
602 | * |
603 | * @param[in] view View whose frustum to split. |
604 | * @param[in] lightDir Direction of the light for which we're generating the shadow map. |
605 | * @param[in] cascade Index of the cascade to generate the frustum for. |
606 | * @param[in] numCascades Maximum number of cascades in the cascaded shadow map. Must be greater than zero. |
607 | * @param[out] outBounds Spherical bounds of the split view frustum. |
608 | * @return Convex volume covering the area of the split view frustum visible from the light. |
609 | */ |
610 | static ConvexVolume getCSMSplitFrustum(const RendererView& view, const Vector3& lightDir, UINT32 cascade, |
611 | UINT32 numCascades, Sphere& outBounds); |
612 | |
613 | /** |
614 | * Finds the distance (along the view direction) of the frustum split for the specified index. Used for cascaded |
615 | * shadow maps. |
616 | * |
617 | * @param[in] view View whose frustum to split. |
618 | * @param[in] index Index of the split. 0 = near plane. |
619 | * @param[in] numCascades Maximum number of cascades in the cascaded shadow map. Must be greater than |
620 | * zero and greater or equal to @p index. |
621 | * @return Distance to the split position along the view direction. |
622 | */ |
623 | static float getCSMSplitDistance(const RendererView& view, UINT32 index, UINT32 numCascades); |
624 | |
625 | /** |
626 | * Calculates a bias that can be applied when rendering shadow maps, in order to reduce shadow artifacts. |
627 | * |
628 | * @param[in] light Light to calculate the depth bias for. |
629 | * @param[in] radius Radius of the light bounds. |
630 | * @param[in] depthRange Range of depths (distance between near and far planes) covered by the shadow. |
631 | * @param[in] mapSize Size of the shadow map, in pixels. |
632 | * @return Depth bias that can be passed to shadow depth rendering shader. |
633 | */ |
634 | static float getDepthBias(const Light& light, float radius, float depthRange, UINT32 mapSize); |
635 | |
636 | /** |
637 | * Calculates a fade transition value that can be used for slowly fading-in the shadow, in order to avoid or reduce |
638 | * shadow acne. |
639 | * |
640 | * @param[in] light Light to calculate the fade transition size for. |
641 | * @param[in] radius Radius of the light bounds. |
642 | * @param[in] depthRange Range of depths (distance between near and far planes) covered by the shadow. |
643 | * @param[in] mapSize Size of the shadow map, in pixels. |
644 | * @return Value that determines the size of the fade transition region. |
645 | */ |
646 | static float getFadeTransition(const Light& light, float radius, float depthRange, UINT32 mapSize); |
647 | |
648 | /** Size of a single shadow map atlas, in pixels. */ |
649 | static const UINT32 MAX_ATLAS_SIZE; |
650 | |
651 | /** Determines how long will an unused shadow map atlas stay allocated, in frames. */ |
652 | static const UINT32 MAX_UNUSED_FRAMES; |
653 | |
654 | /** Determines the minimal resolution of a shadow map. */ |
655 | static const UINT32 MIN_SHADOW_MAP_SIZE; |
656 | |
657 | /** Determines the resolution at which shadow maps begin fading out. */ |
658 | static const UINT32 SHADOW_MAP_FADE_SIZE; |
659 | |
660 | /** Size of the border of a shadow map in a shadow map atlas, in pixels. */ |
661 | static const UINT32 SHADOW_MAP_BORDER; |
662 | |
663 | /** Percent of the length of a single cascade in a CSM, in which to fade out the cascade. */ |
664 | static const float CASCADE_FRACTION_FADE; |
665 | |
666 | UINT32 mShadowMapSize; |
667 | |
668 | Vector<ShadowMapAtlas> mDynamicShadowMaps; |
669 | Vector<ShadowCascadedMap> mCascadedShadowMaps; |
670 | Vector<ShadowCubemap> mShadowCubemaps; |
671 | |
672 | Vector<ShadowInfo> mShadowInfos; |
673 | |
674 | Vector<LightShadows> mSpotLightShadows; |
675 | Vector<LightShadows> mRadialLightShadows; |
676 | Vector<PerViewLightShadows> mDirectionalLightShadows; |
677 | |
678 | SPtr<VertexDeclaration> mPositionOnlyVD; |
679 | |
680 | // Mesh information used for drawing near & far planes |
681 | mutable SPtr<IndexBuffer> mPlaneIB; |
682 | mutable SPtr<VertexBuffer> mPlaneVB; |
683 | |
684 | // Mesh information used for drawing a shadow frustum |
685 | mutable SPtr<IndexBuffer> mFrustumIB; |
686 | mutable SPtr<VertexBuffer> mFrustumVB; |
687 | |
688 | Vector<bool> mRenderableVisibility; // Transient |
689 | Vector<ShadowMapOptions> mSpotLightShadowOptions; // Transient |
690 | Vector<ShadowMapOptions> mRadialLightShadowOptions; // Transient |
691 | }; |
692 | |
693 | /* @} */ |
694 | }} |
695 | |