reflectionManager.cpp
Engine/source/scene/reflectionManager.cpp
Public Variables
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 )
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