skylight.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  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/Skylight.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 <string>
  39. #include "T3D/gameFunctions.h"
  40. #include "postFx/postEffect.h"
  41. #include "renderInstance/renderProbeMgr.h"
  42. #include "lighting/probeManager.h"
  43. #include "math/util/sphereMesh.h"
  44. #include "materials/materialManager.h"
  45. #include "math/util/matrixSet.h"
  46. #include "gfx/bitmap/cubemapSaver.h"
  47. #include "materials/materialFeatureTypes.h"
  48. #include "materials/shaderData.h"
  49. #include "gfx/gfxTextureManager.h"
  50. #include "gfx/bitmap/imageUtils.h"
  51. #include "T3D/lighting/IBLUtilities.h"
  52. extern bool gEditingMission;
  53. extern ColorI gCanvasClearColor;
  54. bool Skylight::smRenderSkylights = true;
  55. bool Skylight::smRenderPreviewProbes = true;
  56. IMPLEMENT_CO_NETOBJECT_V1(Skylight);
  57. ConsoleDocClass(Skylight,
  58. "@brief An example scene object which renders a mesh.\n\n"
  59. "This class implements a basic SceneObject that can exist in the world at a "
  60. "3D position and render itself. There are several valid ways to render an "
  61. "object in Torque. This class implements the preferred rendering method which "
  62. "is to submit a MeshRenderInst along with a Material, vertex buffer, "
  63. "primitive buffer, and transform and allow the RenderMeshMgr handle the "
  64. "actual setup and rendering for you.\n\n"
  65. "See the C++ code for implementation details.\n\n"
  66. "@ingroup Examples\n");
  67. ImplementEnumType(SkylightReflectionModeEnum,
  68. "Type of mesh data available in a shape.\n"
  69. "@ingroup gameObjects")
  70. { Skylight::StaticCubemap, "Static Cubemap", "Uses a static CubemapData" },
  71. { Skylight::BakedCubemap, "Baked Cubemap", "Uses a cubemap baked from the probe's current position" },
  72. EndImplementEnumType;
  73. //-----------------------------------------------------------------------------
  74. // Object setup and teardown
  75. //-----------------------------------------------------------------------------
  76. Skylight::Skylight()
  77. {
  78. // Flag this object so that it will always
  79. // be sent across the network to clients
  80. mNetFlags.set(Ghostable | ScopeAlways);
  81. mTypeMask = LightObjectType | MarkerObjectType;
  82. mReflectionModeType = StaticCubemap;
  83. mEnabled = true;
  84. mBake = false;
  85. mDirty = false;
  86. mCubemap = NULL;
  87. mReflectionPath = "";
  88. mProbeUniqueID = "";
  89. mEditorShapeInst = NULL;
  90. mEditorShape = NULL;
  91. mIrridianceMap = NULL;
  92. mPrefilterMap = NULL;
  93. mBrdfTexture = NULL;
  94. mResourcesCreated = false;
  95. mPrefilterSize = 512;
  96. mPrefilterMipLevels = 6;
  97. mProbeInfo = new ProbeInfo();
  98. }
  99. Skylight::~Skylight()
  100. {
  101. if (mEditorShapeInst)
  102. SAFE_DELETE(mEditorShapeInst);
  103. if (mReflectionModeType != StaticCubemap && mCubemap)
  104. mCubemap->deleteObject();
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Object Editing
  108. //-----------------------------------------------------------------------------
  109. void Skylight::initPersistFields()
  110. {
  111. addGroup("Rendering");
  112. addProtectedField("enabled", TypeBool, Offset(mEnabled, Skylight),
  113. &_setEnabled, &defaultProtectedGetFn, "Regenerate Voxel Grid");
  114. endGroup("Rendering");
  115. addGroup("Reflection");
  116. //addField("ReflectionMode", TypeSkylightReflectionModeEnum, Offset(mReflectionModeType, Skylight),
  117. // "The type of mesh data to use for collision queries.");
  118. //addField("reflectionPath", TypeImageFilename, Offset(mReflectionPath, Skylight),
  119. // "The type of mesh data to use for collision queries.");
  120. addField("StaticCubemap", TypeCubemapName, Offset(mCubemapName, Skylight), "Cubemap used instead of reflection texture if fullReflect is off.");
  121. //addProtectedField("Bake", TypeBool, Offset(mBake, Skylight),
  122. // &_doBake, &defaultProtectedGetFn, "Regenerate Voxel Grid", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
  123. endGroup("Reflection");
  124. Con::addVariable("$Light::renderSkylights", TypeBool, &Skylight::smRenderSkylights,
  125. "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
  126. "@note Only works for shadow mapped lights.\n\n"
  127. "@ingroup Lighting");
  128. Con::addVariable("$Light::renderPreviewProbes", TypeBool, &Skylight::smRenderPreviewProbes,
  129. "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
  130. "@note Only works for shadow mapped lights.\n\n"
  131. "@ingroup Lighting");
  132. // SceneObject already handles exposing the transform
  133. Parent::initPersistFields();
  134. }
  135. void Skylight::inspectPostApply()
  136. {
  137. Parent::inspectPostApply();
  138. mDirty = true;
  139. // Flag the network mask to send the updates
  140. // to the client object
  141. setMaskBits(-1);
  142. }
  143. bool Skylight::_setEnabled(void *object, const char *index, const char *data)
  144. {
  145. Skylight* probe = reinterpret_cast< Skylight* >(object);
  146. probe->mEnabled = dAtob(data);
  147. probe->setMaskBits(-1);
  148. return true;
  149. }
  150. bool Skylight::_doBake(void *object, const char *index, const char *data)
  151. {
  152. Skylight* probe = reinterpret_cast< Skylight* >(object);
  153. if (probe->mDirty)
  154. probe->bake(probe->mReflectionPath, 256);
  155. return false;
  156. }
  157. bool Skylight::onAdd()
  158. {
  159. if (!Parent::onAdd())
  160. return false;
  161. mObjBox.minExtents.set(-1, -1, -1);
  162. mObjBox.maxExtents.set(1, 1, 1);
  163. // Skip our transform... it just dirties mask bits.
  164. Parent::setTransform(mObjToWorld);
  165. resetWorldBox();
  166. // Add this object to the scene
  167. addToScene();
  168. if (isServerObject())
  169. {
  170. if (!mPersistentId)
  171. mPersistentId = getOrCreatePersistentId();
  172. mProbeUniqueID = std::to_string(mPersistentId->getUUID().getHash()).c_str();
  173. }
  174. // Refresh this object's material (if any)
  175. if (isClientObject())
  176. updateMaterial();
  177. setMaskBits(-1);
  178. return true;
  179. }
  180. void Skylight::onRemove()
  181. {
  182. // Remove this object from the scene
  183. removeFromScene();
  184. Parent::onRemove();
  185. }
  186. void Skylight::setTransform(const MatrixF & mat)
  187. {
  188. // Let SceneObject handle all of the matrix manipulation
  189. Parent::setTransform(mat);
  190. mDirty = true;
  191. // Dirty our network mask so that the new transform gets
  192. // transmitted to the client object
  193. setMaskBits(TransformMask);
  194. }
  195. U32 Skylight::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
  196. {
  197. // Allow the Parent to get a crack at writing its info
  198. U32 retMask = Parent::packUpdate(conn, mask, stream);
  199. if (stream->writeFlag(mask & InitialUpdateMask))
  200. {
  201. //initial work, just in case?
  202. }
  203. // Write our transform information
  204. if (stream->writeFlag(mask & TransformMask))
  205. {
  206. mathWrite(*stream, getTransform());
  207. mathWrite(*stream, getScale());
  208. }
  209. /*if (stream->writeFlag(mask & BakeInfoMask))
  210. {
  211. stream->write(mReflectionPath);
  212. stream->write(mProbeUniqueID);
  213. }*/
  214. if (stream->writeFlag(mask & EnabledMask))
  215. {
  216. stream->writeFlag(mEnabled);
  217. }
  218. /*if (stream->writeFlag(mask & ModeMask))
  219. {
  220. stream->write((U32)mReflectionModeType);
  221. }*/
  222. if (stream->writeFlag(mask & CubemapMask))
  223. {
  224. stream->write(mCubemapName);
  225. }
  226. return retMask;
  227. }
  228. void Skylight::unpackUpdate(NetConnection *conn, BitStream *stream)
  229. {
  230. // Let the Parent read any info it sent
  231. Parent::unpackUpdate(conn, stream);
  232. if (stream->readFlag())
  233. {
  234. //some initial work?
  235. createGeometry();
  236. }
  237. if (stream->readFlag()) // TransformMask
  238. {
  239. mathRead(*stream, &mObjToWorld);
  240. mathRead(*stream, &mObjScale);
  241. setTransform(mObjToWorld);
  242. }
  243. /*if (stream->readFlag()) // BakeInfoMask
  244. {
  245. stream->read(&mReflectionPath);
  246. stream->read(&mProbeUniqueID);
  247. }*/
  248. if (stream->readFlag()) // EnabledMask
  249. {
  250. mEnabled = stream->readFlag();
  251. }
  252. bool isMaterialDirty = false;
  253. /*if (stream->readFlag()) // ModeMask
  254. {
  255. U32 reflectModeType = StaticCubemap;
  256. stream->read(&reflectModeType);
  257. mReflectionModeType = (ReflectionModeType)reflectModeType;
  258. isMaterialDirty = true;
  259. }*/
  260. if (stream->readFlag()) // CubemapMask
  261. {
  262. stream->read(&mCubemapName);
  263. isMaterialDirty = true;
  264. }
  265. updateProbeParams();
  266. if(isMaterialDirty)
  267. updateMaterial();
  268. }
  269. void Skylight::createGeometry()
  270. {
  271. // Clean up our previous shape
  272. if (mEditorShapeInst)
  273. SAFE_DELETE(mEditorShapeInst);
  274. mEditorShape = NULL;
  275. String shapeFile = "tools/resources/ReflectProbeSphere.dae";
  276. // Attempt to get the resource from the ResourceManager
  277. mEditorShape = ResourceManager::get().load(shapeFile);
  278. if (mEditorShape)
  279. {
  280. mEditorShapeInst = new TSShapeInstance(mEditorShape, isClientObject());
  281. }
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Object Rendering
  285. //-----------------------------------------------------------------------------
  286. void Skylight::updateProbeParams()
  287. {
  288. if (mProbeInfo == nullptr)
  289. return;
  290. mProbeInfo->mIntensity = 1;
  291. mProbeInfo->mAmbient = LinearColorF(0, 0, 0, 0);
  292. mProbeInfo->mProbeShapeType = ProbeInfo::Sphere;
  293. mProbeInfo->setPosition(getPosition());
  294. //Update the bounds
  295. mObjBox.minExtents.set(-1, -1, -1);
  296. mObjBox.maxExtents.set(1, 1, 1);
  297. // Skip our transform... it just dirties mask bits.
  298. Parent::setTransform(mObjToWorld);
  299. resetWorldBox();
  300. F32 visDist = gClientSceneGraph->getVisibleDistance();
  301. Box3F skylightBounds = Box3F(visDist * 2);
  302. skylightBounds.setCenter(Point3F::Zero);
  303. mProbeInfo->setPosition(Point3F::Zero);
  304. mProbeInfo->mBounds = skylightBounds;
  305. setGlobalBounds();
  306. mProbeInfo->mIsSkylight = true;
  307. mProbeInfo->mScore = -1.0f; //sky comes first
  308. }
  309. bool Skylight::createClientResources()
  310. {
  311. //irridiance resources
  312. mIrridianceMap = GFX->createCubemap();
  313. mIrridianceMap->initDynamic(128, GFXFormatR16G16B16A16F, 1);
  314. //prefilter resources - we share the irridiance stateblock
  315. mPrefilterMap = GFX->createCubemap();
  316. mPrefilterMap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F, mPrefilterMipLevels);
  317. //brdf lookup resources
  318. //make the brdf lookup texture the same size as the prefilter texture
  319. mBrdfTexture = TEXMGR->createTexture(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXRenderTargetProfile, 1, 0);
  320. mResourcesCreated = true;
  321. return true;
  322. }
  323. void Skylight::updateMaterial()
  324. {
  325. if ((mReflectionModeType == BakedCubemap) && !mProbeUniqueID.isEmpty())
  326. {
  327. bool validCubemap = true;
  328. char fileName[256];
  329. dSprintf(fileName, 256, "%s%s.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str());
  330. Vector<FileName> fileNames;
  331. if (Platform::isFile(fileName))
  332. {
  333. if (!mCubemap)
  334. {
  335. mCubemap = new CubemapData();
  336. mCubemap->registerObject();
  337. }
  338. mCubemap->setCubemapFile(FileName(fileName));
  339. }
  340. else
  341. {
  342. validCubemap = false;
  343. }
  344. if (validCubemap)
  345. {
  346. if (mCubemap->mCubemap)
  347. mCubemap->updateFaces();
  348. else
  349. mCubemap->createMap();
  350. mDirty = false;
  351. mProbeInfo->mCubemap = &mCubemap->mCubemap;
  352. }
  353. /*for (U32 i = 0; i < 6; ++i)
  354. {
  355. char faceFile[256];
  356. dSprintf(faceFile, sizeof(faceFile), "%s%s_%i.png", mReflectionPath.c_str(),
  357. mProbeUniqueID.c_str(), i);
  358. if (Platform::isFile(faceFile))
  359. {
  360. fileNames.push_back(FileName(faceFile));
  361. }
  362. else
  363. {
  364. validCubemap = false;
  365. break;
  366. }
  367. }
  368. if (validCubemap)
  369. {
  370. if (!mCubemap)
  371. {
  372. mCubemap = new CubemapData();
  373. mCubemap->registerObject();
  374. }
  375. for(U32 i=0; i < 6; i++)
  376. mCubemap->setCubeFaceFile(i, fileNames[i]);
  377. mCubemap->createMap();
  378. mCubemap->updateFaces();
  379. mProbeInfo->mCubemap = &mCubemap->mCubemap;
  380. }*/
  381. }
  382. else if (mReflectionModeType == StaticCubemap && !mCubemapName.isEmpty())
  383. {
  384. Sim::findObject(mCubemapName, mCubemap);
  385. if (!mCubemap)
  386. return;
  387. if (mCubemap->mCubemap)
  388. mCubemap->updateFaces();
  389. else
  390. mCubemap->createMap();
  391. mProbeInfo->mCubemap = &mCubemap->mCubemap;
  392. }
  393. //calculateSHTerms();
  394. generateTextures();
  395. //Now that the work is done, assign the relevent maps
  396. if (mPrefilterMap.isValid())
  397. {
  398. mProbeInfo->mCubemap = &mPrefilterMap;
  399. mProbeInfo->mIrradianceCubemap = &mIrridianceMap;
  400. mProbeInfo->mBRDFTexture = &mBrdfTexture;
  401. }
  402. }
  403. void Skylight::generateTextures()
  404. {
  405. if (!mCubemap)
  406. return;
  407. if (!mResourcesCreated)
  408. {
  409. if (!createClientResources())
  410. {
  411. Con::errorf("SkyLight::createIrridianceMap: Failed to create resources");
  412. return;
  413. }
  414. }
  415. //GFXTransformSaver saver;
  416. GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
  417. IBLUtilities::GenerateIrradianceMap(renderTarget, mCubemap->mCubemap, mIrridianceMap);
  418. //Write it out
  419. char fileName[256];
  420. dSprintf(fileName, 256, "levels/test/irradiance.DDS");
  421. CubemapSaver::save(mIrridianceMap, fileName);
  422. if (!Platform::isFile(fileName))
  423. {
  424. Con::errorf("Failed to properly save out the skylight baked irradiance!");
  425. }
  426. //create prefilter cubemap (radiance)
  427. IBLUtilities::GeneratePrefilterMap(renderTarget, mCubemap->mCubemap, mPrefilterMipLevels, mPrefilterMap);
  428. //Write it out
  429. fileName[256];
  430. dSprintf(fileName, 256, "levels/test/prefilter.DDS");
  431. CubemapSaver::save(mPrefilterMap, fileName);
  432. if (!Platform::isFile(fileName))
  433. {
  434. Con::errorf("Failed to properly save out the skylight baked irradiance!");
  435. }
  436. //create brdf lookup
  437. IBLUtilities::GenerateBRDFTexture(mBrdfTexture);
  438. /*FileStream fs;
  439. if (fs.open("levels/test/brdf.DDS", Torque::FS::File::Write))
  440. {
  441. // Read back the render target, dxt compress it, and write it to disk.
  442. GBitmap brdfBmp(mBrdfTexture.getHeight(), mBrdfTexture.getWidth(), false, GFXFormatR8G8B8A8);
  443. mBrdfTexture.copyToBmp(&brdfBmp);
  444. brdfBmp.extrudeMipLevels();
  445. DDSFile *brdfDDS = DDSFile::createDDSFileFromGBitmap(&brdfBmp);
  446. ImageUtil::ddsCompress(brdfDDS, GFXFormatBC1);
  447. // Write result to file stream
  448. brdfDDS->write(fs);
  449. delete brdfDDS;
  450. }
  451. fs.close();*/
  452. }
  453. void Skylight::prepRenderImage(SceneRenderState *state)
  454. {
  455. if (!mEnabled || !Skylight::smRenderSkylights)
  456. return;
  457. Point3F distVec = getPosition() - state->getCameraPosition();
  458. F32 dist = distVec.len();
  459. //special hook-in for skylights
  460. Point3F camPos = state->getCameraPosition();
  461. mProbeInfo->mBounds.setCenter(camPos);
  462. mProbeInfo->setPosition(camPos);
  463. //Submit our probe to actually do the probe action
  464. // Get a handy pointer to our RenderPassmanager
  465. //RenderPassManager *renderPass = state->getRenderPass();
  466. PROBEMGR->registerSkylight(mProbeInfo, this);
  467. if (Skylight::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mCubemap != nullptr)
  468. {
  469. GFXTransformSaver saver;
  470. // Calculate the distance of this object from the camera
  471. Point3F cameraOffset;
  472. getRenderTransform().getColumn(3, &cameraOffset);
  473. cameraOffset -= state->getDiffuseCameraPosition();
  474. F32 dist = cameraOffset.len();
  475. if (dist < 0.01f)
  476. dist = 0.01f;
  477. // Set up the LOD for the shape
  478. F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
  479. mEditorShapeInst->setDetailFromDistance(state, dist * invScale);
  480. // Make sure we have a valid level of detail
  481. if (mEditorShapeInst->getCurrentDetail() < 0)
  482. return;
  483. BaseMatInstance* probePrevMat = mEditorShapeInst->getMaterialList()->getMaterialInst(0);
  484. setPreviewMatParameters(state, probePrevMat);
  485. // GFXTransformSaver is a handy helper class that restores
  486. // the current GFX matrices to their original values when
  487. // it goes out of scope at the end of the function
  488. // Set up our TS render state
  489. TSRenderState rdata;
  490. rdata.setSceneState(state);
  491. rdata.setFadeOverride(1.0f);
  492. // We might have some forward lit materials
  493. // so pass down a query to gather lights.
  494. LightQuery query;
  495. query.init(getWorldSphere());
  496. rdata.setLightQuery(&query);
  497. // Set the world matrix to the objects render transform
  498. MatrixF mat = getRenderTransform();
  499. mat.scale(Point3F(1, 1, 1));
  500. GFX->setWorldMatrix(mat);
  501. // Animate the the shape
  502. mEditorShapeInst->animate();
  503. // Allow the shape to submit the RenderInst(s) for itself
  504. mEditorShapeInst->render(rdata);
  505. saver.restore();
  506. }
  507. // If the light is selected or light visualization
  508. // is enabled then register the callback.
  509. const bool isSelectedInEditor = (gEditingMission && isSelected());
  510. if (isSelectedInEditor)
  511. {
  512. }
  513. }
  514. void Skylight::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat)
  515. {
  516. if (!mat->getFeatures().hasFeature(MFT_isDeferred))
  517. return;
  518. //Set up the params
  519. MaterialParameters *matParams = mat->getMaterialParameters();
  520. //Get the deferred render target
  521. NamedTexTarget* deferredTexTarget = NamedTexTarget::find("deferred");
  522. GFXTextureObject *deferredTexObject = deferredTexTarget->getTexture();
  523. if (!deferredTexObject)
  524. return;
  525. GFX->setTexture(0, deferredTexObject);
  526. //Set the cubemap
  527. GFX->setCubeTexture(1, mCubemap->mCubemap);
  528. //Set the invViewMat
  529. MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet();
  530. const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera();
  531. MaterialParameterHandle *invViewMat = mat->getMaterialParameterHandle("$invViewMat");
  532. matParams->setSafe(invViewMat, worldToCameraXfm);
  533. }
  534. DefineEngineMethod(Skylight, postApply, void, (), ,
  535. "A utility method for forcing a network update.\n")
  536. {
  537. object->inspectPostApply();
  538. }
  539. void Skylight::bake(String outputPath, S32 resolution)
  540. {
  541. GFXDEBUGEVENT_SCOPE(Skylight_Bake, ColorI::WHITE);
  542. PostEffect *preCapture = dynamic_cast<PostEffect*>(Sim::findObject("AL_PreCapture"));
  543. PostEffect *deferredShading = dynamic_cast<PostEffect*>(Sim::findObject("AL_DeferredShading"));
  544. if (preCapture)
  545. preCapture->enable();
  546. if (deferredShading)
  547. deferredShading->disable();
  548. //if (mReflectionModeType == StaticCubemap || mReflectionModeType == BakedCubemap || mReflectionModeType == SkyLight)
  549. {
  550. if (!mCubemap)
  551. {
  552. mCubemap = new CubemapData();
  553. mCubemap->registerObject();
  554. }
  555. }
  556. if (mReflectionModeType == BakedCubemap)
  557. {
  558. if (mReflectionPath.isEmpty() || !mPersistentId)
  559. {
  560. if (!mPersistentId)
  561. mPersistentId = getOrCreatePersistentId();
  562. mReflectionPath = outputPath.c_str();
  563. mProbeUniqueID = std::to_string(mPersistentId->getUUID().getHash()).c_str();
  564. }
  565. }
  566. bool validCubemap = true;
  567. // Save the current transforms so we can restore
  568. // it for child control rendering below.
  569. GFXTransformSaver saver;
  570. //bool saveEditingMission = gEditingMission;
  571. //gEditingMission = false;
  572. //Set this to true to use the prior method where it goes through the SPT_Reflect path for the bake
  573. bool probeRenderState = Skylight::smRenderSkylights;
  574. Skylight::smRenderSkylights = false;
  575. for (U32 i = 0; i < 6; ++i)
  576. {
  577. GFXTexHandle blendTex;
  578. blendTex.set(resolution, resolution, GFXFormatR8G8B8A8, &GFXRenderTargetProfile, "");
  579. GFXTextureTargetRef mBaseTarget = GFX->allocRenderToTextureTarget();
  580. GFX->clearTextureStateImmediate(0);
  581. mBaseTarget->attachTexture(GFXTextureTarget::Color0, blendTex);
  582. // Standard view that will be overridden below.
  583. VectorF vLookatPt(0.0f, 0.0f, 0.0f), vUpVec(0.0f, 0.0f, 0.0f), vRight(0.0f, 0.0f, 0.0f);
  584. switch (i)
  585. {
  586. case 0: // D3DCUBEMAP_FACE_POSITIVE_X:
  587. vLookatPt = VectorF(1.0f, 0.0f, 0.0f);
  588. vUpVec = VectorF(0.0f, 1.0f, 0.0f);
  589. break;
  590. case 1: // D3DCUBEMAP_FACE_NEGATIVE_X:
  591. vLookatPt = VectorF(-1.0f, 0.0f, 0.0f);
  592. vUpVec = VectorF(0.0f, 1.0f, 0.0f);
  593. break;
  594. case 2: // D3DCUBEMAP_FACE_POSITIVE_Y:
  595. vLookatPt = VectorF(0.0f, 1.0f, 0.0f);
  596. vUpVec = VectorF(0.0f, 0.0f, -1.0f);
  597. break;
  598. case 3: // D3DCUBEMAP_FACE_NEGATIVE_Y:
  599. vLookatPt = VectorF(0.0f, -1.0f, 0.0f);
  600. vUpVec = VectorF(0.0f, 0.0f, 1.0f);
  601. break;
  602. case 4: // D3DCUBEMAP_FACE_POSITIVE_Z:
  603. vLookatPt = VectorF(0.0f, 0.0f, 1.0f);
  604. vUpVec = VectorF(0.0f, 1.0f, 0.0f);
  605. break;
  606. case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z:
  607. vLookatPt = VectorF(0.0f, 0.0f, -1.0f);
  608. vUpVec = VectorF(0.0f, 1.0f, 0.0f);
  609. break;
  610. }
  611. // create camera matrix
  612. VectorF cross = mCross(vUpVec, vLookatPt);
  613. cross.normalizeSafe();
  614. MatrixF matView(true);
  615. matView.setColumn(0, cross);
  616. matView.setColumn(1, vLookatPt);
  617. matView.setColumn(2, vUpVec);
  618. matView.setPosition(getPosition());
  619. matView.inverse();
  620. // set projection to 90 degrees vertical and horizontal
  621. F32 left, right, top, bottom;
  622. F32 nearPlane = 100.f;
  623. F32 farDist = 10000.f;
  624. MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, nearPlane);
  625. Frustum frustum(false, left, right, top, bottom, nearPlane, farDist);
  626. renderFrame(&mBaseTarget, matView, frustum, StaticObjectType | StaticShapeObjectType & EDITOR_RENDER_TYPEMASK, ColorI::RED);
  627. mBaseTarget->resolve();
  628. mCubemap->setCubeFaceTexture(i, blendTex);
  629. char fileName[256];
  630. dSprintf(fileName, 256, "%s%s_%i.png", mReflectionPath.c_str(),
  631. mProbeUniqueID.c_str(), i);
  632. FileStream stream;
  633. if (!stream.open(fileName, Torque::FS::File::Write))
  634. {
  635. Con::errorf("ReflectionProbe::bake(): Couldn't open cubemap face file fo writing " + String(fileName));
  636. if (preCapture)
  637. preCapture->disable();
  638. if (deferredShading)
  639. deferredShading->enable();
  640. return;
  641. }
  642. GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8);
  643. blendTex->copyToBmp(&bitmap);
  644. bitmap.writeBitmap("png", stream);
  645. if (Platform::isFile(fileName) && mCubemap)
  646. {
  647. mCubemap->setCubeFaceFile(i, FileName(fileName));
  648. }
  649. else
  650. {
  651. validCubemap = false;
  652. break;
  653. }
  654. bitmap.deleteImage();
  655. }
  656. if (validCubemap)
  657. {
  658. if (mCubemap->mCubemap)
  659. mCubemap->updateFaces();
  660. else
  661. mCubemap->createMap();
  662. char fileName[256];
  663. dSprintf(fileName, 256, "%s%s.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str());
  664. CubemapSaver::save(mCubemap->mCubemap, fileName);
  665. if (!Platform::isFile(fileName))
  666. {
  667. validCubemap = false; //if we didn't save right, just
  668. Con::errorf("Failed to properly save out the skylight baked cubemap!");
  669. }
  670. }
  671. if (validCubemap)
  672. {
  673. mDirty = false;
  674. //remove the temp files
  675. for (U32 i = 0; i < 6; i++)
  676. {
  677. char fileName[256];
  678. dSprintf(fileName, 256, "%s%s_%i.png", mReflectionPath.c_str(),
  679. mProbeUniqueID.c_str(), i);
  680. Platform::fileDelete(fileName);
  681. }
  682. }
  683. //calculateSHTerms();
  684. Skylight::smRenderSkylights = probeRenderState;
  685. setMaskBits(-1);
  686. if (preCapture)
  687. preCapture->disable();
  688. if (deferredShading)
  689. deferredShading->enable();
  690. }
  691. DefineEngineMethod(Skylight, Bake, void, (String outputPath, S32 resolution), ("", 256),
  692. "@brief returns true if control object is inside the fog\n\n.")
  693. {
  694. object->bake(outputPath, resolution);
  695. }