Torque3D Documentation / _generateds / renderProbeMgr.cpp

renderProbeMgr.cpp

Engine/source/renderInstance/renderProbeMgr.cpp

More...

Public Defines

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