// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. #include "RendererShadow.h" #include "XInput.h" #include "DXUTMisc.h" #include "DXUTCamera.h" #include "Renderer.h" #include "UIHelpers.h" #define CASCADES 1 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Renderer Shadows (wrapper for shadow_lib) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const float DEFAULT_LIGHT_SIZE = 3.0f; const DirectX::XMFLOAT3 DEFAULT_LIGHT_POS(-25, 25, 25); const DirectX::XMFLOAT3 DEFAULT_LIGHT_LOOK_AT(0, 0, 0); const DirectX::XMFLOAT3 DEFAULT_SHADOW_COLOR(0.25f, 0.25f, 0.25f); RendererShadow::RendererShadow() { m_shadowLibContext = NULL; m_PCSSEnabled = false; m_lightSize = DEFAULT_LIGHT_SIZE; m_lightPos = DEFAULT_LIGHT_POS; m_lightLookAt = DEFAULT_LIGHT_LOOK_AT; m_shadowColor = DEFAULT_SHADOW_COLOR; m_worldSpaceBBox0.x = m_worldSpaceBBox0.y = m_worldSpaceBBox0.z = -100; m_worldSpaceBBox1.x = m_worldSpaceBBox1.y = m_worldSpaceBBox1.z = 100; // Penumbra params m_PCSSParams.fMaxThreshold = 80.0f; m_PCSSParams.fMaxClamp = 40.0f; m_PCSSParams.fMinSizePercent = 3.0f; m_PCSSParams.fMinWeightExponent = 5.0f; m_PCSSParams.fMinWeightThresholdPercent = 20.0f; m_softShadowTestScale = 0.002f; memset(&m_shadowBufferSRV, 0, sizeof(m_shadowBufferSRV)); m_shadowMapHandle = NULL; m_shadowBufferHandle = NULL; } RendererShadow::~RendererShadow() { ReleaseResources(); } void RendererShadow::createResources(ID3D11Device *pd3dDevice, ID3D11DeviceContext* context, CFirstPersonCamera* camera) { m_camera = camera; #if !CASCADES uint32_t shadowMapScale = 5; uint32_t shadowMapWidth = 1024; uint32_t shadowMapHeight = 1024; // SM Desc m_SMDesc.eViewType = GFSDK_ShadowLib_ViewType_Single; m_SMDesc.eMapType = GFSDK_ShadowLib_MapType_Texture; #else uint32_t shadowMapScale = 5; uint32_t shadowMapWidth = 1024; uint32_t shadowMapHeight = 1024; // SM Desc m_SMDesc.eViewType = GFSDK_ShadowLib_ViewType_Cascades_2; m_SMDesc.eMapType = GFSDK_ShadowLib_MapType_TextureArray; #endif m_SMDesc.uResolutionWidth = shadowMapWidth * shadowMapScale; m_SMDesc.uResolutionHeight = shadowMapHeight * shadowMapScale; m_SMDesc.uArraySize = m_SMDesc.eViewType; for (int j = 0; j < GFSDK_ShadowLib_ViewType_Cascades_4; j++) { m_SMDesc.ViewLocation[j].uMapID = j; m_SMDesc.ViewLocation[j].v2Origin.x = 0; m_SMDesc.ViewLocation[j].v2Origin.y = 0; m_SMDesc.ViewLocation[j].v2Dimension.x = shadowMapWidth * shadowMapScale; m_SMDesc.ViewLocation[j].v2Dimension.y = shadowMapHeight * shadowMapScale; } // SM Render Params m_SMRenderParams.iDepthBias = 1000; m_SMRenderParams.fSlopeScaledDepthBias = 8; // SB Render Params m_SBRenderParams.eTechniqueType = GFSDK_ShadowLib_TechniqueType_PCSS; m_SBRenderParams.eQualityType = GFSDK_ShadowLib_QualityType_High; // DLL version GFSDK_ShadowLib_Version DLLVersion; GFSDK_ShadowLib_Status retCode = GFSDK_ShadowLib_GetDLLVersion(&DLLVersion); // Header version GFSDK_ShadowLib_Version headerVersion; headerVersion.uMajor = GFSDK_SHADOWLIB_MAJOR_VERSION; headerVersion.uMinor = GFSDK_SHADOWLIB_MINOR_VERSION; // Do they match? if (DLLVersion.uMajor == headerVersion.uMajor && DLLVersion.uMinor == headerVersion.uMinor) { GFSDK_ShadowLib_DeviceContext deviceAndContext; deviceAndContext.pD3DDevice = pd3dDevice; deviceAndContext.pDeviceContext = context; retCode = GFSDK_ShadowLib_Create(&headerVersion, &m_shadowLibContext, &deviceAndContext, NULL); if (retCode != GFSDK_ShadowLib_Status_Ok) assert(false); } else { assert(false); } } void RendererShadow::ReleaseResources() { SAFE_RELEASE(m_downsampledShadowMap.pTexture); SAFE_RELEASE(m_downsampledShadowMap.pSRV); SAFE_RELEASE(m_downsampledShadowMap.pRTV); if (m_shadowLibContext != NULL) { m_shadowLibContext->Destroy(); m_shadowLibContext = NULL; } } void RendererShadow::setScreenResolution(float FovyRad, UINT Width, UINT Height, UINT uSampleCount, ID3D11DepthStencilView* pReadOnlyDSV) { changeShadowSettings(Width, Height, uSampleCount, pReadOnlyDSV); } void RendererShadow::changeShadowSettings(UINT Width, UINT Height, UINT uSampleCount, ID3D11DepthStencilView* pReadOnlyDSV) { m_SBDesc.uResolutionWidth = Width; m_SBDesc.uResolutionHeight = Height; m_SBDesc.uSampleCount = uSampleCount; m_SBDesc.ReadOnlyDSV.pDSV = pReadOnlyDSV; reloadBuffers(); } void RendererShadow::reloadBuffers() { { m_shadowLibContext->RemoveMap(&m_shadowMapHandle); if (m_SMDesc.eMapType == GFSDK_ShadowLib_MapType_Texture && m_SMDesc.eViewType == GFSDK_ShadowLib_ViewType_Single && m_SBRenderParams.eTechniqueType == GFSDK_ShadowLib_TechniqueType_PCSS) { m_SMDesc.bDownsample = true; } m_shadowLibContext->AddMap(&m_SMDesc, &m_shadowMapHandle); } if (m_SMDesc.eMapType == GFSDK_ShadowLib_MapType_Texture && m_SMDesc.eViewType == GFSDK_ShadowLib_ViewType_Single) { m_downsampledShadowMap.uWidth = m_SMDesc.uResolutionWidth >> 1; m_downsampledShadowMap.uHeight = m_SMDesc.uResolutionHeight >> 1; m_downsampledShadowMap.uSampleCount = 1; m_downsampledShadowMap.Format = DXGI_FORMAT_R32_FLOAT; SAFE_RELEASE(m_downsampledShadowMap.pTexture); SAFE_RELEASE(m_downsampledShadowMap.pSRV); SAFE_RELEASE(m_downsampledShadowMap.pRTV); m_shadowLibContext->DevModeCreateTexture2D(&m_downsampledShadowMap); } m_shadowLibContext->RemoveBuffer(&m_shadowBufferHandle); m_shadowLibContext->AddBuffer(&m_SBDesc, &m_shadowBufferHandle); } //-------------------------------------------------------------------------------------- // Data passed to the shadow map render function //-------------------------------------------------------------------------------------- struct ShadowMapRenderFunctionParams { Renderer* renderer; }; static ShadowMapRenderFunctionParams s_RenderParams; //-------------------------------------------------------------------------------------- // Shadow map render function //-------------------------------------------------------------------------------------- static void ShadowMapRenderFunction(void* pParams, gfsdk_float4x4* pViewProj) { ShadowMapRenderFunctionParams* pRP = (ShadowMapRenderFunctionParams*)pParams; DirectX::XMMATRIX viewProjection; memcpy(&viewProjection, &pViewProj->_11, sizeof(gfsdk_float4x4)); pRP->renderer->renderDepthOnly(&viewProjection); } void RendererShadow::renderShadowMaps(Renderer* renderer) { // select technique GFSDK_ShadowLib_TechniqueType technique = m_SBRenderParams.eTechniqueType; m_SBRenderParams.eTechniqueType = m_PCSSEnabled ? GFSDK_ShadowLib_TechniqueType_PCSS : GFSDK_ShadowLib_TechniqueType_PCF; if (technique != m_SBRenderParams.eTechniqueType) reloadBuffers(); DirectX::XMMATRIX viewMatrix = m_camera->GetViewMatrix(); DirectX::XMMATRIX projMatrix = m_camera->GetProjMatrix(); memcpy(&m_SMRenderParams.m4x4EyeViewMatrix, &viewMatrix.r[0], sizeof(gfsdk_float4x4)); memcpy(&m_SMRenderParams.m4x4EyeProjectionMatrix, &projMatrix.r[0], sizeof(gfsdk_float4x4)); // TODO: (better world space bbox needed) m_SMRenderParams.v3WorldSpaceBBox[0] = m_worldSpaceBBox0; m_SMRenderParams.v3WorldSpaceBBox[1] = m_worldSpaceBBox1; m_SMRenderParams.LightDesc.eLightType = GFSDK_ShadowLib_LightType_Directional; memcpy(&m_SMRenderParams.LightDesc.v3LightPos, &m_lightPos.x, sizeof(gfsdk_float3)); memcpy(&m_SMRenderParams.LightDesc.v3LightLookAt, &m_lightLookAt.x, sizeof(gfsdk_float3)); m_SMRenderParams.LightDesc.fLightSize = m_lightSize; m_SMRenderParams.LightDesc.bLightFalloff = false; // Scene specific setup for the shadow map phase that follows s_RenderParams.renderer = renderer; m_SMRenderParams.fnpDrawFunction = GFSDK_ShadowLib_FunctionPointer(ShadowMapRenderFunction); m_SMRenderParams.pDrawFunctionParams = &s_RenderParams; // render shadow map m_shadowLibContext->RenderMap(m_shadowMapHandle, &m_SMRenderParams); } void RendererShadow::renderShadowBuffer(ID3D11ShaderResourceView* pDepthStencilSRV, ID3D11ShaderResourceView* pResolvedDepthStencilSRV) { if (m_SBRenderParams.eTechniqueType == GFSDK_ShadowLib_TechniqueType_PCSS && m_SMDesc.eMapType == GFSDK_ShadowLib_MapType_Texture && m_SMDesc.eViewType == GFSDK_ShadowLib_ViewType_Single) { m_tempResources.pDownsampledShadowMap = &m_downsampledShadowMap; m_shadowLibContext->SetTempResources(&m_tempResources); } m_SBRenderParams.PCSSPenumbraParams = m_PCSSParams; m_SBRenderParams.fSoftShadowTestScale = m_softShadowTestScale; m_shadowLibContext->ClearBuffer(m_shadowBufferHandle); m_SBRenderParams.DepthBufferDesc.DepthStencilSRV.pSRV = pDepthStencilSRV; m_shadowLibContext->RenderBuffer(m_shadowMapHandle, m_shadowBufferHandle, &m_SBRenderParams); m_shadowLibContext->FinalizeBuffer(m_shadowBufferHandle, &m_shadowBufferSRV); } void RendererShadow::modulateShadowBuffer(ID3D11RenderTargetView* pOutputRTV) { GFSDK_ShadowLib_RenderTargetView ColorRTV; ColorRTV.pRTV = pOutputRTV; gfsdk_float3 v3ShadowColor = { m_shadowColor.x, m_shadowColor.y, m_shadowColor.z }; m_shadowLibContext->ModulateBuffer(m_shadowBufferHandle, &ColorRTV, v3ShadowColor, GFSDK_ShadowLib_ModulateBufferMask_RGB); } void RendererShadow::displayShadowMaps(ID3D11RenderTargetView* pOutputRTV, UINT Width, UINT Height) { GFSDK_ShadowLib_RenderTargetView ColorRTV; ColorRTV.pRTV = pOutputRTV; float fMapResW = (float)m_SMDesc.uResolutionWidth; float fMapResH = (float)m_SMDesc.uResolutionHeight; float fWidthScale = Width / ((float)m_SMDesc.uArraySize * fMapResW); fWidthScale = (fWidthScale > 1.0f) ? (1.0f) : (fWidthScale); float fOneFifth = (float)Height / (5.0f); float fHeightScale = fOneFifth / fMapResH; fHeightScale = (fHeightScale > 1.0f) ? (1.0f) : (fHeightScale); float fScale = (fHeightScale < fWidthScale) ? (fHeightScale) : (fWidthScale); fMapResW = floorf(fMapResW * fScale); fMapResH = floorf(fMapResH * fScale); for (unsigned int j = 0; j < (unsigned int)m_SMDesc.uArraySize; j++) { m_shadowLibContext->DevModeDisplayMap(m_shadowBufferHandle, &ColorRTV, m_shadowMapHandle, j, j * (unsigned int)fMapResW + j, Height - (unsigned int)fMapResH, fScale); } } void RendererShadow::displayMapFrustums(ID3D11RenderTargetView* pOutputRTV, ID3D11DepthStencilView* pDSV) { gfsdk_float3 v3Color; v3Color.x = 1.0f; v3Color.y = 0.0f; v3Color.z = 0.0f; GFSDK_ShadowLib_RenderTargetView ColorRTV; ColorRTV.pRTV = pOutputRTV; GFSDK_ShadowLib_DepthStencilView DSV; DSV.pDSV = pDSV; unsigned int NumViews; NumViews = m_SMDesc.eViewType; for (unsigned int j = 0; j < NumViews; j++) { switch (j) { case 0: v3Color.x = 1.0f; v3Color.y = 0.0f; v3Color.z = 0.0f; break; case 1: v3Color.x = 0.0f; v3Color.y = 1.0f; v3Color.z = 0.0f; break; case 2: v3Color.x = 0.0f; v3Color.y = 0.0f; v3Color.z = 1.0f; break; case 3: v3Color.x = 1.0f; v3Color.y = 1.0f; v3Color.z = 0.0f; break; } m_shadowLibContext->DevModeDisplayMapFrustum(m_shadowBufferHandle, &ColorRTV, &DSV, m_shadowMapHandle, j, v3Color); } } void RendererShadow::displayShadowBuffer(ID3D11RenderTargetView* pOutputRTV) { gfsdk_float2 v2Scale; v2Scale.x = 1.0f; v2Scale.y = 1.0f; GFSDK_ShadowLib_RenderTargetView ColorRTV; ColorRTV.pRTV = pOutputRTV; m_shadowLibContext->DevModeDisplayBuffer(m_shadowBufferHandle, &ColorRTV, v2Scale, NULL); } void RendererShadow::toggleDisplayCascades(bool bToggle) { m_shadowLibContext->DevModeToggleDebugCascadeShader(m_shadowBufferHandle, bToggle); } void RendererShadow::drawUI() { ImGui::Checkbox("PCSS", &m_PCSSEnabled); ImGui::ColorEdit3("Shadow Color", &(m_shadowColor.x)); ImGui::DragFloat("Light Size", &m_lightSize, 0.05f, 0.0f, 100.0f); ImGui::DragFloat3("Light Position", &(m_lightPos.x)); ImGui_DragFloat3Dir("Light LookAt", &(m_lightLookAt.x)); ImGui::DragFloat("SoftShadowTestScale", &(m_softShadowTestScale), 0.0001f, 0.0f, 10.0f); if (m_PCSSEnabled) { ImGui::DragFloat("PCSS: fMaxClamp", &(m_PCSSParams.fMaxClamp), 0.001f, 0.0f, 100.0f); ImGui::DragFloat("PCSS: fMaxThreshold", &(m_PCSSParams.fMaxThreshold), 0.001f, 0.0f, 100.0f); ImGui::DragFloat("PCSS: fMinSizePercent", &(m_PCSSParams.fMinSizePercent), 0.001f, 0.0f, 100.0f); ImGui::DragFloat("PCSS: fMinWeightExponent", &(m_PCSSParams.fMinWeightExponent), 0.001f, 0.0f, 100.0f); ImGui::DragFloat("PCSS: fMinWeightThresholdPercent", &(m_PCSSParams.fMinWeightThresholdPercent), 0.001f, 0.0f, 100.0f); ImGui::DragFloat("PCSS: fBlockerSearchDitherPercent", &(m_PCSSParams.fBlockerSearchDitherPercent), 0.001f, 0.0f, 100.0f); ImGui::DragFloat("PCSS: fFilterDitherPercent", &(m_PCSSParams.fFilterDitherPercent), 0.001f, 0.0f, 100.0f); } }