renderProbeMgr.cpp
Engine/source/renderInstance/renderProbeMgr.cpp
Public Defines
define
Public Functions
ConsoleDocClass(RenderProbeMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin which uses object callbacks <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendering.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers object <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances and calls its delegate " "method <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> perform rendering. It is used infrequently <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> specialized " "scene objects which perform custom <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendering.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )
DefineEngineMethod(RenderProbeMgr , bakeProbe , void , (ReflectionProbe *probe) , (nullAsType< ReflectionProbe * >()) , "@brief Bakes the cubemaps <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> reflection probe\n\n." )
DefineEngineMethod(RenderProbeMgr , bakeProbes , void , () , "@brief Iterates over all reflection probes in the scene and bakes their cubemaps\n\n." )
Detailed Description
Public Defines
TORQUE_GFX_VISUAL_DEBUG()
Public Functions
AscendingReflectProbeInfluence(const void * a, const void * b)
ConsoleDocClass(RenderProbeMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin which uses object callbacks <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendering.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers object <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances and calls its delegate " "method <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> perform rendering. It is used infrequently <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> specialized " "scene objects which perform custom <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendering.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )
DefineEngineMethod(RenderProbeMgr , bakeProbe , void , (ReflectionProbe *probe) , (nullAsType< ReflectionProbe * >()) , "@brief Bakes the cubemaps <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> reflection probe\n\n." )
DefineEngineMethod(RenderProbeMgr , bakeProbes , void , () , "@brief Iterates over all reflection probes in the scene and bakes their cubemaps\n\n." )
IMPLEMENT_CONOBJECT(RenderProbeMgr )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23#include "renderProbeMgr.h" 24#include "console/consoleTypes.h" 25#include "scene/sceneObject.h" 26#include "materials/materialManager.h" 27#include "scene/sceneRenderState.h" 28#include "math/util/sphereMesh.h" 29#include "math/util/matrixSet.h" 30#include "materials/processedMaterial.h" 31#include "renderInstance/renderDeferredMgr.h" 32#include "math/mPolyhedron.impl.h" 33#include "gfx/gfxTransformSaver.h" 34#include "lighting/advanced/advancedLightBinManager.h" //for ssao 35#include "gfx/gfxDebugEvent.h" 36#include "shaderGen/shaderGenVars.h" 37#include "materials/shaderData.h" 38 39#include "gfx/gfxTextureManager.h" 40#include "scene/reflectionManager.h" 41 42#include "postFx/postEffect.h" 43#include "T3D/lighting/reflectionProbe.h" 44#include "T3D/lighting/IBLUtilities.h" 45 46//For our cameraQuery setup 47#include "T3D/gameTSCtrl.h" 48 49#include "T3D/Scene.h" 50 51#define TORQUE_GFX_VISUAL_DEBUG //renderdoc debugging 52 53IMPLEMENT_CONOBJECT(RenderProbeMgr); 54 55ConsoleDocClass( RenderProbeMgr, 56 "@brief A render bin which uses object callbacks for rendering.\n\n" 57 "This render bin gathers object render instances and calls its delegate " 58 "method to perform rendering. It is used infrequently for specialized " 59 "scene objects which perform custom rendering.\n\n" 60 "@ingroup RenderBin\n" ); 61 62RenderProbeMgr *RenderProbeMgr::smProbeManager = NULL; 63 64bool RenderProbeMgr::smRenderReflectionProbes = true; 65F32 RenderProbeMgr::smMaxProbeDrawDistance = 100; 66S32 RenderProbeMgr::smMaxProbesPerFrame = 8; 67 68S32 QSORT_CALLBACK AscendingReflectProbeInfluence(const void* a, const void* b) 69{ 70 // Debug Profiling. 71 PROFILE_SCOPE(AdvancedLightBinManager_AscendingReflectProbeInfluence); 72 73 // Fetch asset definitions. 74 const ProbeRenderInst* pReflectProbeA = (*(ProbeRenderInst**)a); 75 const ProbeRenderInst* pReflectProbeB = (*(ProbeRenderInst**)b); 76 //sort by score 77 return pReflectProbeA->mScore - pReflectProbeB->mScore; 78} 79 80// 81// 82ProbeRenderInst::ProbeRenderInst() : 83 mIsEnabled(true), 84 mTransform(true), 85 mDirty(false), 86 mPriority(1.0f), 87 mScore(0.0f), 88 mPrefilterCubemap(NULL), 89 mIrradianceCubemap(NULL), 90 mRadius(1.0f), 91 mProbeRefOffset(0, 0, 0), 92 mProbeRefScale(1,1,1), 93 mAtten(0.0), 94 mCubemapIndex(0), 95 mProbeIdx(0), 96 mProbeShapeType(Box) 97{ 98} 99 100ProbeRenderInst::~ProbeRenderInst() 101{ 102 if (mPrefilterCubemap && mPrefilterCubemap.isValid()) 103 { 104 mPrefilterCubemap.free(); 105 } 106 if (mIrradianceCubemap && mIrradianceCubemap.isValid()) 107 { 108 mIrradianceCubemap.free(); 109 } 110} 111 112void ProbeRenderInst::set(const ProbeRenderInst *probeInfo) 113{ 114 mTransform = probeInfo->mTransform; 115 mPrefilterCubemap = probeInfo->mPrefilterCubemap; 116 mIrradianceCubemap = probeInfo->mIrradianceCubemap; 117 mRadius = probeInfo->mRadius; 118 mProbeShapeType = probeInfo->mProbeShapeType; 119 mBounds = probeInfo->mBounds; 120 mScore = probeInfo->mScore; 121 mAtten = probeInfo->mAtten; 122} 123 124// 125// 126ProbeShaderConstants::ProbeShaderConstants() 127 : mInit(false), 128 mShader(NULL), 129 mProbePositionSC(NULL), 130 mProbeRefPosSC(NULL), 131 mRefScaleSC(NULL), 132 mProbeConfigDataSC(NULL), 133 mProbeSpecularCubemapSC(NULL), 134 mProbeIrradianceCubemapSC(NULL), 135 mProbeCountSC(NULL), 136 mBRDFTextureMap(NULL), 137 mSkylightCubemapIdxSC(NULL), 138 mWorldToObjArraySC(NULL) 139{ 140} 141 142ProbeShaderConstants::~ProbeShaderConstants() 143{ 144 if (mShader.isValid()) 145 { 146 mShader->getReloadSignal().remove(this, &ProbeShaderConstants::_onShaderReload); 147 mShader = NULL; 148 } 149} 150 151void ProbeShaderConstants::init(GFXShader* shader) 152{ 153 if (mShader.getPointer() != shader) 154 { 155 if (mShader.isValid()) 156 mShader->getReloadSignal().remove(this, &ProbeShaderConstants::_onShaderReload); 157 158 mShader = shader; 159 mShader->getReloadSignal().notify(this, &ProbeShaderConstants::_onShaderReload); 160 } 161 162 //Reflection Probes 163 mProbePositionSC = shader->getShaderConstHandle(ShaderGenVars::probePosition); 164 mProbeRefPosSC = shader->getShaderConstHandle(ShaderGenVars::probeRefPos); 165 mRefScaleSC = shader->getShaderConstHandle(ShaderGenVars::refScale); 166 mWorldToObjArraySC = shader->getShaderConstHandle(ShaderGenVars::worldToObjArray); 167 mProbeConfigDataSC = shader->getShaderConstHandle(ShaderGenVars::probeConfigData); 168 mProbeSpecularCubemapSC = shader->getShaderConstHandle(ShaderGenVars::specularCubemapAR); 169 mProbeIrradianceCubemapSC = shader->getShaderConstHandle(ShaderGenVars::irradianceCubemapAR); 170 mProbeCountSC = shader->getShaderConstHandle(ShaderGenVars::probeCount); 171 172 mBRDFTextureMap = shader->getShaderConstHandle(ShaderGenVars::BRDFTextureMap); 173 174 mSkylightCubemapIdxSC = shader->getShaderConstHandle(ShaderGenVars::skylightCubemapIdx); 175 176 mInit = true; 177} 178 179bool ProbeShaderConstants::isValid() 180{ 181 if (mProbePositionSC->isValid() || 182 mProbeConfigDataSC->isValid() || 183 mRefScaleSC->isValid() || 184 mProbeSpecularCubemapSC->isValid() || 185 mProbeIrradianceCubemapSC->isValid()) 186 return true; 187 188 return false; 189} 190 191void ProbeShaderConstants::_onShaderReload() 192{ 193 if (mShader.isValid()) 194 init(mShader); 195} 196 197// 198// 199RenderProbeMgr::RenderProbeMgr() 200: RenderBinManager(RenderPassManager::RIT_Probes, 1.0f, 1.0f), 201 mLastShader(nullptr), 202 mLastConstants(nullptr), 203 mProbesDirty(false), 204 mHasSkylight(false), 205 mSkylightCubemapIdx(-1), 206 mCubeMapCount(0), 207 mDefaultSkyLight(nullptr), 208 mUseHDRCaptures(true) 209{ 210 mEffectiveProbeCount = 0; 211 mMipCount = 0; 212 213 mProbeArrayEffect = nullptr; 214 215 smProbeManager = this; 216 217 mCubeMapCount = 0; 218 mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE; 219 220 for (U32 i = 0; i < PROBE_MAX_COUNT; i++) 221 { 222 mCubeMapSlots[i] = false; 223 } 224 225 mPrefilterSize = 64; 226 mPrefilterMipLevels = mLog2(F32(mPrefilterSize)) + 1; 227} 228 229RenderProbeMgr::RenderProbeMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder) 230 : RenderBinManager(riType, renderOrder, processAddOrder) 231{ 232 mCubeMapCount = 0; 233 dMemset(mCubeMapSlots, false, sizeof(mCubeMapSlots)); 234 mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE; 235 mDefaultSkyLight = nullptr; 236 mEffectiveProbeCount = 0; 237 mHasSkylight = false; 238 mSkylightCubemapIdx = -1; 239 mLastConstants = nullptr; 240 mMipCount = 0; 241 mProbesDirty = false; 242 mUseHDRCaptures = true; 243 244 mPrefilterSize = 64; 245 mPrefilterMipLevels = mLog2(F32(mPrefilterSize)) + 1; 246} 247 248RenderProbeMgr::~RenderProbeMgr() 249{ 250 mLastShader = NULL; 251 mLastConstants = NULL; 252 253 for (ProbeConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++) 254 { 255 if (i->value) 256 SAFE_DELETE(i->value); 257 } 258 mConstantLookup.clear(); 259} 260 261bool RenderProbeMgr::onAdd() 262{ 263 if (!Parent::onAdd()) 264 return false; 265 266 mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); 267 mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); 268 269 //pre-allocate a few slots 270 mIrradianceArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_IRRAD_SIZE, PROBE_FORMAT); 271 mPrefilterArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_PREFILTER_SIZE, PROBE_FORMAT); 272 mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE; 273 274 //create our own default default skylight 275 mDefaultSkyLight = new ProbeRenderInst; 276 mDefaultSkyLight->mProbeShapeType = ProbeRenderInst::Skylight; 277 mDefaultSkyLight->mIsEnabled = false; 278 279 String defaultIrradMapPath = GFXTextureManager::getDefaultIrradianceCubemapPath(); 280 if (!mDefaultSkyLight->mIrradianceCubemap.set(defaultIrradMapPath)) 281 { 282 Con::errorf("RenderProbeMgr::onAdd: Failed to load default irradiance cubemap"); 283 return false; 284 } 285 286 String defaultPrefilterPath = GFXTextureManager::getDefaultPrefilterCubemapPath(); 287 if (!mDefaultSkyLight->mPrefilterCubemap.set(defaultPrefilterPath)) 288 { 289 Con::errorf("RenderProbeMgr::onAdd: Failed to load default prefilter cubemap"); 290 return false; 291 } 292 293 String brdfTexturePath = GFXTextureManager::getBRDFTexturePath(); 294 if (!mBRDFTexture.set(brdfTexturePath, &GFXTexturePersistentSRGBProfile, "BRDFTexture")) 295 { 296 Con::errorf("RenderProbeMgr::onAdd: Failed to load BRDF Texture"); 297 return false; 298 } 299 300 return true; 301} 302 303void RenderProbeMgr::onRemove() 304{ 305 Parent::onRemove(); 306} 307 308void RenderProbeMgr::initPersistFields() 309{ 310 Parent::initPersistFields(); 311} 312 313void RenderProbeMgr::consoleInit() 314{ 315 Parent::consoleInit(); 316 317 // Vars for debug rendering while the RoadEditor is open, only used if smEditorOpen is true. 318 Con::addVariable("$pref::maxProbeDrawDistance", TypeF32, &RenderProbeMgr::smMaxProbeDrawDistance, "Max distance for reflection probes to render.\n"); 319 Con::addVariable("$pref::MaxProbesPerFrame", TypeS32, &RenderProbeMgr::smMaxProbesPerFrame, "Max number of Environment Probes that can be rendered per-frame.\n"); 320} 321 322void RenderProbeMgr::registerProbe(ProbeRenderInst* newProbe) 323{ 324 //Can't have over the probe limit 325 if (mRegisteredProbes.size() + 1 >= PROBE_MAX_COUNT) 326 return; 327 328 mRegisteredProbes.push_back(newProbe); 329 330 newProbe->mProbeIdx = mRegisteredProbes.size() - 1; 331 332 const U32 cubeIndex = _findNextEmptyCubeSlot(); 333 if (cubeIndex == INVALID_CUBE_SLOT) 334 { 335 Con::warnf("RenderProbeMgr::addProbe: Invalid cubemap slot."); 336 return; 337 } 338 339 //check if we need to resize the cubemap array 340 if (cubeIndex >= mCubeSlotCount) 341 { 342 //alloc temp array handles 343 GFXCubemapArrayHandle irr = GFXCubemapArrayHandle(GFX->createCubemapArray()); 344 GFXCubemapArrayHandle prefilter = GFXCubemapArrayHandle(GFX->createCubemapArray()); 345 346 irr->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_IRRAD_SIZE, PROBE_FORMAT); 347 prefilter->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_PREFILTER_SIZE, PROBE_FORMAT); 348 349 mIrradianceArray->copyTo(irr); 350 mPrefilterArray->copyTo(prefilter); 351 352 //assign the temp handles to the new ones, this will destroy the old ones as well 353 mIrradianceArray = irr; 354 mPrefilterArray = prefilter; 355 356 mCubeSlotCount += PROBE_ARRAY_SLOT_BUFFER_SIZE; 357 } 358 359 newProbe->mCubemapIndex = cubeIndex; 360 //mark cubemap slot as taken 361 mCubeMapSlots[cubeIndex] = true; 362 mCubeMapCount++; 363 364#ifdef TORQUE_DEBUG 365 Con::warnf("RenderProbeMgr::registerProbe: Registered probe %u to cubeIndex %u", newProbe->mProbeIdx, cubeIndex); 366#endif 367 368 mProbesDirty = true; 369} 370 371void RenderProbeMgr::unregisterProbe(U32 probeIdx) 372{ 373 //Mostly for consolidation, but also lets us sanity check or prep any other data we need for rendering this in one place at time of flagging for render 374 if (probeIdx >= mRegisteredProbes.size()) 375 return; 376 377 if (mRegisteredProbes[probeIdx]->mCubemapIndex == INVALID_CUBE_SLOT) 378 return; 379 380 //mark cubemap slot as available now 381 mCubeMapSlots[mRegisteredProbes[probeIdx]->mCubemapIndex] = false; 382 mCubeMapCount--; 383 384 mRegisteredProbes.erase(probeIdx); 385 386 //recalculate all the probe's indicies just to be sure 387 for (U32 i = 0; i < mRegisteredProbes.size(); i++) 388 { 389 mRegisteredProbes[i]->mProbeIdx = i; 390 } 391 392 //rebuild our probe data 393 mProbesDirty = true; 394} 395 396void RenderProbeMgr::submitProbe(const ProbeRenderInst& newProbe) 397{ 398 mActiveProbes.push_back(newProbe); 399} 400 401// 402// 403PostEffect* RenderProbeMgr::getProbeArrayEffect() 404{ 405 if (!mProbeArrayEffect) 406 { 407 mProbeArrayEffect = dynamic_cast<PostEffect*>(Sim::findObject("reflectionProbeArrayPostFX")); 408 409 if (!mProbeArrayEffect) 410 return nullptr; 411 } 412 return mProbeArrayEffect; 413} 414 415//remove 416//Con::setIntVariable("lightMetrics::activeReflectionProbes", mReflectProbeBin.size()); 417//Con::setIntVariable("lightMetrics::culledReflectProbes", 0/*mNumLightsCulled*/); 418// 419 420void RenderProbeMgr::updateProbes() 421{ 422 mProbesDirty = true; 423} 424 425void RenderProbeMgr::updateProbeTexture(ProbeRenderInst* probeInfo) 426{ 427 if (probeInfo->mIrradianceCubemap.isNull() || !probeInfo->mIrradianceCubemap->isInitialized()) 428 { 429 Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized irradiance map!"); 430 return; 431 } 432 433 if (probeInfo->mPrefilterCubemap.isNull() || !probeInfo->mPrefilterCubemap->isInitialized()) 434 { 435 Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized specular map!"); 436 return; 437 } 438 439 const U32 cubeIndex = probeInfo->mCubemapIndex; 440 mIrradianceArray->updateTexture(probeInfo->mIrradianceCubemap, cubeIndex); 441 mPrefilterArray->updateTexture(probeInfo->mPrefilterCubemap, cubeIndex); 442 443#ifdef TORQUE_DEBUG 444 Con::warnf("UpdatedProbeTexture - probeIdx: %u on cubeIndex %u, Irrad validity: %d, Prefilter validity: %d", probeInfo->mProbeIdx, cubeIndex, 445 probeInfo->mIrradianceCubemap->isInitialized(), probeInfo->mPrefilterCubemap->isInitialized()); 446#endif 447} 448 449void RenderProbeMgr::reloadTextures() 450{ 451 U32 probeCount = mRegisteredProbes.size(); 452 for (U32 i = 0; i < probeCount; i++) 453 { 454 updateProbeTexture(mRegisteredProbes[i]); 455 } 456 457 mProbesDirty = true; 458} 459 460void RenderProbeMgr::_setupPerFrameParameters(const SceneRenderState *state) 461{ 462 PROFILE_SCOPE(RenderProbeMgr_SetupPerFrameParameters); 463 464 mProbeData = ProbeDataSet(smMaxProbesPerFrame); 465 466 getBestProbes(state->getCameraPosition(), &mProbeData); 467} 468 469ProbeShaderConstants* RenderProbeMgr::getProbeShaderConstants(GFXShaderConstBuffer* buffer) 470{ 471 if (!buffer) 472 return NULL; 473 474 PROFILE_SCOPE(ProbeManager_GetProbeShaderConstants); 475 476 GFXShader* shader = buffer->getShader(); 477 478 // Check to see if this is the same shader, we'll get hit repeatedly by 479 // the same one due to the render bin loops. 480 if (mLastShader.getPointer() != shader) 481 { 482 ProbeConstantMap::Iterator iter = mConstantLookup.find(shader); 483 if (iter != mConstantLookup.end()) 484 { 485 mLastConstants = iter->value; 486 } 487 else 488 { 489 ProbeShaderConstants* psc = new ProbeShaderConstants(); 490 mConstantLookup[shader] = psc; 491 492 mLastConstants = psc; 493 } 494 495 // Set our new shader 496 mLastShader = shader; 497 } 498 499 /*if (mLastConstants == nullptr) 500 { 501 ProbeShaderConstants* psc = new ProbeShaderConstants(); 502 mConstantLookup[shader] = psc; 503 504 mLastConstants = psc; 505 }*/ 506 507 // Make sure that our current lighting constants are initialized 508 if (mLastConstants && !mLastConstants->mInit) 509 mLastConstants->init(shader); 510 511 return mLastConstants; 512} 513 514void RenderProbeMgr::setupSGData(SceneData& data, const SceneRenderState* state, LightInfo* light) 515{ 516 //ensure they're sorted for forward rendering 517 mActiveProbes.sort(_probeScoreCmp); 518} 519 520void RenderProbeMgr::_update4ProbeConsts(const SceneData &sgData, 521 MatrixSet &matSet, 522 ProbeShaderConstants *probeShaderConsts, 523 GFXShaderConstBuffer *shaderConsts) 524{ 525 PROFILE_SCOPE(ProbeManager_Update4ProbeConsts); 526 527 // Skip over gathering lights if we don't have to! 528 if (probeShaderConsts->isValid()) 529 { 530 PROFILE_SCOPE(ProbeManager_Update4ProbeConsts_setProbes); 531 532 const U32 MAX_FORWARD_PROBES = 4; 533 ProbeDataSet probeSet(MAX_FORWARD_PROBES); 534 535 matSet.restoreSceneViewProjection(); 536 537 getBestProbes(sgData.objTrans->getPosition(), &probeSet); 538 539 static AlignedArray<Point4F> probePositionAlignedArray(probeSet.maxProbeCount, sizeof(Point4F)); 540 static AlignedArray<Point4F> refScaleAlignedArray(probeSet.maxProbeCount, sizeof(Point4F)); 541 static AlignedArray<Point4F> probeRefPositionAlignedArray(probeSet.maxProbeCount, sizeof(Point4F)); 542 static AlignedArray<Point4F> probeConfigAlignedArray(probeSet.maxProbeCount, sizeof(Point4F)); 543 544 for (U32 i = 0; i < probeSet.maxProbeCount; i++) 545 { 546 probePositionAlignedArray[i] = probeSet.probePositionArray[i]; 547 probeRefPositionAlignedArray[i] = probeSet.probeRefPositionArray[i]; 548 refScaleAlignedArray[i] = probeSet.refScaleArray[i]; 549 probeConfigAlignedArray[i] = probeSet.probeConfigArray[i]; 550 } 551 552 shaderConsts->setSafe(probeShaderConsts->mProbeCountSC, (S32)probeSet.effectiveProbeCount); 553 554 shaderConsts->setSafe(probeShaderConsts->mProbePositionSC, probePositionAlignedArray); 555 shaderConsts->setSafe(probeShaderConsts->mProbeRefPosSC, probeRefPositionAlignedArray); 556 557 if(probeShaderConsts->isValid()) 558 shaderConsts->set(probeShaderConsts->mWorldToObjArraySC, probeSet.probeWorldToObjArray.address(), probeSet.effectiveProbeCount, GFXSCT_Float4x4); 559 560 shaderConsts->setSafe(probeShaderConsts->mRefScaleSC, refScaleAlignedArray); 561 shaderConsts->setSafe(probeShaderConsts->mProbeConfigDataSC, probeConfigAlignedArray); 562 563 shaderConsts->setSafe(probeShaderConsts->mSkylightCubemapIdxSC, (float)probeSet.skyLightIdx); 564 565 if(probeShaderConsts->mBRDFTextureMap->getSamplerRegister() != -1 && mBRDFTexture.isValid()) 566 GFX->setTexture(probeShaderConsts->mBRDFTextureMap->getSamplerRegister(), mBRDFTexture); 567 568 if(probeShaderConsts->mProbeSpecularCubemapSC->getSamplerRegister() != -1) 569 GFX->setCubeArrayTexture(probeShaderConsts->mProbeSpecularCubemapSC->getSamplerRegister(), mPrefilterArray); 570 if(probeShaderConsts->mProbeIrradianceCubemapSC->getSamplerRegister() != -1) 571 GFX->setCubeArrayTexture(probeShaderConsts->mProbeIrradianceCubemapSC->getSamplerRegister(), mIrradianceArray); 572 } 573} 574 575S32 QSORT_CALLBACK RenderProbeMgr::_probeScoreCmp(const ProbeRenderInst* a, const ProbeRenderInst* b) 576{ 577 F32 diff = a->getScore() - b->getScore(); 578 return diff > 0 ? 1 : diff < 0 ? -1 : 0; 579} 580 581void RenderProbeMgr::getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet) 582{ 583 PROFILE_SCOPE(ProbeManager_getBestProbes); 584 585 //Array rendering 586 U32 probeCount = mActiveProbes.size(); 587 588 Vector<S8> bestPickProbes; 589 bestPickProbes.setSize(probeDataSet->maxProbeCount); 590 bestPickProbes.fill(-1); 591 592 probeDataSet->effectiveProbeCount = 0; 593 for (U32 i = 0; i < probeCount; i++) 594 { 595 if (probeDataSet->skyLightIdx != -1 && probeDataSet->effectiveProbeCount >= probeDataSet->maxProbeCount) 596 break; 597 598 const ProbeRenderInst& curEntry = mActiveProbes[i]; 599 if (!curEntry.mIsEnabled) 600 continue; 601 602 if (curEntry.mProbeShapeType != ProbeRenderInst::Skylight) 603 { 604 if (probeDataSet->effectiveProbeCount < probeDataSet->maxProbeCount) 605 { 606 bestPickProbes[probeDataSet->effectiveProbeCount] = i; 607 probeDataSet->effectiveProbeCount++; 608 } 609 } 610 else 611 { 612 probeDataSet->skyLightIdx = curEntry.mCubemapIndex; 613 } 614 } 615 616 //Grab our best probe picks 617 for (U32 i = 0; i < bestPickProbes.size(); i++) 618 { 619 if (bestPickProbes[i] == -1) 620 continue; 621 622 const ProbeRenderInst& curEntry = mActiveProbes[bestPickProbes[i]]; 623 624 MatrixF p2A = curEntry.getTransform(); 625 p2A.inverse(); 626 probeDataSet->refScaleArray[i] = curEntry.mProbeRefScale / p2A.getScale(); 627 628 Point3F probePos = curEntry.getPosition(); 629 Point3F refPos = probePos + curEntry.mProbeRefOffset * probeDataSet->refScaleArray[i].asPoint3F(); 630 probeDataSet->probeWorldToObjArray[i] = curEntry.getTransform(); 631 632 probeDataSet->probePositionArray[i] = Point4F(probePos.x, probePos.y, probePos.z, 0); 633 probeDataSet->probeRefPositionArray[i] = Point4F(refPos.x, refPos.y, refPos.z, 0); 634 635 probeDataSet->probeConfigArray[i] = Point4F(curEntry.mProbeShapeType, 636 curEntry.mRadius, 637 curEntry.mAtten, 638 curEntry.mCubemapIndex); 639 } 640} 641 642void RenderProbeMgr::getProbeTextureData(ProbeTextureArrayData* probeTextureSet) 643{ 644 probeTextureSet->BRDFTexture = mBRDFTexture; 645 probeTextureSet->prefilterArray = mPrefilterArray; 646 probeTextureSet->irradianceArray = mIrradianceArray; 647} 648 649void RenderProbeMgr::setProbeInfo(ProcessedMaterial *pmat, 650 const Material *mat, 651 const SceneData &sgData, 652 const SceneRenderState *state, 653 U32 pass, 654 GFXShaderConstBuffer *shaderConsts) 655{ 656 657 // Skip this if we're rendering from the deferred bin. 658 if (sgData.binType == SceneData::DeferredBin) 659 return; 660 661 PROFILE_SCOPE(ProbeManager_setProbeInfo); 662 663 ProbeShaderConstants *psc = getProbeShaderConstants(shaderConsts); 664 665 // NOTE: If you encounter a crash from this point forward 666 // while setting a shader constant its probably because the 667 // mConstantLookup has bad shaders/constants in it. 668 // 669 // This is a known crash bug that can occur if materials/shaders 670 // are reloaded and the light manager is not reset. 671 // 672 // We should look to fix this by clearing the table. 673 MatrixSet matSet = state->getRenderPass()->getMatrixSet(); 674 675 // Update the forward shading light constants. 676 _update4ProbeConsts(sgData, matSet, psc, shaderConsts); 677} 678 679//----------------------------------------------------------------------------- 680// render objects 681//----------------------------------------------------------------------------- 682void RenderProbeMgr::render( SceneRenderState *state ) 683{ 684 if (getProbeArrayEffect() == nullptr) 685 { 686 mActiveProbes.clear(); 687 return; 688 } 689 690 GFXDEBUGEVENT_SCOPE(RenderProbeMgr_render, ColorI::WHITE); 691 692 //Sort the active probes 693 mActiveProbes.sort(_probeScoreCmp); 694 695 // Initialize and set the per-frame data 696 _setupPerFrameParameters(state); 697 698 // Early out if nothing to draw. 699 if (!RenderProbeMgr::smRenderReflectionProbes || (!state->isDiffusePass() && !state->isReflectPass()) || (mProbeData.effectiveProbeCount == 0 && mProbeData.skyLightIdx == -1)) 700 { 701 getProbeArrayEffect()->setSkip(true); 702 mActiveProbes.clear(); 703 return; 704 } 705 706 GFXTransformSaver saver; 707 708 //Visualization 709 String useDebugAtten = Con::getVariable("$Probes::showAttenuation", "0"); 710 mProbeArrayEffect->setShaderMacro("DEBUGVIZ_ATTENUATION", useDebugAtten); 711 712 String useDebugSpecCubemap = Con::getVariable("$Probes::showSpecularCubemaps", "0"); 713 mProbeArrayEffect->setShaderMacro("DEBUGVIZ_SPECCUBEMAP", useDebugSpecCubemap); 714 715 String useDebugDiffuseCubemap = Con::getVariable("$Probes::showDiffuseCubemaps", "0"); 716 mProbeArrayEffect->setShaderMacro("DEBUGVIZ_DIFFCUBEMAP", useDebugDiffuseCubemap); 717 718 String useDebugContrib = Con::getVariable("$Probes::showProbeContrib", "0"); 719 mProbeArrayEffect->setShaderMacro("DEBUGVIZ_CONTRIB", useDebugContrib); 720 721 if(mProbeData.skyLightIdx != -1 && mProbeData.effectiveProbeCount == 0) 722 mProbeArrayEffect->setShaderMacro("SKYLIGHT_ONLY", "1"); 723 else 724 mProbeArrayEffect->setShaderMacro("SKYLIGHT_ONLY", "0"); 725 726 String probePerFrame = Con::getVariable("$pref::MaxProbesPerFrame", "8"); 727 mProbeArrayEffect->setShaderMacro("MAX_PROBES", probePerFrame); 728 729 //ssao mask 730 if (AdvancedLightBinManager::smUseSSAOMask) 731 { 732 //find ssaoMask 733 NamedTexTargetRef ssaoTarget = NamedTexTarget::find("ssaoMask"); 734 GFXTextureObject* pTexObj = ssaoTarget->getTexture(); 735 if (pTexObj) 736 { 737 mProbeArrayEffect->setShaderMacro("USE_SSAO_MASK"); 738 mProbeArrayEffect->setTexture(6, pTexObj); 739 } 740 } 741 else 742 { 743 mProbeArrayEffect->setTexture(6, GFXTexHandle(NULL)); 744 } 745 746 mProbeArrayEffect->setTexture(3, mBRDFTexture); 747 mProbeArrayEffect->setCubemapArrayTexture(4, mPrefilterArray); 748 mProbeArrayEffect->setCubemapArrayTexture(5, mIrradianceArray); 749 750 mProbeArrayEffect->setShaderConst("$numProbes", (S32)mProbeData.effectiveProbeCount); 751 mProbeArrayEffect->setShaderConst("$skylightCubemapIdx", (S32)mProbeData.skyLightIdx); 752 753 mProbeArrayEffect->setShaderConst("$cubeMips", (float)mPrefilterArray->getMipMapLevels()); 754 755 //also set up some colors 756 Vector<Point4F> contribColors; 757 758 contribColors.setSize(mProbeData.effectiveProbeCount); 759 760 if (mProbeData.effectiveProbeCount != 0) 761 { 762 if (useDebugContrib == String("1")) 763 { 764 MRandomLCG RandomGen; 765 RandomGen.setSeed(mProbeData.effectiveProbeCount); 766 767 for (U32 i = 0; i < mProbeData.effectiveProbeCount; i++) 768 { 769 //we're going to cheat here a little for consistent debugging behavior. The first 3 probes will always have R G and then B for their colors, every other will be random 770 if (i == 0) 771 contribColors[i] = Point4F(1, 0, 0, 1); 772 else if (i == 1) 773 contribColors[i] = Point4F(0, 1, 0, 1); 774 else if (i == 2) 775 contribColors[i] = Point4F(0, 0, 1, 1); 776 else 777 contribColors[i] = Point4F(RandomGen.randF(0, 1), RandomGen.randF(0, 1), RandomGen.randF(0, 1), 1); 778 } 779 } 780 } 781 782 mProbeArrayEffect->setShaderConst("$probeContribColors", contribColors); 783 784 mProbeArrayEffect->setShaderConst("$inProbePosArray", mProbeData.probePositionArray); 785 mProbeArrayEffect->setShaderConst("$inRefPosArray", mProbeData.probeRefPositionArray); 786 mProbeArrayEffect->setShaderConst("$worldToObjArray", mProbeData.probeWorldToObjArray); 787 mProbeArrayEffect->setShaderConst("$refScaleArray", mProbeData.refScaleArray); 788 mProbeArrayEffect->setShaderConst("$probeConfigData", mProbeData.probeConfigArray); 789 790 // Make sure the effect is gonna render. 791 getProbeArrayEffect()->setSkip(false); 792 793 mActiveProbes.clear(); 794} 795 796void RenderProbeMgr::bakeProbe(ReflectionProbe *probe) 797{ 798 GFXDEBUGEVENT_SCOPE(RenderProbeMgr_Bake, ColorI::WHITE); 799 800 Con::warnf("RenderProbeMgr::bakeProbe() - Beginning bake!"); 801 U32 startMSTime = Platform::getRealMilliseconds(); 802 803 String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); 804 U32 resolution = Con::getIntVariable("$pref::ReflectionProbes::BakeResolution", 64); 805 U32 prefilterMipLevels = mLog2(F32(resolution)) + 1; 806 bool renderWithProbes = Con::getIntVariable("$pref::ReflectionProbes::RenderWithProbes", false); 807 808 ReflectionProbe* clientProbe = nullptr; 809 810 if (probe->isServerObject()) 811 clientProbe = static_cast<ReflectionProbe*>(probe->getClientObject()); 812 else 813 return; 814 815 if (clientProbe == nullptr) 816 return; 817 818 String probePrefilterPath = clientProbe->getPrefilterMapPath(); 819 String probeIrradPath = clientProbe->getIrradianceMapPath(); 820 821 if (clientProbe->mReflectionModeType != ReflectionProbe::DynamicCubemap) 822 { 823 //Prep our bake path 824 if (probePrefilterPath.isEmpty() || probeIrradPath.isEmpty()) 825 { 826 Con::errorf("RenderProbeMgr::bake() - Unable to bake our captures because probe doesn't have a path set"); 827 return; 828 } 829 } 830 831 // Save the current transforms so we can restore 832 // it for child control rendering below. 833 GFXTransformSaver saver; 834 835 bool probeRenderState = RenderProbeMgr::smRenderReflectionProbes; 836 837 F32 farPlane = 1000.0f; 838 839 ReflectorDesc reflDesc; 840 reflDesc.texSize = resolution; 841 reflDesc.farDist = farPlane; 842 reflDesc.detailAdjust = 1; 843 reflDesc.objectTypeMask = probe->mProbeShapeType == ProbeRenderInst::ProbeShapeType::Skylight ? SKYLIGHT_CAPTURE_TYPEMASK : REFLECTION_PROBE_CAPTURE_TYPEMASK; 844 845 CubeReflector cubeRefl; 846 cubeRefl.registerReflector(probe, &reflDesc); 847 848 ReflectParams reflParams; 849 850 //need to get the query somehow. Likely do some sort of get function to fetch from the guiTSControl that's active 851 CameraQuery query; //need to get the last cameraQuery 852 query.fov = 90; //90 degree slices for each of the 6 sides 853 query.nearPlane = 0.1f; 854 query.farPlane = farPlane; 855 query.headMatrix = MatrixF(); 856 query.cameraMatrix = clientProbe->getTransform(); 857 858 Frustum culler; 859 culler.set(false, 860 query.fov, 861 1.0f, 862 query.nearPlane, 863 query.farPlane, 864 query.cameraMatrix); 865 866 S32 stereoTarget = GFX->getCurrentStereoTarget(); 867 868 Point2I maxRes(2048, 2048); //basically a boundary so we don't go over this and break stuff 869 870 reflParams.culler = culler; 871 reflParams.eyeId = stereoTarget; 872 reflParams.query = &query; 873 reflParams.startOfUpdateMs = startMSTime; 874 reflParams.viewportExtent = maxRes; 875 876 if (!renderWithProbes) 877 RenderProbeMgr::smRenderReflectionProbes = false; 878 879 GFXFormat reflectFormat; 880 881 if (mUseHDRCaptures) 882 reflectFormat = GFXFormatR16G16B16A16F; 883 else 884 reflectFormat = GFXFormatR8G8B8A8; 885 const GFXFormat oldRefFmt = REFLECTMGR->getReflectFormat(); 886 REFLECTMGR->setReflectFormat(reflectFormat); 887 888 mProbeArrayEffect->setShaderConst("$CAPTURING", true); 889 cubeRefl.updateReflection(reflParams, clientProbe->getTransform().getPosition()+clientProbe->mProbeRefOffset); 890 mProbeArrayEffect->setShaderConst("$CAPTURING", false); 891 892 //Now, save out the maps 893 //create irridiance cubemap 894 if (cubeRefl.getCubemap()) 895 { 896 //Just to ensure we're prepped for the generation 897 clientProbe->createClientResources(); 898 899 //Prep it with whatever resolution we've dictated for our bake 900 clientProbe->mIrridianceMap->mCubemap->initDynamic(resolution, reflectFormat); 901 clientProbe->mPrefilterMap->mCubemap->initDynamic(resolution, reflectFormat); 902 903 GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); 904 905 IBLUtilities::GenerateIrradianceMap(renderTarget, cubeRefl.getCubemap(), clientProbe->mIrridianceMap->mCubemap); 906 IBLUtilities::GeneratePrefilterMap(renderTarget, cubeRefl.getCubemap(), prefilterMipLevels, clientProbe->mPrefilterMap->mCubemap); 907 908 U32 endMSTime = Platform::getRealMilliseconds(); 909 F32 diffTime = F32(endMSTime - startMSTime); 910 Con::warnf("RenderProbeMgr::bake() - Finished Capture! Took %g milliseconds", diffTime); 911 Con::warnf("RenderProbeMgr::bake() - Beginning save now!"); 912 913 IBLUtilities::SaveCubeMap(clientProbe->getIrradianceMapPath(), clientProbe->mIrridianceMap->mCubemap); 914 IBLUtilities::SaveCubeMap(clientProbe->getPrefilterMapPath(), clientProbe->mPrefilterMap->mCubemap); 915 } 916 else 917 { 918 Con::errorf("RenderProbeMgr::bake() - Didn't generate a valid scene capture cubemap, unable to generate prefilter and irradiance maps!"); 919 } 920 921 if (!renderWithProbes) 922 RenderProbeMgr::smRenderReflectionProbes = probeRenderState; 923 924 cubeRefl.unregisterReflector(); 925 926 U32 endMSTime = Platform::getRealMilliseconds(); 927 F32 diffTime = F32(endMSTime - startMSTime); 928 929 probe->setMaskBits(-1); 930 931 Con::warnf("RenderProbeMgr::bake() - Finished bake! Took %g milliseconds", diffTime); 932 REFLECTMGR->setReflectFormat(oldRefFmt); 933} 934 935void RenderProbeMgr::bakeProbes() 936{ 937 Vector<ReflectionProbe*> probes; 938 939 Scene::getRootScene()->findObjectByType<ReflectionProbe>(probes); 940 941 for (U32 i = 0; i < probes.size(); i++) 942 { 943 if (probes[i]->isClientObject()) 944 continue; 945 946 bakeProbe(probes[i]); 947 } 948} 949 950DefineEngineMethod(RenderProbeMgr, bakeProbe, void, (ReflectionProbe* probe), (nullAsType< ReflectionProbe*>()), 951 "@brief Bakes the cubemaps for a reflection probe\n\n.") 952{ 953 if(probe != nullptr) 954 object->bakeProbe(probe); 955} 956 957DefineEngineMethod(RenderProbeMgr, bakeProbes, void, (),, "@brief Iterates over all reflection probes in the scene and bakes their cubemaps\n\n.") 958{ 959 object->bakeProbes(); 960} 961