reflector.cpp

Engine/source/scene/reflector.cpp

More...

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" )
sgn(F32 a)

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 &params )
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 &params, 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 &params, 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 &params, 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 &params )
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 &params )
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 &params )
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