reflector.cpp
Engine/source/scene/reflector.cpp
Public Variables
Public Functions
ConsoleDocClass(ReflectorDesc , "@brief A datablock which defines performance and quality properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "dynamic <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reflections.\n\n</a>" "<a href="/coding/class/classreflectordesc/">ReflectorDesc</a> is not itself <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> reflection and does not <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> reflections. " "It is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dummy class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> holding and exposing <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the user <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> set of " "reflection related properties. Objects which support dynamic reflections " "may then reference <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ReflectorDesc.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classreflectordesc/">ReflectorDesc</a>( ExampleReflectorDesc )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " texSize = 256;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " nearDist = 0.1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " farDist = 500;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " objectTypeMask = 0xFFFFFFFF;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " detailAdjust = 1.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " priority = 1.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " maxRateMs = 0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " useOcclusionQuery = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBaseData::cubeReflectorDesc\n</a>" "@ingroup enviroMisc" )
Detailed Description
Public Variables
ColorI gCanvasClearColor
Public Functions
ConsoleDocClass(ReflectorDesc , "@brief A datablock which defines performance and quality properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "dynamic <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reflections.\n\n</a>" "<a href="/coding/class/classreflectordesc/">ReflectorDesc</a> is not itself <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> reflection and does not <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> reflections. " "It is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dummy class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> holding and exposing <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the user <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> set of " "reflection related properties. Objects which support dynamic reflections " "may then reference <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ReflectorDesc.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classreflectordesc/">ReflectorDesc</a>( ExampleReflectorDesc )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " texSize = 256;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " nearDist = 0.1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " farDist = 500;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " objectTypeMask = 0xFFFFFFFF;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " detailAdjust = 1.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " priority = 1.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " maxRateMs = 0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " useOcclusionQuery = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBaseData::cubeReflectorDesc\n</a>" "@ingroup enviroMisc" )
IMPLEMENT_CO_DATABLOCK_V1(ReflectorDesc )
sgn(F32 a)
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/reflector.h" 26 27#include "console/consoleTypes.h" 28#include "gfx/gfxCubemap.h" 29#include "gfx/gfxDebugEvent.h" 30#include "gfx/gfxTransformSaver.h" 31#include "scene/sceneManager.h" 32#include "scene/sceneRenderState.h" 33#include "core/stream/bitStream.h" 34#include "scene/reflectionManager.h" 35#include "gui/3d/guiTSControl.h" 36#include "ts/tsShapeInstance.h" 37#include "gfx/gfxOcclusionQuery.h" 38#include "lighting/lightManager.h" 39#include "lighting/shadowMap/lightShadowMap.h" 40#include "math/mathUtils.h" 41#include "math/util/frustum.h" 42#include "gfx/screenshot.h" 43#include "postFx/postEffectManager.h" 44 45extern ColorI gCanvasClearColor; 46 47 48//------------------------------------------------------------------------- 49// ReflectorDesc 50//------------------------------------------------------------------------- 51 52IMPLEMENT_CO_DATABLOCK_V1( ReflectorDesc ); 53 54ConsoleDocClass( ReflectorDesc, 55 "@brief A datablock which defines performance and quality properties for " 56 "dynamic reflections.\n\n" 57 58 "ReflectorDesc is not itself a reflection and does not render reflections. " 59 "It is a dummy class for holding and exposing to the user a set of " 60 "reflection related properties. Objects which support dynamic reflections " 61 "may then reference a ReflectorDesc.\n\n" 62 63 "@tsexample\n" 64 "datablock ReflectorDesc( ExampleReflectorDesc )\n" 65 "{\n" 66 " texSize = 256;\n" 67 " nearDist = 0.1;\n" 68 " farDist = 500;\n" 69 " objectTypeMask = 0xFFFFFFFF;\n" 70 " detailAdjust = 1.0;\n" 71 " priority = 1.0;\n" 72 " maxRateMs = 0;\n" 73 " useOcclusionQuery = true;\n" 74 "};\n" 75 "@endtsexample\n" 76 77 "@see ShapeBaseData::cubeReflectorDesc\n" 78 "@ingroup enviroMisc" 79); 80 81ReflectorDesc::ReflectorDesc() 82{ 83 texSize = 256; 84 nearDist = 0.1f; 85 farDist = 1000.0f; 86 objectTypeMask = 0xFFFFFFFF; 87 detailAdjust = 1.0f; 88 priority = 1.0f; 89 maxRateMs = 15; 90 useOcclusionQuery = true; 91} 92 93ReflectorDesc::~ReflectorDesc() 94{ 95} 96 97void ReflectorDesc::initPersistFields() 98{ 99 addGroup( "ReflectorDesc" ); 100 101 addField( "texSize", TypeS32, Offset( texSize, ReflectorDesc ), 102 "Size in pixels of the (square) reflection texture. For a cubemap " 103 "this value is interpreted as size of each face." ); 104 105 addField( "nearDist", TypeF32, Offset( nearDist, ReflectorDesc ), 106 "Near plane distance to use when rendering this reflection. Adjust " 107 "this to limit self-occlusion artifacts." ); 108 109 addField( "farDist", TypeF32, Offset( farDist, ReflectorDesc ), 110 "Far plane distance to use when rendering reflections." ); 111 112 addField( "objectTypeMask", TypeS32, Offset( objectTypeMask, ReflectorDesc ), 113 "Object types which render into this reflection." ); 114 115 addField( "detailAdjust", TypeF32, Offset( detailAdjust, ReflectorDesc ), 116 "Scale applied to lod calculation of objects rendering into " 117 "this reflection ( modulates $pref::TS::detailAdjust )." ); 118 119 addField( "priority", TypeF32, Offset( priority, ReflectorDesc ), 120 "Priority for updating this reflection, relative to others." ); 121 122 addField( "maxRateMs", TypeS32, Offset( maxRateMs, ReflectorDesc ), 123 "If less than maxRateMs has elapsed since this relfection was last " 124 "updated, then do not update it again. This 'skip' can be disabled by " 125 "setting maxRateMs to zero." ); 126 127 addField( "useOcclusionQuery", TypeBool, Offset( useOcclusionQuery, ReflectorDesc ), 128 "If available on the device use HOQs to determine if the reflective object " 129 "is visible before updating its reflection." ); 130 131 endGroup( "ReflectorDesc" ); 132 133 Parent::initPersistFields(); 134} 135 136void ReflectorDesc::packData( BitStream *stream ) 137{ 138 Parent::packData( stream ); 139 140 stream->write( texSize ); 141 stream->write( nearDist ); 142 stream->write( farDist ); 143 stream->write( objectTypeMask ); 144 stream->write( detailAdjust ); 145 stream->write( priority ); 146 stream->write( maxRateMs ); 147 stream->writeFlag( useOcclusionQuery ); 148} 149 150void ReflectorDesc::unpackData( BitStream *stream ) 151{ 152 Parent::unpackData( stream ); 153 154 stream->read( &texSize ); 155 stream->read( &nearDist ); 156 stream->read( &farDist ); 157 stream->read( &objectTypeMask ); 158 stream->read( &detailAdjust ); 159 stream->read( &priority ); 160 stream->read( &maxRateMs ); 161 useOcclusionQuery = stream->readFlag(); 162} 163 164bool ReflectorDesc::preload( bool server, String &errorStr ) 165{ 166 if ( !Parent::preload( server, errorStr ) ) 167 return false; 168 169 return true; 170} 171 172//------------------------------------------------------------------------- 173// ReflectorBase 174//------------------------------------------------------------------------- 175ReflectorBase::ReflectorBase() 176{ 177 mEnabled = false; 178 mOccluded = false; 179 mIsRendering = false; 180 mDesc = NULL; 181 mObject = NULL; 182 mOcclusionQuery = GFX->createOcclusionQuery(); 183 mQueryPending = false; 184 score = 0.0f; 185 lastUpdateMs = 0; 186} 187 188ReflectorBase::~ReflectorBase() 189{ 190 delete mOcclusionQuery; 191} 192 193void ReflectorBase::unregisterReflector() 194{ 195 if ( mEnabled ) 196 { 197 REFLECTMGR->unregisterReflector( this ); 198 mEnabled = false; 199 } 200} 201 202F32 ReflectorBase::calcScore( const ReflectParams ¶ms ) 203{ 204 PROFILE_SCOPE( ReflectorBase_calcScore ); 205 206 // First check the occlusion query to see if we're hidden. 207 if ( mDesc->useOcclusionQuery && 208 mOcclusionQuery ) 209 { 210 GFXOcclusionQuery::OcclusionQueryStatus status = mOcclusionQuery->getStatus( false ); 211 212 if ( status == GFXOcclusionQuery::Waiting ) 213 { 214 mQueryPending = true; 215 // Don't change mOccluded since we don't know yet, use the value 216 // from last frame. 217 } 218 else 219 { 220 mQueryPending = false; 221 222 if ( status == GFXOcclusionQuery::Occluded ) 223 mOccluded = true; 224 else if ( status == GFXOcclusionQuery::NotOccluded ) 225 mOccluded = false; 226 } 227 } 228 229 // If we're disabled for any reason then there 230 // is nothing more left to do. 231 if ( !mEnabled || 232 mOccluded || 233 params.culler.isCulled( mObject->getWorldBox() ) ) 234 { 235 score = 0; 236 return score; 237 } 238 239 // This mess is calculating a score based on LOD. 240 241 /* 242 F32 sizeWS = getMax( object->getWorldBox().len_z(), 0.001f ); 243 Point3F cameraOffset = params.culler.getPosition() - object->getPosition(); 244 F32 dist = getMax( cameraOffset.len(), 0.01f ); 245 F32 worldToScreenScaleY = ( params.culler.getNearDist() * params.viewportExtent.y ) / 246 ( params.culler.getNearTop() - params.culler.getNearBottom() ); 247 F32 sizeSS = sizeWS / dist * worldToScreenScaleY; 248 */ 249 250 if ( mDesc->priority == -1.0f ) 251 { 252 score = 1000.0f; 253 return score; 254 } 255 256 F32 lodFactor = 1.0f; //sizeSS; 257 258 F32 maxRate = getMax( (F32)mDesc->maxRateMs, 1.0f ); 259 U32 delta = params.startOfUpdateMs - lastUpdateMs; 260 F32 timeFactor = getMax( (F32)delta / maxRate - 1.0f, 0.0f ); 261 262 score = mDesc->priority * timeFactor * lodFactor; 263 264 return score; 265} 266 267 268//------------------------------------------------------------------------- 269// CubeReflector 270//------------------------------------------------------------------------- 271 272CubeReflector::CubeReflector() 273 : mLastTexSize( 0 ) 274{ 275} 276 277void CubeReflector::registerReflector( SceneObject *object, 278 ReflectorDesc *desc ) 279{ 280 if ( mEnabled ) 281 return; 282 283 mEnabled = true; 284 mObject = object; 285 mDesc = desc; 286 REFLECTMGR->registerReflector( this ); 287} 288 289void CubeReflector::unregisterReflector() 290{ 291 if ( !mEnabled ) 292 return; 293 294 REFLECTMGR->unregisterReflector( this ); 295 296 mEnabled = false; 297} 298 299void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F explicitPostion) 300{ 301 GFXDEBUGEVENT_SCOPE( CubeReflector_UpdateReflection, ColorI::WHITE ); 302 303 mIsRendering = true; 304 305 // Setup textures and targets... 306 S32 texDim = mDesc->texSize; 307 texDim = getMax( texDim, 32 ); 308 309 // Protect against the reflection texture being bigger 310 // than the current game back buffer. 311 texDim = getMin( texDim, params.viewportExtent.x ); 312 texDim = getMin( texDim, params.viewportExtent.y ); 313 314 bool texResize = ( texDim != mLastTexSize ); 315 316 const GFXFormat reflectFormat = REFLECTMGR->getReflectFormat(); 317 318 if ( texResize || 319 mCubemap.isNull() || 320 mCubemap->getFormat() != reflectFormat ) 321 { 322 mCubemap = GFX->createCubemap(); 323 mCubemap->initDynamic( texDim, reflectFormat ); 324 } 325 326 mDepthBuff = LightShadowMap::_getDepthTarget( texDim, texDim ); 327 328 if ( mRenderTarget.isNull() ) 329 mRenderTarget = GFX->allocRenderToTextureTarget(); 330 331 GFX->pushActiveRenderTarget(); 332 mRenderTarget->attachTexture( GFXTextureTarget::DepthStencil, mDepthBuff ); 333 334 335 F32 oldVisibleDist = gClientSceneGraph->getVisibleDistance(); 336 gClientSceneGraph->setVisibleDistance( mDesc->farDist ); 337 338 339 for ( U32 i = 0; i < 6; i++ ) 340 updateFace( params, i, explicitPostion); 341 342 343 GFX->popActiveRenderTarget(); 344 345 gClientSceneGraph->setVisibleDistance(oldVisibleDist); 346 347 mIsRendering = false; 348 mLastTexSize = texDim; 349} 350 351void CubeReflector::updateFace( const ReflectParams ¶ms, U32 faceidx, Point3F explicitPostion) 352{ 353 GFXDEBUGEVENT_SCOPE( CubeReflector_UpdateFace, ColorI::WHITE ); 354 355 // store current matrices 356 GFXTransformSaver saver; 357 358 // set projection to 90 degrees vertical and horizontal 359 F32 left, right, top, bottom; 360 MathUtils::makeFrustum( &left, &right, &top, &bottom, M_HALFPI_F, 1.0f, mDesc->nearDist ); 361 GFX->setFrustum( left, right, bottom, top, mDesc->nearDist, mDesc->farDist ); 362 363 // We don't use a special clipping projection, but still need to initialize 364 // this for objects like SkyBox which will use it during a reflect pass. 365 gClientSceneGraph->setNonClipProjection( GFX->getProjectionMatrix() ); 366 367 // Standard view that will be overridden below. 368 VectorF vLookatPt(0.0f, 0.0f, 0.0f), vUpVec(0.0f, 0.0f, 0.0f), vRight(0.0f, 0.0f, 0.0f); 369 370 switch( faceidx ) 371 { 372 case 0 : // D3DCUBEMAP_FACE_POSITIVE_X: 373 vLookatPt = VectorF( 1.0f, 0.0f, 0.0f ); 374 vUpVec = VectorF( 0.0f, 1.0f, 0.0f ); 375 break; 376 case 1 : // D3DCUBEMAP_FACE_NEGATIVE_X: 377 vLookatPt = VectorF( -1.0f, 0.0f, 0.0f ); 378 vUpVec = VectorF( 0.0f, 1.0f, 0.0f ); 379 break; 380 case 2 : // D3DCUBEMAP_FACE_POSITIVE_Y: 381 vLookatPt = VectorF( 0.0f, 1.0f, 0.0f ); 382 vUpVec = VectorF( 0.0f, 0.0f,-1.0f ); 383 break; 384 case 3 : // D3DCUBEMAP_FACE_NEGATIVE_Y: 385 vLookatPt = VectorF( 0.0f, -1.0f, 0.0f ); 386 vUpVec = VectorF( 0.0f, 0.0f, 1.0f ); 387 break; 388 case 4 : // D3DCUBEMAP_FACE_POSITIVE_Z: 389 vLookatPt = VectorF( 0.0f, 0.0f, 1.0f ); 390 vUpVec = VectorF( 0.0f, 1.0f, 0.0f ); 391 break; 392 case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z: 393 vLookatPt = VectorF( 0.0f, 0.0f, -1.0f ); 394 vUpVec = VectorF( 0.0f, 1.0f, 0.0f ); 395 break; 396 } 397 398 // create camera matrix 399 VectorF cross = mCross( vUpVec, vLookatPt ); 400 cross.normalizeSafe(); 401 402 MatrixF matView(true); 403 matView.setColumn( 0, cross ); 404 matView.setColumn( 1, vLookatPt ); 405 matView.setColumn( 2, vUpVec ); 406 407 if (explicitPostion == Point3F::Max) 408 { 409 matView.setPosition(mObject->getPosition()); 410 } 411 else 412 { 413 matView.setPosition(explicitPostion); 414 } 415 matView.inverse(); 416 417 GFX->setWorldMatrix(matView); 418 GFX->clearTextureStateImmediate(0); 419 mRenderTarget->attachTexture( GFXTextureTarget::Color0, mCubemap, faceidx ); 420 GFX->setActiveRenderTarget(mRenderTarget); 421 GFX->clear( GFXClearStencil | GFXClearTarget | GFXClearZBuffer, gCanvasClearColor, 1.0f, 0 ); 422 423 SceneRenderState reflectRenderState 424 ( 425 gClientSceneGraph, 426 SPT_Reflect, 427 SceneCameraState::fromGFX() 428 ); 429 430 reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); 431 reflectRenderState.setDiffuseCameraTransform( params.query->headMatrix ); 432 433 // render scene 434 LIGHTMGR->registerGlobalLights( &reflectRenderState.getCullingFrustum(), false ); 435 gClientSceneGraph->renderSceneNoLights( &reflectRenderState, mDesc->objectTypeMask ); 436 LIGHTMGR->unregisterAllLights(); 437 438 // Clean up. 439 mRenderTarget->resolve(); 440} 441 442F32 CubeReflector::calcFaceScore( const ReflectParams ¶ms, U32 faceidx ) 443{ 444 if ( Parent::calcScore( params ) <= 0.0f ) 445 return score; 446 447 VectorF vLookatPt(0.0f, 0.0f, 0.0f); 448 449 switch( faceidx ) 450 { 451 case 0 : // D3DCUBEMAP_FACE_POSITIVE_X: 452 vLookatPt = VectorF( 1.0f, 0.0f, 0.0f ); 453 break; 454 case 1 : // D3DCUBEMAP_FACE_NEGATIVE_X: 455 vLookatPt = VectorF( -1.0f, 0.0f, 0.0f ); 456 break; 457 case 2 : // D3DCUBEMAP_FACE_POSITIVE_Y: 458 vLookatPt = VectorF( 0.0f, 1.0f, 0.0f ); 459 break; 460 case 3 : // D3DCUBEMAP_FACE_NEGATIVE_Y: 461 vLookatPt = VectorF( 0.0f, -1.0f, 0.0f ); 462 break; 463 case 4 : // D3DCUBEMAP_FACE_POSITIVE_Z: 464 vLookatPt = VectorF( 0.0f, 0.0f, 1.0f ); 465 break; 466 case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z: 467 vLookatPt = VectorF( 0.0f, 0.0f, -1.0f ); 468 break; 469 } 470 471 VectorF cameraDir; 472 params.query->cameraMatrix.getColumn( 1, &cameraDir ); 473 474 F32 dot = mDot( cameraDir, -vLookatPt ); 475 476 dot = getMax( ( dot + 1.0f ) / 2.0f, 0.1f ); 477 478 score *= dot; 479 480 return score; 481} 482 483F32 CubeReflector::CubeFaceReflector::calcScore( const ReflectParams ¶ms ) 484{ 485 score = cube->calcFaceScore( params, faceIdx ); 486 mOccluded = cube->isOccluded(); 487 return score; 488} 489 490 491//------------------------------------------------------------------------- 492// PlaneReflector 493//------------------------------------------------------------------------- 494 495void PlaneReflector::registerReflector( SceneObject *object, 496 ReflectorDesc *desc ) 497{ 498 mEnabled = true; 499 mObject = object; 500 mDesc = desc; 501 mLastDir = Point3F::One; 502 mLastPos = Point3F::Max; 503 504 REFLECTMGR->registerReflector( this ); 505} 506 507F32 PlaneReflector::calcScore( const ReflectParams ¶ms ) 508{ 509 if ( Parent::calcScore( params ) <= 0.0f || score >= 1000.0f ) 510 return score; 511 512 // The planar reflection is view dependent to score it 513 // higher if the view direction and/or position has changed. 514 515 // Get the current camera info. 516 VectorF camDir = params.query->cameraMatrix.getForwardVector(); 517 Point3F camPos = params.query->cameraMatrix.getPosition(); 518 519 // Scale up the score based on the view direction change. 520 F32 dot = mDot( camDir, mLastDir ); 521 dot = ( 1.0f - dot ) * 1000.0f; 522 score += dot * mDesc->priority; 523 524 // Also account for the camera movement. 525 score += ( camPos - mLastPos ).lenSquared() * mDesc->priority; 526 527 return score; 528} 529 530void PlaneReflector::updateReflection( const ReflectParams ¶ms ) 531{ 532 PROFILE_SCOPE(PlaneReflector_updateReflection); 533 GFXDEBUGEVENT_SCOPE( PlaneReflector_updateReflection, ColorI::WHITE ); 534 535 mIsRendering = true; 536 537 S32 texDim = mDesc->texSize; 538 texDim = getMax( texDim, 32 ); 539 540 // Protect against the reflection texture being bigger 541 // than the current game back buffer. 542 texDim = getMin( texDim, params.viewportExtent.x ); 543 texDim = getMin( texDim, params.viewportExtent.y ); 544 545 S32 currentTarget = params.eyeId >= 0 ? params.eyeId : 0; 546 547 const Point2I texSize = Point2I(texDim, texDim); 548 549 bool texResize = (texSize != mLastTexSize); 550 mLastTexSize = texSize; 551 552 if ( texResize || 553 innerReflectTex[currentTarget].isNull() || 554 innerReflectTex[currentTarget]->getSize() != texSize || 555 reflectTex->getFormat() != REFLECTMGR->getReflectFormat() ) 556 { 557 innerReflectTex[currentTarget] = REFLECTMGR->allocRenderTarget( texSize ); 558 } 559 560 if ( texResize || depthBuff.isNull() ) 561 { 562 depthBuff = LightShadowMap::_getDepthTarget(texSize.x, texSize.y); 563 } 564 565 reflectTex = innerReflectTex[currentTarget]; 566 567 // store current matrices 568 GFXTransformSaver saver; 569 570 Frustum frustum; 571 572 S32 stereoTarget = GFX->getCurrentStereoTarget(); 573 if (stereoTarget != -1) 574 { 575 MathUtils::makeFovPortFrustum(&frustum, false, params.query->nearPlane, params.query->farPlane, params.query->fovPort[stereoTarget]); 576 } 577 else 578 { 579 Point2I viewport(params.viewportExtent); 580 if (GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide) 581 { 582 viewport.x *= 0.5f; 583 } 584 F32 aspectRatio = F32(viewport.x) / F32(viewport.y); 585 frustum.set(false, params.query->fov, aspectRatio, params.query->nearPlane, params.query->farPlane); 586 } 587 588 // Manipulate the frustum for tiled screenshots 589 const bool screenShotMode = gScreenShot && gScreenShot->isPending(); 590 if ( screenShotMode ) 591 gScreenShot->tileFrustum( frustum ); 592 593 GFX->setFrustum( frustum ); 594 595 // Store the last view info for scoring. 596 mLastDir = params.query->cameraMatrix.getForwardVector(); 597 mLastPos = params.query->cameraMatrix.getPosition(); 598 599 setGFXMatrices( params.query->cameraMatrix ); 600 601 // Adjust the detail amount 602 F32 detailAdjustBackup = TSShapeInstance::smDetailAdjust; 603 TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust; 604 605 606 if(reflectTarget.isNull()) 607 reflectTarget = GFX->allocRenderToTextureTarget(); 608 reflectTarget->attachTexture( GFXTextureTarget::Color0, innerReflectTex[currentTarget] ); 609 reflectTarget->attachTexture( GFXTextureTarget::DepthStencil, depthBuff ); 610 GFX->pushActiveRenderTarget(); 611 GFX->setActiveRenderTarget( reflectTarget ); 612 613 U32 objTypeFlag = -1; 614 SceneCameraState reflectCameraState = SceneCameraState::fromGFX(); 615 LIGHTMGR->registerGlobalLights( &reflectCameraState.getFrustum(), false ); 616 617 // Since we can sometime be rendering a reflection for 1 or 2 frames before 618 // it gets updated do to the lag associated with getting the results from 619 // a HOQ we can sometimes see into parts of the reflection texture that 620 // have nothing but clear color ( eg. under the water ). 621 // To make this look less crappy use the ambient color of the sun. 622 // 623 // In the future we may want to fix this instead by having the scatterSky 624 // render a skirt or something in its lower half. 625 // 626 LinearColorF clearColor = gClientSceneGraph->getAmbientLightColor(); 627 GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, clearColor, 1.0f, 0 ); 628 629 if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide) 630 { 631 // Store previous values 632 RectI originalVP = GFX->getViewport(); 633 MatrixF origNonClipProjection = gClientSceneGraph->getNonClipProjection(); 634 PFXFrameState origPFXState = PFXMGR->getFrameState(); 635 636 MatrixF inverseEyeTransforms[2]; 637 Frustum gfxFrustum; 638 639 // Calculate viewport based on texture size 640 RectI stereoViewports[2]; 641 stereoViewports[0] = params.query->stereoViewports[0]; 642 stereoViewports[1] = params.query->stereoViewports[1]; 643 stereoViewports[0].extent.x = stereoViewports[1].extent.x = texSize.x / 2; 644 stereoViewports[0].extent.y = stereoViewports[1].extent.y = texSize.y; 645 stereoViewports[0].point.x = 0; 646 stereoViewports[1].point.x = stereoViewports[0].extent.x; 647 648 // Calculate world transforms for eyes 649 inverseEyeTransforms[0] = params.query->eyeTransforms[0]; 650 inverseEyeTransforms[1] = params.query->eyeTransforms[1]; 651 inverseEyeTransforms[0].inverse(); 652 inverseEyeTransforms[1].inverse(); 653 654 // 655 // Render left half of display 656 // 657 658 GFX->setViewport(stereoViewports[0]); 659 GFX->setCurrentStereoTarget(0); 660 MathUtils::makeFovPortFrustum(&gfxFrustum, params.query->ortho, params.query->nearPlane, params.query->farPlane, params.query->fovPort[0]); 661 gfxFrustum.update(); 662 GFX->setFrustum(gfxFrustum); 663 664 setGFXMatrices( params.query->eyeTransforms[0] ); 665 666 SceneRenderState renderStateLeft 667 ( 668 gClientSceneGraph, 669 SPT_Reflect, 670 SceneCameraState::fromGFX() 671 ); 672 673 renderStateLeft.setSceneRenderStyle(SRS_SideBySide); 674 renderStateLeft.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); 675 renderStateLeft.setDiffuseCameraTransform(params.query->headMatrix); 676 //renderStateLeft.disableAdvancedLightingBins(true); 677 678 gClientSceneGraph->renderSceneNoLights( &renderStateLeft, objTypeFlag ); 679 680 // 681 // Render right half of display 682 // 683 684 GFX->setViewport(stereoViewports[1]); 685 GFX->setCurrentStereoTarget(1); 686 MathUtils::makeFovPortFrustum(&gfxFrustum, params.query->ortho, params.query->nearPlane, params.query->farPlane, params.query->fovPort[1]); 687 gfxFrustum.update(); 688 GFX->setFrustum(gfxFrustum); 689 690 setGFXMatrices( params.query->eyeTransforms[1] ); 691 692 SceneRenderState renderStateRight 693 ( 694 gClientSceneGraph, 695 SPT_Reflect, 696 SceneCameraState::fromGFX() 697 ); 698 699 renderStateRight.setSceneRenderStyle(SRS_SideBySide); 700 renderStateRight.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); 701 renderStateRight.setDiffuseCameraTransform( params.query->headMatrix ); 702 //renderStateRight.disableAdvancedLightingBins(true); 703 704 gClientSceneGraph->renderSceneNoLights( &renderStateRight, objTypeFlag ); 705 706 // Restore previous values 707 GFX->setFrustum(frustum); 708 GFX->setViewport(originalVP); 709 gClientSceneGraph->setNonClipProjection(origNonClipProjection); 710 PFXMGR->setFrameState(origPFXState); 711 GFX->setCurrentStereoTarget(-1); 712 } 713 else 714 { 715 SceneRenderState reflectRenderState 716 ( 717 gClientSceneGraph, 718 SPT_Reflect, 719 SceneCameraState::fromGFX() 720 ); 721 722 reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); 723 reflectRenderState.setDiffuseCameraTransform( params.query->headMatrix ); 724 725 gClientSceneGraph->renderSceneNoLights( &reflectRenderState, objTypeFlag ); 726 } 727 728 LIGHTMGR->unregisterAllLights(); 729 730 // Clean up. 731 reflectTarget->resolve(); 732 GFX->popActiveRenderTarget(); 733 734#ifdef DEBUG_REFLECT_TEX 735 static U32 reflectStage = 0; 736 char buf[128]; dSprintf(buf, 128, "F:\\REFLECT-OUT%i.PNG", reflectStage); 737 //reflectTex->dumpToDisk("PNG", buf); 738 reflectStage++; 739 if (reflectStage > 1) reflectStage = 0; 740#endif 741 742 // Restore detail adjust amount. 743 TSShapeInstance::smDetailAdjust = detailAdjustBackup; 744 745 mIsRendering = false; 746} 747 748void PlaneReflector::setGFXMatrices( const MatrixF &camTrans ) 749{ 750 if ( objectSpace ) 751 { 752 // set up camera transform relative to object 753 MatrixF invObjTrans = mObject->getRenderTransform(); 754 invObjTrans.inverse(); 755 MatrixF relCamTrans = invObjTrans * camTrans; 756 757 MatrixF camReflectTrans = getCameraReflection( relCamTrans ); 758 MatrixF objTrans = mObject->getRenderTransform() * camReflectTrans; 759 objTrans.inverse(); 760 761 GFX->setWorldMatrix(objTrans); 762 763 // use relative reflect transform for modelview since clip plane is in object space 764 objTrans = camReflectTrans; 765 objTrans.inverse(); 766 767 // set new projection matrix 768 gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() ); 769 MatrixF clipProj = getFrustumClipProj(objTrans); 770 GFX->setProjectionMatrix( clipProj ); 771 } 772 else 773 { 774 // set world mat from new camera view 775 MatrixF camReflectTrans = getCameraReflection( camTrans ); 776 camReflectTrans.inverse(); 777 GFX->setWorldMatrix( camReflectTrans ); 778 779 // set new projection matrix 780 gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() ); 781 MatrixF clipProj = getFrustumClipProj( camReflectTrans ); 782 GFX->setProjectionMatrix( clipProj ); 783 } 784} 785 786MatrixF PlaneReflector::getCameraReflection( const MatrixF &camTrans ) 787{ 788 Point3F normal = refplane; 789 790 // Figure out new cam position 791 Point3F camPos = camTrans.getPosition(); 792 F32 dist = refplane.distToPlane( camPos ); 793 Point3F newCamPos = camPos - normal * dist * 2.0; 794 795 // Figure out new look direction 796 Point3F i, j, k; 797 camTrans.getColumn( 0, &i ); 798 camTrans.getColumn( 1, &j ); 799 camTrans.getColumn( 2, &k ); 800 801 i = MathUtils::reflect( i, normal ); 802 j = MathUtils::reflect( j, normal ); 803 k = MathUtils::reflect( k, normal ); 804 //mCross( i, j, &k ); 805 806 807 MatrixF newTrans(true); 808 newTrans.setColumn( 0, i ); 809 newTrans.setColumn( 1, j ); 810 newTrans.setColumn( 2, k ); 811 812 newTrans.setPosition( newCamPos ); 813 814 return newTrans; 815} 816 817inline F32 sgn(F32 a) 818{ 819 if (a > 0.0F) return (1.0F); 820 if (a < 0.0F) return (-1.0F); 821 return (0.0F); 822} 823 824MatrixF PlaneReflector::getFrustumClipProj( MatrixF &modelview ) 825{ 826 static MatrixF rotMat(EulerF( static_cast<F32>(M_PI / 2.f), 0.0, 0.0)); 827 static MatrixF invRotMat(EulerF( -static_cast<F32>(M_PI / 2.f), 0.0, 0.0)); 828 829 830 MatrixF revModelview = modelview; 831 revModelview = rotMat * revModelview; // add rotation to modelview because it needs to be removed from projection 832 833 // rotate clip plane into modelview space 834 Point4F clipPlane; 835 Point3F pnt = refplane * -(refplane.d + 0.0 ); 836 Point3F norm = refplane; 837 838 revModelview.mulP( pnt ); 839 revModelview.mulV( norm ); 840 norm.normalize(); 841 842 clipPlane.set( norm.x, norm.y, norm.z, -mDot( pnt, norm ) ); 843 844 845 // Manipulate projection matrix 846 //------------------------------------------------------------------------ 847 MatrixF proj = GFX->getProjectionMatrix(); 848 proj.mul( invRotMat ); // reverse rotation imposed by Torque 849 proj.transpose(); // switch to row-major order 850 851 // Calculate the clip-space corner point opposite the clipping plane 852 // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and 853 // transform it into camera space by multiplying it 854 // by the inverse of the projection matrix 855 Vector4F q; 856 q.x = sgn(clipPlane.x) / proj(0,0); 857 q.y = sgn(clipPlane.y) / proj(1,1); 858 q.z = -1.0F; 859 q.w = ( 1.0F - proj(2,2) ) / proj(3,2); 860 861 F32 a = 1.0 / (clipPlane.x * q.x + clipPlane.y * q.y + clipPlane.z * q.z + clipPlane.w * q.w); 862 863 Vector4F c = clipPlane * a; 864 865 // CodeReview [ags 1/23/08] Come up with a better way to deal with this. 866 if(GFX->getAdapterType() == OpenGL) 867 c.z += 1.0f; 868 869 // Replace the third column of the projection matrix 870 proj.setColumn( 2, c ); 871 proj.transpose(); // convert back to column major order 872 proj.mul( rotMat ); // restore Torque rotation 873 874 return proj; 875} 876