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.
603 lines
19 KiB
C++
603 lines
19 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.
|
|
#if !defined(SHADOWRENDERER_H)
|
|
#define SHADOWRENDERER_H
|
|
|
|
|
|
#include "ShadowUtils.h"
|
|
#include <IRenderAuxGeom.h>
|
|
#include <VectorSet.h>
|
|
#include <AzCore/Jobs/LegacyJobExecutor.h>
|
|
|
|
#define OMNI_SIDES_NUM 6
|
|
|
|
// data used to compute a custom shadow frustum for near shadows
|
|
struct CustomShadowMapFrustumData
|
|
{
|
|
AABB aabb;
|
|
};
|
|
|
|
struct ShadowMapFrustum
|
|
{
|
|
enum eFrustumType // NOTE: Be careful when modifying the enum as it is used for sorting frustums in SCompareByLightIds
|
|
{
|
|
e_GsmDynamic = 0,
|
|
e_GsmDynamicDistance = 1,
|
|
e_GsmCached = 2,
|
|
e_HeightMapAO = 3,
|
|
e_Nearest = 4,
|
|
e_PerObject = 5,
|
|
|
|
e_NumTypes
|
|
};
|
|
|
|
eFrustumType m_eFrustumType;
|
|
|
|
Matrix44A mLightProjMatrix;
|
|
Matrix44A mLightViewMatrix;
|
|
|
|
// flags
|
|
bool bUseAdditiveBlending;
|
|
bool bIncrementalUpdate;
|
|
|
|
// if set to true - m_castersList contains all casters in light radius
|
|
// and all other members related only to single frustum projection case are undefined
|
|
bool bOmniDirectionalShadow;
|
|
uint8 nOmniFrustumMask;
|
|
uint8 nInvalidatedFrustMask[MAX_GPU_NUM]; //for each GPU
|
|
bool bBlendFrustum;
|
|
float fBlendVal;
|
|
|
|
uint32 nShadowGenMask;
|
|
bool bIsMGPUCopy;
|
|
|
|
bool bHWPCFCompare;
|
|
|
|
uint8 nShadowPoolUpdateRate;
|
|
|
|
//sampling parameters
|
|
f32 fWidthS, fWidthT;
|
|
f32 fBlurS, fBlurT;
|
|
|
|
//fading distance per light source
|
|
float fShadowFadingDist;
|
|
|
|
ETEX_Format m_eReqTF;
|
|
ETEX_Type m_eReqTT;
|
|
|
|
//texture in pool
|
|
bool bUseShadowsPool;
|
|
struct ShadowMapFrustum* pPrevFrustum = nullptr;
|
|
struct ShadowMapFrustum* pFrustumOwner = nullptr;
|
|
class CTexture* pDepthTex;
|
|
|
|
//3d engine parameters
|
|
float fFOV;
|
|
float fNearDist;
|
|
float fFarDist;
|
|
int nTexSize;
|
|
|
|
//shadow renderer parameters - should be in separate structure
|
|
//atlas parameters
|
|
int nTextureWidth;
|
|
int nTextureHeight;
|
|
bool bUnwrapedOmniDirectional;
|
|
int nShadowMapSize;
|
|
|
|
//packer params
|
|
uint nPackID[OMNI_SIDES_NUM];
|
|
int packX[OMNI_SIDES_NUM];
|
|
int packY[OMNI_SIDES_NUM];
|
|
int packWidth[OMNI_SIDES_NUM];
|
|
int packHeight[OMNI_SIDES_NUM];
|
|
|
|
int nResetID;
|
|
float fFrustrumSize;
|
|
float fProjRatio;
|
|
float fDepthTestBias;
|
|
float fDepthConstBias;
|
|
float fDepthSlopeBias;
|
|
PodArray<struct IShadowCaster*> m_castersList;
|
|
PodArray<struct IShadowCaster*> m_jobExecutedCastersList;
|
|
|
|
CCamera FrustumPlanes[OMNI_SIDES_NUM];
|
|
uint32 nShadowGenID[RT_COMMAND_BUF_COUNT][OMNI_SIDES_NUM];
|
|
AABB aabbCasters; //casters bbox in world space
|
|
Vec3 vLightSrcRelPos; // relative world space
|
|
Vec3 vProjTranslation; // dst position
|
|
float fRadius;
|
|
int nUpdateFrameId;
|
|
IRenderNode* pLightOwner = nullptr;
|
|
uint32 uCastersListCheckSum;
|
|
int nShadowMapLod; // currently use as GSMLod, can be used as cubemap side, -1 means this variable is not used
|
|
|
|
uint32 m_Flags;
|
|
|
|
struct ShadowCacheData
|
|
{
|
|
enum eUpdateStrategy
|
|
{
|
|
// Renders the entire cached shadowmap in one pass.
|
|
// Generally used for a single frame when an event (script, level load, proximity to frustum border, etc.) requests an update of the cache.
|
|
// Will revert to one of the other methods after the update occurs.
|
|
eFullUpdate,
|
|
|
|
// Cached shadow frustums will constantly check if updates are required due to moving objects or proximity to the frustum border.
|
|
// Has potentially very high CPU overhead because each cached shadow map frustum culls the octree each frame.
|
|
// Potentially higher GPU overhead because may render extra dynamic or distant objects each frame.
|
|
eIncrementalUpdate,
|
|
|
|
// Updates must triggered manually via script. Most optimal solution, but requires manual setup.
|
|
eManualUpdate,
|
|
|
|
// Updates may either be triggered manually by script or when the camera moves too close to the border of the shadow frustum
|
|
eManualOrDistanceUpdate
|
|
};
|
|
|
|
ShadowCacheData() { Reset(); }
|
|
|
|
void Reset()
|
|
{
|
|
memset(mOctreePath, 0x0, sizeof(mOctreePath));
|
|
memset(mOctreePathNodeProcessed, 0x0, sizeof(mOctreePathNodeProcessed));
|
|
mProcessedCasters.clear();
|
|
mProcessedTerrainCasters.clear();
|
|
}
|
|
|
|
static const int MAX_TRAVERSAL_PATH_LENGTH = 32;
|
|
uint8 mOctreePath[MAX_TRAVERSAL_PATH_LENGTH];
|
|
uint8 mOctreePathNodeProcessed[MAX_TRAVERSAL_PATH_LENGTH];
|
|
|
|
VectorSet<struct IShadowCaster*> mProcessedCasters;
|
|
VectorSet<uint64> mProcessedTerrainCasters;
|
|
}* pShadowCacheData = nullptr;
|
|
|
|
|
|
ShadowMapFrustum()
|
|
{
|
|
ZeroStruct(*this);
|
|
fProjRatio = 1.f;
|
|
|
|
//initial frustum position should be outside of the visible map
|
|
vProjTranslation = Vec3(-1000.0f, -1000.0f, -1000.0f);
|
|
|
|
bUnwrapedOmniDirectional = false;
|
|
nShadowMapSize = 0;
|
|
|
|
nUpdateFrameId = -1000;
|
|
|
|
pPrevFrustum = nullptr;
|
|
aabbCasters.Reset();
|
|
}
|
|
|
|
ShadowMapFrustum(const ShadowMapFrustum& rOther)
|
|
{
|
|
(*this) = rOther;
|
|
}
|
|
|
|
~ShadowMapFrustum()
|
|
{
|
|
// make sure that the renderer isn't using this shadow frustum anymore
|
|
threadID nThreadID = 0;
|
|
gEnv->pRenderer->EF_Query(EFQ_RenderThreadList, nThreadID);
|
|
gEnv->pRenderer->GetFinalizeShadowRendItemJobExecutor(nThreadID)->WaitForCompletion();
|
|
|
|
SAFE_DELETE(pShadowCacheData);
|
|
}
|
|
|
|
ShadowMapFrustum& operator=(const ShadowMapFrustum& rOther)
|
|
{
|
|
m_eFrustumType = rOther.m_eFrustumType;
|
|
mLightProjMatrix = rOther.mLightProjMatrix;
|
|
mLightViewMatrix = rOther.mLightViewMatrix;
|
|
|
|
bUseAdditiveBlending = rOther.bUseAdditiveBlending;
|
|
bOmniDirectionalShadow = rOther.bOmniDirectionalShadow;
|
|
bBlendFrustum = rOther.bBlendFrustum;
|
|
fBlendVal = rOther.fBlendVal;
|
|
bIncrementalUpdate = rOther.bIncrementalUpdate;
|
|
nOmniFrustumMask = rOther.nOmniFrustumMask;
|
|
memcpy(nInvalidatedFrustMask, rOther.nInvalidatedFrustMask, sizeof(nInvalidatedFrustMask));
|
|
nShadowGenMask = rOther.nShadowGenMask;
|
|
|
|
bHWPCFCompare = rOther.bHWPCFCompare;
|
|
|
|
nShadowPoolUpdateRate = rOther.nShadowPoolUpdateRate;
|
|
|
|
fWidthS = rOther.fWidthS;
|
|
fWidthT = rOther.fWidthT;
|
|
fBlurS = rOther.fBlurS;
|
|
fBlurT = rOther.fBlurT;
|
|
|
|
fShadowFadingDist = rOther.fShadowFadingDist;
|
|
|
|
m_eReqTF = rOther.m_eReqTF;
|
|
m_eReqTT = rOther.m_eReqTT;
|
|
|
|
bUseShadowsPool = rOther.bUseShadowsPool;
|
|
|
|
// those pointer are not owned by the shadowfrustum, so we don't need a deep copy
|
|
pFrustumOwner = rOther.pFrustumOwner;
|
|
pDepthTex = rOther.pDepthTex;
|
|
pLightOwner = rOther.pLightOwner;
|
|
|
|
fFOV = rOther.fFOV;
|
|
fNearDist = rOther.fNearDist;
|
|
fFarDist = rOther.fFarDist;
|
|
nTexSize = rOther.nTexSize;
|
|
|
|
nTextureWidth = rOther.nTextureWidth;
|
|
nTextureHeight = rOther.nTextureHeight;
|
|
bUnwrapedOmniDirectional = rOther.bUnwrapedOmniDirectional;
|
|
nShadowMapSize = rOther.nShadowMapSize;
|
|
|
|
memcpy(nPackID, rOther.nPackID, sizeof(nPackID));
|
|
memcpy(packX, rOther.packX, sizeof(packX));
|
|
memcpy(packY, rOther.packY, sizeof(packY));
|
|
memcpy(packWidth, rOther.packWidth, sizeof(packWidth));
|
|
memcpy(packHeight, rOther.packHeight, sizeof(packHeight));
|
|
|
|
nResetID = rOther.nResetID;
|
|
fFrustrumSize = rOther.fFrustrumSize;
|
|
fProjRatio = rOther.fProjRatio;
|
|
fDepthTestBias = rOther.fDepthTestBias;
|
|
fDepthConstBias = rOther.fDepthConstBias;
|
|
fDepthSlopeBias = rOther.fDepthSlopeBias;
|
|
|
|
m_castersList = rOther.m_castersList;
|
|
m_jobExecutedCastersList = rOther.m_jobExecutedCastersList;
|
|
|
|
memcpy(FrustumPlanes, rOther.FrustumPlanes, sizeof(FrustumPlanes));
|
|
memcpy(nShadowGenID, rOther.nShadowGenID, sizeof(nShadowGenID));
|
|
|
|
aabbCasters = rOther.aabbCasters;
|
|
vLightSrcRelPos = rOther.vLightSrcRelPos;
|
|
vProjTranslation = rOther.vProjTranslation;
|
|
fRadius = rOther.fRadius;
|
|
nUpdateFrameId = rOther.nUpdateFrameId;
|
|
|
|
uCastersListCheckSum = rOther.uCastersListCheckSum;
|
|
nShadowMapLod = rOther.nShadowMapLod;
|
|
m_Flags = rOther.m_Flags;
|
|
|
|
bIsMGPUCopy = rOther.bIsMGPUCopy;
|
|
if (rOther.pShadowCacheData != nullptr)
|
|
{
|
|
if (pShadowCacheData == nullptr)
|
|
{
|
|
pShadowCacheData = new ShadowCacheData();
|
|
}
|
|
*pShadowCacheData = *rOther.pShadowCacheData;
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pShadowCacheData);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void GetSideViewport(int nSide, int* pViewport)
|
|
{
|
|
if (bUseShadowsPool)
|
|
{
|
|
pViewport[0] = packX[nSide];
|
|
pViewport[1] = packY[nSide];
|
|
pViewport[2] = packWidth[nSide];
|
|
pViewport[3] = packHeight[nSide];
|
|
}
|
|
else
|
|
{
|
|
//simplest cubemap 6 faces unwrap
|
|
pViewport[0] = nShadowMapSize * (nSide % 3);
|
|
pViewport[1] = nShadowMapSize * (nSide / 3);
|
|
pViewport[2] = nShadowMapSize;
|
|
pViewport[3] = nShadowMapSize;
|
|
}
|
|
}
|
|
|
|
void GetTexOffset(int nSide, float* pOffset, float* pScale, int nShadowsPoolSizeX, int nShadowsPoolSizeY)
|
|
{
|
|
if (bUseShadowsPool)
|
|
{
|
|
pScale[0] = float(nShadowMapSize) / nShadowsPoolSizeX; //SHADOWS_POOL_SZ 1024
|
|
pScale[1] = float(nShadowMapSize) / nShadowsPoolSizeY;
|
|
pOffset[0] = float(packX[nSide]) / nShadowsPoolSizeX;
|
|
pOffset[1] = float(packY[nSide]) / nShadowsPoolSizeY;
|
|
}
|
|
else
|
|
{
|
|
pOffset[0] = 1.0f / 3.0f * (nSide % 3);
|
|
pOffset[1] = 1.0f / 2.0f * (nSide / 3);
|
|
pScale[0] = 1.0f / 3.0f;
|
|
pScale[1] = 1.0f / 2.0f;
|
|
}
|
|
}
|
|
|
|
void RequestUpdate()
|
|
{
|
|
for (int i = 0; i < MAX_GPU_NUM; i++)
|
|
{
|
|
nInvalidatedFrustMask[i] = 0x3F;
|
|
}
|
|
}
|
|
|
|
bool isUpdateRequested(int nMaskNum)
|
|
{
|
|
assert(nMaskNum >= 0 && nMaskNum < MAX_GPU_NUM);
|
|
/*if (nMaskNum==-1) //request from 3dengine
|
|
{
|
|
for (int i=0; i<MAX_GPU_NUM; i++)
|
|
{
|
|
if(nInvalidatedFrustMask[i]>0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}*/
|
|
|
|
return (nInvalidatedFrustMask[nMaskNum] > 0);
|
|
}
|
|
|
|
bool IsCached() const
|
|
{
|
|
return m_eFrustumType == e_GsmCached || m_eFrustumType == e_HeightMapAO;
|
|
}
|
|
|
|
ILINE bool IntersectAABB(const AABB& bbox, bool* pAllIn) const
|
|
{
|
|
if (bOmniDirectionalShadow)
|
|
{
|
|
return bbox.IsOverlapSphereBounds(vLightSrcRelPos + vProjTranslation, fFarDist);
|
|
}
|
|
else
|
|
{
|
|
bool bDummy = false;
|
|
if (bBlendFrustum)
|
|
{
|
|
if (FrustumPlanes[1].IsAABBVisible_EH(bbox, pAllIn) > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return FrustumPlanes[0].IsAABBVisible_EH(bbox, bBlendFrustum ? &bDummy : pAllIn) > 0;
|
|
}
|
|
}
|
|
|
|
ILINE bool IntersectSphere(const Sphere& sp, bool* pAllIn)
|
|
{
|
|
if (bOmniDirectionalShadow)
|
|
{
|
|
return Distance::Point_PointSq(sp.center, vLightSrcRelPos + vProjTranslation) < sqr(fFarDist + sp.radius);
|
|
}
|
|
else
|
|
{
|
|
uint8 res = 0;
|
|
if (bBlendFrustum)
|
|
{
|
|
res = FrustumPlanes[1].IsSphereVisible_FH(sp);
|
|
* pAllIn = (res == CULL_INCLUSION);
|
|
if (res != CULL_EXCLUSION)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
res = FrustumPlanes[0].IsSphereVisible_FH(sp);
|
|
* pAllIn = bBlendFrustum ? false : (res == CULL_INCLUSION);
|
|
return res != CULL_EXCLUSION;
|
|
}
|
|
}
|
|
|
|
void UnProject(float sx, float sy, float sz, float* px, float* py, float* pz, IRenderer* pRend)
|
|
{
|
|
const int shadowViewport[4] = {0, 0, 1, 1};
|
|
|
|
Matrix44A mIden;
|
|
mIden.SetIdentity();
|
|
|
|
//FIX remove float arrays
|
|
pRend->UnProject(sx, sy, sz,
|
|
px, py, pz,
|
|
(float*)&mLightViewMatrix,
|
|
(float*)&mIden,
|
|
shadowViewport);
|
|
}
|
|
|
|
Vec3& UnProjectVertex3d(int sx, int sy, int sz, Vec3& vert, IRenderer* pRend)
|
|
{
|
|
float px;
|
|
float py;
|
|
float pz;
|
|
UnProject((float)sx, (float)sy, (float)sz, &px, &py, &pz, pRend);
|
|
vert.x = (float)px;
|
|
vert.y = (float)py;
|
|
vert.z = (float)pz;
|
|
|
|
// pRend->DrawBall(vert,10);
|
|
|
|
return vert;
|
|
}
|
|
|
|
void UpdateOmniFrustums()
|
|
{
|
|
const float sCubeVector[6][7] =
|
|
{
|
|
{1, 0, 0, 0, 0, 1, -90}, //posx
|
|
{-1, 0, 0, 0, 0, 1, 90}, //negx
|
|
{0, 1, 0, 0, 0, -1, 0}, //posy
|
|
{0, -1, 0, 0, 0, 1, 0}, //negy
|
|
{0, 0, 1, 0, 1, 0, 0}, //posz
|
|
{0, 0, -1, 0, 1, 0, 0}, //negz
|
|
};
|
|
|
|
const Vec3 vPos = vLightSrcRelPos + vProjTranslation;
|
|
for (int nS = 0; nS < OMNI_SIDES_NUM; ++nS)
|
|
{
|
|
const Vec3 vForward = Vec3(sCubeVector[nS][0], sCubeVector[nS][1], sCubeVector[nS][2]);
|
|
const Vec3 vUp = Vec3(sCubeVector[nS][3], sCubeVector[nS][4], sCubeVector[nS][5]);
|
|
const Matrix33 matRot = Matrix33::CreateOrientation(vForward, vUp, DEG2RAD(sCubeVector[nS][6]));
|
|
const float fov = bUnwrapedOmniDirectional ? (float)DEG2RAD_R(g_fOmniShadowFov) : (float)DEG2RAD_R(90.0f);
|
|
|
|
FrustumPlanes[nS].SetMatrix(Matrix34(matRot, vPos));
|
|
FrustumPlanes[nS].SetFrustum(nTexSize, nTexSize, fov, fNearDist, fFarDist);
|
|
}
|
|
}
|
|
|
|
void DrawFrustum(IRenderer* pRend, int nFrames = 1)
|
|
{
|
|
if (abs(nUpdateFrameId - pRend->GetFrameID()) > nFrames)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//if(!arrLightViewMatrix[0] && !arrLightViewMatrix[5] && !arrLightViewMatrix[10])
|
|
//return;
|
|
|
|
IRenderAuxGeom* pRendAux = pRend->GetIRenderAuxGeom();
|
|
const ColorF cCascadeColors[] = { Col_Red, Col_Green, Col_Blue, Col_Yellow, Col_Magenta, Col_Cyan, Col_Black, Col_White };
|
|
const uint nColorCount = sizeof(cCascadeColors) / sizeof(cCascadeColors[0]);
|
|
|
|
Vec3 vert1, vert2;
|
|
ColorB c0 = cCascadeColors[nShadowMapLod % nColorCount];
|
|
{
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(0, 0, 0, vert1, pRend), c0,
|
|
UnProjectVertex3d(0, 0, 1, vert2, pRend), c0);
|
|
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(1, 0, 0, vert1, pRend), c0,
|
|
UnProjectVertex3d(1, 0, 1, vert2, pRend), c0);
|
|
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(1, 1, 0, vert1, pRend), c0,
|
|
UnProjectVertex3d(1, 1, 1, vert2, pRend), c0);
|
|
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(0, 1, 0, vert1, pRend), c0,
|
|
UnProjectVertex3d(0, 1, 1, vert2, pRend), c0);
|
|
}
|
|
|
|
for (int i = 0; i <= 1; i++)
|
|
{
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(0, 0, i, vert1, pRend), c0,
|
|
UnProjectVertex3d(1, 0, i, vert2, pRend), c0);
|
|
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(1, 0, i, vert1, pRend), c0,
|
|
UnProjectVertex3d(1, 1, i, vert2, pRend), c0);
|
|
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(1, 1, i, vert1, pRend), c0,
|
|
UnProjectVertex3d(0, 1, i, vert2, pRend), c0);
|
|
|
|
pRendAux->DrawLine(
|
|
UnProjectVertex3d(0, 1, i, vert1, pRend), c0,
|
|
UnProjectVertex3d(0, 0, i, vert2, pRend), c0);
|
|
}
|
|
}
|
|
|
|
void ResetCasterLists()
|
|
{
|
|
m_castersList.Clear();
|
|
m_jobExecutedCastersList.Clear();
|
|
}
|
|
|
|
void GetMemoryUsage(ICrySizer* pSizer) const;
|
|
};
|
|
|
|
struct ShadowFrustumMGPUCache
|
|
: public ISyncMainWithRenderListener
|
|
{
|
|
StaticArray<ShadowMapFrustum*, MAX_GSM_LODS_NUM> m_pStaticShadowMapFrustums;
|
|
ShadowMapFrustum* m_pHeightMapAOFrustum;
|
|
|
|
uint32 nUpdateMaskMT;
|
|
uint32 nUpdateMaskRT;
|
|
|
|
ShadowFrustumMGPUCache()
|
|
: nUpdateMaskMT(0)
|
|
, nUpdateMaskRT(0)
|
|
{
|
|
m_pHeightMapAOFrustum = NULL;
|
|
m_pStaticShadowMapFrustums.fill(NULL);
|
|
};
|
|
|
|
void Init()
|
|
{
|
|
m_pHeightMapAOFrustum = new ShadowMapFrustum;
|
|
m_pHeightMapAOFrustum->pShadowCacheData = new ShadowMapFrustum::ShadowCacheData;
|
|
|
|
for (int i = 0; i < m_pStaticShadowMapFrustums.size(); ++i)
|
|
{
|
|
m_pStaticShadowMapFrustums[i] = new ShadowMapFrustum;
|
|
m_pStaticShadowMapFrustums[i]->pShadowCacheData = new ShadowMapFrustum::ShadowCacheData;
|
|
}
|
|
|
|
nUpdateMaskMT = nUpdateMaskRT = 0;
|
|
}
|
|
|
|
void Release()
|
|
{
|
|
SAFE_DELETE(m_pHeightMapAOFrustum);
|
|
for (int i = 0; i < m_pStaticShadowMapFrustums.size(); ++i)
|
|
{
|
|
SAFE_DELETE(m_pStaticShadowMapFrustums[i]);
|
|
}
|
|
}
|
|
|
|
void DeleteFromCache(IShadowCaster* pCaster)
|
|
{
|
|
for (int i = 0; i < m_pStaticShadowMapFrustums.size(); ++i)
|
|
{
|
|
ShadowMapFrustum* pFr = m_pStaticShadowMapFrustums[i];
|
|
if (pFr)
|
|
{
|
|
pFr->m_castersList.Delete(pCaster);
|
|
pFr->m_jobExecutedCastersList.Delete(pCaster);
|
|
}
|
|
}
|
|
|
|
if (m_pHeightMapAOFrustum)
|
|
{
|
|
m_pHeightMapAOFrustum->m_castersList.Delete(pCaster);
|
|
m_pHeightMapAOFrustum->m_jobExecutedCastersList.Delete(pCaster);
|
|
}
|
|
}
|
|
|
|
virtual void SyncMainWithRender()
|
|
{
|
|
/** What we need here is the renderer telling the main thread to update the shadow frustum cache when all GPUs are done
|
|
* with the current frustum.
|
|
*
|
|
* So in case the main thread has done a full update (nUpdateMaskMT has bits for all GPUs set) we need to copy
|
|
* the update mask to the renderer. Note that we reset the main thread update mask in the same spot to avoid doing it in
|
|
* the next frame again.
|
|
*
|
|
* Otherwise just copy the renderer's progress back to the main thread. The main thread will automatically do a full update
|
|
* when nUpdateMaskMT reaches 0 */
|
|
const int nFullUpdateMask = (1 << gEnv->pRenderer->GetActiveGPUCount()) - 1;
|
|
if (nUpdateMaskMT == nFullUpdateMask)
|
|
{
|
|
nUpdateMaskRT = nUpdateMaskMT;
|
|
nUpdateMaskMT = 0xFFFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
nUpdateMaskMT = nUpdateMaskRT;
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif
|