123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733 |
- /*
- * 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 : Light sources manager
- #include "Cry3DEngine_precompiled.h"
- #include "3dEngine.h"
- #include "ObjMan.h"
- #include "VisAreas.h"
- #include "AABBSV.h"
- #include "LightEntity.h"
- #include "ObjectsTree.h"
- #include "ClipVolumeManager.h"
- ILightSource* C3DEngine::CreateLightSource()
- {
- // construct new object
- CLightEntity* pLightEntity = new CLightEntity();
- m_lstStaticLights.Add(pLightEntity);
- return pLightEntity;
- }
- void C3DEngine::DeleteLightSource(ILightSource* pLightSource)
- {
- if (m_lstStaticLights.Delete((CLightEntity*)pLightSource) || pLightSource == m_pSun)
- {
- if (pLightSource == m_pSun)
- {
- m_pSun = NULL;
- }
- delete pLightSource;
- }
- else
- {
- assert(!"Light object not found");
- }
- }
- void CLightEntity::Release(bool)
- {
- Get3DEngine()->UnRegisterEntityDirect(this);
- Get3DEngine()->DeleteLightSource(this);
- }
- void CLightEntity::SetLightProperties(const CDLight& light)
- {
- C3DEngine* engine = Get3DEngine();
- m_light = light;
- m_bShadowCaster = (m_light.m_Flags & DLF_CASTSHADOW_MAPS) != 0;
- m_light.m_fBaseRadius = m_light.m_fRadius;
- m_light.m_fLightFrustumAngle = CLAMP(m_light.m_fLightFrustumAngle, 0.f, (LIGHT_PROJECTOR_MAX_FOV / 2.f));
- if (!(m_light.m_Flags & (DLF_PROJECT | DLF_AREA_LIGHT)))
- {
- m_light.m_fLightFrustumAngle = 90.f / 2.f;
- }
- m_light.m_pOwner = this;
- if (m_light.m_Flags & DLF_ATTACH_TO_SUN)
- {
- m_dwRndFlags |= ERF_RENDER_ALWAYS | ERF_HUD;
- }
- engine->GetLightEntities()->Delete((ILightSource*)this);
- PodArray<ILightSource*>& lightEntities = *engine->GetLightEntities();
- //on consoles we force all lights (except sun) to be deferred
- if (GetCVars()->e_DynamicLightsForceDeferred && !(m_light.m_Flags & (DLF_SUN | DLF_POST_3D_RENDERER)))
- {
- m_light.m_Flags |= DLF_DEFERRED_LIGHT;
- }
- if (light.m_Flags & DLF_DEFERRED_LIGHT)
- {
- lightEntities.Add((ILightSource*)this);
- }
- else
- {
- lightEntities.InsertBefore((ILightSource*)this, 0);
- }
- }
- void C3DEngine::ResetCasterCombinationsCache()
- {
- for (int nSunInUse = 0; nSunInUse < 2; nSunInUse++)
- {
- // clear user counters
- for (ShadowFrustumListsCacheUsers::iterator it = m_FrustumsCacheUsers[nSunInUse].begin(); it != m_FrustumsCacheUsers[nSunInUse].end(); ++it)
- {
- it->second = 0;
- }
- }
- }
- void C3DEngine::DeleteAllStaticLightSources()
- {
- for (int i = 0; i < m_lstStaticLights.Count(); i++)
- {
- delete m_lstStaticLights[i];
- }
- m_lstStaticLights.Reset();
- m_pSun = NULL;
- }
- void C3DEngine::InitShadowFrustums(const SRenderingPassInfo& passInfo)
- {
- assert(passInfo.IsGeneralPass());
- FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
- AZ_TRACE_METHOD();
- if (m_pSun)
- {
- CDLight* pLight = &m_pSun->GetLightProperties();
- CLightEntity* pLightEntity = (CLightEntity*)pLight->m_pOwner;
- if (passInfo.RenderShadows() && (pLight->m_Flags & DLF_CASTSHADOW_MAPS) && pLight->m_Id >= 0)
- {
- pLightEntity->UpdateGSMLightSourceShadowFrustum(passInfo);
- if (pLightEntity->m_pShadowMapInfo)
- {
- pLight->m_pShadowMapFrustums = pLightEntity->m_pShadowMapInfo->pGSM;
- }
- }
- _smart_ptr<IMaterial> pMat = pLightEntity->GetMaterial();
- if (pMat)
- {
- pLight->m_Shader = pMat->GetShaderItem();
- }
- // update copy of light ion the renderer
- if (pLight->m_Id >= 0)
- {
- CDLight* pRndLight = NULL;
- GetRenderer()->EF_Query(EFQ_LightSource, pLight->m_Id, pRndLight);
- assert(pLight->m_Id == pRndLight->m_Id);
- pRndLight->m_pShadowMapFrustums = pLight->m_pShadowMapFrustums;
- pRndLight->m_Shader = pLight->m_Shader;
- pRndLight->m_Flags = pLight->m_Flags;
- }
- // add per object shadow frustums
- m_nCustomShadowFrustumCount = 0;
- if (passInfo.RenderShadows() && GetCVars()->e_ShadowsPerObject > 0)
- {
- const uint nFrustumCount = m_lstPerObjectShadows.size();
- if (nFrustumCount > m_lstCustomShadowFrustums.size())
- {
- m_lstCustomShadowFrustums.resize(nFrustumCount);
- }
- for (uint i = 0; i < nFrustumCount; ++i)
- {
- if (m_lstPerObjectShadows[i].pCaster)
- {
- ShadowMapFrustum* pFr = &m_lstCustomShadowFrustums[i];
- pFr->m_eFrustumType = ShadowMapFrustum::e_PerObject;
- CLightEntity::ProcessPerObjectFrustum(pFr, &m_lstPerObjectShadows[i], m_pSun, passInfo);
- ++m_nCustomShadowFrustumCount;
- }
- }
- }
- }
- if (passInfo.RenderShadows())
- {
- ResetCasterCombinationsCache();
- }
- }
- void C3DEngine::AddPerObjectShadow(IShadowCaster* pCaster, float fConstBias, float fSlopeBias, float fJitter, const Vec3& vBBoxScale, uint nTexSize)
- {
- SPerObjectShadow* pOS = GetPerObjectShadow(pCaster);
- if (!pOS)
- {
- pOS = &m_lstPerObjectShadows.AddNew();
- }
- pOS->pCaster = pCaster;
- pOS->fConstBias = fConstBias;
- pOS->fSlopeBias = fSlopeBias;
- pOS->fJitter = fJitter;
- pOS->vBBoxScale = vBBoxScale;
- pOS->nTexSize = nTexSize;
- }
- void C3DEngine::RemovePerObjectShadow(IShadowCaster* pCaster)
- {
- SPerObjectShadow* pOS = GetPerObjectShadow(pCaster);
- if (pOS)
- {
- FRAME_PROFILER("C3DEngine::RemovePerObjectShadow", GetSystem(), PROFILE_3DENGINE);
- size_t nIndex = (size_t)(pOS - m_lstPerObjectShadows.begin());
- m_lstPerObjectShadows.Delete(nIndex);
- }
- }
- struct SPerObjectShadow* C3DEngine::GetPerObjectShadow(IShadowCaster* pCaster)
- {
- for (int i = 0; i < m_lstPerObjectShadows.Count(); ++i)
- {
- if (m_lstPerObjectShadows[i].pCaster == pCaster)
- {
- return &m_lstPerObjectShadows[i];
- }
- }
- return NULL;
- }
- void C3DEngine::GetCustomShadowMapFrustums(ShadowMapFrustum*& arrFrustums, int& nFrustumCount)
- {
- arrFrustums = m_lstCustomShadowFrustums.begin();
- nFrustumCount = m_nCustomShadowFrustumCount;
- }
- // delete pLight->m_pProjCamera;
- //pLight->m_pProjCamera=0;
- //if(pLight->m_pShader)
- // SAFE_RELEASE(pLight->m_pShader);
- namespace
- {
- static inline bool CmpCastShadowFlag(const CDLight* p1, const CDLight* p2)
- {
- // move sun first
- if ((p1->m_Flags & DLF_SUN) > (p2->m_Flags & DLF_SUN))
- {
- return true;
- }
- else if ((p1->m_Flags & DLF_SUN) < (p2->m_Flags & DLF_SUN))
- {
- return false;
- }
- // move shadow casters first
- if ((p1->m_Flags & DLF_CASTSHADOW_MAPS) > (p2->m_Flags & DLF_CASTSHADOW_MAPS))
- {
- return true;
- }
- else if ((p1->m_Flags & DLF_CASTSHADOW_MAPS) < (p2->m_Flags & DLF_CASTSHADOW_MAPS))
- {
- return false;
- }
- // get some sorting consistency for shadow casters
- if (p1->m_pOwner > p2->m_pOwner)
- {
- return true;
- }
- else if (p1->m_pOwner < p2->m_pOwner)
- {
- return false;
- }
- return false;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void C3DEngine::SubmitSun(const SRenderingPassInfo& passInfo)
- {
- assert(passInfo.IsGeneralPass());
- FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
- AZ_TRACE_METHOD();
- if (m_pSun)
- {
- CDLight* light = &m_pSun->GetLightProperties();
- GetRenderer()->EF_ADDDlight(light, passInfo);
- }
- }
- void C3DEngine::RemoveEntityLightSources(IRenderNode* pEntity)
- {
- for (int i = 0; i < m_lstStaticLights.Count(); i++)
- {
- if (m_lstStaticLights[i] == pEntity)
- {
- m_lstStaticLights.Delete(i);
- if (pEntity == m_pSun)
- {
- m_pSun = NULL;
- }
- i--;
- }
- }
- }
- ILightSource* C3DEngine::GetSunEntity()
- {
- return m_pSun;
- }
- void C3DEngine::OnCasterDeleted(IShadowCaster* pCaster)
- {
- FUNCTION_PROFILER(gEnv->pSystem, PROFILE_3DENGINE);
- { // make sure pointer to object will not be used somewhere in the renderer
- if (m_pSun)
- {
- m_pSun->OnCasterDeleted(pCaster);
- }
- if (GetRenderer()->GetActiveGPUCount() > 1)
- {
- if (ShadowFrustumMGPUCache* pFrustumCache = GetRenderer()->GetShadowFrustumMGPUCache())
- {
- pFrustumCache->DeleteFromCache(pCaster);
- }
- }
- // remove from per object shadows list
- RemovePerObjectShadow(pCaster);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- void CLightVolumesMgr::Init()
- {
- m_bUpdateLightVolumes = false;
- for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
- {
- m_pLightVolumes[i].reserve(LV_MAX_COUNT);
- m_pLightVolsInfo[i].reserve(LV_MAX_COUNT);
- }
- memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
- memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
- }
- void CLightVolumesMgr::Reset()
- {
- for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
- {
- stl::free_container(m_pLightVolumes[i]);
- }
- m_bUpdateLightVolumes = false;
- memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
- memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
- }
- //////////////////////////////////////////////////////////////////////////
- uint16 CLightVolumesMgr::RegisterVolume(const Vec3& vPos, f32 fRadius, uint8 nClipVolumeRef, const SRenderingPassInfo& passInfo)
- {
- DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
- IF ((m_bUpdateLightVolumes && (lightVolsInfo.size() < LV_MAX_COUNT)) && fRadius < 256.0f, 1)
- {
- FUNCTION_PROFILER_3DENGINE;
- int32 nPosx = (int32)(floorf(vPos.x * LV_CELL_RSIZEX));
- int32 nPosy = (int32)(floorf(vPos.y * LV_CELL_RSIZEY));
- int32 nPosz = (int32)(floorf(vPos.z * LV_CELL_RSIZEZ));
- // Check if world cell has any light volume, else add new one
- uint16 nHashIndex = GetWorldHashBucketKey(nPosx, nPosy, nPosz);
- uint16* pCurrentVolumeID = &m_nWorldCells[nHashIndex];
- while (*pCurrentVolumeID != 0)
- {
- SLightVolInfo& sVolInfo = *lightVolsInfo[*pCurrentVolumeID - 1];
- int32 nVolumePosx = (int32)(floorf(sVolInfo.vVolume.x * LV_CELL_RSIZEX));
- int32 nVolumePosy = (int32)(floorf(sVolInfo.vVolume.y * LV_CELL_RSIZEY));
- int32 nVolumePosz = (int32)(floorf(sVolInfo.vVolume.z * LV_CELL_RSIZEZ));
- if (nPosx == nVolumePosx &&
- nPosy == nVolumePosy &&
- nPosz == nVolumePosz &&
- nClipVolumeRef == sVolInfo.nClipVolumeID)
- {
- return (uint16) * pCurrentVolumeID;
- }
- pCurrentVolumeID = &sVolInfo.nNextVolume;
- }
- // create new volume
- SLightVolInfo* pLightVolInfo = new SLightVolInfo(vPos, fRadius, nClipVolumeRef);
- lightVolsInfo.push_back(pLightVolInfo);
- *pCurrentVolumeID = lightVolsInfo.size();
- return *pCurrentVolumeID;
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- void CLightVolumesMgr::RegisterLight(const CDLight& pDL, uint32 nLightID, [[maybe_unused]] const SRenderingPassInfo& passInfo)
- {
- IF ((m_bUpdateLightVolumes && !(pDL.m_Flags & LV_DLF_LIGHTVOLUMES_MASK)), 1)
- {
- FUNCTION_PROFILER_3DENGINE;
- const f32 fColCheck = (f32) fsel(pDL.m_Color.r + pDL.m_Color.g + pDL.m_Color.b - 0.333f, 1.0f, 0.0f); //light color > threshold
- const f32 fRadCheck = (f32) fsel(pDL.m_fRadius - 0.5f, 1.0f, 0.0f); //light radius > threshold
- if (fColCheck * fRadCheck)
- {
- //if the radius is large than certain value, all the the world light cells will be lighted anyway. So we just add the light to all the cells
- //the input radius restriction will be added too
- if(floorf(pDL.m_fRadius*LV_LIGHT_CELL_R_SIZE) > LV_LIGHTS_WORLD_BUCKET_SIZE)
- {
- for (int32 idx = 0; idx < LV_LIGHTS_WORLD_BUCKET_SIZE; idx++)
- {
- SLightCell& lightCell = m_pWorldLightCells[idx];
- CryPrefetch(&lightCell);
- if (lightCell.nLightCount < LV_LIGHTS_MAX_COUNT)
- {
- lightCell.nLightID[lightCell.nLightCount] = nLightID;
- lightCell.nLightCount += 1;
- }
- }
- }
- else
- {
- int32 nMiny = (int32)(floorf((pDL.m_Origin.y - pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
- int32 nMaxy = (int32)(floorf((pDL.m_Origin.y + pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
- int32 nMinx = (int32)(floorf((pDL.m_Origin.x - pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
- int32 nMaxx = (int32)(floorf((pDL.m_Origin.x + pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
- // Register light into all cells touched by light radius
- for (int32 y = nMiny, ymax = nMaxy; y <= ymax; ++y)
- {
- for (int32 x = nMinx, xmax = nMaxx; x <= xmax; ++x)
- {
- SLightCell& lightCell = m_pWorldLightCells[GetWorldHashBucketKey(x, y, 1, LV_LIGHTS_WORLD_BUCKET_SIZE)];
- CryPrefetch(&lightCell);
- if (lightCell.nLightCount < LV_LIGHTS_MAX_COUNT)
- {
- //only if the las light added to the cell wasn't the same light
- if (!(lightCell.nLightCount > 0 && lightCell.nLightID[lightCell.nLightCount - 1] == nLightID))
- {
- lightCell.nLightID[lightCell.nLightCount] = nLightID;
- lightCell.nLightCount += 1;
- }
- }
- }
- }
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CLightVolumesMgr::AddLight(const SRenderLight& pLight, const SLightVolInfo* __restrict pVolInfo, SLightVolume& pVolume)
- {
- // Check for clip volume
- if (pLight.m_nStencilRef[0] == pVolInfo->nClipVolumeID || pLight.m_nStencilRef[1] == pVolInfo->nClipVolumeID ||
- pLight.m_nStencilRef[0] == CClipVolumeManager::AffectsEverythingStencilRef)
- {
- const Vec4* __restrict vLight = (Vec4*) &pLight.m_Origin.x;
- const Vec4& vVolume = pVolInfo->vVolume;
- const f32 fDimCheck = (f32) fsel(vLight->w - vVolume.w * 0.1f, 1.0f, 0.0f); //light radius not more than 10x smaller than volume radius
- const f32 fOverlapCheck = (f32) fsel(sqr(vVolume.x - vLight->x) + sqr(vVolume.y - vLight->y) + sqr(vVolume.z - vLight->z) - sqr(vVolume.w + vLight->w), 0.0f, 1.0f);// touches volumes
- if (fDimCheck * fOverlapCheck)
- {
- float fAttenuationBulbSize = pLight.m_fAttenuationBulbSize;
- Vec3 lightColor = *((Vec3*)&pLight.m_Color);
- // Adjust light intensity so that the intended brightness is reached 1 meter from the light's surface
- IF (!(pLight.m_Flags & (DLF_AREA_LIGHT | DLF_AMBIENT)), 1)
- {
- fAttenuationBulbSize = max(fAttenuationBulbSize, 0.001f);
- // Solve I * 1 / (1 + d/lightsize)^2 = 1
- float intensityMul = 1.0f + 1.0f / fAttenuationBulbSize;
- intensityMul *= intensityMul;
- lightColor *= intensityMul;
- }
- pVolume.pData.push_back();
- SLightVolume::SLightData& lightData = pVolume.pData[pVolume.pData.size() - 1];
- lightData.vPos = *vLight;
- lightData.vColor = Vec4(lightColor, fAttenuationBulbSize);
- lightData.vParams = Vec4(0.f, 0.f, 0.f, 0.f);
- IF (pLight.m_Flags & DLF_PROJECT, 1)
- {
- lightData.vParams = Vec4(pLight.m_ObjMatrix.GetColumn0(), cos_tpl(DEG2RAD(pLight.m_fLightFrustumAngle)));
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CLightVolumesMgr::Update(const SRenderingPassInfo& passInfo)
- {
- uint32 nThreadID = passInfo.ThreadID();
- DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[nThreadID];
- if (!m_bUpdateLightVolumes || lightVolsInfo.empty())
- {
- return;
- }
- FUNCTION_PROFILER_3DENGINE;
- TArray<SRenderLight>* pLights = GetRenderer()->EF_GetDeferredLights(passInfo);
- const uint32 nLightCount = pLights->size();
- uint32 nLightVols = lightVolsInfo.size();
- LightVolumeVector& lightVols = m_pLightVolumes[nThreadID];
- uint32 existingLightVolsCount = 0; //This is 0, that just means we will be overwriting all existing light volumes
-
- //If this is a recursive pass (not the first time that this is called this frame), we're just going to be adding on new light volumes to the existing collection
- if (passInfo.IsRecursivePass())
- {
- existingLightVolsCount = lightVols.size();
- //If no new light volumes have been added, don't bother updating
- if (nLightVols == existingLightVolsCount)
- {
- return;
- }
- }
- lightVols.resize(nLightVols);
- if (!nLightCount)
- {
- //Start out existingLightVolsCount to avoid clearing out existing light volumes when we don't need to
- for (uint32 v = existingLightVolsCount; v < nLightVols; ++v)
- {
- lightVols[v].pData.resize(0);
- }
- return;
- }
- const int MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE = 1024;
- if (nLightCount > MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE)
- {
- CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, "More lights in the scene (%d) than supported by the Light Volume Update function (%d). Extra lights will be ignored.",
- nLightCount, MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE);
- }
- //This can be a uint8 array because nLightVols should never be greater than 256(LV_MAX_COUNT)
- assert(LV_MAX_COUNT <= 256);
- uint8 lightProcessedStateArray[MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE];
- //Start at the number of light volumes that already exist so that we don't end up re-updating light volumes unnecessarily.
- for (uint32 v = existingLightVolsCount; v < nLightVols; ++v)
- {
- const Vec4* __restrict vBVol = &lightVolsInfo[v]->vVolume;
- int32 nMiny = (int32)(floorf((vBVol->y - vBVol->w) * LV_LIGHT_CELL_R_SIZE));
- int32 nMaxy = (int32)(floorf((vBVol->y + vBVol->w) * LV_LIGHT_CELL_R_SIZE));
- int32 nMinx = (int32)(floorf((vBVol->x - vBVol->w) * LV_LIGHT_CELL_R_SIZE));
- int32 nMaxx = (int32)(floorf((vBVol->x + vBVol->w) * LV_LIGHT_CELL_R_SIZE));
- lightVols[v].pData.resize(0);
- // Loop through active light cells touching bounding volume (~avg 2 cells)
- for (int32 y = nMiny, ymax = nMaxy; y <= ymax; ++y)
- {
- for (int32 x = nMinx, xmax = nMaxx; x <= xmax; ++x)
- {
- const SLightCell& lightCell = m_pWorldLightCells[GetWorldHashBucketKey(x, y, 1, LV_LIGHTS_WORLD_BUCKET_SIZE)];
- CryPrefetch(&lightCell);
- const SRenderLight& pFirstDL = (*pLights)[lightCell.nLightID[0]];
- CryPrefetch(&pFirstDL);
- CryPrefetch(&pFirstDL.m_ObjMatrix);
- for (uint32 l = 0; (l < lightCell.nLightCount) & (lightVols[v].pData.size() < LIGHTVOLUME_MAXLIGHTS); ++l)
- {
- const int32 nLightId = lightCell.nLightID[l];
- //Only allow IDs < MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE to continue or else we'll overflow access to
- //lightProcessedStateArray[MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE]. Skipping the extra lights shouldn't really matter
- //since A) folks won't be using that many lights, and B) for the case of light emitting particles, they tend to be grouped
- //so that the individual contributions tend to bleed together anyway.
- if (nLightId >= MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE)
- {
- continue;
- }
- if (static_cast<uint32>(nLightId) < nLightCount)
- {
- const SRenderLight& pDL = (*pLights)[nLightId];
- const int32 nNextLightId = lightCell.nLightID[(l + 1) & (LIGHTVOLUME_MAXLIGHTS - 1)];
- const SRenderLight& pNextDL = (*pLights)[nNextLightId];
- CryPrefetch(&pNextDL);
- CryPrefetch(&pNextDL.m_ObjMatrix);
- IF(lightProcessedStateArray[nLightId] != v + 1, 1)
- {
- lightProcessedStateArray[nLightId] = v + 1;
- AddLight(pDL, &*lightVolsInfo[v], lightVols[v]);
- }
- }
- }
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CLightVolumesMgr::Clear(const SRenderingPassInfo& passInfo)
- {
- DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
- m_bUpdateLightVolumes = false;
- if (GetCVars()->e_LightVolumes && passInfo.IsGeneralPass() && GetCVars()->e_DynamicLights)
- {
- memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
- memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
- //Clean up volume info data
- for (size_t i = 0; i < lightVolsInfo.size(); ++i)
- {
- delete lightVolsInfo[i];
- }
- m_pLightVolsInfo[passInfo.ThreadID()].clear();
- m_bUpdateLightVolumes = (GetCVars()->e_LightVolumes == 1) ? true : false;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CLightVolumesMgr::GetLightVolumes(threadID nThreadID, SLightVolume*& pLightVols, uint32& nNumVols)
- {
- pLightVols = 0;
- nNumVols = 0;
- if (GetCVars()->e_LightVolumes == 1 && GetCVars()->e_DynamicLights && !m_pLightVolumes[nThreadID].empty())
- {
- pLightVols = &m_pLightVolumes[nThreadID][0];
- nNumVols = m_pLightVolumes[nThreadID].size();
- }
- }
- void C3DEngine::GetLightVolumes(threadID nThreadID, SLightVolume*& pLightVols, uint32& nNumVols)
- {
- m_LightVolumesMgr.GetLightVolumes(nThreadID, pLightVols, nNumVols);
- }
- uint16 C3DEngine::RegisterVolumeForLighting(const Vec3& vPos, f32 fRadius, uint8 nClipVolumeRef, const SRenderingPassInfo& passInfo)
- {
- return m_LightVolumesMgr.RegisterVolume(vPos, fRadius, nClipVolumeRef, passInfo);
- }
- //////////////////////////////////////////////////////////////////////////
- #ifndef _RELEASE
- void CLightVolumesMgr::DrawDebug(const SRenderingPassInfo& passInfo)
- {
- DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
- IRenderer* pRenderer = GetRenderer();
- IRenderAuxGeom* pAuxGeom = GetRenderer()->GetIRenderAuxGeom();
- if (!pAuxGeom || !passInfo.IsGeneralPass())
- {
- return;
- }
- ColorF cWhite = ColorF(1, 1, 1, 1);
- ColorF cBad = ColorF(1.0f, 0.0, 0.0f, 1.0f);
- ColorF cWarning = ColorF(1.0f, 1.0, 0.0f, 1.0f);
- ColorF cGood = ColorF(0.0f, 0.5, 1.0f, 1.0f);
- ColorF cSingleCell = ColorF(0.0f, 1.0, 0.0f, 1.0f);
- const uint32 nLightVols = lightVolsInfo.size();
- LightVolumeVector& lightVols = m_pLightVolumes[passInfo.ThreadID()];
- const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
- float fYLine = 8.0f, fYStep = 20.0f;
- GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, (float*)&cWhite.r, false, "Light Volumes Info (count %d)", nLightVols);
- for (uint32 v = 0; v < nLightVols; ++v) // draw each light volume
- {
- SLightVolume& lv = lightVols[v];
- SLightVolInfo& lvInfo = *lightVolsInfo[v];
- ColorF& cCol = (lv.pData.size() >= 10) ? cBad : ((lv.pData.size() >= 5) ? cWarning : cGood);
- const Vec3 vPos = Vec3(lvInfo.vVolume.x, lvInfo.vVolume.y, lvInfo.vVolume.z);
- const float fCamDistSq = (vPos - vCamPos).len2();
- cCol.a = max(0.25f, min(1.0f, 1024.0f / (fCamDistSq + 1e-6f)));
- pRenderer->DrawLabelEx(vPos, 1.3f, (float*)&cCol.r, true, true, "Id: %d\nPos: %.2f %.2f %.2f\nRadius: %.2f\nLights: %d\nOutLights: %d",
- v, vPos.x, vPos.y, vPos.z, lvInfo.vVolume.w, lv.pData.size(), (*(int32*)&lvInfo.vVolume.w) & (1 << 31) ? 1 : 0);
- if (GetCVars()->e_LightVolumesDebug == 2)
- {
- const float fSideSize = 0.707f * sqrtf(lvInfo.vVolume.w * lvInfo.vVolume.w * 2);
- pAuxGeom->DrawAABB(AABB(vPos - Vec3(fSideSize), vPos + Vec3(fSideSize)), false, cCol, eBBD_Faceted);
- }
- if (GetCVars()->e_LightVolumesDebug == 3)
- {
- cBad.a = 1.0f;
- const Vec3 vCellPos = Vec3(floorf((lvInfo.vVolume.x) * LV_CELL_RSIZEX) * LV_CELL_SIZEX,
- floorf((lvInfo.vVolume.y) * LV_CELL_RSIZEY) * LV_CELL_SIZEY,
- floorf((lvInfo.vVolume.z) * LV_CELL_RSIZEZ) * LV_CELL_SIZEZ);
- const Vec3 vMin = vCellPos;
- const Vec3 vMax = vMin + Vec3(LV_CELL_SIZEX, LV_CELL_SIZEY, LV_CELL_SIZEZ);
- pAuxGeom->DrawAABB(AABB(vMin, vMax), false, cBad, eBBD_Faceted);
- }
- }
- }
- #endif
|