Torque3D Documentation / _generateds / reflectionManager.cpp

reflectionManager.cpp

Engine/source/scene/reflectionManager.cpp

More...

Public Functions

DefineEngineFunction(setReflectFormat , void , (GFXFormat format) , "Set the reflection texture <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">format.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GFX\n</a>" )

Detailed Description

Public Variables

 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 

Public Functions

compareReflectors(const void * a, const void * b)

DefineEngineFunction(setReflectFormat , void , (GFXFormat format) , "Set the reflection texture <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">format.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GFX\n</a>" )

GFX_ImplementTextureProfile(ReflectRenderTargetProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf6773a6da8ddf28520016603401b8f23">GFXTextureProfile::SRGB</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )

GFX_ImplementTextureProfile(RefractTextureProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf6773a6da8ddf28520016603401b8f23">GFXTextureProfile::SRGB</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )

  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 "platform/platform.h"
 25#include "scene/reflectionManager.h"
 26
 27#include "platform/profiler.h"
 28#include "platform/platformTimer.h"
 29#include "console/consoleTypes.h"
 30#include "core/tAlgorithm.h"
 31#include "math/mMathFn.h"
 32#include "math/mathUtils.h"
 33#include "T3D/gameBase/gameConnection.h"
 34#include "ts/tsShapeInstance.h"
 35#include "gui/3d/guiTSControl.h"
 36#include "scene/sceneManager.h"
 37#include "gfx/gfxDebugEvent.h"
 38#include "gfx/gfxStringEnumTranslate.h"
 39#include "gfx/screenshot.h"
 40#include "core/module.h"
 41#include "scene/reflectionMatHook.h"
 42#include "console/engineAPI.h"
 43
 44
 45MODULE_BEGIN( ReflectionManager )
 46
 47   MODULE_INIT
 48   {
 49      ManagedSingleton< ReflectionManager >::createSingleton();
 50      ReflectionManager::initConsole();
 51   }
 52   
 53   MODULE_SHUTDOWN
 54   {
 55      ManagedSingleton< ReflectionManager >::deleteSingleton();
 56   }
 57
 58MODULE_END;
 59
 60
 61GFX_ImplementTextureProfile( ReflectRenderTargetProfile, 
 62                             GFXTextureProfile::DiffuseMap, 
 63                             GFXTextureProfile::PreserveSize | GFXTextureProfile::RenderTarget | GFXTextureProfile::SRGB | GFXTextureProfile::Pooled,
 64                             GFXTextureProfile::NONE );
 65
 66GFX_ImplementTextureProfile( RefractTextureProfile,
 67                             GFXTextureProfile::DiffuseMap,
 68                             GFXTextureProfile::PreserveSize | 
 69                             GFXTextureProfile::RenderTarget |
 70                             GFXTextureProfile::SRGB | 
 71                             GFXTextureProfile::Pooled,
 72                             GFXTextureProfile::NONE );
 73
 74static S32 QSORT_CALLBACK compareReflectors( const void *a, const void *b )
 75{
 76   const ReflectorBase *A = *((ReflectorBase**)a);
 77   const ReflectorBase *B = *((ReflectorBase**)b);     
 78   
 79   F32 dif = B->score - A->score;
 80   return (S32)mFloor( dif );
 81}
 82
 83
 84U32 ReflectionManager::smFrameReflectionMS = 10;
 85F32 ReflectionManager::smRefractTexScale = 0.5f;
 86
 87ReflectionManager::ReflectionManager() 
 88 : mReflectFormat( GFXFormatR8G8B8A8_SRGB ),
 89   mUpdateRefract( true ),
 90   mLastUpdateMs( 0 )
 91{
 92   mTimer = PlatformTimer::create();
 93
 94   GFXDevice::getDeviceEventSignal().notify( this, &ReflectionManager::_handleDeviceEvent );
 95}
 96
 97void ReflectionManager::initConsole()
 98{
 99   Con::addVariable( "$pref::Reflect::refractTexScale", TypeF32, &ReflectionManager::smRefractTexScale, "RefractTex has dimensions equal to the active render target scaled in both x and y by this float.\n"
100      "@ingroup Rendering");
101   Con::addVariable( "$pref::Reflect::frameLimitMS", TypeS32, &ReflectionManager::smFrameReflectionMS, "ReflectionManager tries not to spend more than this amount of time updating reflections per frame.\n"
102      "@ingroup Rendering");
103}
104
105ReflectionManager::~ReflectionManager()
106{
107   SAFE_DELETE( mTimer );
108   AssertFatal( mReflectors.size() == 0, "ReflectionManager, some reflectors were left nregistered!" );
109
110   GFXDevice::getDeviceEventSignal().remove( this, &ReflectionManager::_handleDeviceEvent );
111}
112
113void ReflectionManager::registerReflector( ReflectorBase *reflector )
114{
115   mReflectors.push_back_unique( reflector );
116}
117
118void ReflectionManager::unregisterReflector( ReflectorBase *reflector )
119{
120   mReflectors.remove( reflector );   
121}
122
123void ReflectionManager::update(  F32 timeSlice, 
124                                 const Point2I &resolution, 
125                                 const CameraQuery &query )
126{
127   GFXDEBUGEVENT_SCOPE( UpdateReflections, ColorI::WHITE );
128
129   if ( mReflectors.empty() )
130      return;
131
132   PROFILE_SCOPE( ReflectionManager_Update );
133
134   // Calculate our target time from the slice.
135   U32 targetMs = timeSlice * smFrameReflectionMS;
136
137   // Setup a culler for testing the 
138   // visibility of reflectors.
139   Frustum culler;
140
141   // jamesu - normally we just need a frustum which covers the current ports, however for SBS mode 
142   // we need something which covers both viewports.
143   S32 stereoTarget = GFX->getCurrentStereoTarget();
144   if (stereoTarget != -1)
145   {
146      // In this case we're rendering in stereo using a specific eye
147      MathUtils::makeFovPortFrustum(&culler, false, query.nearPlane, query.farPlane, query.fovPort[stereoTarget], query.headMatrix);
148   }
149   else if (GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide)
150   {
151      // Calculate an ideal culling size here, we'll just assume double fov based on the first fovport based on 
152      // the head position.
153      FovPort port = query.fovPort[0];
154      F32 upSize = query.nearPlane * port.upTan;
155      F32 downSize = query.nearPlane * port.downTan;
156
157      F32 top = upSize;
158      F32 bottom = -downSize;
159
160      F32 fovInRadians = mAtan2((top - bottom) / 2.0f, query.nearPlane) * 3.0f;
161
162      culler.set(false,
163         fovInRadians,
164         (F32)(query.stereoViewports[0].extent.x + query.stereoViewports[1].extent.x) / (F32)query.stereoViewports[0].extent.y,
165         query.nearPlane,
166         query.farPlane,
167         query.headMatrix);
168   }
169   else
170   {
171      // Normal culling
172      culler.set(false,
173         query.fov,
174         (F32)resolution.x / (F32)resolution.y,
175         query.nearPlane,
176         query.farPlane,
177         query.cameraMatrix);
178   }
179
180   // Manipulate the frustum for tiled screenshots
181   const bool screenShotMode = gScreenShot && gScreenShot->isPending();
182   if ( screenShotMode )
183      gScreenShot->tileFrustum( culler );
184
185   // We use the frame time and not real time 
186   // here as this may be called multiple times 
187   // within a frame.
188   U32 startOfUpdateMs = Platform::getVirtualMilliseconds();
189
190   // Save this for interested parties.
191   mLastUpdateMs = startOfUpdateMs;
192
193   ReflectParams refparams;
194   refparams.query = &query;
195   refparams.viewportExtent = resolution;
196   refparams.culler = culler;
197   refparams.startOfUpdateMs = startOfUpdateMs;
198   refparams.eyeId = stereoTarget;
199
200   // Update the reflection score.
201   ReflectorList::iterator reflectorIter = mReflectors.begin();
202   for ( ; reflectorIter != mReflectors.end(); reflectorIter++ )
203      (*reflectorIter)->calcScore( refparams );
204
205   // Sort them by the score.
206   dQsort( mReflectors.address(), mReflectors.size(), sizeof(ReflectorBase*), compareReflectors );
207   
208   // Update as many reflections as we can 
209   // within the target time limit.
210   mTimer->getElapsedMs();
211   mTimer->reset();
212   U32 numUpdated = 0;
213   reflectorIter = mReflectors.begin();
214   for ( ; reflectorIter != mReflectors.end(); reflectorIter++ )
215   {      
216      // We're sorted by score... so once we reach 
217      // a zero score we have nothing more to update.
218      if ( (*reflectorIter)->score <= 0.0f && !screenShotMode )
219         break;
220
221      (*reflectorIter)->updateReflection( refparams );
222
223     if (stereoTarget != 0) // only update MS if we're not rendering the left eye in separate mode
224     {
225        (*reflectorIter)->lastUpdateMs = startOfUpdateMs;
226     }
227
228      numUpdated++;
229
230      // If we run out of update time then stop.
231      if ( mTimer->getElapsedMs() > targetMs && !screenShotMode && (*reflectorIter)->score < 1000.0f )
232         break;
233   }
234
235   // Set metric/debug related script variables...
236
237   U32 numVisible = 0;
238   U32 numOccluded = 0;
239
240   reflectorIter = mReflectors.begin();
241   for ( ; reflectorIter != mReflectors.end(); reflectorIter++ )
242   {      
243      ReflectorBase *pReflector = (*reflectorIter);
244      if ( pReflector->isOccluded() )
245         numOccluded++;
246      else
247         numVisible++;
248   }
249
250#ifdef TORQUE_GATHER_METRICS
251   U32 numEnabled = mReflectors.size();   
252   U32 totalElapsed = mTimer->getElapsedMs();
253   const GFXTextureProfileStats &stats = ReflectRenderTargetProfile.getStats();
254   
255   F32 mb = ( stats.activeBytes / 1024.0f ) / 1024.0f;
256   char temp[256];
257
258   dSprintf( temp, 256, "%s %d %0.2f\n", 
259      ReflectRenderTargetProfile.getName().c_str(),
260      stats.activeCount,
261      mb );   
262
263   Con::setVariable( "$Reflect::textureStats", temp );
264   Con::setIntVariable( "$Reflect::renderTargetsAllocated", stats.allocatedTextures );
265   Con::setIntVariable( "$Reflect::poolSize", stats.activeCount );
266   Con::setIntVariable( "$Reflect::numObjects", numEnabled );   
267   Con::setIntVariable( "$Reflect::numVisible", numVisible ); 
268   Con::setIntVariable( "$Reflect::numOccluded", numOccluded );
269   Con::setIntVariable( "$Reflect::numUpdated", numUpdated );
270   Con::setIntVariable( "$Reflect::elapsed", totalElapsed );
271#endif
272}
273
274GFXTexHandle ReflectionManager::allocRenderTarget( const Point2I &size )
275{
276   return GFXTexHandle( size.x, size.y, mReflectFormat, 
277                        &ReflectRenderTargetProfile, 
278                        avar("%s() - mReflectTex (line %d)", __FUNCTION__, __LINE__) );
279}
280
281GFXTextureObject* ReflectionManager::getRefractTex( bool forceUpdate )
282{
283   GFXTarget *target = GFX->getActiveRenderTarget();
284   GFXFormat targetFormat = target->getFormat();
285   const Point2I &targetSize = target->getSize();
286
287   // D3D11 needs to be the same size as the active target
288   U32 desWidth = targetSize.x;
289   U32 desHeight = targetSize.y;
290
291
292   if ( mRefractTex.isNull() || 
293        mRefractTex->getWidth() != desWidth ||
294        mRefractTex->getHeight() != desHeight ||
295        mRefractTex->getFormat() != targetFormat )
296   {
297      mRefractTex.set( desWidth, desHeight, targetFormat, &RefractTextureProfile, "mRefractTex" );    
298      mUpdateRefract = true;
299   }
300
301   if ( forceUpdate || mUpdateRefract )
302   {
303      target->resolveTo( mRefractTex );   
304      mUpdateRefract = false;
305   }
306
307   return mRefractTex;
308}
309
310BaseMatInstance* ReflectionManager::getReflectionMaterial( BaseMatInstance *inMat ) const
311{
312   // See if we have an existing material hook.
313   ReflectionMaterialHook *hook = static_cast<ReflectionMaterialHook*>( inMat->getHook( ReflectionMaterialHook::Type ) );
314   if ( !hook )
315   {
316      // Create a hook and initialize it using the incoming material.
317      hook = new ReflectionMaterialHook;
318      hook->init( inMat );
319      inMat->addHook( hook );
320   }
321
322   return hook->getReflectMat();
323}
324
325bool ReflectionManager::_handleDeviceEvent( GFXDevice::GFXDeviceEventType evt )
326{
327   switch( evt )
328   {
329   case GFXDevice::deStartOfFrame:
330   case GFXDevice::deStartOfField:
331
332      mUpdateRefract = true;
333      break;
334
335   case GFXDevice::deDestroy:
336      
337      mRefractTex = NULL;      
338      break;  
339      
340   default:
341      break;
342   }
343
344   return true;
345}
346
347DefineEngineFunction( setReflectFormat, void, ( GFXFormat format ),,
348   "Set the reflection texture format.\n"
349   "@ingroup GFX\n" )
350{
351   REFLECTMGR->setReflectFormat( format );
352}
353
354