You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2017 lines
76 KiB
C++
2017 lines
76 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : shadows support.
|
|
|
|
|
|
#include "RenderDll_precompiled.h"
|
|
#include "DriverD3D.h"
|
|
#include <IEntityRenderState.h>
|
|
#include "../Common/Shadow_Renderer.h"
|
|
#include "../Common/ReverseDepth.h"
|
|
#include "D3DPostProcess.h"
|
|
|
|
#include "I3DEngine.h"
|
|
|
|
#include "GraphicsPipeline/Common/GraphicsPipelinePass.h"
|
|
|
|
#include "Common/RenderView.h"
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
#include "D3D_SVO.h"
|
|
#endif
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#include AZ_RESTRICTED_FILE(D3DShadows_cpp)
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
CryCriticalSection g_cDynTexLock;
|
|
}
|
|
|
|
void CD3D9Renderer::EF_PrepareShadowGenRenderList()
|
|
{
|
|
AZ_TRACE_METHOD();
|
|
int nThreadID = m_RP.m_nFillThreadID;
|
|
int nCurRecLevel = SRendItem::m_RecurseLevel[nThreadID];
|
|
assert(nCurRecLevel >= 0);
|
|
int NumDynLights = m_RP.m_DLights[nThreadID][nCurRecLevel].Num();
|
|
|
|
//TFIX nCurRecLevel+1 is incorrect
|
|
TArray<SRenderLight>& arrDeferLights = CDeferredShading::Instance().GetLights(nThreadID, nCurRecLevel);
|
|
|
|
RegisterFinalizeShadowJobs(nThreadID);
|
|
|
|
if (NumDynLights <= 0 && arrDeferLights.Num() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int nLightID = 0; nLightID < NumDynLights; nLightID++)
|
|
{
|
|
SRenderLight* pLight = &m_RP.m_DLights[nThreadID][nCurRecLevel][nLightID];
|
|
EF_PrepareShadowGenForLight(pLight, nLightID);
|
|
}
|
|
|
|
for (uint32 nDeferLightID = 0; nDeferLightID < arrDeferLights.Num(); nDeferLightID++)
|
|
{
|
|
SRenderLight* pLight = &arrDeferLights[nDeferLightID];
|
|
EF_PrepareShadowGenForLight(pLight, (NumDynLights + nDeferLightID));
|
|
}
|
|
|
|
// add custom frustums
|
|
{
|
|
ShadowMapFrustum* arrCustomFrustums;
|
|
int nFrustumCount;
|
|
gEnv->p3DEngine->GetCustomShadowMapFrustums(arrCustomFrustums, nFrustumCount);
|
|
|
|
for (uint32 i = 0; i < nFrustumCount; ++i)
|
|
{
|
|
if (PrepareShadowGenForFrustum(&arrCustomFrustums[i], NULL, 0, i))
|
|
{
|
|
SRenderPipeline::SShadowFrustumToRender* pToRender = m_RP.SShadowFrustumToRenderList[nThreadID].AddIndex(1);
|
|
pToRender->pFrustum = &arrCustomFrustums[i];
|
|
pToRender->nRecursiveLevel = nCurRecLevel;
|
|
pToRender->nLightID = 0;
|
|
pToRender->pLight = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CD3D9Renderer::EF_PrepareShadowGenForLight(SRenderLight* pLight, int nLightID)
|
|
{
|
|
assert((unsigned int) nLightID < (MAX_REND_LIGHTS + MAX_DEFERRED_LIGHTS));
|
|
if ((unsigned int) nLightID >= (MAX_REND_LIGHTS + MAX_DEFERRED_LIGHTS))
|
|
{
|
|
//Warning("CRenderer::EF_PrepareShadowGenForLight: Too many light sources used ..."); // redundant
|
|
return false;
|
|
}
|
|
int nThreadID = m_RP.m_nFillThreadID;
|
|
int nCurRecLevel = SRendItem::m_RecurseLevel[nThreadID];
|
|
assert(nCurRecLevel >= 0);
|
|
if (!(pLight->m_Flags & DLF_CASTSHADOW_MAPS))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const int nLightFrustumBaseID = nLightID * MAX_SHADOWMAP_LOD;
|
|
|
|
ShadowMapFrustum** ppSMFrustumList = pLight->m_pShadowMapFrustums;
|
|
if (!ppSMFrustumList)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ShadowMapFrustum* pCopyFrustum = NULL;
|
|
|
|
int32 nCurLOD = 0;
|
|
|
|
for (int nCaster = 0; *ppSMFrustumList && nCaster != MAX_GSM_LODS_NUM; ++ppSMFrustumList, ++nCaster)
|
|
{
|
|
//use pools
|
|
if (CV_r_UseShadowsPool && pLight->m_Flags & DLF_DEFERRED_LIGHT)
|
|
{
|
|
(*ppSMFrustumList)->bUseShadowsPool = true;
|
|
}
|
|
else
|
|
{
|
|
(*ppSMFrustumList)->bUseShadowsPool = false;
|
|
}
|
|
|
|
if (PrepareShadowGenForFrustum(*ppSMFrustumList, pLight, nLightFrustumBaseID, nCurLOD))
|
|
{
|
|
SRenderPipeline::SShadowFrustumToRender* pToRender = m_RP.SShadowFrustumToRenderList[nThreadID].AddIndex(1);
|
|
pToRender->pFrustum = (*ppSMFrustumList);
|
|
pToRender->nRecursiveLevel = nCurRecLevel;
|
|
pToRender->nLightID = nLightID;
|
|
pToRender->pLight = pLight;
|
|
nCurLOD++;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CD3D9Renderer::PrepareShadowGenForFrustum(ShadowMapFrustum* pCurFrustum, SRenderLight* pLight, [[maybe_unused]] int nLightFrustumBaseID, [[maybe_unused]] int nLOD)
|
|
{
|
|
int nThreadID = m_RP.m_nFillThreadID;
|
|
assert(SRendItem::m_RecurseLevel[nThreadID] == 0);
|
|
|
|
PROFILE_FRAME(PrepareShadowGenForFrustum);
|
|
|
|
//validate shadow frustum
|
|
assert(pCurFrustum);
|
|
if (!pCurFrustum)
|
|
{
|
|
return false;
|
|
}
|
|
if (pCurFrustum->m_castersList.IsEmpty() && pCurFrustum->m_jobExecutedCastersList.IsEmpty() &&
|
|
!pCurFrustum->IsCached() && pCurFrustum->m_eFrustumType != ShadowMapFrustum::e_GsmDynamicDistance)
|
|
{
|
|
return false;
|
|
}
|
|
if (pCurFrustum->IsCached() && pCurFrustum->nTexSize == 0)
|
|
{
|
|
return false;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//regenerate on reset device
|
|
if (pCurFrustum->nResetID != m_nFrameReset)
|
|
{
|
|
pCurFrustum->nResetID = m_nFrameReset;
|
|
pCurFrustum->RequestUpdate();
|
|
}
|
|
|
|
int nShadowGenGPU = 0;
|
|
|
|
if (GetActiveGPUCount() > 1 && CV_r_ShadowGenMode == 1)
|
|
{
|
|
//TOFIx: make m_nFrameSwapID - double buffered
|
|
nShadowGenGPU = gRenDev->RT_GetCurrGpuID();
|
|
|
|
pCurFrustum->nOmniFrustumMask = 0x3F;
|
|
//in case there was switch on the fly - regenerate all faces
|
|
if (pCurFrustum->nInvalidatedFrustMask[nShadowGenGPU] > 0)
|
|
{
|
|
pCurFrustum->nInvalidatedFrustMask[nShadowGenGPU] = 0x3F;
|
|
}
|
|
}
|
|
|
|
SDynTexture_Shadow* pTX = NULL;
|
|
|
|
|
|
bool bNotNeedUpdate = false;
|
|
if (pCurFrustum->bOmniDirectionalShadow)
|
|
{
|
|
bNotNeedUpdate = !(pCurFrustum->nInvalidatedFrustMask[nShadowGenGPU] & pCurFrustum->nOmniFrustumMask);
|
|
}
|
|
else
|
|
{
|
|
bNotNeedUpdate = !pCurFrustum->isUpdateRequested(nShadowGenGPU);
|
|
}
|
|
|
|
if (bNotNeedUpdate && !pCurFrustum->bUseShadowsPool)
|
|
{
|
|
memset(pCurFrustum->nShadowGenID[nThreadID], 0xFF, sizeof(pCurFrustum->nShadowGenID[nThreadID]));
|
|
return pCurFrustum->nShadowGenMask != 0;
|
|
}
|
|
|
|
|
|
if (pCurFrustum->bUseShadowsPool)
|
|
{
|
|
pCurFrustum->nShadowPoolUpdateRate = min((uint32)CRenderer::CV_r_ShadowPoolMaxFrames, (uint32)pCurFrustum->nShadowPoolUpdateRate);
|
|
if (!bNotNeedUpdate)
|
|
{
|
|
pCurFrustum->nShadowPoolUpdateRate >>= 2;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// update is requested - we should generate new shadow map
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//force unwrap frustum
|
|
if (pCurFrustum->bOmniDirectionalShadow)
|
|
{
|
|
pCurFrustum->bUnwrapedOmniDirectional = true;
|
|
}
|
|
else
|
|
{
|
|
pCurFrustum->bUnwrapedOmniDirectional = false;
|
|
}
|
|
|
|
ETEX_Type eTT = (pCurFrustum->bOmniDirectionalShadow && !pCurFrustum->bUnwrapedOmniDirectional) ? eTT_Cube : eTT_2D;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//recalculate LOF rendering params
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//calc texture resolution and frustum resolution
|
|
pCurFrustum->nTexSize = max(pCurFrustum->nTexSize, 32);
|
|
pCurFrustum->nTextureWidth = pCurFrustum->nTexSize;
|
|
pCurFrustum->nTextureHeight = pCurFrustum->nTexSize;
|
|
pCurFrustum->nShadowMapSize = pCurFrustum->nTexSize;
|
|
|
|
if (pCurFrustum->bUnwrapedOmniDirectional)
|
|
{
|
|
pCurFrustum->nTextureWidth = pCurFrustum->nTexSize * 3;
|
|
pCurFrustum->nTextureHeight = pCurFrustum->nTexSize * 2;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//Select shadow buffers format
|
|
//////////////////////////////////////////////////////////////////////////
|
|
ETEX_Format eTF = eTF_D32F;
|
|
if (pCurFrustum->IsCached())
|
|
{
|
|
eTF = CV_r_ShadowsCacheFormat == 0 ? eTF_D32F : eTF_D16;
|
|
}
|
|
else if IsCVarConstAccess(constexpr) (CV_r_shadowtexformat == 0)
|
|
{
|
|
eTF = eTF_D32F;
|
|
}
|
|
else if IsCVarConstAccess(constexpr) (CV_r_shadowtexformat == 1)
|
|
{
|
|
eTF = eTF_D16;
|
|
}
|
|
else
|
|
{
|
|
eTF = eTF_D24S8;
|
|
}
|
|
|
|
if (pCurFrustum->bOmniDirectionalShadow && !(pCurFrustum->bUnwrapedOmniDirectional))
|
|
{
|
|
pCurFrustum->bHWPCFCompare = false;
|
|
}
|
|
else
|
|
{
|
|
const bool bSun = pLight && (pLight->m_Flags & DLF_SUN) != 0;
|
|
pCurFrustum->bHWPCFCompare = !bSun || (CV_r_ShadowsPCFiltering != 0);
|
|
}
|
|
//assign requested texture format
|
|
pCurFrustum->m_eReqTF = eTF;
|
|
pCurFrustum->m_eReqTT = eTT;
|
|
|
|
//assign owners
|
|
pCurFrustum->pFrustumOwner = pCurFrustum;
|
|
|
|
//actual view camera position
|
|
Vec3 vCamOrigin = iSystem->GetViewCamera().GetPosition();
|
|
|
|
CCamera tmpCamera;
|
|
|
|
int nSides = 1;
|
|
if (pCurFrustum->bOmniDirectionalShadow)
|
|
{
|
|
nSides = OMNI_SIDES_NUM;
|
|
}
|
|
|
|
// Static shadow map might not have any active casters, so don't reset nShadowGenMask every frame
|
|
if (!pCurFrustum->IsCached())
|
|
{
|
|
pCurFrustum->nShadowGenMask = pCurFrustum->m_eFrustumType == ShadowMapFrustum::e_GsmDynamicDistance ? 1 : 0;
|
|
}
|
|
Matrix44 m;
|
|
|
|
for (int nS = 0; nS < nSides; nS++)
|
|
{
|
|
//update check for shadow frustums
|
|
if (pCurFrustum->bOmniDirectionalShadow && !pCurFrustum->bUseShadowsPool)
|
|
{
|
|
if (!((pCurFrustum->nInvalidatedFrustMask[nShadowGenGPU] & pCurFrustum->nOmniFrustumMask) & (1 << nS)))
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
pCurFrustum->nInvalidatedFrustMask[nShadowGenGPU] &= ~(1 << nS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCurFrustum->nInvalidatedFrustMask[nShadowGenGPU] = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Calc frustum CCamera for current frustum
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (!pCurFrustum->bOmniDirectionalShadow)
|
|
{
|
|
if (pCurFrustum->m_Flags & (DLF_PROJECT | DLF_AREA_LIGHT))
|
|
{
|
|
SRenderLight instLight = *pLight;
|
|
if (pLight->m_Flags & DLF_AREA_LIGHT)
|
|
{
|
|
// Pull the shadow frustum back to encompas the area of the light source.
|
|
float fMaxSize = max(pLight->m_fAreaWidth, pLight->m_fAreaHeight);
|
|
float fScale = fMaxSize / max(tanf(DEG2RAD(pLight->m_fLightFrustumAngle)), 0.0001f);
|
|
|
|
Vec3 vOffsetDir = fScale * pLight->m_ObjMatrix.GetColumn0().GetNormalized();
|
|
instLight.SetPosition(instLight.m_Origin - vOffsetDir);
|
|
instLight.m_fProjectorNearPlane = fScale;
|
|
}
|
|
|
|
// Frustum angle is clamped to prevent projection matrix problems.
|
|
// We clamp here because area lights and non-shadow casting lights can cast 180 degree light.
|
|
CShadowUtils::GetCubemapFrustumForLight(&instLight, 0, min(2 * pLight->m_fLightFrustumAngle, 175.0f), &(pCurFrustum->mLightProjMatrix), &(pCurFrustum->mLightViewMatrix), false);
|
|
}
|
|
else
|
|
{
|
|
if (pCurFrustum->m_eFrustumType == ShadowMapFrustum::e_PerObject)
|
|
{
|
|
AABB lsBounds = CShadowUtils::GetShadowMatrixForCasterBox(pCurFrustum->mLightProjMatrix, pCurFrustum->mLightViewMatrix, pCurFrustum, 20.f);
|
|
|
|
// normalize filter filter kernel size to dimensions of light space bounding box
|
|
pCurFrustum->fWidthS *= pCurFrustum->nTextureWidth / (lsBounds.max.x - lsBounds.min.x);
|
|
pCurFrustum->fWidthT *= pCurFrustum->nTextureHeight / (lsBounds.max.y - lsBounds.min.y);
|
|
}
|
|
else if (pCurFrustum->m_eFrustumType != ShadowMapFrustum::e_HeightMapAO)
|
|
{
|
|
CShadowUtils::GetShadowMatrixOrtho(pCurFrustum->mLightProjMatrix, pCurFrustum->mLightViewMatrix, m_CameraMatrix, pCurFrustum, false);
|
|
}
|
|
}
|
|
|
|
//Pre-multiply matrices
|
|
Matrix44 mViewProj = Matrix44(pCurFrustum->mLightViewMatrix) * Matrix44(pCurFrustum->mLightProjMatrix);
|
|
pCurFrustum->mLightViewMatrix = mViewProj;
|
|
pCurFrustum->mLightProjMatrix.SetIdentity();
|
|
|
|
tmpCamera = gEnv->p3DEngine->GetRenderingCamera();
|
|
}
|
|
else
|
|
{
|
|
tmpCamera = pCurFrustum->FrustumPlanes[nS];
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Invoke IRenderNode::Render Jobs
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 nShadowGenID = m_nShadowGenId[nThreadID];
|
|
m_nShadowGenId[nThreadID] += 1;
|
|
|
|
pCurFrustum->nShadowGenID[nThreadID][nS] = nShadowGenID;
|
|
|
|
uint32 nRenderingFlags = SRenderingPassInfo::DEFAULT_FLAGS;
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (CSvoRenderer::GetRsmColorMap(*pCurFrustum))
|
|
{
|
|
// we need correct diffuse texture for every chunk
|
|
nRenderingFlags |= SRenderingPassInfo::DISABLE_RENDER_CHUNK_MERGE;
|
|
}
|
|
#endif
|
|
// create a matching rendering pass info for shadows
|
|
SRenderingPassInfo passInfo = SRenderingPassInfo::CreateShadowPassRenderingInfo(tmpCamera, pCurFrustum->m_Flags, pCurFrustum->nShadowMapLod,
|
|
pCurFrustum->IsCached(), pCurFrustum->bIsMGPUCopy, &pCurFrustum->nShadowGenMask, nS, nShadowGenID, nRenderingFlags);
|
|
|
|
StartInvokeShadowMapRenderJobs(pCurFrustum, passInfo);
|
|
}//nSides
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CD3D9Renderer::PrepareShadowGenForFrustumNonJobs([[maybe_unused]] const int nFlags)
|
|
{
|
|
int nThreadID = m_RP.m_nFillThreadID;
|
|
int nCurRecLevel = SRendItem::m_RecurseLevel[nThreadID];
|
|
assert(nCurRecLevel >= 0);
|
|
|
|
CCamera tmpCamera;
|
|
|
|
for (int i = 0; i < m_RP.SShadowFrustumToRenderList[nThreadID].size(); ++i)
|
|
{
|
|
SRenderPipeline::SShadowFrustumToRender& rFrustumToRender = m_RP.SShadowFrustumToRenderList[nThreadID][i];
|
|
ShadowMapFrustum* pCurFrustum = rFrustumToRender.pFrustum;
|
|
SRenderLight* pLight = rFrustumToRender.pLight;
|
|
|
|
int nSides = pCurFrustum->bOmniDirectionalShadow ? OMNI_SIDES_NUM : 1;
|
|
|
|
for (int nS = 0; nS < nSides; nS++)
|
|
{
|
|
if (pCurFrustum->nShadowGenID[nThreadID][nS] == 0xFFFFFFFF)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Calc frustum CCamera for current frustum
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (!pCurFrustum->bOmniDirectionalShadow)
|
|
{
|
|
tmpCamera = gEnv->p3DEngine->GetRenderingCamera();
|
|
}
|
|
else
|
|
{
|
|
tmpCamera = pCurFrustum->FrustumPlanes[nS];
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Invoke IRenderNode::Render
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
uint32 nRenderingFlags = SRenderingPassInfo::DEFAULT_FLAGS;
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (CSvoRenderer::GetRsmColorMap(*pCurFrustum))
|
|
{
|
|
// we need correct diffuse texture for every chunk
|
|
nRenderingFlags |= SRenderingPassInfo::DISABLE_RENDER_CHUNK_MERGE;
|
|
}
|
|
#endif
|
|
|
|
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
|
|
if (IsRenderToTextureActive())
|
|
{
|
|
// the shadow render pass needs to know if we are rendering to texture
|
|
nRenderingFlags |= SRenderingPassInfo::RENDER_SCENE_TO_TEXTURE;
|
|
}
|
|
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
|
|
|
|
// create a matching rendering pass info for shadows
|
|
SRenderingPassInfo passInfo = SRenderingPassInfo::CreateShadowPassRenderingInfo(tmpCamera, pCurFrustum->m_Flags, pCurFrustum->nShadowMapLod,
|
|
pCurFrustum->IsCached(), pCurFrustum->bIsMGPUCopy, &pCurFrustum->nShadowGenMask, nS, pCurFrustum->nShadowGenID[nThreadID][nS], nRenderingFlags);
|
|
|
|
for (int casterIdx = 0; casterIdx < pCurFrustum->m_castersList.Count(); ++casterIdx)
|
|
{
|
|
IShadowCaster* pEnt = pCurFrustum->m_castersList[casterIdx];
|
|
|
|
//TOFIX reactivate OmniDirectionalShadow
|
|
if (pCurFrustum->bOmniDirectionalShadow)
|
|
{
|
|
AABB aabb = pEnt->GetBBoxVirtual();
|
|
//!!! Reactivate proper camera
|
|
bool bVis = tmpCamera.IsAABBVisible_F(aabb);
|
|
if (!bVis)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ((pCurFrustum->m_Flags & DLF_DIFFUSEOCCLUSION) && pEnt->HasOcclusionmap(0, pCurFrustum->pLightOwner))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
gEnv->p3DEngine->RenderRenderNode_ShadowPass(pEnt, passInfo, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: GetTextureRect()
|
|
// Desc: Get the dimensions of the texture
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT GetTextureRect(CTexture* pTexture, RECT* pRect)
|
|
{
|
|
pRect->left = 0;
|
|
pRect->top = 0;
|
|
pRect->right = pTexture->GetWidth();
|
|
pRect->bottom = pTexture->GetHeight();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CD3D9Renderer::OnEntityDeleted(IRenderNode* pRenderNode)
|
|
{
|
|
m_pRT->RC_EntityDelete(pRenderNode);
|
|
}
|
|
|
|
void _DrawText(ISystem* pSystem, int x, int y, const float fScale, const char* format, ...)
|
|
PRINTF_PARAMS(5, 6);
|
|
|
|
void _DrawText([[maybe_unused]] ISystem* pSystem, int x, int y, const float fScale, const char* format, ...)
|
|
{
|
|
char buffer[512];
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsprintf_s(buffer, format, args);
|
|
va_end(args);
|
|
|
|
float color[4] = {0, 1, 0, 1};
|
|
gEnv->pRenderer->Draw2dLabel((float)x, (float)y, fScale, color, false, buffer);
|
|
}
|
|
|
|
void CD3D9Renderer::DrawAllShadowsOnTheScreen()
|
|
{
|
|
float width = 800;
|
|
float height = 600;
|
|
|
|
TransformationMatrices backupSceneMatrices;
|
|
|
|
Set2DMode(static_cast<uint32>(width), static_cast<uint32>(height), backupSceneMatrices);
|
|
|
|
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
|
|
EF_SetSrgbWrite(false);
|
|
|
|
int nMaxCount = 16;
|
|
|
|
float fArrDim = max(4.f, sqrtf((float)nMaxCount));
|
|
float fPicDimX = width / fArrDim;
|
|
float fPicDimY = height / fArrDim;
|
|
int nShadowId = 0;
|
|
SDynTexture_Shadow* pTX = SDynTexture_Shadow::s_RootShadow.m_NextShadow;
|
|
for (float x = 0; nShadowId < nMaxCount && x < width - 10; x += fPicDimX)
|
|
{
|
|
for (float y = 0; nShadowId < nMaxCount && y < height - 10; y += fPicDimY)
|
|
{
|
|
static ICVar* pVar = iConsole->GetCVar("e_ShadowsDebug");
|
|
if (pVar && pVar->GetIVal() == 1)
|
|
{
|
|
while (pTX->m_pTexture && (pTX->m_pTexture->m_nAccessFrameID + 2) < GetFrameID(false) && pTX != &SDynTexture_Shadow::s_RootShadow)
|
|
{
|
|
pTX = pTX->m_NextShadow;
|
|
}
|
|
}
|
|
|
|
if (pTX == &SDynTexture_Shadow::s_RootShadow)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pTX->m_pTexture && pTX->pLightOwner)
|
|
{
|
|
CTexture* tp = pTX->m_pTexture;
|
|
if (tp)
|
|
{
|
|
int nSavedAccessFrameID = pTX->m_pTexture->m_nAccessFrameID;
|
|
|
|
|
|
SetState(/*GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | */ GS_NODEPTHTEST);
|
|
if (tp->GetTextureType() == eTT_2D)
|
|
{
|
|
//Draw2dImage(x, y, fPicDimX-1, fPicDimY-1, tp->GetID(), 0,1,1,0,180);
|
|
|
|
// set shader
|
|
CShader* pSH(CShaderMan::s_ShaderShadowMaskGen);
|
|
|
|
uint32 nPasses = 0;
|
|
static CCryNameTSCRC TechName = "DebugShadowMap";
|
|
pSH->FXSetTechnique(TechName);
|
|
pSH->FXBegin(&nPasses, FEF_DONTSETSTATES | FEF_DONTSETTEXTURES);
|
|
pSH->FXBeginPass(0);
|
|
|
|
Matrix44A origMatProj = m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj;
|
|
Matrix44A origMatView = m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView;
|
|
Matrix44A* m = &m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj;
|
|
mathMatrixOrthoOffCenterLH(m, 0.0f, (float)width, (float)height, 0.0f, -1e30f, 1e30f);
|
|
m = &m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView;
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView.SetIdentity();
|
|
|
|
SetState(GS_NODEPTHTEST);
|
|
STexState ts(FILTER_LINEAR, false);
|
|
ts.m_nAnisotropy = 1;
|
|
tp->Apply(0, CTexture::GetTexState(ts));
|
|
D3DSetCull(eCULL_None);
|
|
|
|
TempDynVB<SVF_P3F_T3F> vb(gcpRendD3D);
|
|
vb.Allocate(4);
|
|
SVF_P3F_T3F* vQuad = vb.Lock();
|
|
|
|
vQuad[0].p = Vec3(x, y, 1);
|
|
vQuad[0].st = Vec3(0, 1, 1);
|
|
//vQuad[0].color.dcolor = (uint32)-1;
|
|
vQuad[1].p = Vec3(x + fPicDimX - 1, y, 1);
|
|
vQuad[1].st = Vec3(1, 1, 1);
|
|
//vQuad[1].color.dcolor = (uint32)-1;
|
|
vQuad[3].p = Vec3(x + fPicDimX - 1, y + fPicDimY - 1, 1);
|
|
vQuad[3].st = Vec3(1, 0, 1);
|
|
//vQuad[3].color.dcolor = (uint32)-1;
|
|
vQuad[2].p = Vec3(x, y + fPicDimY - 1, 1);
|
|
vQuad[2].st = Vec3(0, 0, 1);
|
|
//vQuad[2].color.dcolor = (uint32)-1;
|
|
|
|
vb.Unlock();
|
|
vb.Bind(0);
|
|
vb.Release();
|
|
|
|
if (!FAILED(FX_SetVertexDeclaration(0, eVF_P3F_T3F)))
|
|
{
|
|
FX_Commit();
|
|
FX_DrawPrimitive(eptTriangleStrip, 0, 4);
|
|
}
|
|
|
|
pSH->FXEndPass();
|
|
pSH->FXEnd();
|
|
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView = origMatView;
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj = origMatProj;
|
|
}
|
|
else
|
|
{
|
|
// set shader
|
|
CShader* pSH(CShaderMan::s_ShaderShadowMaskGen);
|
|
|
|
uint32 nPasses = 0;
|
|
static CCryNameTSCRC TechName = "DebugCubeMap";
|
|
pSH->FXSetTechnique(TechName);
|
|
pSH->FXBegin(&nPasses, FEF_DONTSETSTATES | FEF_DONTSETTEXTURES);
|
|
pSH->FXBeginPass(0);
|
|
|
|
float fSizeX = fPicDimX / 3;
|
|
float fSizeY = fPicDimY / 2;
|
|
float fx = ScaleCoordX(x);
|
|
fSizeX = ScaleCoordX(fSizeX);
|
|
float fy = ScaleCoordY(y);
|
|
fSizeY = ScaleCoordY(fSizeY);
|
|
float fOffsX[] = {fx, fx + fSizeX, fx + fSizeX * 2, fx, fx + fSizeX, fx + fSizeX * 2};
|
|
float fOffsY[] = {fy, fy, fy, fy + fSizeY, fy + fSizeY, fy + fSizeY};
|
|
Vec3 vTC0[] = {Vec3(1, 1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, 1), Vec3(1, 1, -1)};
|
|
Vec3 vTC1[] = {Vec3(1, 1, -1), Vec3(-1, 1, 1), Vec3(1, 1, -1), Vec3(1, -1, 1), Vec3(1, 1, 1), Vec3(-1, 1, -1)};
|
|
Vec3 vTC2[] = {Vec3(1, -1, -1), Vec3(-1, -1, 1), Vec3(1, 1, 1), Vec3(1, -1, -1), Vec3(1, -1, 1), Vec3(-1, -1, -1)};
|
|
Vec3 vTC3[] = {Vec3(1, -1, 1), Vec3(-1, -1, -1), Vec3(-1, 1, 1), Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(1, -1, -1)};
|
|
|
|
Matrix44A origMatProj = m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj;
|
|
Matrix44A origMatView = m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView;
|
|
Matrix44A* m = &m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj;
|
|
mathMatrixOrthoOffCenterLH(m, 0.0f, (float)m_width, (float)m_height, 0.0f, -1e30f, 1e30f);
|
|
m = &m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView;
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView.SetIdentity();
|
|
|
|
SetState(GS_NODEPTHTEST);
|
|
STexState ts(FILTER_LINEAR, false);
|
|
ts.m_nAnisotropy = 1;
|
|
tp->Apply(0, CTexture::GetTexState(ts));
|
|
|
|
D3DSetCull(eCULL_None);
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
TempDynVB<SVF_P3F_T3F> vb(gcpRendD3D);
|
|
vb.Allocate(4);
|
|
SVF_P3F_T3F* vQuad = vb.Lock();
|
|
|
|
vQuad[0].p = Vec3(fOffsX[i], fOffsY[i], 1);
|
|
vQuad[0].st = vTC0[i];
|
|
//vQuad[0].color.dcolor = (uint32)-1;
|
|
vQuad[1].p = Vec3(fOffsX[i] + fSizeX - 1, fOffsY[i], 1);
|
|
vQuad[1].st = vTC1[i];
|
|
//vQuad[1].color.dcolor = (uint32)-1;
|
|
vQuad[3].p = Vec3(fOffsX[i] + fSizeX - 1, fOffsY[i] + fSizeY - 1, 1);
|
|
vQuad[3].st = vTC2[i];
|
|
//vQuad[3].color.dcolor = (uint32)-1;
|
|
vQuad[2].p = Vec3(fOffsX[i], fOffsY[i] + fSizeY - 1, 1);
|
|
vQuad[2].st = vTC3[i];
|
|
//vQuad[2].color.dcolor = (uint32)-1;
|
|
|
|
vb.Unlock();
|
|
vb.Bind(0);
|
|
vb.Release();
|
|
|
|
if (!FAILED(FX_SetVertexDeclaration(0, eVF_P3F_T3F)))
|
|
{
|
|
FX_Commit();
|
|
FX_DrawPrimitive(eptTriangleStrip, 0, 4);
|
|
}
|
|
}
|
|
|
|
pSH->FXEndPass();
|
|
pSH->FXEnd();
|
|
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView = origMatView;
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj = origMatProj;
|
|
}
|
|
|
|
pTX->m_pTexture->m_nAccessFrameID = nSavedAccessFrameID;
|
|
ILightSource* pLS = (ILightSource*)pTX->pLightOwner;
|
|
|
|
_DrawText(iSystem, (int)(x / width * 800.f), (int)(y / height * 600.f), 1.0f, "%s \n %d %d-%d %d x%d",
|
|
pTX->m_pTexture->GetSourceName(),
|
|
pTX->m_nUniqueID,
|
|
pTX->m_pTexture ? pTX->m_pTexture->m_nUpdateFrameID : 0,
|
|
pTX->m_pTexture ? pTX->m_pTexture->m_nAccessFrameID : 0,
|
|
pTX->nObjectsRenderedCount,
|
|
pTX->m_nWidth);
|
|
|
|
if (pLS->GetLightProperties().m_sName)
|
|
{
|
|
_DrawText(iSystem, (int)(x / width * 800.f), (int)(y / height * 600.f) + 32, 1.0f, "%s", pLS->GetLightProperties().m_sName);
|
|
}
|
|
}
|
|
}
|
|
pTX = pTX->m_NextShadow;
|
|
}
|
|
}
|
|
|
|
Unset2DMode(backupSceneMatrices);
|
|
}
|
|
|
|
Vec3 UnProject(ShadowMapFrustum* pFr, Vec3 vPoint)
|
|
{
|
|
const int shadowViewport[4] = {0, 0, 1, 1};
|
|
|
|
Vec3 vRes(0, 0, 0);
|
|
gRenDev->UnProject(vPoint.x, vPoint.y, vPoint.z,
|
|
&vRes.x, &vRes.y, &vRes.z,
|
|
(float*)&pFr->mLightViewMatrix,
|
|
(float*)&pFr->mLightProjMatrix,
|
|
shadowViewport);
|
|
|
|
return vRes;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace
|
|
{
|
|
struct CompareRSMRendItem
|
|
{
|
|
bool operator()(const SRendItem& a, const SRendItem& b) const
|
|
{
|
|
// Decal objects should be rendered last
|
|
int nDecalA = (a.ObjSort & FOB_DECAL_MASK);
|
|
int nDecalB = (b.ObjSort & FOB_DECAL_MASK);
|
|
if ((nDecalA == 0) != (nDecalB == 0)) // Sort by decal flag
|
|
{
|
|
return nDecalA < nDecalB;
|
|
}
|
|
|
|
if (nDecalA && nDecalB)
|
|
{
|
|
// decal sorting
|
|
uint32 objSortA_Low(a.ObjSort & 0xFFFF);
|
|
uint32 objSortA_High(a.ObjSort & ~0xFFFF);
|
|
uint32 objSortB_Low(b.ObjSort & 0xFFFF);
|
|
uint32 objSortB_High(b.ObjSort & ~0xFFFF);
|
|
|
|
if (objSortA_Low != objSortB_Low)
|
|
{
|
|
return objSortA_Low < objSortB_Low;
|
|
}
|
|
|
|
if (a.SortVal != b.SortVal)
|
|
{
|
|
return a.SortVal < b.SortVal;
|
|
}
|
|
|
|
return objSortA_High < objSortB_High;
|
|
}
|
|
else
|
|
{
|
|
// usual sorting
|
|
if (a.SortVal != b.SortVal) // Sort by shaders
|
|
{
|
|
return a.SortVal < b.SortVal;
|
|
}
|
|
|
|
if (a.pElem != b.pElem) // Sort by geometry
|
|
{
|
|
return a.pElem < b.pElem;
|
|
}
|
|
|
|
return a.ObjSort < b.ObjSort;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
bool CD3D9Renderer::PrepareDepthMap(ShadowMapFrustum* lof, int nLightFrustumID, bool bClearPool)
|
|
{
|
|
int nThreadList = m_RP.m_nProcessThreadID;
|
|
assert(lof);
|
|
if (!lof)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//select shadowgen gpu
|
|
int nShadowGenGPU = 0;
|
|
if (GetActiveGPUCount() > 1 && CV_r_ShadowGenMode == 1)
|
|
{
|
|
//TOFIx: make m_nFrameSwapID - double buffered
|
|
nShadowGenGPU = gRenDev->RT_GetCurrGpuID();
|
|
}
|
|
|
|
if (GetActiveGPUCount() > 1 && lof->IsCached())
|
|
{
|
|
ShadowFrustumMGPUCache* pFrustumCache = GetShadowFrustumMGPUCache();
|
|
pFrustumCache->nUpdateMaskRT &= ~(1 << gRenDev->RT_GetCurrGpuID());
|
|
}
|
|
|
|
// Save previous camera
|
|
int vX, vY, vWidth, vHeight;
|
|
GetViewport(&vX, &vY, &vWidth, &vHeight);
|
|
Matrix44 camMatr = m_CameraMatrix;
|
|
|
|
// Setup matrices
|
|
Matrix44A origMatView = m_RP.m_TI[nThreadList].m_matView;
|
|
Matrix44A origMatProj = m_RP.m_TI[nThreadList].m_matProj;
|
|
|
|
Matrix44A* m = &m_RP.m_TI[nThreadList].m_matProj;
|
|
m->SetIdentity();
|
|
m = &m_RP.m_TI[nThreadList].m_matView;
|
|
m->SetIdentity();
|
|
|
|
lof->mLightProjMatrix.SetIdentity();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Assign RTs
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool bTextureFromDynPool = false;
|
|
|
|
if (lof->bUseShadowsPool)
|
|
{
|
|
lof->nTextureWidth = m_nShadowPoolWidth;
|
|
lof->nTextureHeight = m_nShadowPoolHeight;
|
|
|
|
//current eTF should be stored in the shadow frustum
|
|
ETEX_Format ePoolTF = lof->m_eReqTF;
|
|
CTexture::s_ptexRT_ShadowPool->Invalidate(m_nShadowPoolWidth, m_nShadowPoolHeight, ePoolTF);
|
|
|
|
if (!CTexture::IsTextureExist(CTexture::s_ptexRT_ShadowPool))
|
|
{
|
|
#if !defined(_RELEASE) && !defined(WIN32) && !defined(WIN64)
|
|
__debugbreak(); // don't want any realloc on consoles
|
|
#endif
|
|
CTexture::s_ptexRT_ShadowPool->CreateRenderTarget(eTF_Unknown, Clr_FarPlane);
|
|
}
|
|
|
|
lof->pDepthTex = CTexture::s_ptexRT_ShadowPool;
|
|
}
|
|
else
|
|
{
|
|
if (lof->m_eFrustumType == ShadowMapFrustum::e_Nearest)
|
|
{
|
|
CTexture* pTX = CTexture::s_ptexNearestShadowMap;
|
|
if (!CTexture::IsTextureExist(pTX))
|
|
{
|
|
pTX->CreateRenderTarget(lof->m_eReqTF, Clr_FarPlane);
|
|
}
|
|
lof->pDepthTex = pTX;
|
|
|
|
lof->fWidthS *= lof->nTextureWidth / (float)pTX->GetWidth();
|
|
lof->fWidthT *= lof->nTextureHeight / (float)pTX->GetHeight();
|
|
|
|
lof->nTextureWidth = pTX->GetWidth();
|
|
lof->nTextureHeight = pTX->GetHeight();
|
|
}
|
|
|
|
else if (lof->IsCached())
|
|
{
|
|
if (lof->m_eFrustumType != ShadowMapFrustum::e_HeightMapAO)
|
|
{
|
|
assert(CV_r_ShadowsCache > 0 && CV_r_ShadowsCache <= MAX_GSM_LODS_NUM);
|
|
const int nStaticMapIndex = clamp_tpl(lof->nShadowMapLod - (CV_r_ShadowsCache - 1), 0, MAX_GSM_LODS_NUM - 1);
|
|
lof->pDepthTex = CTexture::s_ptexCachedShadowMap[nStaticMapIndex];
|
|
}
|
|
else
|
|
{
|
|
lof->pDepthTex = CTexture::s_ptexHeightMapAODepth[0];
|
|
}
|
|
}
|
|
else if (lof->m_eFrustumType != ShadowMapFrustum::e_GsmDynamicDistance)
|
|
{
|
|
bTextureFromDynPool = true;
|
|
SDynTexture_Shadow* pDynTX = SDynTexture_Shadow::GetForFrustum(lof);
|
|
lof->pDepthTex = pDynTX->m_pTexture;
|
|
}
|
|
}
|
|
|
|
if (CTexture::IsTextureExist(lof->pDepthTex))
|
|
{
|
|
int nSides = 1;
|
|
if (lof->bOmniDirectionalShadow)
|
|
{
|
|
nSides = OMNI_SIDES_NUM;
|
|
}
|
|
|
|
int sideIndex;
|
|
int nFirstShadowGenRI, nLastShadowGenRI;
|
|
|
|
int nOldScissor = CV_r_scissor;
|
|
int old_CV_r_nodrawnear = CV_r_nodrawnear;
|
|
int nPersFlags = m_RP.m_TI[nThreadList].m_PersFlags;
|
|
int nPersFlags2 = m_RP.m_PersFlags2;
|
|
int nStateAnd = m_RP.m_StateAnd;
|
|
m_RP.m_TI[nThreadList].m_PersFlags &= ~(RBPF_HDR | RBPF_MIRRORCULL); // In a mirrorcull pass (i.e. cubemap gen), remove mirrorculling for shadow gen (omni shadows should re-enable it later on)
|
|
m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_SHADOWGEN;
|
|
|
|
if (!(lof->m_Flags & DLF_DIRECTIONAL))
|
|
{
|
|
m_RP.m_PersFlags2 |= RBPF2_DRAWTOCUBE;
|
|
}
|
|
|
|
//hack remove texkill for eTF_DF24 and eTF_D24S8
|
|
if (lof->m_eReqTF == eTF_R32F || lof->m_eReqTF == eTF_R16G16F || lof->m_eReqTF == eTF_R16F || lof->m_eReqTF == eTF_R16G16B16A16F ||
|
|
lof->m_eReqTF == eTF_D16 || lof->m_eReqTF == eTF_D24S8 || lof->m_eReqTF == eTF_D32F || lof->m_eReqTF == eTF_D32FS8)
|
|
{
|
|
m_RP.m_PersFlags2 |= RBPF2_NOALPHABLEND;
|
|
m_RP.m_StateAnd &= ~GS_BLEND_MASK;
|
|
}
|
|
|
|
if (lof->m_eReqTF == eTF_R32F || lof->m_eReqTF == eTF_R16G16F || lof->m_eReqTF == eTF_R16F || lof->m_eReqTF == eTF_R16G16B16A16F)
|
|
{
|
|
m_RP.m_PersFlags2 |= RBPF2_NOALPHATEST;
|
|
m_RP.m_StateAnd &= ~GS_ALPHATEST_MASK;
|
|
}
|
|
CCamera saveCam = GetCamera();
|
|
Vec3 vPos = lof->vLightSrcRelPos + lof->vProjTranslation;
|
|
|
|
SDepthTexture depthTarget;
|
|
ZeroStruct(depthTarget);
|
|
|
|
for (sideIndex = 0; sideIndex < nSides; sideIndex++)
|
|
{
|
|
if (nLightFrustumID >= 0)//skip for custom fustum
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//compute shadow recursive level
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const int nThreadID = m_RP.m_nProcessThreadID;
|
|
const int nShadowRecur = lof->nShadowGenID[nThreadID][sideIndex];
|
|
|
|
if (nShadowRecur == 0xFFFFFFFF)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
assert(nShadowRecur >= 0 && nShadowRecur < MAX_SHADOWMAP_FRUSTUMS);
|
|
|
|
assert(nThreadID >= 0 && nThreadID < 2);
|
|
nFirstShadowGenRI = SRendItem::m_ShadowsStartRI[nThreadID][nShadowRecur];
|
|
nLastShadowGenRI = SRendItem::m_ShadowsEndRI[nThreadID][nShadowRecur];
|
|
const bool bClearRequired = lof->IsCached() && !lof->bIncrementalUpdate;
|
|
// If there's something to render, sort by lights.
|
|
if (nLastShadowGenRI - nFirstShadowGenRI > 0)
|
|
{
|
|
auto& renderItems = CRenderView::CurrentRenderView()->GetRenderItems(SG_SORT_GROUP, EFSLIST_SHADOW_GEN);
|
|
SRendItem* pFirst = &renderItems[nFirstShadowGenRI];
|
|
SRendItem::mfSortByLight(pFirst, nLastShadowGenRI - nFirstShadowGenRI, true, false, false);
|
|
}
|
|
else if (!bClearRequired)
|
|
{
|
|
// Nothing to render and there's no need to clear, so we can just continue.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
depthTarget.nWidth = lof->nTextureWidth;
|
|
depthTarget.nHeight = lof->nTextureHeight;
|
|
depthTarget.nFrameAccess = -1;
|
|
depthTarget.bBusy = false;
|
|
depthTarget.pTex = lof->pDepthTex;
|
|
depthTarget.pTarget = lof->pDepthTex->GetDevTexture()->Get2DTexture();
|
|
depthTarget.pSurf = lof->bOmniDirectionalShadow && !(lof->bUnwrapedOmniDirectional)
|
|
? static_cast<D3DDepthSurface*>(lof->pDepthTex->GetDeviceDepthStencilSurf(sideIndex, 1))
|
|
: static_cast<D3DDepthSurface*>(lof->pDepthTex->GetDeviceDepthStencilSurf());
|
|
|
|
CCamera tmpCamera;
|
|
if (!lof->bOmniDirectionalShadow)
|
|
{
|
|
*m = lof->mLightViewMatrix;
|
|
m_RP.m_TI[nThreadList].m_PersFlags &= ~RBPF_REVERSE_DEPTH;
|
|
|
|
uint32 depthState = ReverseDepthHelper::ConvertDepthFunc(m_RP.m_CurState);
|
|
FX_SetState(m_RP.m_CurState, m_RP.m_CurAlphaRef, depthState);
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (!(lof->m_Flags & DLF_DIRECTIONAL) && CSvoRenderer::GetRsmColorMap(*lof))
|
|
{
|
|
m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_MIRRORCULL;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
const Matrix34& m34 = lof->FrustumPlanes[sideIndex].GetMatrix();
|
|
CameraViewParameters c;
|
|
c.Perspective(tmpCamera.GetFov(), tmpCamera.GetProjRatio(), tmpCamera.GetNearPlane(), tmpCamera.GetFarPlane());
|
|
Vec3 vEyeC = tmpCamera.GetPosition();
|
|
Vec3 vAtC = vEyeC + Vec3(m34(0, 1), m34(1, 1), m34(2, 1));
|
|
Vec3 vUpC = Vec3(m34(0, 2), m34(1, 2), m34(2, 2));
|
|
c.LookAt(vEyeC, vAtC, vUpC);
|
|
ApplyViewParameters(c);
|
|
CShadowUtils::GetCubemapFrustum(FTYP_SHADOWOMNIPROJECTION, lof, sideIndex, &m_RP.m_TI[nThreadList].m_matProj, &m_RP.m_TI[nThreadList].m_matView, NULL);
|
|
|
|
//enable back facing for omni lights for now
|
|
m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_MIRRORCULL;
|
|
if (lof->m_Flags & DLF_AREA_LIGHT)
|
|
{
|
|
m_RP.m_TI[nThreadList].m_PersFlags &= ~RBPF_MIRRORCULL;
|
|
}
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (!(lof->m_Flags & DLF_DIRECTIONAL) && CSvoRenderer::GetRsmColorMap(*lof))
|
|
{
|
|
m_RP.m_TI[nThreadList].m_PersFlags &= ~RBPF_MIRRORCULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
EF_SetCameraInfo();
|
|
|
|
//assign for shader's parameters
|
|
SRenderPipeline::ShadowInfo& shadowInfo = m_RP.m_ShadowInfo;
|
|
shadowInfo.m_pCurShadowFrustum = lof;
|
|
shadowInfo.m_nOmniLightSide = sideIndex;
|
|
shadowInfo.vViewerPos = saveCam.GetPosition();
|
|
|
|
{
|
|
CStandardGraphicsPipeline::ShadowParameters shadowParams;
|
|
shadowParams.m_ShadowFrustum = lof;
|
|
shadowParams.m_OmniLightSideIndex = sideIndex;
|
|
shadowParams.m_ViewerPos = shadowInfo.vViewerPos;
|
|
GetGraphicsPipeline().UpdatePerShadowConstantBuffer(shadowParams);
|
|
|
|
AzRHI::ConstantBuffer* perShadow = GetGraphicsPipeline().GetPerShadowConstantBuffer().get();
|
|
m_DevMan.BindConstantBuffer(eHWSC_Vertex, perShadow, eConstantBufferShaderSlot_PerPass);
|
|
m_DevMan.BindConstantBuffer(eHWSC_Pixel, perShadow, eConstantBufferShaderSlot_PerPass);
|
|
m_DevMan.BindConstantBuffer(eHWSC_Geometry, perShadow, eConstantBufferShaderSlot_PerPass);
|
|
m_DevMan.BindConstantBuffer(eHWSC_Hull, perShadow, eConstantBufferShaderSlot_PerPass);
|
|
m_DevMan.BindConstantBuffer(eHWSC_Domain, perShadow, eConstantBufferShaderSlot_PerPass);
|
|
m_DevMan.BindConstantBuffer(eHWSC_Compute, perShadow, eConstantBufferShaderSlot_PerPass);
|
|
}
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (CSvoRenderer::GetRsmColorMap(*lof, true) && CSvoRenderer::GetRsmNormlMap(*lof, true))
|
|
{
|
|
FX_PushRenderTarget(0, CSvoRenderer::GetInstance()->GetRsmColorMap(*lof), &depthTarget, lof->m_eReqTT == eTT_Cube ? sideIndex : -1);
|
|
FX_PushRenderTarget(1, CSvoRenderer::GetInstance()->GetRsmNormlMap(*lof), NULL, lof->m_eReqTT == eTT_Cube ? sideIndex : -1);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
FX_PushRenderTarget(0, nullptr, &depthTarget, lof->m_eReqTT == eTT_Cube ? sideIndex : -1);
|
|
FX_SetColorDontCareActions(0, true, true);
|
|
}
|
|
|
|
//SDW-GEN_REND_PATH
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// clear frame buffer after RT push
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (!lof->bIncrementalUpdate)
|
|
{
|
|
uint32_t clearFlags = 0;
|
|
|
|
const bool bReverseDepth = (m_RP.m_TI[nThreadList].m_PersFlags & RBPF_REVERSE_DEPTH) != 0;
|
|
|
|
if (lof->bUseShadowsPool)
|
|
{
|
|
if (bClearPool)
|
|
{
|
|
const RECT rect = { lof->packX[sideIndex], lof->packY[sideIndex], lof->packX[sideIndex] + lof->packWidth[sideIndex], lof->packY[sideIndex] + lof->packHeight[sideIndex] };
|
|
|
|
FX_ClearTarget(&depthTarget, CLEAR_ZBUFFER, Clr_FarPlane_R.r, 0, 1, &rect, false);
|
|
clearFlags |= CLEAR_ZBUFFER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (CSvoRenderer::GetRsmColorMap(*lof, true) && CSvoRenderer::GetRsmNormlMap(*lof, true))
|
|
{
|
|
FX_ClearTarget(CSvoRenderer::GetInstance()->GetRsmColorMap(*lof), Clr_Transparent);
|
|
FX_ClearTarget(CSvoRenderer::GetInstance()->GetRsmNormlMap(*lof), Clr_Transparent);
|
|
clearFlags |= CLEAR_RTARGET;
|
|
}
|
|
#endif
|
|
FX_ClearTarget(&depthTarget, CLEAR_ZBUFFER | CLEAR_STENCIL, Clr_FarPlane_R.r, 0);
|
|
clearFlags |= CLEAR_ZBUFFER | CLEAR_STENCIL;
|
|
#if defined(CRY_USE_METAL)
|
|
//Clear calls are cached until a draw call is made. If there is nothing in the caster list no draw calls will be made.
|
|
//Hence make a draw call to clear the render targets.
|
|
if (lof->m_castersList.IsEmpty() && lof->m_jobExecutedCastersList.IsEmpty())
|
|
{
|
|
FX_Commit();
|
|
FX_ClearTargetRegion();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
m_pNewTarget[0]->m_ClearFlags = 0;
|
|
|
|
FX_SetColorDontCareActions(0, !(clearFlags & CLEAR_RTARGET), false);
|
|
FX_SetColorDontCareActions(1, !(clearFlags & CLEAR_RTARGET), false);
|
|
FX_SetColorDontCareActions(2, !(clearFlags & CLEAR_RTARGET), false);
|
|
#if !defined(OPENGL_ES) // some drivers don't play well with the following
|
|
FX_SetStencilDontCareActions(0, !(clearFlags & CLEAR_STENCIL), true);
|
|
FX_SetStencilDontCareActions(1, !(clearFlags & CLEAR_STENCIL), true);
|
|
FX_SetStencilDontCareActions(2, !(clearFlags & CLEAR_STENCIL), true);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// CONFETTI BEGIN: David Srour
|
|
// Metal Load/Store Actions
|
|
FX_SetColorDontCareActions(0, true, true);
|
|
FX_SetStencilDontCareActions(0, true, true);
|
|
FX_SetColorDontCareActions(1, true, true);
|
|
FX_SetStencilDontCareActions(1, true, true);
|
|
FX_SetColorDontCareActions(2, true, true);
|
|
FX_SetStencilDontCareActions(2, true, true);
|
|
// CONFETTI END
|
|
}
|
|
|
|
//set proper side-viewport
|
|
if (lof->bUnwrapedOmniDirectional || lof->bUseShadowsPool)
|
|
{
|
|
int arrViewport[4];
|
|
lof->GetSideViewport(sideIndex, arrViewport);
|
|
RT_SetViewport(arrViewport[0], arrViewport[1], arrViewport[2], arrViewport[3]);
|
|
}
|
|
|
|
FX_Commit(true);
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (!CSvoRenderer::GetRsmColorMap(*lof))
|
|
#endif
|
|
{
|
|
FX_SetState(GS_COLMASK_NONE, -1);
|
|
m_RP.m_PersFlags2 |= RBPF2_DISABLECOLORWRITES;
|
|
m_RP.m_StateOr |= GS_COLMASK_NONE;
|
|
}
|
|
|
|
if (lof->fDepthSlopeBias > 0.0f && (lof->m_Flags & DLF_DIRECTIONAL))
|
|
{
|
|
float fShadowsBias = CV_r_ShadowsBias;
|
|
float fShadowsSlopeScaleBias = lof->fDepthSlopeBias;
|
|
|
|
//adjust nearest slope fer nearest custom frustum
|
|
if (lof->m_eFrustumType == ShadowMapFrustum::e_Nearest)
|
|
{
|
|
fShadowsSlopeScaleBias *= 7.0f;
|
|
}
|
|
|
|
SStateRaster CurRS = m_StatesRS[m_nCurStateRS];
|
|
CurRS.Desc.DepthBias = 0;
|
|
CurRS.Desc.DepthBiasClamp = fShadowsBias * 20;
|
|
CurRS.Desc.SlopeScaledDepthBias = fShadowsSlopeScaleBias;
|
|
SetRasterState(&CurRS);
|
|
}
|
|
|
|
int nBorder = max(4, lof->nShadowMapSize / 64);
|
|
|
|
if (!(lof->m_Flags & DLF_LIGHT_BEAM))
|
|
{
|
|
D3DSetCull(eCULL_None);
|
|
}
|
|
else
|
|
{
|
|
D3DSetCull(eCULL_Back);
|
|
m_RP.m_PersFlags2 |= RBPF2_LIGHTSHAFTS;
|
|
}
|
|
|
|
if (nLightFrustumID < 0)
|
|
{
|
|
FX_ProcessRenderList(EFSLIST_GENERAL, 0, FX_FlushShader_ShadowGen, false);
|
|
FX_ProcessRenderList(EFSLIST_GENERAL, 1, FX_FlushShader_ShadowGen, false);
|
|
}
|
|
else
|
|
if (!lof->m_castersList.IsEmpty() || !lof->m_jobExecutedCastersList.IsEmpty())
|
|
{
|
|
FX_ProcessRenderList(nFirstShadowGenRI,
|
|
nLastShadowGenRI,
|
|
EFSLIST_SHADOW_GEN, 0, FX_FlushShader_ShadowGen, false);
|
|
}
|
|
|
|
FX_PopRenderTarget(0);
|
|
|
|
#if defined(FEATURE_SVO_GI)
|
|
if (CSvoRenderer::GetRsmColorMap(*lof) && CSvoRenderer::GetRsmNormlMap(*lof))
|
|
{
|
|
FX_PopRenderTarget(1);
|
|
}
|
|
#endif
|
|
|
|
m_RP.m_PersFlags2 &= ~RBPF2_DISABLECOLORWRITES;
|
|
m_RP.m_StateOr &= ~GS_COLMASK_NONE;
|
|
if (CV_r_ShadowsBias > 0.0f)
|
|
{
|
|
SStateRaster CurRS = m_StatesRS[m_nCurStateRS];
|
|
CurRS.Desc.DepthBias = 0;
|
|
CurRS.Desc.DepthBiasClamp = 0;
|
|
CurRS.Desc.SlopeScaledDepthBias = 0;
|
|
SetRasterState(&CurRS);
|
|
}
|
|
}
|
|
|
|
m_RP.m_TI[nThreadList].m_PersFlags &= ~RBPF_SHADOWGEN;
|
|
SetCamera(saveCam);
|
|
if (lof->m_eReqTT == eTT_Cube)
|
|
{
|
|
lof->mLightViewMatrix.SetIdentity();
|
|
lof->mLightViewMatrix.SetTranslation(vPos);
|
|
lof->mLightViewMatrix.Transpose();
|
|
}
|
|
|
|
if (!(lof->m_Flags & DLF_DIRECTIONAL))
|
|
{
|
|
m_RP.m_PersFlags2 &= ~RBPF2_DRAWTOCUBE;
|
|
}
|
|
|
|
m_RP.m_TI[nThreadList].m_PersFlags &= ~RBPF_MIRRORCULL;
|
|
m_RP.m_PersFlags2 &= ~RBPF2_LIGHTSHAFTS;
|
|
|
|
CV_r_nodrawnear = old_CV_r_nodrawnear;
|
|
CV_r_scissor = nOldScissor;
|
|
|
|
m_RP.m_TI[nThreadList].m_PersFlags = nPersFlags;
|
|
m_RP.m_PersFlags2 = nPersFlags2;
|
|
m_RP.m_StateAnd = nStateAnd;
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
}
|
|
else if (bTextureFromDynPool)
|
|
{
|
|
iLog->Log("Error: cannot create depth texture for frustum '%d' (skipping)", lof->nShadowMapLod);
|
|
}
|
|
|
|
m_RP.m_TI[nThreadList].m_matView = origMatView;
|
|
m_RP.m_TI[nThreadList].m_matProj = origMatProj;
|
|
m_CameraMatrix = camMatr;
|
|
EF_SetCameraInfo();
|
|
RT_SetViewport(vX, vY, vWidth, vHeight);
|
|
|
|
return true;
|
|
}
|
|
|
|
void CD3D9Renderer::ConfigShadowTexgen(int Num, ShadowMapFrustum* pFr, int nFrustNum, [[maybe_unused]] bool bScreenToLocalBasis, bool bUseComparisonSampling)
|
|
{
|
|
Matrix44A shadowMat, mTexScaleBiasMat, mLightView, mLightProj, mLightViewProj;
|
|
bool bGSM = false;
|
|
|
|
//check for successful PrepareDepthMap
|
|
if (!pFr->pDepthTex && !pFr->bUseShadowsPool)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float fOffsetX = 0.5f;
|
|
float fOffsetY = 0.5f;
|
|
const Matrix44A mClipToTexSpace = Matrix44(0.5f, 0.0f, 0.0f, 0.0f,
|
|
0.0f, -0.5f, 0.0f, 0.0f,
|
|
0.0f, 0.0f, 1.0f, 0.0f,
|
|
fOffsetX, fOffsetY, 0.0f, 1.0f);
|
|
|
|
mTexScaleBiasMat = mClipToTexSpace;
|
|
|
|
if ((pFr->bOmniDirectionalShadow || pFr->bUseShadowsPool) && nFrustNum > -1)
|
|
{
|
|
if (!pFr->bOmniDirectionalShadow)
|
|
{
|
|
mLightView = pFr->mLightViewMatrix;
|
|
mLightProj.SetIdentity();
|
|
}
|
|
else
|
|
{
|
|
CShadowUtils::GetCubemapFrustum(FTYP_SHADOWOMNIPROJECTION, pFr, nFrustNum, &mLightProj, &mLightView);
|
|
}
|
|
|
|
float arrOffs[2];
|
|
float arrScale[2];
|
|
pFr->GetTexOffset(nFrustNum, arrOffs, arrScale, m_nShadowPoolWidth, m_nShadowPoolHeight);
|
|
|
|
//calculate crop matrix for frustum
|
|
//TD: investigate proper half-texel offset with mCropView
|
|
Matrix44 mCropView(arrScale[0], 0.0f, 0.0f, 0.0f,
|
|
0.0f, arrScale[1], 0.0f, 0.0f,
|
|
0.0f, 0.0f, 1.0f, 0.0f,
|
|
arrOffs[0], arrOffs[1], 0.0f, 1.0f);
|
|
|
|
// multiply the projection matrix with it
|
|
mTexScaleBiasMat = mTexScaleBiasMat * mCropView;
|
|
|
|
//constants for gsm atlas
|
|
m_cEF.m_TempVecs[6].x = arrOffs[0];
|
|
m_cEF.m_TempVecs[6].y = arrOffs[1];
|
|
}
|
|
else
|
|
{
|
|
mLightView = pFr->mLightViewMatrix;
|
|
|
|
if (pFr->m_eFrustumType == ShadowMapFrustum::e_GsmDynamicDistance)
|
|
{
|
|
Matrix44 mCropView(IDENTITY);
|
|
mCropView.m00 = (float)pFr->packWidth[0] / pFr->pDepthTex->GetWidth();
|
|
mCropView.m11 = (float)pFr->packHeight[0] / pFr->pDepthTex->GetHeight();
|
|
mCropView.m30 = (float)pFr->packX[0] / pFr->pDepthTex->GetWidth();
|
|
mCropView.m31 = (float)pFr->packY[0] / pFr->pDepthTex->GetHeight();
|
|
|
|
mTexScaleBiasMat = mTexScaleBiasMat * mCropView;
|
|
}
|
|
|
|
mLightProj.SetIdentity();
|
|
bGSM = true;
|
|
}
|
|
|
|
mLightViewProj = mLightView * mLightProj;
|
|
shadowMat = mLightViewProj * mTexScaleBiasMat;
|
|
|
|
//set shadow matrix
|
|
gRenDev->m_TempMatrices[Num][0] = shadowMat.GetTransposed();
|
|
m_cEF.m_TempVecs[5] = Vec4(mLightViewProj.m30, mLightViewProj.m31, mLightViewProj.m32, 1);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Deferred shadow pass setup
|
|
//////////////////////////////////////////////////////////////////////////
|
|
Matrix44 mScreenToShadow;
|
|
int vpX, vpY, vpWidth, vpHeight;
|
|
GetViewport(&vpX, &vpY, &vpWidth, &vpHeight);
|
|
FX_DeferredShadowPassSetup(gRenDev->m_TempMatrices[Num][0], pFr, (float)vpWidth, (float)vpHeight,
|
|
mScreenToShadow, pFr->m_eFrustumType == ShadowMapFrustum::e_Nearest);
|
|
|
|
#if defined(VOLUMETRIC_FOG_SHADOWS)
|
|
//use cur TexGen for homogeneous position reconstruction
|
|
if (bScreenToLocalBasis && CRenderer::CV_r_FogShadowsMode == 1)
|
|
{
|
|
Matrix44A mLocalScale;
|
|
mLocalScale.SetIdentity();
|
|
gRenDev->m_TempMatrices[Num][0] = mScreenToShadow.GetTransposed();
|
|
float fScreenScale = (CV_r_FogShadows == 2) ? 4.0f : 2.0f;
|
|
mLocalScale.m00 = fScreenScale;
|
|
mLocalScale.m11 = fScreenScale;
|
|
gRenDev->m_TempMatrices[Num][0] = gRenDev->m_TempMatrices[Num][0] * mLocalScale;
|
|
}
|
|
#endif
|
|
|
|
gRenDev->m_TempMatrices[Num][2].m33 = 0.0f;
|
|
if (bGSM && pFr->bBlendFrustum)
|
|
{
|
|
const float fBlendVal = pFr->fBlendVal;
|
|
|
|
m_cEF.m_TempVecs[15][0] = fBlendVal;
|
|
m_cEF.m_TempVecs[15][1] = 1.0f / (1.0f - fBlendVal);
|
|
m_cEF.m_TempVecs[15][2] = 0.0f;
|
|
m_cEF.m_TempVecs[15][3] = 0.0f;
|
|
|
|
m_cEF.m_TempVecs[6] = Vec4(1.f, 1.f, 0.f, 0.f);
|
|
if (pFr->m_eFrustumType == ShadowMapFrustum::e_GsmDynamicDistance)
|
|
{
|
|
m_cEF.m_TempVecs[6].x = pFr->pDepthTex->GetWidth() / float(pFr->packWidth[0]);
|
|
m_cEF.m_TempVecs[6].y = pFr->pDepthTex->GetHeight() / float(pFr->packHeight[0]);
|
|
m_cEF.m_TempVecs[6].z = -pFr->packX[0] / float(pFr->packWidth[0]);
|
|
m_cEF.m_TempVecs[6].w = -pFr->packY[0] / float(pFr->packHeight[0]);
|
|
}
|
|
|
|
const ShadowMapFrustum* pPrevFr = pFr->pPrevFrustum;
|
|
if (pPrevFr)
|
|
{
|
|
Matrix44A mLightViewPrev = pPrevFr->mLightViewMatrix;
|
|
Matrix44A shadowMatPrev = mLightViewPrev * mClipToTexSpace; // NOTE: no sub-rect here as blending code assumes full [0-1] UV range;
|
|
|
|
FX_DeferredShadowPassSetupBlend(shadowMatPrev.GetTransposed(), Num, (float)vpWidth, (float)vpHeight);
|
|
|
|
m_cEF.m_TempVecs[2][2] = 1.f / (pPrevFr->fFarDist);
|
|
|
|
float fBlendValPrev = pPrevFr->fBlendVal;
|
|
|
|
m_cEF.m_TempVecs[15][2] = fBlendValPrev;
|
|
m_cEF.m_TempVecs[15][3] = 1.0f / (1.0f - fBlendValPrev);
|
|
}
|
|
}
|
|
|
|
Matrix33 mRotMatrix(mLightView);
|
|
mRotMatrix.OrthonormalizeFast();
|
|
gRenDev->m_TempMatrices[0][1] = Matrix44(mRotMatrix).GetTransposed();
|
|
|
|
if (Num >= 0)
|
|
{
|
|
if (!pFr->pDepthTex && !pFr->bUseShadowsPool)
|
|
{
|
|
Warning("Warning: CD3D9Renderer::ConfigShadowTexgen: pFr->depth_tex_id not set");
|
|
}
|
|
else
|
|
{
|
|
int nID = 0;
|
|
int nIDBlured = 0;
|
|
if (pFr->bUseShadowsPool)
|
|
{
|
|
nID = CTexture::s_ptexRT_ShadowPool->GetID();
|
|
}
|
|
else
|
|
if (pFr->pDepthTex != NULL)
|
|
{
|
|
nID = pFr->pDepthTex->GetID();
|
|
}
|
|
|
|
m_RP.m_ShadowCustomTexBind[Num * 2 + 0] = nID;
|
|
m_RP.m_ShadowCustomTexBind[Num * 2 + 1] = nIDBlured;
|
|
m_RP.m_ShadowCustomComparisonSampling[Num * 2 + 0] = bUseComparisonSampling;
|
|
|
|
m_cEF.m_TempVecs[8][0] = pFr->fShadowFadingDist;
|
|
|
|
assert(Num < 4);
|
|
if (pFr->bHWPCFCompare)
|
|
{
|
|
if (pFr->m_Flags & DLF_DIRECTIONAL)
|
|
{
|
|
//linear case + constant offset
|
|
m_cEF.m_TempVecs[1][Num] = pFr->fDepthConstBias;
|
|
if (pFr->m_eFrustumType == ShadowMapFrustum::e_Nearest)
|
|
{
|
|
m_cEF.m_TempVecs[1][Num] *= 3.0f;
|
|
}
|
|
}
|
|
else
|
|
if (pFr->m_Flags & DLF_PROJECT)
|
|
{
|
|
//non-linear case
|
|
m_cEF.m_TempVecs[1][Num] = pFr->fDepthConstBias;
|
|
}
|
|
else
|
|
{
|
|
m_cEF.m_TempVecs[1][Num] = pFr->fDepthConstBias;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//linear case
|
|
m_cEF.m_TempVecs[1][Num] = pFr->fDepthTestBias;
|
|
}
|
|
|
|
m_cEF.m_TempVecs[2][Num] = 1.f / (pFr->fFarDist);
|
|
m_cEF.m_TempVecs[9][Num] = 1.f / pFr->nTexSize;
|
|
m_cEF.m_TempVecs[3][Num] = 0.0f;
|
|
|
|
float fShadowJitter = m_shadowJittering;
|
|
|
|
if (pFr->m_Flags & DLF_DIRECTIONAL)
|
|
{
|
|
float fFilteredArea = fShadowJitter * (pFr->fWidthS + pFr->fBlurS);
|
|
|
|
if (pFr->m_eFrustumType == ShadowMapFrustum::e_Nearest)
|
|
{
|
|
fFilteredArea *= 0.1f;
|
|
}
|
|
|
|
m_cEF.m_TempVecs[4].x = fFilteredArea;
|
|
m_cEF.m_TempVecs[4].y = fFilteredArea;
|
|
}
|
|
else
|
|
{
|
|
fShadowJitter = 2.0;
|
|
m_cEF.m_TempVecs[4].x = fShadowJitter;
|
|
;
|
|
m_cEF.m_TempVecs[4].y = fShadowJitter;
|
|
|
|
if (pFr->bOmniDirectionalShadow)
|
|
{
|
|
m_cEF.m_TempVecs[4].x *= 1.0f / 3.0f;
|
|
m_cEF.m_TempVecs[4].y *= 1.0f / 2.0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================================================
|
|
void CD3D9Renderer::FX_SetupForwardShadows(bool bUseShaderPermutations)
|
|
{
|
|
const int FORWARD_SHADOWS_CASCADE0_SINGLE_TAP = 0x10;
|
|
const int FORWARD_SHADOWS_CLOUD_SHADOWS = 0x20;
|
|
|
|
const int nThreadID = m_RP.m_nProcessThreadID;
|
|
const int nSunFrustumID = 0;
|
|
|
|
const int nStartIdx = SRendItem::m_StartFrust[nThreadID][nSunFrustumID];
|
|
const int nEndIdx = SRendItem::m_EndFrust[nThreadID][nSunFrustumID];
|
|
|
|
if (bUseShaderPermutations)
|
|
{
|
|
m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3] |
|
|
g_HWSR_MaskBit[HWSR_LIGHT_TEX_PROJ]);
|
|
}
|
|
|
|
uint32 nCascadeMask = 0;
|
|
for (int a = nStartIdx, cascadeCount = 0; a < nEndIdx && cascadeCount < 4; ++a)
|
|
{
|
|
ShadowMapFrustum* pFr = &m_RP.m_SMFrustums[nThreadID][nSunFrustumID][a];
|
|
nCascadeMask |= 0x1 << a;
|
|
|
|
ConfigShadowTexgen(cascadeCount, pFr, -1, true);
|
|
|
|
if (bUseShaderPermutations)
|
|
{
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0 + cascadeCount];
|
|
}
|
|
|
|
++cascadeCount;
|
|
}
|
|
|
|
// only do full pcf filtering on nearest shadow cascade
|
|
if (nCascadeMask > 0 && m_RP.m_SMFrustums[nThreadID][nSunFrustumID][nStartIdx].nShadowMapLod != 0)
|
|
{
|
|
nCascadeMask |= FORWARD_SHADOWS_CASCADE0_SINGLE_TAP;
|
|
}
|
|
|
|
if (m_bCloudShadowsEnabled && m_cloudShadowTexId > 0)
|
|
{
|
|
nCascadeMask |= FORWARD_SHADOWS_CLOUD_SHADOWS;
|
|
|
|
if (bUseShaderPermutations)
|
|
{
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_LIGHT_TEX_PROJ];
|
|
}
|
|
}
|
|
|
|
// store cascade mask in m_TempVecs[4].z
|
|
*alias_cast<uint32*>(&m_cEF.m_TempVecs[4].z) = nCascadeMask;
|
|
}
|
|
|
|
void CD3D9Renderer::FX_SetupShadowsForTransp()
|
|
{
|
|
PROFILE_FRAME(SetupShadowsForTransp);
|
|
|
|
m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_POINT_LIGHT] | g_HWSR_MaskBit[HWSR_SHADOW_MIXED_MAP_G16R16]);
|
|
|
|
CRenderObject* pObj = m_RP.m_pCurObject;
|
|
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_PARTICLE_SHADOW];
|
|
|
|
if (m_shadowJittering > 0.0f)
|
|
{
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SHADOW_JITTERING];
|
|
}
|
|
|
|
// Always use PCF for shadows for transparent
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_HW_PCF_COMPARE ];
|
|
|
|
FX_SetupForwardShadows(true);
|
|
}
|
|
|
|
void CD3D9Renderer::FX_SetupShadowsForFog()
|
|
{
|
|
PROFILE_FRAME(FX_SetupShadowsForFog);
|
|
|
|
m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_POINT_LIGHT] | g_HWSR_MaskBit[HWSR_HW_PCF_COMPARE] | g_HWSR_MaskBit[HWSR_SHADOW_JITTERING] |
|
|
g_HWSR_MaskBit[HWSR_SHADOW_MIXED_MAP_G16R16]);
|
|
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_HW_PCF_COMPARE] | g_HWSR_MaskBit[HWSR_PARTICLE_SHADOW];
|
|
|
|
FX_SetupForwardShadows();
|
|
}
|
|
|
|
|
|
bool CD3D9Renderer::FX_PrepareDepthMapsForLight(const SRenderLight& rLight, int nLightID, bool bClearPool)
|
|
{
|
|
int nThreadID = m_RP.m_nProcessThreadID;
|
|
int nCurRecLevel = SRendItem::m_RecurseLevel[nThreadID];
|
|
assert(nCurRecLevel >= 0);
|
|
|
|
if ((m_RP.m_TI[nThreadID].m_PersFlags & RBPF_NO_SHADOWGEN) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//render all valid shadow frustums
|
|
const int nStartIdx = SRendItem::m_StartFrust[nThreadID][nLightID];
|
|
const int nEndIdx = SRendItem::m_EndFrust[nThreadID][nLightID];
|
|
if (nStartIdx == nEndIdx)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
AZ_Assert((nEndIdx - nStartIdx) <= MAX_GSM_LODS_NUM, "Number of shadow frustums is more than max GSM LODs supported.");
|
|
|
|
bool processedAtLeastOneShadow = false;
|
|
|
|
for (int nFrustIdx = nEndIdx - 1; nFrustIdx >= nStartIdx; --nFrustIdx)
|
|
{
|
|
ShadowMapFrustum* pCurFrustum = &m_RP.m_SMFrustums[nThreadID][nCurRecLevel][nFrustIdx];
|
|
|
|
int nLightFrustumID = nLightID * MAX_SHADOWMAP_LOD + (nFrustIdx - nStartIdx);
|
|
if (!pCurFrustum)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (pCurFrustum->m_eReqTT == eTT_1D || pCurFrustum->m_eReqTF == eTF_Unknown)
|
|
{
|
|
// looks like unitialized shadow frustum for 1 frame - some mt issue
|
|
continue;
|
|
}
|
|
|
|
const bool bSun = (rLight.m_Flags & DLF_SUN) != 0;
|
|
|
|
// Per-object shadows are added to the "custom" shadow list in CRenderer::FinalizeRendItems_FindShadowFrustums.
|
|
// Do not render them twice.
|
|
if (pCurFrustum->m_eFrustumType != ShadowMapFrustum::e_PerObject)
|
|
{
|
|
#ifndef _RELEASE
|
|
char frustumLabel[64];
|
|
|
|
if (bSun)
|
|
{
|
|
const int nShadowRecur = pCurFrustum->nShadowGenID[nThreadID][0];
|
|
const int nRendItemCount = nShadowRecur != 0xFFFFFFFF ? (SRendItem::m_ShadowsEndRI[nThreadID][nShadowRecur] - SRendItem::m_ShadowsStartRI[nThreadID][nShadowRecur]) : 0;
|
|
|
|
const char* frustumTextSun[] =
|
|
{
|
|
"GSM FRUSTUM %i",
|
|
"GSM DISTANCE FRUSTUM %i",
|
|
"GSM CACHED FRUSTUM %i",
|
|
"HEIGHT MAP AO FRUSTUM %i",
|
|
"NEAREST FRUSTUM",
|
|
"UNKNOWN"
|
|
};
|
|
|
|
frustumLabel[0] = 0;
|
|
|
|
if (!pCurFrustum->IsCached() || nRendItemCount > 0)
|
|
{
|
|
sprintf_s(frustumLabel, frustumTextSun[pCurFrustum->m_eFrustumType], m_RP.m_SMFrustums[nThreadID][nCurRecLevel][nFrustIdx].nShadowMapLod);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(frustumLabel, "FRUSTUM %i", nFrustIdx - nStartIdx);
|
|
}
|
|
|
|
if (frustumLabel[0])
|
|
{
|
|
PROFILE_LABEL_PUSH(frustumLabel);
|
|
}
|
|
#endif
|
|
// merge cached shadow maps and corresponding dynamic shadow maps.
|
|
if (bSun && pCurFrustum->m_eFrustumType == ShadowMapFrustum::e_GsmDynamicDistance)
|
|
{
|
|
assert(0 <= nStartIdx && nStartIdx <= nEndIdx && nEndIdx <= m_RP.m_SMFrustums[nThreadID][nCurRecLevel].size());
|
|
auto pBegin = m_RP.m_SMFrustums[nThreadID][nCurRecLevel].Data() + nStartIdx;
|
|
auto pEnd = m_RP.m_SMFrustums[nThreadID][nCurRecLevel].Data() + nEndIdx;
|
|
auto pCachedFrustum = std::find_if(pBegin, pEnd,
|
|
[=](ShadowMapFrustum& fr)
|
|
{
|
|
return fr.nShadowMapLod == pCurFrustum->nShadowMapLod && fr.m_eFrustumType == ShadowMapFrustum::e_GsmCached;
|
|
});
|
|
|
|
pCurFrustum->pDepthTex = NULL;
|
|
if (pCachedFrustum != pEnd)
|
|
{
|
|
FX_MergeShadowMaps(pCurFrustum, pCachedFrustum);
|
|
processedAtLeastOneShadow = true;
|
|
}
|
|
}
|
|
|
|
if (PrepareDepthMap(pCurFrustum, nLightFrustumID, bClearPool))
|
|
{
|
|
bClearPool = false;
|
|
processedAtLeastOneShadow = true;
|
|
}
|
|
|
|
#ifndef _RELEASE
|
|
if (frustumLabel[0])
|
|
{
|
|
PROFILE_LABEL_POP(frustumLabel);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return processedAtLeastOneShadow;
|
|
}
|
|
|
|
void CD3D9Renderer::EF_PrepareCustomShadowMaps()
|
|
{
|
|
int nThreadID = m_RP.m_nProcessThreadID;
|
|
int nCurRecLevel = SRendItem::m_RecurseLevel[nThreadID];
|
|
assert(nCurRecLevel >= 0);
|
|
|
|
if ((m_RP.m_TI[nThreadID].m_PersFlags & RBPF_NO_SHADOWGEN) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int NumDynLights = m_RP.m_DLights[nThreadID][nCurRecLevel].Num();
|
|
|
|
TArray<SRenderLight>& arrDeferLights = CDeferredShading::Instance().GetLights(nThreadID, nCurRecLevel);
|
|
|
|
if (NumDynLights <= 0 && arrDeferLights.Num() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Find AABB of all nearest objects. Compute once for all lights as this can be slow
|
|
AABB aabbCasters(AABB::RESET);
|
|
m_RP.m_arrCustomShadowMapFrustumData[nThreadID].CoalesceMemory();
|
|
size_t shadowMapArraySize = m_RP.m_arrCustomShadowMapFrustumData[nThreadID].size();
|
|
for (size_t i = 0; i < shadowMapArraySize; ++i)
|
|
{
|
|
aabbCasters.Add(m_RP.m_arrCustomShadowMapFrustumData[nThreadID][i].aabb);
|
|
}
|
|
|
|
// AABBs are added in world space but without camera position applied
|
|
aabbCasters.min += GetCamera().GetPosition();
|
|
aabbCasters.max += GetCamera().GetPosition();
|
|
|
|
// add nearest frustum if it has been set up
|
|
for (int nLightID = 0; nLightID < NumDynLights; nLightID++)
|
|
{
|
|
SRenderLight* pLight = &m_RP.m_DLights[nThreadID][nCurRecLevel][nLightID];
|
|
|
|
if (!(pLight->m_Flags & DLF_CASTSHADOW_MAPS))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//shadows for nearest objects
|
|
if (CV_r_DrawNearShadows && pLight->m_Flags & DLF_DIRECTIONAL)
|
|
{
|
|
int nStartIdx = SRendItem::m_StartFrust[nThreadID][nLightID];
|
|
TArray<ShadowMapFrustum>& arrFrustums = m_RP.m_SMFrustums[nThreadID][nCurRecLevel];
|
|
if (!arrFrustums.empty() && nStartIdx >= 0 && nStartIdx < arrFrustums.size())
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//prepare custom frustums for sun
|
|
if (!m_RP.m_arrCustomShadowMapFrustumData[nThreadID].empty())
|
|
{
|
|
//copy sun frustum
|
|
ShadowMapFrustum* pCustomFrustum = arrFrustums.AddIndex(1);
|
|
ShadowMapFrustum* pSunFrustum = &arrFrustums[nStartIdx];
|
|
memcpy(pCustomFrustum, pSunFrustum, sizeof(ShadowMapFrustum));
|
|
|
|
const int nFrustumIndex = arrFrustums.Num() - 1;
|
|
m_RP.m_SMCustomFrustumIDs[nThreadID][nCurRecLevel].Add(nFrustumIndex);
|
|
|
|
pCustomFrustum->m_eFrustumType = ShadowMapFrustum::e_Nearest;
|
|
pCustomFrustum->bUseShadowsPool = false;
|
|
pCustomFrustum->bUseAdditiveBlending = true;
|
|
pCustomFrustum->fShadowFadingDist = 1.0f;
|
|
pCustomFrustum->fDepthConstBias = 0.0001f;
|
|
|
|
Matrix44A& mPrj = pCustomFrustum->mLightProjMatrix;
|
|
Matrix44A& mView = pCustomFrustum->mLightViewMatrix;
|
|
pCustomFrustum->aabbCasters = aabbCasters;
|
|
CShadowUtils::GetShadowMatrixForObject(mPrj, mView, pCustomFrustum);
|
|
pCustomFrustum->mLightViewMatrix = pCustomFrustum->mLightViewMatrix * pCustomFrustum->mLightProjMatrix;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
}
|
|
}
|
|
}
|
|
|
|
// prepare depth maps for all custom frustums
|
|
for (int32* pID = m_RP.m_SMCustomFrustumIDs[nThreadID][nCurRecLevel].begin(); pID != m_RP.m_SMCustomFrustumIDs[nThreadID][nCurRecLevel].end(); ++pID)
|
|
{
|
|
ShadowMapFrustum& curFrustum = m_RP.m_SMFrustums[nThreadID][nCurRecLevel][*pID];
|
|
PrepareDepthMap(&curFrustum, curFrustum.m_eFrustumType == ShadowMapFrustum::e_Nearest ? -1 : *pID, true);
|
|
}
|
|
}
|
|
|
|
void CD3D9Renderer::EF_PrepareAllDepthMaps()
|
|
{
|
|
int nThreadID = m_RP.m_nProcessThreadID;
|
|
int nCurRecLevel = SRendItem::m_RecurseLevel[nThreadID];
|
|
assert(nCurRecLevel >= 0);
|
|
|
|
int NumDynLights = m_RP.m_DLights[nThreadID][nCurRecLevel].Num();
|
|
|
|
TArray<SRenderLight>& arrDeferLights = CDeferredShading::Instance().GetLights(nThreadID, nCurRecLevel);
|
|
|
|
if (NumDynLights <= 0 && arrDeferLights.Num() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool haveShadows = false;
|
|
for (int nLightID = 0; nLightID < NumDynLights; nLightID++)
|
|
{
|
|
SRenderLight* pLight = &m_RP.m_DLights[nThreadID][SRendItem::m_RecurseLevel[nThreadID]][nLightID];
|
|
|
|
if (!(pLight->m_Flags & DLF_CASTSHADOW_MAPS))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
haveShadows |= FX_PrepareDepthMapsForLight(*pLight, nLightID);
|
|
}
|
|
|
|
if (!haveShadows && m_clearShadowMaskTexture)
|
|
{
|
|
FX_ClearShadowMaskTexture();
|
|
m_clearShadowMaskTexture = false;
|
|
}
|
|
else
|
|
{
|
|
m_clearShadowMaskTexture = true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if IsCVarConstAccess(constexpr) (!CV_r_UseShadowsPool)
|
|
{
|
|
for (uint32 nDeferLightID = 0; nDeferLightID < arrDeferLights.Num(); nDeferLightID++)
|
|
{
|
|
SRenderLight* pLight = &arrDeferLights[nDeferLightID];
|
|
if (!(pLight->m_Flags & DLF_CASTSHADOW_MAPS))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int nDeferLightIdx = nDeferLightID + NumDynLights;
|
|
assert((unsigned int) nDeferLightIdx < (MAX_REND_LIGHTS + MAX_DEFERRED_LIGHTS));
|
|
if ((unsigned int) nDeferLightIdx >= (MAX_REND_LIGHTS + MAX_DEFERRED_LIGHTS))
|
|
{
|
|
Warning("CD3D9Renderer::EF_PrepareAllDepthMaps: Too many light sources used ...");
|
|
return;
|
|
}
|
|
|
|
FX_PrepareDepthMapsForLight(*pLight, nDeferLightIdx);
|
|
}
|
|
}
|
|
|
|
// prepare custom depth maps
|
|
{
|
|
PROFILE_LABEL_SCOPE("CUSTOM MAPS");
|
|
const uint64 nPrevRTFlags = m_RP.m_FlagsShader_RT;
|
|
uint32 nPrefRendFlags = m_RP.m_nRendFlags;
|
|
m_RP.m_nRendFlags = 0;
|
|
|
|
EF_PrepareCustomShadowMaps();
|
|
|
|
m_RP.m_nRendFlags = nPrefRendFlags;
|
|
m_RP.m_FlagsShader_RT = nPrevRTFlags;
|
|
}
|
|
}
|
|
|
|
void CD3D9Renderer::FX_MergeShadowMaps(ShadowMapFrustum* pDst, const ShadowMapFrustum* pSrc)
|
|
{
|
|
if (!pDst || !pSrc)
|
|
{
|
|
return;
|
|
}
|
|
AZ_TRACE_METHOD();
|
|
|
|
CRY_ASSERT(pSrc->m_eFrustumType == ShadowMapFrustum::e_GsmCached);
|
|
CRY_ASSERT(pDst->m_eFrustumType == ShadowMapFrustum::e_GsmDynamicDistance);
|
|
CRY_ASSERT(pDst->nShadowMapLod == pSrc->nShadowMapLod);
|
|
|
|
const int nThreadID = m_RP.m_nProcessThreadID;
|
|
const int nShadowRecur = pDst->nShadowGenID[nThreadID][0];
|
|
const int nRendItemCount = nShadowRecur != 0xFFFFFFFF ? (SRendItem::m_ShadowsEndRI[nThreadID][nShadowRecur] - SRendItem::m_ShadowsStartRI[nThreadID][nShadowRecur]) : 0;
|
|
|
|
// get crop rectangle for projection
|
|
Matrix44r mReproj = Matrix44r(pDst->mLightViewMatrix).GetInverted() * Matrix44r(pSrc->mLightViewMatrix);
|
|
Vec4r srcClipPosTL = Vec4r(-1, -1, 0, 1) * mReproj;
|
|
srcClipPosTL /= srcClipPosTL.w;
|
|
|
|
const float fSnap = 2.0f / pSrc->pDepthTex->GetWidth();
|
|
Vec4 crop = Vec4(
|
|
crop.x = fSnap * int(srcClipPosTL.x / fSnap),
|
|
crop.y = fSnap * int(srcClipPosTL.y / fSnap),
|
|
crop.z = 2.0f * pDst->nTextureWidth / float(pSrc->nTextureWidth),
|
|
crop.w = 2.0f * pDst->nTextureHeight / float(pSrc->nTextureHeight)
|
|
);
|
|
|
|
Matrix44 cropMatrix(IDENTITY);
|
|
cropMatrix.m00 = 2.f / crop.z;
|
|
cropMatrix.m11 = 2.f / crop.w;
|
|
cropMatrix.m30 = -(1.0f + cropMatrix.m00 * crop.x);
|
|
cropMatrix.m31 = -(1.0f + cropMatrix.m11 * crop.y);
|
|
|
|
const bool bOutsideFrustum = abs(crop.x) > 1.0f || abs(crop.x + crop.z) > 1.0f || abs(crop.y) > 1.0f || abs(crop.y + crop.w) > 1.0f;
|
|
const bool bEmptyCachedFrustum = pSrc->nShadowGenMask == 0;
|
|
const bool bRequireCopy = bOutsideFrustum || bEmptyCachedFrustum || nRendItemCount > 0;
|
|
|
|
pDst->pDepthTex = NULL;
|
|
pDst->bIncrementalUpdate = true;
|
|
pDst->mLightViewMatrix = pSrc->mLightViewMatrix * cropMatrix;
|
|
|
|
// do we need to merge static shadows into the dynamic shadow map?
|
|
if (bRequireCopy)
|
|
{
|
|
ETEX_Format texFormat = CV_r_ShadowsCacheFormat == 0 ? eTF_D32F : eTF_D16;
|
|
|
|
SDynTexture_Shadow* pDynTex = SDynTexture_Shadow::GetForFrustum(pDst);
|
|
pDst->pDepthTex = pDynTex->m_pTexture;
|
|
|
|
SDepthTexture depthSurface;
|
|
|
|
depthSurface.nWidth = pDst->nTextureWidth;
|
|
depthSurface.nHeight = pDst->nTextureHeight;
|
|
depthSurface.nFrameAccess = -1;
|
|
depthSurface.bBusy = false;
|
|
depthSurface.pTex = pDst->pDepthTex;
|
|
depthSurface.pSurf = pDst->pDepthTex->GetDeviceDepthStencilSurf();
|
|
depthSurface.pTarget = pDst->pDepthTex->GetDevTexture()->Get2DTexture();
|
|
|
|
if (bEmptyCachedFrustum)
|
|
{
|
|
gcpRendD3D->FX_ClearTarget(&depthSurface, CLEAR_ZBUFFER | CLEAR_STENCIL, Clr_FarPlane.r, 0);
|
|
}
|
|
else
|
|
{
|
|
uint64 nSaveFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
|
|
|
|
int iTempX, iTempY, iWidth, iHeight;
|
|
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
|
|
|
|
gcpRendD3D->FX_PushRenderTarget(0, (CTexture*)NULL, &depthSurface);
|
|
gcpRendD3D->FX_SetActiveRenderTargets();
|
|
gcpRendD3D->RT_SetViewport(0, 0, pDst->pDepthTex->GetWidth(), pDst->pDepthTex->GetHeight());
|
|
|
|
FX_SetStencilDontCareActions(0, true, true);
|
|
|
|
static CCryNameTSCRC pTechCopyShadowMap("ReprojectShadowMap");
|
|
SPostEffectsUtils::ShBeginPass(CShaderMan::s_ShaderShadowMaskGen, pTechCopyShadowMap, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
|
|
|
|
gRenDev->FX_SetState(GS_DEPTHWRITE | GS_DEPTHFUNC_NOTEQUAL);
|
|
|
|
Matrix44 mReprojDstToSrc = pDst->mLightViewMatrix.GetInverted() * pSrc->mLightViewMatrix;
|
|
|
|
static CCryNameR paramReprojMatDstToSrc("g_mReprojDstToSrc");
|
|
CShaderMan::s_ShaderShadowMaskGen->FXSetPSFloat(paramReprojMatDstToSrc, (Vec4*) mReprojDstToSrc.GetData(), 4);
|
|
|
|
Matrix44 mReprojSrcToDst = pSrc->mLightViewMatrix.GetInverted() * pDst->mLightViewMatrix;
|
|
static CCryNameR paramReprojMatSrcToDst("g_mReprojSrcToDst");
|
|
CShaderMan::s_ShaderShadowMaskGen->FXSetPSFloat(paramReprojMatSrcToDst, (Vec4*) mReprojSrcToDst.GetData(), 4);
|
|
|
|
pSrc->pDepthTex->Apply(0, CTexture::GetTexState(STexState(FILTER_POINT, true)));
|
|
|
|
SPostEffectsUtils::DrawFullScreenTri(depthSurface.nWidth, depthSurface.nHeight);
|
|
SPostEffectsUtils::ShEndPass();
|
|
|
|
gcpRendD3D->FX_PopRenderTarget(0);
|
|
gcpRendD3D->RT_SetViewport(iTempX, iTempY, iWidth, iHeight);
|
|
|
|
gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;
|
|
}
|
|
|
|
pDst->packWidth[0] = pDst->nTextureWidth;
|
|
pDst->packHeight[0] = pDst->nTextureHeight;
|
|
|
|
pDst->packX[0] = pDst->packY[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
pDst->packX[0] = int((crop.x * 0.5f + 0.5f) * pSrc->pDepthTex->GetWidth() + 0.5f);
|
|
pDst->packY[0] = int((-(crop.y + crop.w) * 0.5f + 0.5f) * pSrc->pDepthTex->GetHeight() + 0.5f);
|
|
pDst->packWidth[0] = pDst->nTextureWidth;
|
|
pDst->packHeight[0] = pDst->nTextureHeight;
|
|
|
|
pDst->pDepthTex = pSrc->pDepthTex;
|
|
pDst->nTexSize = pSrc->nTexSize;
|
|
pDst->nTextureWidth = pSrc->nTextureWidth;
|
|
pDst->nTextureHeight = pSrc->nTextureHeight;
|
|
}
|
|
|
|
pDst->fNearDist = pSrc->fNearDist;
|
|
pDst->fFarDist = pSrc->fFarDist;
|
|
pDst->fDepthConstBias = pSrc->fDepthConstBias;
|
|
pDst->fDepthTestBias = pSrc->fDepthTestBias;
|
|
pDst->fDepthSlopeBias = pSrc->fDepthSlopeBias;
|
|
}
|
|
|
|
void CD3D9Renderer::FX_ClearShadowMaskTexture()
|
|
{
|
|
const int arraySize = CTexture::s_ptexShadowMask->StreamGetNumSlices();
|
|
SResourceView curSliceRVDesc = SResourceView::RenderTargetView(CTexture::s_ptexShadowMask->GetTextureDstFormat(), 0, 1);
|
|
for (int i = 0; i < arraySize; ++i)
|
|
{
|
|
curSliceRVDesc.m_Desc.nFirstSlice = i;
|
|
SResourceView& firstSliceRV = CTexture::s_ptexShadowMask->GetResourceView(curSliceRVDesc);
|
|
|
|
#if defined(CRY_USE_METAL)
|
|
static ICVar* pVar = iConsole->GetCVar("e_ShadowsClearShowMaskAtLoad");
|
|
if (pVar && pVar->GetIVal())
|
|
{
|
|
FX_ClearTarget(static_cast<D3DSurface*>(firstSliceRV.m_pDeviceResourceView), Clr_Transparent, 0, nullptr);
|
|
|
|
// On metal we have to submit a draw call in order for a clear to take affect.
|
|
// Doing the commit/clear target region will produce the needed draw call for the clear.
|
|
FX_PushRenderTarget(0, static_cast<D3DSurface*>(firstSliceRV.m_pDeviceResourceView), nullptr);
|
|
|
|
RT_SetViewport(0, 0, CTexture::s_ptexShadowMask->GetWidth(), CTexture::s_ptexShadowMask->GetHeight());
|
|
FX_Commit();
|
|
FX_ClearTargetRegion();
|
|
FX_PopRenderTarget(0);
|
|
}
|
|
#else
|
|
FX_ClearTarget(static_cast<D3DSurface*>(firstSliceRV.m_pDeviceResourceView), Clr_Transparent, 0, nullptr);
|
|
#endif
|
|
}
|
|
}
|
|
|