Torque3D Documentation / _generateds / reflectionProbe.cpp

reflectionProbe.cpp

Engine/source/T3D/lighting/reflectionProbe.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(ReflectionProbe , "@brief An example scene object which renders <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mesh.\n\n</a>" "This class implements <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> basic <a href="/coding/class/classsceneobject/">SceneObject</a> that can exist in the world at <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> " "3D position and <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> itself. There are several valid ways <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> an " "object in Torque. This class implements the preferred rendering method which " "is <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> submit <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/structmeshrenderinst/">MeshRenderInst</a> along with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Material, vertex buffer, " "primitive buffer, and transform and allow the <a href="/coding/class/classrendermeshmgr/">RenderMeshMgr</a> handle the " "actual setup and rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">you.\n\n</a>" "See the C++code <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> implementation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">details.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Examples\n</a>" )
DefineEngineMethod(ReflectionProbe , Bake , void , () , "@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(ReflectionProbe , postApply , void , () , "A utility method <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> forcing <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> network <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">update.\n</a>" )
ImplementEnumType(ReflectionModeEnum , "Type of mesh data available in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@ingroup gameObjects" )
ImplementEnumType(ReflectProbeType , "Type of mesh data available in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@ingroup gameObjects" )

Detailed Description

Public Variables

 EndImplementEnumType 
ColorI gCanvasClearColor 
bool gEditingMission 

For frame signal.

Public Functions

ConsoleDocClass(ReflectionProbe , "@brief An example scene object which renders <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mesh.\n\n</a>" "This class implements <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> basic <a href="/coding/class/classsceneobject/">SceneObject</a> that can exist in the world at <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> " "3D position and <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> itself. There are several valid ways <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> an " "object in Torque. This class implements the preferred rendering method which " "is <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> submit <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/structmeshrenderinst/">MeshRenderInst</a> along with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Material, vertex buffer, " "primitive buffer, and transform and allow the <a href="/coding/class/classrendermeshmgr/">RenderMeshMgr</a> handle the " "actual setup and rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">you.\n\n</a>" "See the C++code <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> implementation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">details.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Examples\n</a>" )

DefineEngineMethod(ReflectionProbe , Bake , void , () , "@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(ReflectionProbe , postApply , void , () , "A utility method <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> forcing <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> network <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">update.\n</a>" )

IMPLEMENT_CO_NETOBJECT_V1(ReflectionProbe )

ImplementEnumType(ReflectionModeEnum , "Type of mesh data available in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@ingroup gameObjects" )

ImplementEnumType(ReflectProbeType , "Type of mesh data available in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@ingroup gameObjects" )

   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
  24#include "T3D/lighting/reflectionProbe.h"
  25#include "math/mathIO.h"
  26#include "scene/sceneRenderState.h"
  27#include "console/consoleTypes.h"
  28#include "core/stream/bitStream.h"
  29#include "materials/baseMatInstance.h"
  30#include "console/engineAPI.h"
  31#include "gfx/gfxDrawUtil.h"
  32#include "gfx/gfxDebugEvent.h"
  33#include "gfx/gfxTransformSaver.h"
  34#include "math/mathUtils.h"
  35#include "gfx/bitmap/gBitmap.h"
  36#include "core/stream/fileStream.h"
  37#include "core/fileObject.h"
  38#include "core/resourceManager.h"
  39#include "console/simPersistID.h"
  40#include "T3D/gameFunctions.h"
  41#include "postFx/postEffect.h"
  42#include "renderInstance/renderProbeMgr.h"
  43#include "renderInstance/renderProbeMgr.h"
  44
  45#include "math/util/sphereMesh.h"
  46#include "materials/materialManager.h"
  47#include "math/util/matrixSet.h"
  48#include "gfx/bitmap/cubemapSaver.h"
  49
  50#include "materials/materialFeatureTypes.h"
  51
  52#include "gfx/gfxTextureManager.h"
  53#include "T3D/lighting/IBLUtilities.h"
  54
  55#include "scene/reflector.h"
  56
  57extern bool gEditingMission;
  58extern ColorI gCanvasClearColor;
  59bool ReflectionProbe::smRenderPreviewProbes = true;
  60
  61IMPLEMENT_CO_NETOBJECT_V1(ReflectionProbe);
  62
  63ConsoleDocClass(ReflectionProbe,
  64   "@brief An example scene object which renders a mesh.\n\n"
  65   "This class implements a basic SceneObject that can exist in the world at a "
  66   "3D position and render itself. There are several valid ways to render an "
  67   "object in Torque. This class implements the preferred rendering method which "
  68   "is to submit a MeshRenderInst along with a Material, vertex buffer, "
  69   "primitive buffer, and transform and allow the RenderMeshMgr handle the "
  70   "actual setup and rendering for you.\n\n"
  71   "See the C++ code for implementation details.\n\n"
  72   "@ingroup Examples\n");
  73
  74ImplementEnumType(ReflectProbeType,
  75   "Type of mesh data available in a shape.\n"
  76   "@ingroup gameObjects")
  77{ ProbeRenderInst::Sphere, "Sphere", "Sphere shaped" },
  78{ ProbeRenderInst::Box, "Box", "Box shape" }
  79EndImplementEnumType;
  80
  81ImplementEnumType(ReflectionModeEnum,
  82   "Type of mesh data available in a shape.\n"
  83   "@ingroup gameObjects")
  84{ ReflectionProbe::NoReflection, "No Reflections", "This probe does not provide any local reflection data"},
  85{ ReflectionProbe::StaticCubemap, "Static Cubemap", "Uses a static CubemapData" },
  86{ ReflectionProbe::BakedCubemap, "Baked Cubemap", "Uses a cubemap baked from the probe's current position" },
  87//{ ReflectionProbe::DynamicCubemap, "Dynamic Cubemap", "Uses a cubemap baked from the probe's current position, updated at a set rate" },
  88   EndImplementEnumType;
  89
  90//-----------------------------------------------------------------------------
  91// Object setup and teardown
  92//-----------------------------------------------------------------------------
  93ReflectionProbe::ReflectionProbe()
  94{
  95   // Flag this object so that it will always
  96   // be sent across the network to clients
  97   mNetFlags.set(Ghostable | ScopeAlways);
  98
  99   mTypeMask = LightObjectType | MarkerObjectType;
 100
 101   mProbeShapeType = ProbeRenderInst::Box;
 102
 103   mReflectionModeType = BakedCubemap;
 104
 105   mEnabled = true;
 106   mBakeReflections = false;
 107   mCubemapDirty = false;
 108
 109   mRadius = 10;
 110   mObjScale = Point3F::One * 10;
 111   mProbeRefScale = Point3F::One*10;
 112
 113   mUseHDRCaptures = true;
 114
 115   mStaticCubemap = NULL;
 116   mProbeUniqueID = "";
 117
 118   mEditorShapeInst = NULL;
 119   mEditorShape = NULL;
 120
 121   mRefreshRateMS = 200;
 122   mDynamicLastBakeMS = 0;
 123
 124   mMaxDrawDistance = 75;
 125
 126   mResourcesCreated = false;
 127   mPrefilterSize = 64;
 128   mPrefilterMipLevels = mLog2(F32(mPrefilterSize));
 129   mPrefilterMap = nullptr;
 130   mIrridianceMap = nullptr;
 131
 132   mProbeRefOffset = Point3F::Zero;
 133   mEditPosOffset = false;
 134
 135   mCaptureMask = REFLECTION_PROBE_CAPTURE_TYPEMASK;
 136}
 137
 138ReflectionProbe::~ReflectionProbe()
 139{
 140   if (mEditorShapeInst)
 141      SAFE_DELETE(mEditorShapeInst);
 142
 143   if (mReflectionModeType == StaticCubemap && mStaticCubemap)
 144      mStaticCubemap->deleteObject();
 145}
 146
 147//-----------------------------------------------------------------------------
 148// Object Editing
 149//-----------------------------------------------------------------------------
 150void ReflectionProbe::initPersistFields()
 151{
 152   addGroup("Rendering");
 153      addProtectedField("enabled", TypeBool, Offset(mEnabled, ReflectionProbe),
 154         &_setEnabled, &defaultProtectedGetFn, "Is the probe enabled or not");
 155   endGroup("Rendering");
 156
 157   addGroup("Reflection");
 158      addProtectedField("radius", TypeF32, Offset(mRadius, ReflectionProbe), &_setRadius, &defaultProtectedGetFn, 
 159         "The name of the material used to render the mesh.");
 160
 161      addProtectedField("EditPosOffset", TypeBool, Offset(mEditPosOffset, ReflectionProbe),
 162      &_toggleEditPosOffset, &defaultProtectedGetFn, "Toggle Edit Pos Offset Mode", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
 163
 164      addField("refOffset", TypePoint3F, Offset(mProbeRefOffset, ReflectionProbe), "The reference positional offset for the probe. This is used for adjusting the perceived center and area of influence.\nHelpful in adjusting parallax issues");
 165      addField("refScale", TypePoint3F, Offset(mProbeRefScale, ReflectionProbe), "The reference scale for the probe. This is used for adjusting the perceived center and area of influence.\nHelpful in adjusting parallax issues");
 166
 167      addProtectedField("ReflectionMode", TypeReflectionModeEnum, Offset(mReflectionModeType, ReflectionProbe), &_setReflectionMode, &defaultProtectedGetFn,
 168         "Used to dictate what sort of cubemap the probes use when using IBL.");
 169
 170      addField("StaticCubemap", TypeCubemapName, Offset(mCubemapName, ReflectionProbe), "This is used when a static cubemap is used. The name of the cubemap is looked up and loaded for the IBL calculations.");
 171
 172      //addField("DynamicReflectionRefreshMS", TypeS32, Offset(mRefreshRateMS, ReflectionProbe), "How often the dynamic cubemap is refreshed in milliseconds. Only works when the ReflectionMode is set to DynamicCubemap.");
 173
 174      addProtectedField("Bake", TypeBool, Offset(mBakeReflections, ReflectionProbe),
 175         &_doBake, &defaultProtectedGetFn, "Bake Probe Reflections", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
 176   endGroup("Reflection");
 177
 178   Con::addVariable("$Light::renderReflectionProbes", TypeBool, &RenderProbeMgr::smRenderReflectionProbes,
 179      "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
 180      "@note Only works for shadow mapped lights.\n\n"
 181      "@ingroup Lighting");
 182
 183   Con::addVariable("$Light::renderPreviewProbes", TypeBool, &ReflectionProbe::smRenderPreviewProbes,
 184      "Toggles rendering of light frustums when the light is selected in the editor.\n\n"
 185      "@note Only works for shadow mapped lights.\n\n"
 186      "@ingroup Lighting");
 187
 188   // SceneObject already handles exposing the transform
 189   Parent::initPersistFields();
 190}
 191
 192void ReflectionProbe::inspectPostApply()
 193{
 194   Parent::inspectPostApply();
 195
 196   mDirty = true;
 197
 198   bool liveUpdates = Con::getBoolVariable("$Probes::liveUpdates", false);
 199   if (liveUpdates)
 200   {
 201      bake();
 202   }
 203
 204   // Flag the network mask to send the updates
 205   // to the client object
 206   setMaskBits(-1);
 207}
 208
 209bool ReflectionProbe::_setEnabled(void *object, const char *index, const char *data)
 210{
 211   ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object);
 212
 213   probe->mEnabled = dAtob(data);
 214   probe->setMaskBits(EnabledMask);
 215
 216   return true;
 217}
 218
 219bool ReflectionProbe::_doBake(void *object, const char *index, const char *data)
 220{
 221   ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object);
 222
 223   probe->bake();
 224   probe->setMaskBits(StaticDataMask);
 225
 226   return false;
 227}
 228
 229bool ReflectionProbe::_toggleEditPosOffset(void *object, const char *index, const char *data)
 230{
 231   ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object);
 232
 233   probe->mEditPosOffset = !probe->mEditPosOffset;
 234
 235   return false;
 236}
 237
 238bool ReflectionProbe::_setRadius(void *object, const char *index, const char *data)
 239{
 240   ReflectionProbe* probe = reinterpret_cast<ReflectionProbe*>(object);
 241
 242   if (probe->mProbeShapeType != ProbeRenderInst::Sphere)
 243      return false;
 244
 245   probe->mObjScale = Point3F(probe->mRadius, probe->mRadius, probe->mRadius);
 246   probe->setMaskBits(StaticDataMask);
 247   
 248   return true;
 249}
 250
 251bool ReflectionProbe::_setReflectionMode(void *object, const char *index, const char *data)
 252{
 253   ReflectionProbe* probe = reinterpret_cast<ReflectionProbe*>(object);
 254
 255   if (!String::compare(data,"Static Cubemap"))
 256   {
 257      probe->mReflectionModeType = StaticCubemap;
 258   }
 259   else if (!String::compare(data, "Baked Cubemap"))
 260   {
 261      //Clear our cubemap if we changed it to be baked, just for cleanliness
 262      probe->mReflectionModeType = BakedCubemap;
 263      probe->mCubemapName = "";
 264   }
 265
 266   probe->setMaskBits(StaticDataMask);
 267
 268   return true;
 269}
 270
 271bool ReflectionProbe::onAdd()
 272{
 273   if (!Parent::onAdd())
 274      return false;
 275
 276   mEditPosOffset = false;
 277
 278   mObjBox.minExtents.set(-0.5, -0.5, -0.5);
 279   mObjBox.maxExtents.set(0.5, 0.5, 0.5);
 280
 281   // Skip our transform... it just dirties mask bits.
 282   Parent::setTransform(mObjToWorld);
 283
 284   resetWorldBox();
 285
 286   // Add this object to the scene
 287   addToScene();
 288
 289   if (isServerObject())
 290   {
 291      if (!mPersistentId)
 292         mPersistentId = getOrCreatePersistentId();
 293
 294      mProbeUniqueID = String::ToString(mPersistentId->getUUID().getHash());
 295   }
 296
 297   // Refresh this object's material (if any)
 298   if (isClientObject())
 299   {
 300      if (!mResourcesCreated && !createClientResources())
 301         return false;
 302
 303      updateProbeParams();
 304   }
 305  
 306   setMaskBits(-1);
 307
 308   return true;
 309}
 310
 311void ReflectionProbe::onRemove()
 312{
 313   if (isClientObject())
 314   {
 315      PROBEMGR->unregisterProbe(mProbeInfo.mProbeIdx);
 316   }
 317
 318   // Remove this object from the scene
 319   removeFromScene();
 320
 321   Parent::onRemove();
 322}
 323
 324void ReflectionProbe::handleDeleteAction()
 325{
 326   //we're deleting it?
 327   //Then we need to clear out the processed cubemaps(if we have them)
 328
 329   if (mReflectionModeType != StaticCubemap)
 330   {
 331      String prefilPath = getPrefilterMapPath();
 332      if (Platform::isFile(prefilPath))
 333      {
 334         Platform::fileDelete(prefilPath);
 335      }
 336
 337      String irrPath = getIrradianceMapPath();
 338      if (Platform::isFile(irrPath))
 339      {
 340         Platform::fileDelete(irrPath);
 341      }
 342   }
 343
 344   Parent::handleDeleteAction();
 345}
 346
 347void ReflectionProbe::setTransform(const MatrixF & mat)
 348{
 349   // Let SceneObject handle all of the matrix manipulation
 350   if (!mEditPosOffset)
 351   {
 352      Parent::setTransform(mat);
 353      setMaskBits(TransformMask);
 354   }
 355   else
 356   {
 357      mProbeRefOffset = mat.getPosition();
 358      setMaskBits(StaticDataMask);
 359   }
 360
 361   mDirty = true;
 362}
 363
 364const MatrixF& ReflectionProbe::getTransform() const 
 365{ 
 366   if (!mEditPosOffset)
 367      return mObjToWorld; 
 368   else
 369   {
 370      MatrixF transformMat = MatrixF::Identity;
 371      transformMat.setPosition(mProbeRefOffset);
 372
 373      return transformMat;
 374   }
 375}
 376
 377void ReflectionProbe::setScale(const VectorF &scale)
 378{
 379   if (!mEditPosOffset)
 380   {
 381      Parent::setScale(scale);
 382      setMaskBits(TransformMask);
 383   }
 384   else
 385   {
 386      mProbeRefScale = scale;
 387      setMaskBits(StaticDataMask);
 388   }
 389
 390   mDirty = true;
 391}
 392
 393const VectorF& ReflectionProbe::getScale() const
 394{ 
 395   if (!mEditPosOffset)
 396      return mObjScale;
 397   else
 398      return mProbeRefScale;
 399}
 400
 401bool ReflectionProbe::writeField(StringTableEntry fieldname, const char *value)
 402{
 403   if (fieldname == StringTable->insert("Bake") || fieldname == StringTable->insert("EditPosOffset"))
 404      return false;
 405
 406   return Parent::writeField(fieldname, value);
 407}
 408
 409U32 ReflectionProbe::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
 410{
 411   // Allow the Parent to get a crack at writing its info
 412   U32 retMask = Parent::packUpdate(conn, mask, stream);
 413
 414   // Write our transform information
 415   if (stream->writeFlag(mask & TransformMask))
 416   {
 417      stream->writeFlag(mEditPosOffset);
 418      mathWrite(*stream, mObjToWorld);
 419      mathWrite(*stream, mObjScale);
 420      mathWrite(*stream, mProbeRefOffset);
 421      mathWrite(*stream, mProbeRefScale);
 422   }
 423
 424   if (stream->writeFlag(mask & StaticDataMask))
 425   {
 426      stream->write((U32)mProbeShapeType);
 427      stream->write(mRadius);
 428      stream->write(mProbeUniqueID);
 429      stream->write((U32)mReflectionModeType);
 430      stream->write(mCubemapName);
 431   }
 432
 433   if (stream->writeFlag(mask & EnabledMask))
 434   {
 435      stream->writeFlag(mEnabled);
 436   }
 437
 438   return retMask;
 439}
 440
 441void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream)
 442{
 443   // Let the Parent read any info it sent
 444   Parent::unpackUpdate(conn, stream);
 445
 446   if (stream->readFlag())  // TransformMask
 447   {
 448      mEditPosOffset = stream->readFlag();
 449      mathRead(*stream, &mObjToWorld);
 450      mathRead(*stream, &mObjScale);
 451
 452      Parent::setTransform(mObjToWorld);
 453
 454      resetWorldBox();
 455
 456      mathRead(*stream, &mProbeRefOffset);
 457      mathRead(*stream, &mProbeRefScale);
 458
 459      mDirty = true;
 460   }
 461
 462   if (stream->readFlag())  // StaticDataMask
 463   {
 464      U32 shapeType = ProbeRenderInst::Sphere;
 465      stream->read(&shapeType);
 466
 467      mProbeShapeType = (ProbeRenderInst::ProbeShapeType)shapeType;
 468
 469      stream->read(&mRadius);
 470
 471      stream->read(&mProbeUniqueID);
 472
 473      U32 oldReflectModeType = mReflectionModeType;
 474      U32 reflectModeType = BakedCubemap;
 475      stream->read(&reflectModeType);
 476      mReflectionModeType = (ReflectionModeType)reflectModeType;
 477
 478      String oldCubemapName = mCubemapName;
 479      stream->read(&mCubemapName);
 480
 481      if(oldReflectModeType != mReflectionModeType || oldCubemapName != mCubemapName)
 482         mCubemapDirty = true;
 483
 484      mDirty = true;
 485   }
 486
 487   if (stream->readFlag())  // EnabledMask
 488   {
 489      mEnabled = stream->readFlag();
 490
 491      mDirty = true;
 492   }
 493}
 494
 495//-----------------------------------------------------------------------------
 496// Object Rendering
 497//-----------------------------------------------------------------------------
 498void ReflectionProbe::updateProbeParams()
 499{
 500   if (!mResourcesCreated)
 501   {
 502      if (!createClientResources())
 503         return;
 504   }
 505
 506   mProbeInfo.mIsEnabled = mEnabled;
 507
 508   mProbeInfo.mProbeShapeType = mProbeShapeType;
 509
 510   if (mProbeShapeType == ProbeRenderInst::Sphere)
 511      mObjScale.set(mRadius, mRadius, mRadius);
 512
 513   Box3F bounds;
 514
 515   if (mProbeShapeType == ProbeRenderInst::Skylight)
 516   {
 517      mProbeInfo.mPosition = Point3F::Zero;
 518      mProbeInfo.mTransform = MatrixF::Identity;
 519
 520      F32 visDist = gClientSceneGraph->getVisibleDistance();
 521      Box3F skylightBounds = Box3F(visDist * 2);
 522
 523      skylightBounds.setCenter(Point3F::Zero);
 524
 525      bounds = skylightBounds;
 526
 527      setGlobalBounds();
 528
 529      mProbeInfo.mScore = 10000.0f;
 530   }
 531   else
 532   {
 533      MatrixF transform = getTransform();
 534      mProbeInfo.mPosition = getPosition();
 535
 536      transform.scale(getScale());
 537      mProbeInfo.mTransform = transform.inverse();
 538
 539      bounds = mWorldBox;
 540
 541      mProbeInfo.mScore = 1;
 542   }
 543
 544   // Skip our transform... it just dirties mask bits.
 545   Parent::setTransform(mObjToWorld);
 546
 547   resetWorldBox();
 548
 549   mProbeInfo.mBounds = bounds;
 550   mProbeInfo.mExtents = getScale();
 551   mProbeInfo.mRadius = mRadius;
 552
 553   mProbeInfo.mProbeRefOffset = mProbeRefOffset;
 554   mProbeInfo.mProbeRefScale = mProbeRefScale;
 555
 556   mProbeInfo.mDirty = true;
 557
 558   if (mCubemapDirty)
 559   {
 560      if (mReflectionModeType == StaticCubemap)
 561         processStaticCubemap();
 562      else if (mReflectionModeType == BakedCubemap)
 563         processBakedCubemap();
 564      else
 565         processDynamicCubemap();
 566   }
 567
 568   PROBEMGR->updateProbes();
 569}
 570
 571void ReflectionProbe::processDynamicCubemap()
 572{
 573   
 574}
 575
 576void ReflectionProbe::processBakedCubemap()
 577{
 578   mProbeInfo.mIsEnabled = false;
 579
 580   if ((mReflectionModeType != BakedCubemap) || mProbeUniqueID.isEmpty())
 581      return;
 582
 583   String irrPath = getIrradianceMapPath();
 584   if (Platform::isFile(irrPath))
 585   {
 586      mIrridianceMap->setCubemapFile(FileName(irrPath));
 587      mIrridianceMap->updateFaces();
 588   }
 589
 590   if (mIrridianceMap == nullptr || mIrridianceMap->mCubemap.isNull())
 591   {
 592      Con::errorf("ReflectionProbe::processDynamicCubemap() - Unable to load baked irradiance map at %s", getIrradianceMapPath().c_str());
 593      return;
 594   }
 595
 596   String prefilPath = getPrefilterMapPath();
 597   if (Platform::isFile(prefilPath))
 598   {
 599      mPrefilterMap->setCubemapFile(FileName(prefilPath));
 600      mPrefilterMap->updateFaces();
 601   }
 602
 603   if (mPrefilterMap == nullptr || mPrefilterMap->mCubemap.isNull())
 604   {
 605      Con::errorf("ReflectionProbe::processDynamicCubemap() - Unable to load baked prefilter map at %s", getPrefilterMapPath().c_str());
 606      return;
 607   }
 608
 609   mProbeInfo.mPrefilterCubemap = mPrefilterMap->mCubemap;
 610   mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
 611
 612   if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
 613   {
 614      mProbeInfo.mIsEnabled = true;
 615
 616      mCubemapDirty = false;
 617
 618      //Update the probe manager with our new texture!
 619      PROBEMGR->updateProbeTexture(&mProbeInfo);
 620
 621      //now, cleanup
 622      mProbeInfo.mPrefilterCubemap.free();
 623      mProbeInfo.mIrradianceCubemap.free();
 624   }
 625}
 626
 627void ReflectionProbe::processStaticCubemap()
 628{
 629   mProbeInfo.mIsEnabled = false;
 630
 631   String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/");
 632
 633   char irradFileName[256];
 634   dSprintf(irradFileName, 256, "%s%s_Irradiance.dds", path.c_str(), mCubemapName.c_str());
 635
 636   if (Platform::isFile(irradFileName))
 637   {
 638      mIrridianceMap->setCubemapFile(FileName(irradFileName));
 639      mIrridianceMap->updateFaces();
 640   }
 641
 642   if (mIrridianceMap == nullptr || mIrridianceMap->mCubemap.isNull())
 643   {
 644      Con::errorf("ReflectionProbe::processStaticCubemap() - Unable to load baked irradiance map at %s", irradFileName);
 645      return;
 646   }
 647
 648   char prefilterFileName[256];
 649   dSprintf(prefilterFileName, 256, "%s%s_Prefilter.dds", path.c_str(), mCubemapName.c_str());
 650
 651   if (Platform::isFile(prefilterFileName))
 652   {
 653      mPrefilterMap->setCubemapFile(FileName(prefilterFileName));
 654      mPrefilterMap->updateFaces();
 655   }
 656
 657   if (mPrefilterMap == nullptr || mPrefilterMap->mCubemap.isNull())
 658   {
 659      Con::errorf("ReflectionProbe::processStaticCubemap() - Unable to load baked prefilter map at %s", prefilterFileName);
 660      return;
 661   }
 662
 663   if (!Platform::isFile(prefilterFileName) || !Platform::isFile(irradFileName))
 664   {
 665      //If we are missing either of the files, just re-run the bake
 666      Sim::findObject(mCubemapName, mStaticCubemap);
 667
 668      if (!mStaticCubemap)
 669      {
 670         Con::errorf("ReflectionProbe::updateMaterial() - unable to find static cubemap file!");
 671         return;
 672      }
 673
 674      if (mStaticCubemap->mCubemap == nullptr)
 675      {
 676         mStaticCubemap->createMap();
 677         mStaticCubemap->updateFaces();
 678      }
 679
 680      if (mUseHDRCaptures)
 681      {
 682         mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
 683         mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
 684      }
 685      else
 686      {
 687         mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
 688         mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
 689      }
 690
 691      GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
 692
 693      IBLUtilities::GenerateIrradianceMap(renderTarget, mStaticCubemap->mCubemap, mIrridianceMap->mCubemap);
 694      IBLUtilities::GeneratePrefilterMap(renderTarget, mStaticCubemap->mCubemap, mPrefilterMipLevels, mPrefilterMap->mCubemap);
 695
 696      IBLUtilities::SaveCubeMap(irradFileName, mIrridianceMap->mCubemap);
 697      IBLUtilities::SaveCubeMap(prefilterFileName, mPrefilterMap->mCubemap);
 698   }
 699
 700   if ((mIrridianceMap != nullptr || !mIrridianceMap->mCubemap.isNull()) && (mPrefilterMap != nullptr || !mPrefilterMap->mCubemap.isNull()))
 701   {
 702      mProbeInfo.mPrefilterCubemap = mPrefilterMap->mCubemap;
 703      mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
 704   }
 705
 706   if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
 707   {
 708      mProbeInfo.mIsEnabled = true;
 709
 710      mCubemapDirty = false;
 711
 712      //Update the probe manager with our new texture!
 713      PROBEMGR->updateProbeTexture(&mProbeInfo);
 714   }
 715}
 716
 717bool ReflectionProbe::createClientResources()
 718{
 719   PROBEMGR->registerProbe(&mProbeInfo);
 720
 721   mProbeInfo.mIsEnabled = false;
 722   
 723   //irridiance resources
 724   if (!mIrridianceMap)
 725   {
 726      mIrridianceMap = new CubemapData();
 727      mIrridianceMap->registerObject();
 728
 729      mIrridianceMap->createMap();
 730   }
 731
 732   //
 733   if (!mPrefilterMap)
 734   {
 735      mPrefilterMap = new CubemapData();
 736      mPrefilterMap->registerObject();
 737
 738      mPrefilterMap->createMap();
 739   }
 740
 741   mResourcesCreated = true;
 742   mCubemapDirty = true;
 743
 744   return true;
 745}
 746
 747String ReflectionProbe::getPrefilterMapPath()
 748{
 749   if (mProbeUniqueID.isEmpty())
 750   {
 751      Con::errorf("ReflectionProbe::getPrefilterMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!");
 752      return "";
 753   }
 754
 755   String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/");
 756
 757   char fileName[256];
 758   dSprintf(fileName, 256, "%s%s_Prefilter.dds", path.c_str(), mProbeUniqueID.c_str());
 759
 760   return fileName;
 761}
 762
 763String ReflectionProbe::getIrradianceMapPath()
 764{
 765   if (mProbeUniqueID.isEmpty())
 766   {
 767      Con::errorf("ReflectionProbe::getIrradianceMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!");
 768      return "";
 769   }
 770
 771   String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/");
 772
 773   char fileName[256];
 774   dSprintf(fileName, 256, "%s%s_Irradiance.dds", path.c_str(), mProbeUniqueID.c_str());
 775
 776   return fileName;
 777}
 778
 779void ReflectionProbe::bake()
 780{
 781   if (mReflectionModeType != BakedCubemap)
 782      return;
 783
 784   PROBEMGR->bakeProbe(this);
 785
 786   setMaskBits(-1);
 787}
 788
 789//-----------------------------------------------------------------------------
 790//Rendering of editing/debug stuff
 791//-----------------------------------------------------------------------------
 792void ReflectionProbe::createEditorResources()
 793{
 794#ifdef TORQUE_TOOLS
 795   // Clean up our previous shape
 796   if (mEditorShapeInst)
 797      SAFE_DELETE(mEditorShapeInst);
 798
 799   mEditorShape = NULL;
 800
 801   String shapeFile = "tools/resources/ReflectProbeSphere.dae";
 802
 803   // Attempt to get the resource from the ResourceManager
 804   mEditorShape = ResourceManager::get().load(shapeFile);
 805   if (mEditorShape)
 806   {
 807      mEditorShapeInst = new TSShapeInstance(mEditorShape, isClientObject());
 808   }
 809#endif
 810}
 811
 812void ReflectionProbe::prepRenderImage(SceneRenderState *state)
 813{
 814   if (!mEnabled || !RenderProbeMgr::smRenderReflectionProbes)
 815      return;
 816
 817   Point3F distVec = getRenderPosition() - state->getCameraPosition();
 818   F32 dist = distVec.len();
 819
 820   //Culling distance. Can be adjusted for performance options considerations via the scalar
 821   if (dist > mMaxDrawDistance * Con::getFloatVariable("$pref::GI::ProbeDrawDistScale", 1.0))
 822   {
 823      mProbeInfo.mScore = mMaxDrawDistance;
 824      return;
 825   }
 826
 827   if (mReflectionModeType == DynamicCubemap && mRefreshRateMS < (Platform::getRealMilliseconds() - mDynamicLastBakeMS))
 828   {
 829      bake();
 830      mDynamicLastBakeMS = Platform::getRealMilliseconds();
 831   }
 832
 833   //Submit our probe to actually do the probe action
 834   // Get a handy pointer to our RenderPassmanager
 835   //RenderPassManager *renderPass = state->getRenderPass();
 836
 837   //Update our score based on our radius, distance
 838   mProbeInfo.mScore = mMax(dist, 1.0f);
 839
 840   Point3F vect = distVec;
 841   vect.normalizeSafe();
 842
 843   //mProbeInfo.mScore *= mMax(mAbs(mDot(vect, state->getCameraTransform().getForwardVector())),0.001f);
 844
 845   PROBEMGR->submitProbe(mProbeInfo);
 846
 847#ifdef TORQUE_TOOLS
 848   if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mPrefilterMap != nullptr)
 849   {
 850      if(!mEditorShapeInst)
 851         createEditorResources();
 852
 853      GFXTransformSaver saver;
 854
 855      // Calculate the distance of this object from the camera
 856      Point3F cameraOffset;
 857      getRenderTransform().getColumn(3, &cameraOffset);
 858      cameraOffset -= state->getDiffuseCameraPosition();
 859      dist = cameraOffset.len();
 860      if (dist < 0.01f)
 861         dist = 0.01f;
 862
 863      // Set up the LOD for the shape
 864      F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
 865
 866      mEditorShapeInst->setDetailFromDistance(state, dist * invScale);
 867
 868      // Make sure we have a valid level of detail
 869      if (mEditorShapeInst->getCurrentDetail() < 0)
 870         return;
 871
 872      BaseMatInstance* probePrevMat = mEditorShapeInst->getMaterialList()->getMaterialInst(0);
 873
 874      setPreviewMatParameters(state, probePrevMat);
 875
 876      // GFXTransformSaver is a handy helper class that restores
 877      // the current GFX matrices to their original values when
 878      // it goes out of scope at the end of the function
 879
 880      // Set up our TS render state      
 881      TSRenderState rdata;
 882      rdata.setSceneState(state);
 883      rdata.setFadeOverride(1.0f);
 884
 885      if(mReflectionModeType != DynamicCubemap)
 886         rdata.setCubemap(mPrefilterMap->mCubemap);
 887      else
 888         rdata.setCubemap(mDynamicCubemap);
 889
 890      // We might have some forward lit materials
 891      // so pass down a query to gather lights.
 892      LightQuery query;
 893      query.init(getWorldSphere());
 894      rdata.setLightQuery(&query);
 895
 896      // Set the world matrix to the objects render transform
 897      MatrixF mat = getRenderTransform();
 898      GFX->setWorldMatrix(mat);
 899
 900      // Animate the the shape
 901      mEditorShapeInst->animate();
 902
 903      // Allow the shape to submit the RenderInst(s) for itself
 904      mEditorShapeInst->render(rdata);
 905
 906      saver.restore();
 907   }
 908
 909   // If the probe is selected or probe visualization
 910   // is enabled then register the callback.
 911   const bool isSelectedInEditor = (gEditingMission && isSelected());
 912   if (isSelectedInEditor)
 913   {
 914      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
 915      ri->renderDelegate.bind(this, &ReflectionProbe::_onRenderViz);
 916      ri->type = RenderPassManager::RIT_Editor;
 917      state->getRenderPass()->addInst(ri);
 918   }
 919#endif
 920}
 921
 922void ReflectionProbe::_onRenderViz(ObjectRenderInst *ri,
 923   SceneRenderState *state,
 924   BaseMatInstance *overrideMat)
 925{
 926   if (!RenderProbeMgr::smRenderReflectionProbes)
 927      return;
 928
 929   GFXDrawUtil *draw = GFX->getDrawUtil();
 930
 931   GFXStateBlockDesc desc;
 932   desc.setZReadWrite(true, false);
 933   desc.setCullMode(GFXCullNone);
 934   desc.setBlend(true);
 935   //desc.fillMode = GFXFillWireframe;
 936
 937   // Base the sphere color on the light color.
 938   ColorI color = ColorI(255, 0, 255, 63);
 939
 940   const MatrixF worldToObjectXfm = mObjToWorld;
 941   if (mProbeShapeType == ProbeRenderInst::Sphere)
 942   {
 943      draw->drawSphere(desc, mRadius, getPosition(), color);
 944   }
 945   else
 946   {
 947      Point3F tscl = worldToObjectXfm.getScale();
 948
 949      Box3F projCube(-mObjScale/2, mObjScale / 2);
 950      projCube.setCenter(getPosition());
 951      draw->drawCube(desc, projCube, color, &worldToObjectXfm);
 952   }
 953
 954   Point3F renderPos = getRenderTransform().getPosition();
 955
 956   Box3F refCube = Box3F(-mProbeRefScale / 2, mProbeRefScale / 2);
 957   refCube.setCenter(renderPos + mProbeRefOffset);
 958   color = ColorI(0, 255, 255, 63);
 959   draw->drawCube(desc, refCube, color, &worldToObjectXfm);
 960}
 961
 962void ReflectionProbe::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat)
 963{
 964   if (!mat->getFeatures().hasFeature(MFT_isDeferred))
 965      return;
 966
 967   //Set up the params
 968   MaterialParameters *matParams = mat->getMaterialParameters();
 969
 970   //Get the deferred render target
 971   NamedTexTarget* deferredTexTarget = NamedTexTarget::find("deferred");
 972
 973   GFXTextureObject *deferredTexObject = deferredTexTarget->getTexture();
 974   if (!deferredTexObject) 
 975      return;
 976
 977   GFX->setTexture(0, deferredTexObject);
 978
 979   //Set the cubemap
 980   GFX->setCubeTexture(1, mPrefilterMap->mCubemap);
 981
 982   //Set the invViewMat
 983   MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet();
 984   const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera();
 985
 986   MaterialParameterHandle *invViewMat = mat->getMaterialParameterHandle("$invViewMat");
 987
 988   matParams->setSafe(invViewMat, worldToCameraXfm);
 989}
 990
 991DefineEngineMethod(ReflectionProbe, postApply, void, (), ,
 992   "A utility method for forcing a network update.\n")
 993{
 994   object->inspectPostApply();
 995}
 996
 997DefineEngineMethod(ReflectionProbe, Bake, void, (), ,
 998   "@brief Bakes the cubemaps for a reflection probe\n\n.")
 999{
1000   ReflectionProbe *clientProbe = (ReflectionProbe*)object->getClientObject();
1001
1002   if (clientProbe)
1003   {
1004      clientProbe->bake();
1005   }
1006}
1007