| 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 | |