reflectionProbe.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "T3D/lighting/reflectionProbe.h"
  23. #include "math/mathIO.h"
  24. #include "scene/sceneRenderState.h"
  25. #include "console/consoleTypes.h"
  26. #include "core/stream/bitStream.h"
  27. #include "materials/baseMatInstance.h"
  28. #include "console/engineAPI.h"
  29. #include "gfx/gfxDrawUtil.h"
  30. #include "gfx/gfxDebugEvent.h"
  31. #include "gfx/gfxTransformSaver.h"
  32. #include "math/mathUtils.h"
  33. #include "gfx/bitmap/gBitmap.h"
  34. #include "core/stream/fileStream.h"
  35. #include "core/fileObject.h"
  36. #include "core/resourceManager.h"
  37. #include "console/simPersistId.h"
  38. #include "T3D/gameFunctions.h"
  39. #include "postFx/postEffect.h"
  40. #include "renderInstance/renderProbeMgr.h"
  41. #include "renderInstance/renderProbeMgr.h"
  42. #include "math/util/sphereMesh.h"
  43. #include "materials/materialManager.h"
  44. #include "math/util/matrixSet.h"
  45. #include "gfx/bitmap/cubemapSaver.h"
  46. #include "materials/materialFeatureTypes.h"
  47. #include "gfx/gfxTextureManager.h"
  48. #include "T3D/lighting/IBLUtilities.h"
  49. #include "scene/reflector.h"
  50. #include "T3D/gameTSCtrl.h"
  51. extern bool gEditingMission;
  52. extern ColorI gCanvasClearColor;
  53. bool ReflectionProbe::smRenderPreviewProbes = true;
  54. IMPLEMENT_CO_NETOBJECT_V1(ReflectionProbe);
  55. ConsoleDocClass(ReflectionProbe,
  56. "@brief An example scene object which renders a mesh.\n\n"
  57. "This class implements a basic SceneObject that can exist in the world at a "
  58. "3D position and render itself. There are several valid ways to render an "
  59. "object in Torque. This class implements the preferred rendering method which "
  60. "is to submit a MeshRenderInst along with a Material, vertex buffer, "
  61. "primitive buffer, and transform and allow the RenderMeshMgr handle the "
  62. "actual setup and rendering for you.\n\n"
  63. "See the C++ code for implementation details.\n\n"
  64. "@ingroup Examples\n");
  65. ImplementEnumType(ReflectProbeType,
  66. "Type of mesh data available in a shape.\n"
  67. "@ingroup gameObjects")
  68. { ProbeRenderInst::Sphere, "Sphere", "Sphere shaped" },
  69. { ProbeRenderInst::Box, "Box", "Box shape" }
  70. EndImplementEnumType;
  71. ImplementEnumType(IndrectLightingModeEnum,
  72. "Type of mesh data available in a shape.\n"
  73. "@ingroup gameObjects")
  74. { ReflectionProbe::NoIndirect, "No Lighting", "This probe does not provide any local indirect lighting data" },
  75. { ReflectionProbe::AmbientColor, "Ambient Color", "Adds a flat color to act as the local indirect lighting" },
  76. { ReflectionProbe::SphericalHarmonics, "Spherical Harmonics", "Creates spherical harmonics data based off the reflection data" },
  77. EndImplementEnumType;
  78. ImplementEnumType(ReflectionModeEnum,
  79. "Type of mesh data available in a shape.\n"
  80. "@ingroup gameObjects")
  81. { ReflectionProbe::NoReflection, "No Reflections", "This probe does not provide any local reflection data"},
  82. { ReflectionProbe::StaticCubemap, "Static Cubemap", "Uses a static CubemapData" },
  83. { ReflectionProbe::BakedCubemap, "Baked Cubemap", "Uses a cubemap baked from the probe's current position" },
  84. //{ ReflectionProbe::DynamicCubemap, "Dynamic Cubemap", "Uses a cubemap baked from the probe's current position, updated at a set rate" },
  85. EndImplementEnumType;
  86. //-----------------------------------------------------------------------------
  87. // Object setup and teardown
  88. //-----------------------------------------------------------------------------
  89. ReflectionProbe::ReflectionProbe()
  90. {
  91. // Flag this object so that it will always
  92. // be sent across the network to clients
  93. mNetFlags.set(Ghostable | ScopeAlways);
  94. mTypeMask = LightObjectType | MarkerObjectType;
  95. mProbeShapeType = ProbeRenderInst::Box;
  96. mIndrectLightingModeType = NoIndirect;
  97. mReflectionModeType = BakedCubemap;
  98. mEnabled = true;
  99. mBake = false;
  100. mDirty = false;
  101. mRadius = 10;
  102. mUseCubemap = false;
  103. mUseHDRCaptures = true;
  104. mStaticCubemap = NULL;
  105. mReflectionPath = "";
  106. mProbeUniqueID = "";
  107. mEditorShapeInst = NULL;
  108. mEditorShape = NULL;
  109. mRefreshRateMS = 200;
  110. mDynamicLastBakeMS = 0;
  111. mMaxDrawDistance = 75;
  112. mResourcesCreated = false;
  113. mProbeInfo = nullptr;
  114. mPrefilterSize = 64;
  115. mPrefilterMipLevels = mLog2(F32(mPrefilterSize));
  116. mPrefilterMap = nullptr;
  117. mIrridianceMap = nullptr;
  118. mProbePosOffset = Point3F::Zero;
  119. mEditPosOffset = false;
  120. mProbeInfoIdx = -1;
  121. mCaptureMask = REFLECTION_PROBE_CAPTURE_TYPEMASK;
  122. }
  123. ReflectionProbe::~ReflectionProbe()
  124. {
  125. if (mEditorShapeInst)
  126. SAFE_DELETE(mEditorShapeInst);
  127. if (mProbeInfo)
  128. SAFE_DELETE(mProbeInfo);
  129. if (mReflectionModeType != StaticCubemap && mStaticCubemap)
  130. mStaticCubemap->deleteObject();
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Object Editing
  134. //-----------------------------------------------------------------------------
  135. void ReflectionProbe::initPersistFields()
  136. {
  137. addGroup("Rendering");
  138. addProtectedField("enabled", TypeBool, Offset(mEnabled, ReflectionProbe),
  139. &_setEnabled, &defaultProtectedGetFn, "Regenerate Voxel Grid");
  140. addField("ProbeShape", TypeReflectProbeType, Offset(mProbeShapeType, ReflectionProbe),
  141. "The type of mesh data to use for collision queries.");
  142. addField("radius", TypeF32, Offset(mRadius, ReflectionProbe), "The name of the material used to render the mesh.");
  143. addField("posOffset", TypePoint3F, Offset(mProbePosOffset, ReflectionProbe), "");
  144. //addProtectedField("EditPosOffset", TypeBool, Offset(mEditPosOffset, ReflectionProbe),
  145. // &_toggleEditPosOffset, &defaultProtectedGetFn, "Toggle Edit Pos Offset Mode", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
  146. endGroup("Rendering");
  147. addGroup("Reflection");
  148. addField("ReflectionMode", TypeReflectionModeEnum, Offset(mReflectionModeType, ReflectionProbe),
  149. "The type of mesh data to use for collision queries.");
  150. addField("reflectionPath", TypeImageFilename, Offset(mReflectionPath, ReflectionProbe),
  151. "The type of mesh data to use for collision queries.");
  152. addField("StaticCubemap", TypeCubemapName, Offset(mCubemapName, ReflectionProbe), "Cubemap used instead of reflection texture if fullReflect is off.");
  153. addProtectedField("Bake", TypeBool, Offset(mBake, ReflectionProbe),
  154. &_doBake, &defaultProtectedGetFn, "Regenerate Voxel Grid", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
  155. endGroup("Reflection");
  156. Con::addVariable("$Light::renderReflectionProbes", TypeBool, &RenderProbeMgr::smRenderReflectionProbes,
  157. "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
  158. "@note Only works for shadow mapped lights.\n\n"
  159. "@ingroup Lighting");
  160. Con::addVariable("$Light::renderPreviewProbes", TypeBool, &ReflectionProbe::smRenderPreviewProbes,
  161. "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
  162. "@note Only works for shadow mapped lights.\n\n"
  163. "@ingroup Lighting");
  164. // SceneObject already handles exposing the transform
  165. Parent::initPersistFields();
  166. }
  167. void ReflectionProbe::inspectPostApply()
  168. {
  169. Parent::inspectPostApply();
  170. mDirty = true;
  171. // Flag the network mask to send the updates
  172. // to the client object
  173. setMaskBits(-1);
  174. }
  175. bool ReflectionProbe::_setEnabled(void *object, const char *index, const char *data)
  176. {
  177. ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object);
  178. probe->mEnabled = dAtob(data);
  179. probe->setMaskBits(-1);
  180. return true;
  181. }
  182. bool ReflectionProbe::_doBake(void *object, const char *index, const char *data)
  183. {
  184. ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object);
  185. //if (probe->mDirty)
  186. // probe->bake(probe->mReflectionPath, 256);
  187. ReflectionProbe *clientProbe = (ReflectionProbe*)probe->getClientObject();
  188. if (clientProbe)
  189. {
  190. clientProbe->bake(clientProbe->mReflectionPath, 64);
  191. }
  192. return false;
  193. }
  194. bool ReflectionProbe::_toggleEditPosOffset(void *object, const char *index, const char *data)
  195. {
  196. ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object);
  197. probe->mEditPosOffset = !probe->mEditPosOffset;
  198. //if (probe->mDirty)
  199. // probe->bake(probe->mReflectionPath, 256);
  200. return false;
  201. }
  202. bool ReflectionProbe::onAdd()
  203. {
  204. if (!Parent::onAdd())
  205. return false;
  206. mEditPosOffset = false;
  207. mObjBox.minExtents.set(-1, -1, -1);
  208. mObjBox.maxExtents.set(1, 1, 1);
  209. //mObjScale.set(mRadius/2, mRadius/2, mRadius/2);
  210. // Skip our transform... it just dirties mask bits.
  211. Parent::setTransform(mObjToWorld);
  212. resetWorldBox();
  213. // Add this object to the scene
  214. addToScene();
  215. if (isServerObject())
  216. {
  217. if (!mPersistentId)
  218. mPersistentId = getOrCreatePersistentId();
  219. mProbeUniqueID = std::to_string(mPersistentId->getUUID().getHash()).c_str();
  220. }
  221. // Refresh this object's material (if any)
  222. if (isClientObject())
  223. {
  224. createGeometry();
  225. updateProbeParams();
  226. }
  227. setMaskBits(-1);
  228. return true;
  229. }
  230. void ReflectionProbe::onRemove()
  231. {
  232. // Remove this object from the scene
  233. removeFromScene();
  234. Parent::onRemove();
  235. }
  236. void ReflectionProbe::handleDeleteAction()
  237. {
  238. //we're deleting it?
  239. //Then we need to clear out the processed cubemaps(if we have them)
  240. String prefilPath = getPrefilterMapPath();
  241. if (Platform::isFile(prefilPath))
  242. {
  243. Platform::fileDelete(prefilPath);
  244. }
  245. String irrPath = getIrradianceMapPath();
  246. if (Platform::isFile(irrPath))
  247. {
  248. Platform::fileDelete(irrPath);
  249. }
  250. Parent::handleDeleteAction();
  251. }
  252. void ReflectionProbe::setTransform(const MatrixF & mat)
  253. {
  254. // Let SceneObject handle all of the matrix manipulation
  255. if (!mEditPosOffset)
  256. Parent::setTransform(mat);
  257. else
  258. mProbePosOffset = mat.getPosition();
  259. mDirty = true;
  260. // Dirty our network mask so that the new transform gets
  261. // transmitted to the client object
  262. setMaskBits(TransformMask);
  263. }
  264. U32 ReflectionProbe::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
  265. {
  266. // Allow the Parent to get a crack at writing its info
  267. U32 retMask = Parent::packUpdate(conn, mask, stream);
  268. // Write our transform information
  269. if (stream->writeFlag(mask & TransformMask))
  270. {
  271. mathWrite(*stream, getTransform());
  272. mathWrite(*stream, getScale());
  273. mathWrite(*stream, mProbePosOffset);
  274. }
  275. if (stream->writeFlag(mask & ShapeTypeMask))
  276. {
  277. stream->write((U32)mProbeShapeType);
  278. }
  279. if (stream->writeFlag(mask & UpdateMask))
  280. {
  281. stream->write(mRadius);
  282. }
  283. if (stream->writeFlag(mask & BakeInfoMask))
  284. {
  285. stream->write(mReflectionPath);
  286. stream->write(mProbeUniqueID);
  287. }
  288. if (stream->writeFlag(mask & EnabledMask))
  289. {
  290. stream->writeFlag(mEnabled);
  291. }
  292. if (stream->writeFlag(mask & ModeMask))
  293. {
  294. stream->write((U32)mIndrectLightingModeType);
  295. stream->write((U32)mReflectionModeType);
  296. }
  297. if (stream->writeFlag(mask & CubemapMask))
  298. {
  299. stream->writeFlag(mUseCubemap);
  300. stream->write(mCubemapName);
  301. }
  302. return retMask;
  303. }
  304. void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream)
  305. {
  306. // Let the Parent read any info it sent
  307. Parent::unpackUpdate(conn, stream);
  308. if (stream->readFlag()) // TransformMask
  309. {
  310. mathRead(*stream, &mObjToWorld);
  311. mathRead(*stream, &mObjScale);
  312. setTransform(mObjToWorld);
  313. mathRead(*stream, &mProbePosOffset);
  314. }
  315. if (stream->readFlag()) // ShapeTypeMask
  316. {
  317. U32 shapeType = ProbeRenderInst::Sphere;
  318. stream->read(&shapeType);
  319. mProbeShapeType = (ProbeRenderInst::ProbeShapeType)shapeType;
  320. createGeometry();
  321. }
  322. if (stream->readFlag()) // UpdateMask
  323. {
  324. stream->read(&mRadius);
  325. }
  326. if (stream->readFlag()) // BakeInfoMask
  327. {
  328. stream->read(&mReflectionPath);
  329. stream->read(&mProbeUniqueID);
  330. }
  331. if (stream->readFlag()) // EnabledMask
  332. {
  333. mEnabled = stream->readFlag();
  334. }
  335. bool isMaterialDirty = false;
  336. if (stream->readFlag()) // ModeMask
  337. {
  338. U32 indirectModeType = AmbientColor;
  339. stream->read(&indirectModeType);
  340. mIndrectLightingModeType = (IndrectLightingModeType)indirectModeType;
  341. U32 reflectModeType = BakedCubemap;
  342. stream->read(&reflectModeType);
  343. mReflectionModeType = (ReflectionModeType)reflectModeType;
  344. isMaterialDirty = true;
  345. }
  346. updateProbeParams();
  347. if (stream->readFlag()) // CubemapMask
  348. {
  349. mUseCubemap = stream->readFlag();
  350. String newCubemapName;
  351. stream->read(&mCubemapName);
  352. //if (newCubemapName != mCubemapName)
  353. {
  354. processStaticCubemap();
  355. }
  356. isMaterialDirty = true;
  357. }
  358. if (isMaterialDirty)
  359. {
  360. updateMaterial();
  361. }
  362. PROBEMGR->updateProbes();
  363. }
  364. void ReflectionProbe::createGeometry()
  365. {
  366. // Clean up our previous shape
  367. if (mEditorShapeInst)
  368. SAFE_DELETE(mEditorShapeInst);
  369. mEditorShape = NULL;
  370. String shapeFile = "tools/resources/ReflectProbeSphere.dae";
  371. // Attempt to get the resource from the ResourceManager
  372. mEditorShape = ResourceManager::get().load(shapeFile);
  373. if (mEditorShape)
  374. {
  375. mEditorShapeInst = new TSShapeInstance(mEditorShape, isClientObject());
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Object Rendering
  380. //-----------------------------------------------------------------------------
  381. void ReflectionProbe::updateProbeParams()
  382. {
  383. if (mProbeInfo == nullptr)
  384. {
  385. mProbeInfo = new ProbeRenderInst();
  386. mProbeInfoIdx = ProbeRenderInst::all.size() - 1;
  387. mProbeInfo->mIsEnabled = false;
  388. }
  389. updateMaterial();
  390. mProbeInfo->mAmbient = LinearColorF(0, 0, 0, 0);
  391. mProbeInfo->mProbeShapeType = mProbeShapeType;
  392. mProbeInfo->mTransform = getWorldTransform();
  393. mProbeInfo->mTransform.inverse();
  394. mProbeInfo->setPosition(getPosition());
  395. //Point3F pos = mProbeInfo->mTransform.getPosition();
  396. //Update the bounds
  397. //mObjBox.minExtents.set(-1, -1, -1);
  398. //mObjBox.maxExtents.set(1, 1, 1);
  399. mObjScale.set(mRadius, mRadius, mRadius);
  400. // Skip our transform... it just dirties mask bits.
  401. Parent::setTransform(mObjToWorld);
  402. resetWorldBox();
  403. mProbeInfo->mBounds = mWorldBox;
  404. mProbeInfo->mRadius = mRadius;
  405. mProbeInfo->mIsSkylight = false;
  406. mProbeInfo->mProbePosOffset = mProbePosOffset;
  407. mProbeInfo->mDirty = true;
  408. mProbeInfo->mScore = mMaxDrawDistance;
  409. }
  410. void ReflectionProbe::processStaticCubemap()
  411. {
  412. if (mReflectionModeType != StaticCubemap)
  413. return;
  414. createClientResources();
  415. Sim::findObject(mCubemapName, mStaticCubemap);
  416. if (!mStaticCubemap)
  417. {
  418. Con::errorf("ReflectionProbe::updateMaterial() - unable to find static cubemap file!");
  419. return;
  420. }
  421. if (mStaticCubemap->mCubemap == nullptr)
  422. {
  423. mStaticCubemap->createMap();
  424. mStaticCubemap->updateFaces();
  425. }
  426. String prefilPath = getPrefilterMapPath();
  427. String irrPath = getIrradianceMapPath();
  428. if (mUseHDRCaptures)
  429. {
  430. mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
  431. mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
  432. }
  433. else
  434. {
  435. mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
  436. mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
  437. }
  438. //if (!Platform::isFile(irrPath) || !Platform::isFile(prefilPath))
  439. {
  440. GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
  441. IBLUtilities::GenerateIrradianceMap(renderTarget, mStaticCubemap->mCubemap, mIrridianceMap->mCubemap);
  442. IBLUtilities::GeneratePrefilterMap(renderTarget, mStaticCubemap->mCubemap, mPrefilterMipLevels, mPrefilterMap->mCubemap);
  443. IBLUtilities::SaveCubeMap(getIrradianceMapPath(), mIrridianceMap->mCubemap);
  444. IBLUtilities::SaveCubeMap(getPrefilterMapPath(), mPrefilterMap->mCubemap);
  445. }
  446. mProbeInfo->mCubemap = mPrefilterMap->mCubemap;
  447. mProbeInfo->mIrradianceCubemap = mIrridianceMap->mCubemap;
  448. }
  449. void ReflectionProbe::updateMaterial()
  450. {
  451. createClientResources();
  452. if (mReflectionModeType != DynamicCubemap)
  453. {
  454. mProbeInfo->mCubeReflector.unregisterReflector();
  455. if ((mReflectionModeType == BakedCubemap) && !mProbeUniqueID.isEmpty())
  456. {
  457. if (mPrefilterMap != nullptr && mPrefilterMap->mCubemap.isValid())
  458. {
  459. mProbeInfo->mCubemap = mPrefilterMap->mCubemap;
  460. }
  461. else
  462. {
  463. mEnabled = false;
  464. }
  465. if (mIrridianceMap != nullptr && mIrridianceMap->mCubemap.isValid())
  466. {
  467. mProbeInfo->mIrradianceCubemap = mIrridianceMap->mCubemap;
  468. }
  469. else
  470. {
  471. mEnabled = false;
  472. }
  473. }
  474. }
  475. else
  476. {
  477. if (mReflectionModeType == DynamicCubemap && !mDynamicCubemap.isNull())
  478. {
  479. mProbeInfo->mCubemap = mDynamicCubemap;
  480. mProbeInfo->mCubeReflector.registerReflector(this, reflectorDesc); //need to decide how we wanna do the reflectorDesc. static name or a field
  481. }
  482. else
  483. {
  484. mEnabled = false;
  485. }
  486. }
  487. if (mBrdfTexture.isValid())
  488. {
  489. mProbeInfo->mBRDFTexture = &mBrdfTexture;
  490. }
  491. //Make us ready to render
  492. if (mEnabled)
  493. mProbeInfo->mIsEnabled = true;
  494. else
  495. mProbeInfo->mIsEnabled = false;
  496. }
  497. bool ReflectionProbe::createClientResources()
  498. {
  499. //irridiance resources
  500. if (!mIrridianceMap)
  501. {
  502. mIrridianceMap = new CubemapData();
  503. mIrridianceMap->registerObject();
  504. mIrridianceMap->createMap();
  505. }
  506. String irrPath = getIrradianceMapPath();
  507. if (Platform::isFile(irrPath))
  508. {
  509. mIrridianceMap->setCubemapFile(FileName(irrPath));
  510. mIrridianceMap->updateFaces();
  511. }
  512. if (mIrridianceMap->mCubemap.isNull())
  513. Con::errorf("ReflectionProbe::createClientResources() - Unable to load baked irradiance map at %s", getIrradianceMapPath().c_str());
  514. //
  515. if (!mPrefilterMap)
  516. {
  517. mPrefilterMap = new CubemapData();
  518. mPrefilterMap->registerObject();
  519. mPrefilterMap->createMap();
  520. }
  521. String prefilPath = getPrefilterMapPath();
  522. if (Platform::isFile(prefilPath))
  523. {
  524. mPrefilterMap->setCubemapFile(FileName(prefilPath));
  525. mPrefilterMap->updateFaces();
  526. }
  527. if (mPrefilterMap->mCubemap.isNull())
  528. Con::errorf("ReflectionProbe::createClientResources() - Unable to load baked prefilter map at %s", getPrefilterMapPath().c_str());
  529. //brdf lookup texture
  530. String brdfPath = Con::getVariable("$Core::BRDFTexture", "core/art/pbr/brdfTexture.dds");
  531. mBrdfTexture = TEXMGR->createTexture(brdfPath, &GFXTexturePersistentProfile);
  532. if (!mBrdfTexture)
  533. {
  534. return false;
  535. }
  536. mResourcesCreated = true;
  537. return true;
  538. }
  539. void ReflectionProbe::generateTextures()
  540. {
  541. }
  542. void ReflectionProbe::prepRenderImage(SceneRenderState *state)
  543. {
  544. if (!mEnabled || !RenderProbeMgr::smRenderReflectionProbes)
  545. return;
  546. Point3F distVec = getRenderPosition() - state->getCameraPosition();
  547. F32 dist = distVec.len();
  548. //Culling distance. Can be adjusted for performance options considerations via the scalar
  549. if (dist > mMaxDrawDistance * Con::getFloatVariable("$pref::GI::ProbeDrawDistScale", 1.0))
  550. {
  551. mProbeInfo->mScore = mMaxDrawDistance;
  552. return;
  553. }
  554. if (mReflectionModeType == DynamicCubemap && mRefreshRateMS < (Platform::getRealMilliseconds() - mDynamicLastBakeMS))
  555. {
  556. bake("", 32);
  557. mDynamicLastBakeMS = Platform::getRealMilliseconds();
  558. }
  559. //Submit our probe to actually do the probe action
  560. // Get a handy pointer to our RenderPassmanager
  561. //RenderPassManager *renderPass = state->getRenderPass();
  562. //Update our score based on our radius, distance
  563. mProbeInfo->mScore = mProbeInfo->mRadius/mMax(dist,1.0f);
  564. Point3F vect = distVec;
  565. vect.normalizeSafe();
  566. mProbeInfo->mScore *= mMax(mAbs(mDot(vect, state->getCameraTransform().getForwardVector())),0.001f);
  567. //Register
  568. PROBEMGR->registerProbe(mProbeInfoIdx);
  569. if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr)
  570. {
  571. GFXTransformSaver saver;
  572. // Calculate the distance of this object from the camera
  573. Point3F cameraOffset;
  574. getRenderTransform().getColumn(3, &cameraOffset);
  575. cameraOffset -= state->getDiffuseCameraPosition();
  576. dist = cameraOffset.len();
  577. if (dist < 0.01f)
  578. dist = 0.01f;
  579. // Set up the LOD for the shape
  580. F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
  581. mEditorShapeInst->setDetailFromDistance(state, dist * invScale);
  582. // Make sure we have a valid level of detail
  583. if (mEditorShapeInst->getCurrentDetail() < 0)
  584. return;
  585. BaseMatInstance* probePrevMat = mEditorShapeInst->getMaterialList()->getMaterialInst(0);
  586. setPreviewMatParameters(state, probePrevMat);
  587. // GFXTransformSaver is a handy helper class that restores
  588. // the current GFX matrices to their original values when
  589. // it goes out of scope at the end of the function
  590. // Set up our TS render state
  591. TSRenderState rdata;
  592. rdata.setSceneState(state);
  593. rdata.setFadeOverride(1.0f);
  594. if(mReflectionModeType != DynamicCubemap)
  595. rdata.setCubemap(mPrefilterMap->mCubemap);
  596. else
  597. rdata.setCubemap(mDynamicCubemap);
  598. // We might have some forward lit materials
  599. // so pass down a query to gather lights.
  600. LightQuery query;
  601. query.init(getWorldSphere());
  602. rdata.setLightQuery(&query);
  603. // Set the world matrix to the objects render transform
  604. MatrixF mat = getRenderTransform();
  605. mat.scale(Point3F(1, 1, 1));
  606. Point3F centerPos = mat.getPosition();
  607. centerPos += mProbePosOffset;
  608. mat.setPosition(centerPos);
  609. GFX->setWorldMatrix(mat);
  610. // Animate the the shape
  611. mEditorShapeInst->animate();
  612. // Allow the shape to submit the RenderInst(s) for itself
  613. mEditorShapeInst->render(rdata);
  614. saver.restore();
  615. }
  616. // If the light is selected or light visualization
  617. // is enabled then register the callback.
  618. const bool isSelectedInEditor = (gEditingMission && isSelected());
  619. if (isSelectedInEditor)
  620. {
  621. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  622. ri->renderDelegate.bind(this, &ReflectionProbe::_onRenderViz);
  623. ri->type = RenderPassManager::RIT_Editor;
  624. state->getRenderPass()->addInst(ri);
  625. }
  626. }
  627. void ReflectionProbe::_onRenderViz(ObjectRenderInst *ri,
  628. SceneRenderState *state,
  629. BaseMatInstance *overrideMat)
  630. {
  631. if (!RenderProbeMgr::smRenderReflectionProbes)
  632. return;
  633. GFXDrawUtil *draw = GFX->getDrawUtil();
  634. GFXStateBlockDesc desc;
  635. desc.setZReadWrite(true, false);
  636. desc.setCullMode(GFXCullNone);
  637. desc.setBlend(true);
  638. // Base the sphere color on the light color.
  639. ColorI color = ColorI::WHITE;
  640. color.alpha = 25;
  641. if (mProbeShapeType == ProbeRenderInst::Sphere)
  642. {
  643. draw->drawSphere(desc, mRadius, getPosition(), color);
  644. }
  645. else
  646. {
  647. const MatrixF worldToObjectXfm = getTransform();
  648. Box3F cube(-Point3F(mRadius, mRadius, mRadius),Point3F(mRadius, mRadius, mRadius));
  649. Box3F wb = getWorldBox();
  650. cube.setCenter(getPosition()+mProbePosOffset);
  651. wb.setCenter(getPosition() + mProbePosOffset);
  652. draw->drawCube(desc, cube, color, &worldToObjectXfm);
  653. draw->drawCube(desc, wb, color, &worldToObjectXfm);
  654. }
  655. }
  656. void ReflectionProbe::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat)
  657. {
  658. if (!mat->getFeatures().hasFeature(MFT_isDeferred))
  659. return;
  660. //Set up the params
  661. MaterialParameters *matParams = mat->getMaterialParameters();
  662. //Get the deferred render target
  663. NamedTexTarget* deferredTexTarget = NamedTexTarget::find("deferred");
  664. GFXTextureObject *deferredTexObject = deferredTexTarget->getTexture();
  665. if (!deferredTexObject)
  666. return;
  667. GFX->setTexture(0, deferredTexObject);
  668. //Set the cubemap
  669. GFX->setCubeTexture(1, mPrefilterMap->mCubemap);
  670. //Set the invViewMat
  671. MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet();
  672. const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera();
  673. MaterialParameterHandle *invViewMat = mat->getMaterialParameterHandle("$invViewMat");
  674. matParams->setSafe(invViewMat, worldToCameraXfm);
  675. }
  676. DefineEngineMethod(ReflectionProbe, postApply, void, (), ,
  677. "A utility method for forcing a network update.\n")
  678. {
  679. object->inspectPostApply();
  680. }
  681. String ReflectionProbe::getPrefilterMapPath()
  682. {
  683. if (mReflectionPath.isEmpty() || mProbeUniqueID.isEmpty())
  684. {
  685. Con::errorf("ReflectionProbe::getPrefilterMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!");
  686. return "";
  687. }
  688. char fileName[256];
  689. dSprintf(fileName, 256, "%s%s_Prefilter.dds", mReflectionPath.c_str(), mProbeUniqueID.c_str());
  690. return fileName;
  691. }
  692. String ReflectionProbe::getIrradianceMapPath()
  693. {
  694. if (mReflectionPath.isEmpty() || mProbeUniqueID.isEmpty())
  695. {
  696. Con::errorf("ReflectionProbe::getIrradianceMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!");
  697. return "";
  698. }
  699. char fileName[256];
  700. dSprintf(fileName, 256, "%s%s_Irradiance.dds", mReflectionPath.c_str(), mProbeUniqueID.c_str());
  701. return fileName;
  702. }
  703. void ReflectionProbe::bake(String outputPath, S32 resolution, bool renderWithProbes)
  704. {
  705. GFXDEBUGEVENT_SCOPE(ReflectionProbe_Bake, ColorI::WHITE);
  706. Con::warnf("ReflectionProbe::bake() - Beginning bake!");
  707. U32 startMSTime = Platform::getRealMilliseconds();
  708. GFXCubemapHandle sceneCaptureCubemap;
  709. if (mReflectionModeType == DynamicCubemap && mDynamicCubemap.isNull())
  710. {
  711. //this is wholely reundant when we actually use the proper dynamic cube reflector
  712. mDynamicCubemap = GFX->createCubemap();
  713. if(mUseHDRCaptures)
  714. mDynamicCubemap->initDynamic(resolution, GFXFormatR16G16B16A16F);
  715. else
  716. mDynamicCubemap->initDynamic(resolution, GFXFormatB8G8R8A8);
  717. sceneCaptureCubemap = mDynamicCubemap;
  718. }
  719. else if (mReflectionModeType != DynamicCubemap)
  720. {
  721. //Prep our bake path
  722. if (mReflectionPath.isEmpty())
  723. {
  724. Con::errorf("ReflectionProbe::bake() - Unable to bake our captures because probe doesn't have a path set");
  725. return;
  726. }
  727. if (mProbeUniqueID.isEmpty())
  728. {
  729. Con::errorf("ReflectionProbe::bake() - Unable to bake our captures because probe doesn't have a unique ID set");
  730. return;
  731. }
  732. }
  733. bool validCubemap = true;
  734. // Save the current transforms so we can restore
  735. // it for child control rendering below.
  736. GFXTransformSaver saver;
  737. bool probeRenderState = RenderProbeMgr::smRenderReflectionProbes;
  738. if (!renderWithProbes)
  739. RenderProbeMgr::smRenderReflectionProbes = false;
  740. F32 farPlane = 1000.0f;
  741. ReflectorDesc reflDesc;
  742. reflDesc.texSize = resolution;
  743. reflDesc.farDist = farPlane;
  744. reflDesc.detailAdjust = 1;
  745. reflDesc.objectTypeMask = -1;
  746. CubeReflector cubeRefl;
  747. cubeRefl.registerReflector(this, &reflDesc);
  748. ReflectParams reflParams;
  749. //need to get the query somehow. Likely do some sort of get function to fetch from the guiTSControl that's active
  750. CameraQuery query; //need to get the last cameraQuery
  751. query.fov = 90; //90 degree slices for each of the 6 sides
  752. query.nearPlane = 0.1f;
  753. query.farPlane = farPlane;
  754. query.headMatrix = MatrixF();
  755. query.cameraMatrix = getTransform();
  756. Frustum culler;
  757. culler.set(false,
  758. query.fov,
  759. (F32)resolution / (F32)resolution,
  760. query.nearPlane,
  761. query.farPlane,
  762. query.cameraMatrix);
  763. S32 stereoTarget = GFX->getCurrentStereoTarget();
  764. Point2I maxRes(2048, 2048); //basically a boundary so we don't go over this and break stuff
  765. reflParams.culler = culler;
  766. reflParams.eyeId = stereoTarget;
  767. reflParams.query = &query;
  768. reflParams.startOfUpdateMs = startMSTime;
  769. reflParams.viewportExtent = maxRes;
  770. cubeRefl.updateReflection(reflParams);
  771. //Now, save out the maps
  772. //create irridiance cubemap
  773. if (cubeRefl.getCubemap())
  774. {
  775. //Just to ensure we're prepped for the generation
  776. createClientResources();
  777. //Prep it with whatever resolution we've dictated for our bake
  778. if (mUseHDRCaptures)
  779. {
  780. mIrridianceMap->mCubemap->initDynamic(resolution, GFXFormatR16G16B16A16F);
  781. mPrefilterMap->mCubemap->initDynamic(resolution, GFXFormatR16G16B16A16F);
  782. }
  783. else
  784. {
  785. mIrridianceMap->mCubemap->initDynamic(resolution, GFXFormatR8G8B8A8);
  786. mPrefilterMap->mCubemap->initDynamic(resolution, GFXFormatR8G8B8A8);
  787. }
  788. GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
  789. IBLUtilities::GenerateIrradianceMap(renderTarget, cubeRefl.getCubemap(), mIrridianceMap->mCubemap);
  790. IBLUtilities::GeneratePrefilterMap(renderTarget, cubeRefl.getCubemap(), mPrefilterMipLevels, mPrefilterMap->mCubemap);
  791. IBLUtilities::SaveCubeMap(getIrradianceMapPath(), mIrridianceMap->mCubemap);
  792. IBLUtilities::SaveCubeMap(getPrefilterMapPath(), mPrefilterMap->mCubemap);
  793. }
  794. else
  795. {
  796. Con::errorf("ReflectionProbe::bake() - Didn't generate a valid scene capture cubemap, unable to generate prefilter and irradiance maps!");
  797. }
  798. if(!renderWithProbes)
  799. RenderProbeMgr::smRenderReflectionProbes = probeRenderState;
  800. setMaskBits(CubemapMask);
  801. cubeRefl.unregisterReflector();
  802. U32 endMSTime = Platform::getRealMilliseconds();
  803. F32 diffTime = F32(endMSTime - startMSTime);
  804. Con::warnf("ReflectionProbe::bake() - Finished bake! Took %g milliseconds", diffTime);
  805. }
  806. DefineEngineMethod(ReflectionProbe, Bake, void, (String outputPath, S32 resolution, bool renderWithProbes), ("", 64, false),
  807. "@brief returns true if control object is inside the fog\n\n.")
  808. {
  809. ReflectionProbe *clientProbe = (ReflectionProbe*)object->getClientObject();
  810. if (clientProbe)
  811. {
  812. clientProbe->bake(outputPath, resolution, renderWithProbes);
  813. }
  814. //object->bake(outputPath, resolution);
  815. }