mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-09 23:40:42 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
743
Engine/source/scene/reflector.cpp
Normal file
743
Engine/source/scene/reflector.cpp
Normal file
|
|
@ -0,0 +1,743 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "scene/reflector.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gfx/gfxCubemap.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "scene/reflectionManager.h"
|
||||
#include "gui/3d/guiTSControl.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "gfx/gfxOcclusionQuery.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "math/util/frustum.h"
|
||||
#include "gfx/screenshot.h"
|
||||
|
||||
extern ColorI gCanvasClearColor;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// ReflectorDesc
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1( ReflectorDesc );
|
||||
|
||||
ConsoleDocClass( ReflectorDesc,
|
||||
"@brief A datablock which defines performance and quality properties for "
|
||||
"dynamic reflections.\n\n"
|
||||
|
||||
"ReflectorDesc is not itself a reflection and does not render reflections. "
|
||||
"It is a dummy class for holding and exposing to the user a set of "
|
||||
"reflection related properties. Objects which support dynamic reflections "
|
||||
"may then reference a ReflectorDesc.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"datablock ReflectorDesc( ExampleReflectorDesc )\n"
|
||||
"{\n"
|
||||
" texSize = 256;\n"
|
||||
" nearDist = 0.1;\n"
|
||||
" farDist = 500;\n"
|
||||
" objectTypeMask = 0xFFFFFFFF;\n"
|
||||
" detailAdjust = 1.0;\n"
|
||||
" priority = 1.0;\n"
|
||||
" maxRateMs = 0;\n"
|
||||
" useOcclusionQuery = true;\n"
|
||||
"};\n"
|
||||
"@endtsexample\n"
|
||||
|
||||
"@see ShapeBaseData::cubeReflectorDesc\n"
|
||||
"@ingroup enviroMisc"
|
||||
);
|
||||
|
||||
ReflectorDesc::ReflectorDesc()
|
||||
{
|
||||
texSize = 256;
|
||||
nearDist = 0.1f;
|
||||
farDist = 1000.0f;
|
||||
objectTypeMask = 0xFFFFFFFF;
|
||||
detailAdjust = 1.0f;
|
||||
priority = 1.0f;
|
||||
maxRateMs = 15;
|
||||
useOcclusionQuery = true;
|
||||
}
|
||||
|
||||
ReflectorDesc::~ReflectorDesc()
|
||||
{
|
||||
}
|
||||
|
||||
void ReflectorDesc::initPersistFields()
|
||||
{
|
||||
addGroup( "ReflectorDesc" );
|
||||
|
||||
addField( "texSize", TypeS32, Offset( texSize, ReflectorDesc ),
|
||||
"Size in pixels of the (square) reflection texture. For a cubemap "
|
||||
"this value is interpreted as size of each face." );
|
||||
|
||||
addField( "nearDist", TypeF32, Offset( nearDist, ReflectorDesc ),
|
||||
"Near plane distance to use when rendering this reflection. Adjust "
|
||||
"this to limit self-occlusion artifacts." );
|
||||
|
||||
addField( "farDist", TypeF32, Offset( farDist, ReflectorDesc ),
|
||||
"Far plane distance to use when rendering reflections." );
|
||||
|
||||
addField( "objectTypeMask", TypeS32, Offset( objectTypeMask, ReflectorDesc ),
|
||||
"Object types which render into this reflection." );
|
||||
|
||||
addField( "detailAdjust", TypeF32, Offset( detailAdjust, ReflectorDesc ),
|
||||
"Scale applied to lod calculation of objects rendering into "
|
||||
"this reflection ( modulates $pref::TS::detailAdjust )." );
|
||||
|
||||
addField( "priority", TypeF32, Offset( priority, ReflectorDesc ),
|
||||
"Priority for updating this reflection, relative to others." );
|
||||
|
||||
addField( "maxRateMs", TypeS32, Offset( maxRateMs, ReflectorDesc ),
|
||||
"If less than maxRateMs has elapsed since this relfection was last "
|
||||
"updated, then do not update it again. This 'skip' can be disabled by "
|
||||
"setting maxRateMs to zero." );
|
||||
|
||||
addField( "useOcclusionQuery", TypeBool, Offset( useOcclusionQuery, ReflectorDesc ),
|
||||
"If available on the device use HOQs to determine if the reflective object "
|
||||
"is visible before updating its reflection." );
|
||||
|
||||
endGroup( "ReflectorDesc" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void ReflectorDesc::packData( BitStream *stream )
|
||||
{
|
||||
Parent::packData( stream );
|
||||
|
||||
stream->write( texSize );
|
||||
stream->write( nearDist );
|
||||
stream->write( farDist );
|
||||
stream->write( objectTypeMask );
|
||||
stream->write( detailAdjust );
|
||||
stream->write( priority );
|
||||
stream->write( maxRateMs );
|
||||
stream->writeFlag( useOcclusionQuery );
|
||||
}
|
||||
|
||||
void ReflectorDesc::unpackData( BitStream *stream )
|
||||
{
|
||||
Parent::unpackData( stream );
|
||||
|
||||
stream->read( &texSize );
|
||||
stream->read( &nearDist );
|
||||
stream->read( &farDist );
|
||||
stream->read( &objectTypeMask );
|
||||
stream->read( &detailAdjust );
|
||||
stream->read( &priority );
|
||||
stream->read( &maxRateMs );
|
||||
useOcclusionQuery = stream->readFlag();
|
||||
}
|
||||
|
||||
bool ReflectorDesc::preload( bool server, String &errorStr )
|
||||
{
|
||||
if ( !Parent::preload( server, errorStr ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// ReflectorBase
|
||||
//-------------------------------------------------------------------------
|
||||
ReflectorBase::ReflectorBase()
|
||||
{
|
||||
mEnabled = false;
|
||||
mOccluded = false;
|
||||
mIsRendering = false;
|
||||
mDesc = NULL;
|
||||
mObject = NULL;
|
||||
mOcclusionQuery = GFX->createOcclusionQuery();
|
||||
mQueryPending = false;
|
||||
}
|
||||
|
||||
ReflectorBase::~ReflectorBase()
|
||||
{
|
||||
delete mOcclusionQuery;
|
||||
}
|
||||
|
||||
void ReflectorBase::unregisterReflector()
|
||||
{
|
||||
if ( mEnabled )
|
||||
{
|
||||
REFLECTMGR->unregisterReflector( this );
|
||||
mEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
F32 ReflectorBase::calcScore( const ReflectParams ¶ms )
|
||||
{
|
||||
PROFILE_SCOPE( ReflectorBase_calcScore );
|
||||
|
||||
// First check the occlusion query to see if we're hidden.
|
||||
if ( mDesc->useOcclusionQuery &&
|
||||
mOcclusionQuery )
|
||||
{
|
||||
GFXOcclusionQuery::OcclusionQueryStatus status = mOcclusionQuery->getStatus( false );
|
||||
|
||||
if ( status == GFXOcclusionQuery::Waiting )
|
||||
{
|
||||
mQueryPending = true;
|
||||
// Don't change mOccluded since we don't know yet, use the value
|
||||
// from last frame.
|
||||
}
|
||||
else
|
||||
{
|
||||
mQueryPending = false;
|
||||
|
||||
if ( status == GFXOcclusionQuery::Occluded )
|
||||
mOccluded = true;
|
||||
else if ( status == GFXOcclusionQuery::NotOccluded )
|
||||
mOccluded = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're disabled for any reason then there
|
||||
// is nothing more left to do.
|
||||
if ( !mEnabled ||
|
||||
mOccluded ||
|
||||
params.culler.isCulled( mObject->getWorldBox() ) )
|
||||
{
|
||||
score = 0;
|
||||
return score;
|
||||
}
|
||||
|
||||
// This mess is calculating a score based on LOD.
|
||||
|
||||
/*
|
||||
F32 sizeWS = getMax( object->getWorldBox().len_z(), 0.001f );
|
||||
Point3F cameraOffset = params.culler.getPosition() - object->getPosition();
|
||||
F32 dist = getMax( cameraOffset.len(), 0.01f );
|
||||
F32 worldToScreenScaleY = ( params.culler.getNearDist() * params.viewportExtent.y ) /
|
||||
( params.culler.getNearTop() - params.culler.getNearBottom() );
|
||||
F32 sizeSS = sizeWS / dist * worldToScreenScaleY;
|
||||
*/
|
||||
|
||||
if ( mDesc->priority == -1.0f )
|
||||
{
|
||||
score = 1000.0f;
|
||||
return score;
|
||||
}
|
||||
|
||||
F32 lodFactor = 1.0f; //sizeSS;
|
||||
|
||||
F32 maxRate = getMax( (F32)mDesc->maxRateMs, 1.0f );
|
||||
U32 delta = params.startOfUpdateMs - lastUpdateMs;
|
||||
F32 timeFactor = getMax( (F32)delta / maxRate - 1.0f, 0.0f );
|
||||
|
||||
score = mDesc->priority * timeFactor * lodFactor;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CubeReflector
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
CubeReflector::CubeReflector()
|
||||
: mLastTexSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void CubeReflector::registerReflector( SceneObject *object,
|
||||
ReflectorDesc *desc )
|
||||
{
|
||||
if ( mEnabled )
|
||||
return;
|
||||
|
||||
mEnabled = true;
|
||||
mObject = object;
|
||||
mDesc = desc;
|
||||
REFLECTMGR->registerReflector( this );
|
||||
}
|
||||
|
||||
void CubeReflector::unregisterReflector()
|
||||
{
|
||||
if ( !mEnabled )
|
||||
return;
|
||||
|
||||
REFLECTMGR->unregisterReflector( this );
|
||||
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
void CubeReflector::updateReflection( const ReflectParams ¶ms )
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( CubeReflector_UpdateReflection, ColorI::WHITE );
|
||||
|
||||
mIsRendering = true;
|
||||
|
||||
// Setup textures and targets...
|
||||
S32 texDim = mDesc->texSize;
|
||||
texDim = getMax( texDim, 32 );
|
||||
|
||||
// Protect against the reflection texture being bigger
|
||||
// than the current game back buffer.
|
||||
texDim = getMin( texDim, params.viewportExtent.x );
|
||||
texDim = getMin( texDim, params.viewportExtent.y );
|
||||
|
||||
bool texResize = ( texDim != mLastTexSize );
|
||||
|
||||
const GFXFormat reflectFormat = REFLECTMGR->getReflectFormat();
|
||||
|
||||
if ( texResize ||
|
||||
cubemap.isNull() ||
|
||||
cubemap->getFormat() != reflectFormat )
|
||||
{
|
||||
cubemap = GFX->createCubemap();
|
||||
cubemap->initDynamic( texDim, reflectFormat );
|
||||
}
|
||||
|
||||
GFXTexHandle depthBuff = LightShadowMap::_getDepthTarget( texDim, texDim );
|
||||
|
||||
if ( renderTarget.isNull() )
|
||||
renderTarget = GFX->allocRenderToTextureTarget();
|
||||
|
||||
GFX->pushActiveRenderTarget();
|
||||
renderTarget->attachTexture( GFXTextureTarget::DepthStencil, depthBuff );
|
||||
|
||||
|
||||
F32 oldVisibleDist = gClientSceneGraph->getVisibleDistance();
|
||||
gClientSceneGraph->setVisibleDistance( mDesc->farDist );
|
||||
|
||||
|
||||
for ( U32 i = 0; i < 6; i++ )
|
||||
updateFace( params, i );
|
||||
|
||||
|
||||
GFX->popActiveRenderTarget();
|
||||
|
||||
gClientSceneGraph->setVisibleDistance(oldVisibleDist);
|
||||
|
||||
mIsRendering = false;
|
||||
mLastTexSize = texDim;
|
||||
}
|
||||
|
||||
void CubeReflector::updateFace( const ReflectParams ¶ms, U32 faceidx )
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( CubeReflector_UpdateFace, ColorI::WHITE );
|
||||
|
||||
// store current matrices
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// set projection to 90 degrees vertical and horizontal
|
||||
F32 left, right, top, bottom;
|
||||
MathUtils::makeFrustum( &left, &right, &top, &bottom, M_HALFPI_F, 1.0f, mDesc->nearDist );
|
||||
GFX->setFrustum( left, right, bottom, top, mDesc->nearDist, mDesc->farDist );
|
||||
|
||||
// We don't use a special clipping projection, but still need to initialize
|
||||
// this for objects like SkyBox which will use it during a reflect pass.
|
||||
gClientSceneGraph->setNonClipProjection( GFX->getProjectionMatrix() );
|
||||
|
||||
// Standard view that will be overridden below.
|
||||
VectorF vLookatPt(0.0f, 0.0f, 0.0f), vUpVec(0.0f, 0.0f, 0.0f), vRight(0.0f, 0.0f, 0.0f);
|
||||
|
||||
switch( faceidx )
|
||||
{
|
||||
case 0 : // D3DCUBEMAP_FACE_POSITIVE_X:
|
||||
vLookatPt = VectorF( 1.0f, 0.0f, 0.0f );
|
||||
vUpVec = VectorF( 0.0f, 1.0f, 0.0f );
|
||||
break;
|
||||
case 1 : // D3DCUBEMAP_FACE_NEGATIVE_X:
|
||||
vLookatPt = VectorF( -1.0f, 0.0f, 0.0f );
|
||||
vUpVec = VectorF( 0.0f, 1.0f, 0.0f );
|
||||
break;
|
||||
case 2 : // D3DCUBEMAP_FACE_POSITIVE_Y:
|
||||
vLookatPt = VectorF( 0.0f, 1.0f, 0.0f );
|
||||
vUpVec = VectorF( 0.0f, 0.0f,-1.0f );
|
||||
break;
|
||||
case 3 : // D3DCUBEMAP_FACE_NEGATIVE_Y:
|
||||
vLookatPt = VectorF( 0.0f, -1.0f, 0.0f );
|
||||
vUpVec = VectorF( 0.0f, 0.0f, 1.0f );
|
||||
break;
|
||||
case 4 : // D3DCUBEMAP_FACE_POSITIVE_Z:
|
||||
vLookatPt = VectorF( 0.0f, 0.0f, 1.0f );
|
||||
vUpVec = VectorF( 0.0f, 1.0f, 0.0f );
|
||||
break;
|
||||
case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z:
|
||||
vLookatPt = VectorF( 0.0f, 0.0f, -1.0f );
|
||||
vUpVec = VectorF( 0.0f, 1.0f, 0.0f );
|
||||
break;
|
||||
}
|
||||
|
||||
// create camera matrix
|
||||
VectorF cross = mCross( vUpVec, vLookatPt );
|
||||
cross.normalizeSafe();
|
||||
|
||||
MatrixF matView(true);
|
||||
matView.setColumn( 0, cross );
|
||||
matView.setColumn( 1, vLookatPt );
|
||||
matView.setColumn( 2, vUpVec );
|
||||
matView.setPosition( mObject->getPosition() );
|
||||
matView.inverse();
|
||||
|
||||
GFX->setWorldMatrix(matView);
|
||||
|
||||
renderTarget->attachTexture( GFXTextureTarget::Color0, cubemap, faceidx );
|
||||
GFX->setActiveRenderTarget( renderTarget );
|
||||
GFX->clear( GFXClearStencil | GFXClearTarget | GFXClearZBuffer, gCanvasClearColor, 1.0f, 0 );
|
||||
|
||||
SceneRenderState reflectRenderState
|
||||
(
|
||||
gClientSceneGraph,
|
||||
SPT_Reflect,
|
||||
SceneCameraState::fromGFX()
|
||||
);
|
||||
|
||||
reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial );
|
||||
reflectRenderState.setDiffuseCameraTransform( params.query->cameraMatrix );
|
||||
reflectRenderState.disableAdvancedLightingBins(true);
|
||||
|
||||
// render scene
|
||||
LIGHTMGR->registerGlobalLights( &reflectRenderState.getFrustum(), false );
|
||||
gClientSceneGraph->renderSceneNoLights( &reflectRenderState, mDesc->objectTypeMask );
|
||||
LIGHTMGR->unregisterAllLights();
|
||||
|
||||
// Clean up.
|
||||
renderTarget->resolve();
|
||||
}
|
||||
|
||||
F32 CubeReflector::calcFaceScore( const ReflectParams ¶ms, U32 faceidx )
|
||||
{
|
||||
if ( Parent::calcScore( params ) <= 0.0f )
|
||||
return score;
|
||||
|
||||
VectorF vLookatPt(0.0f, 0.0f, 0.0f);
|
||||
|
||||
switch( faceidx )
|
||||
{
|
||||
case 0 : // D3DCUBEMAP_FACE_POSITIVE_X:
|
||||
vLookatPt = VectorF( 1.0f, 0.0f, 0.0f );
|
||||
break;
|
||||
case 1 : // D3DCUBEMAP_FACE_NEGATIVE_X:
|
||||
vLookatPt = VectorF( -1.0f, 0.0f, 0.0f );
|
||||
break;
|
||||
case 2 : // D3DCUBEMAP_FACE_POSITIVE_Y:
|
||||
vLookatPt = VectorF( 0.0f, 1.0f, 0.0f );
|
||||
break;
|
||||
case 3 : // D3DCUBEMAP_FACE_NEGATIVE_Y:
|
||||
vLookatPt = VectorF( 0.0f, -1.0f, 0.0f );
|
||||
break;
|
||||
case 4 : // D3DCUBEMAP_FACE_POSITIVE_Z:
|
||||
vLookatPt = VectorF( 0.0f, 0.0f, 1.0f );
|
||||
break;
|
||||
case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z:
|
||||
vLookatPt = VectorF( 0.0f, 0.0f, -1.0f );
|
||||
break;
|
||||
}
|
||||
|
||||
VectorF cameraDir;
|
||||
params.query->cameraMatrix.getColumn( 1, &cameraDir );
|
||||
|
||||
F32 dot = mDot( cameraDir, -vLookatPt );
|
||||
|
||||
dot = getMax( ( dot + 1.0f ) / 2.0f, 0.1f );
|
||||
|
||||
score *= dot;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
F32 CubeReflector::CubeFaceReflector::calcScore( const ReflectParams ¶ms )
|
||||
{
|
||||
score = cube->calcFaceScore( params, faceIdx );
|
||||
mOccluded = cube->isOccluded();
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// PlaneReflector
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void PlaneReflector::registerReflector( SceneObject *object,
|
||||
ReflectorDesc *desc )
|
||||
{
|
||||
mEnabled = true;
|
||||
mObject = object;
|
||||
mDesc = desc;
|
||||
mLastDir = Point3F::One;
|
||||
mLastPos = Point3F::Max;
|
||||
|
||||
REFLECTMGR->registerReflector( this );
|
||||
}
|
||||
|
||||
F32 PlaneReflector::calcScore( const ReflectParams ¶ms )
|
||||
{
|
||||
if ( Parent::calcScore( params ) <= 0.0f || score >= 1000.0f )
|
||||
return score;
|
||||
|
||||
// The planar reflection is view dependent to score it
|
||||
// higher if the view direction and/or position has changed.
|
||||
|
||||
// Get the current camera info.
|
||||
VectorF camDir = params.query->cameraMatrix.getForwardVector();
|
||||
Point3F camPos = params.query->cameraMatrix.getPosition();
|
||||
|
||||
// Scale up the score based on the view direction change.
|
||||
F32 dot = mDot( camDir, mLastDir );
|
||||
dot = ( 1.0f - dot ) * 1000.0f;
|
||||
score += dot * mDesc->priority;
|
||||
|
||||
// Also account for the camera movement.
|
||||
score += ( camPos - mLastPos ).lenSquared() * mDesc->priority;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
void PlaneReflector::updateReflection( const ReflectParams ¶ms )
|
||||
{
|
||||
PROFILE_SCOPE(PlaneReflector_updateReflection);
|
||||
GFXDEBUGEVENT_SCOPE( PlaneReflector_updateReflection, ColorI::WHITE );
|
||||
|
||||
mIsRendering = true;
|
||||
|
||||
S32 texDim = mDesc->texSize;
|
||||
texDim = getMax( texDim, 32 );
|
||||
|
||||
// Protect against the reflection texture being bigger
|
||||
// than the current game back buffer.
|
||||
texDim = getMin( texDim, params.viewportExtent.x );
|
||||
texDim = getMin( texDim, params.viewportExtent.y );
|
||||
|
||||
bool texResize = ( texDim != mLastTexSize );
|
||||
mLastTexSize = texDim;
|
||||
|
||||
const Point2I texSize( texDim, texDim );
|
||||
|
||||
if ( texResize ||
|
||||
reflectTex.isNull() ||
|
||||
reflectTex->getFormat() != REFLECTMGR->getReflectFormat() )
|
||||
reflectTex = REFLECTMGR->allocRenderTarget( texSize );
|
||||
|
||||
GFXTexHandle depthBuff = LightShadowMap::_getDepthTarget( texSize.x, texSize.y );
|
||||
|
||||
// store current matrices
|
||||
GFXTransformSaver saver;
|
||||
|
||||
F32 aspectRatio = F32( params.viewportExtent.x ) / F32( params.viewportExtent.y );
|
||||
|
||||
Frustum frustum;
|
||||
frustum.set(false, params.query->fov, aspectRatio, params.query->nearPlane, params.query->farPlane);
|
||||
|
||||
// Manipulate the frustum for tiled screenshots
|
||||
const bool screenShotMode = gScreenShot && gScreenShot->isPending();
|
||||
if ( screenShotMode )
|
||||
gScreenShot->tileFrustum( frustum );
|
||||
|
||||
GFX->setFrustum( frustum );
|
||||
|
||||
// Store the last view info for scoring.
|
||||
mLastDir = params.query->cameraMatrix.getForwardVector();
|
||||
mLastPos = params.query->cameraMatrix.getPosition();
|
||||
|
||||
if ( objectSpace )
|
||||
{
|
||||
// set up camera transform relative to object
|
||||
MatrixF invObjTrans = mObject->getRenderTransform();
|
||||
invObjTrans.inverse();
|
||||
MatrixF relCamTrans = invObjTrans * params.query->cameraMatrix;
|
||||
|
||||
MatrixF camReflectTrans = getCameraReflection( relCamTrans );
|
||||
MatrixF camTrans = mObject->getRenderTransform() * camReflectTrans;
|
||||
camTrans.inverse();
|
||||
|
||||
GFX->setWorldMatrix( camTrans );
|
||||
|
||||
// use relative reflect transform for modelview since clip plane is in object space
|
||||
camTrans = camReflectTrans;
|
||||
camTrans.inverse();
|
||||
|
||||
// set new projection matrix
|
||||
gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() );
|
||||
MatrixF clipProj = getFrustumClipProj( camTrans );
|
||||
GFX->setProjectionMatrix( clipProj );
|
||||
}
|
||||
else
|
||||
{
|
||||
MatrixF camTrans = params.query->cameraMatrix;
|
||||
|
||||
// set world mat from new camera view
|
||||
MatrixF camReflectTrans = getCameraReflection( camTrans );
|
||||
camReflectTrans.inverse();
|
||||
GFX->setWorldMatrix( camReflectTrans );
|
||||
|
||||
// set new projection matrix
|
||||
gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() );
|
||||
MatrixF clipProj = getFrustumClipProj( camReflectTrans );
|
||||
GFX->setProjectionMatrix( clipProj );
|
||||
}
|
||||
|
||||
// Adjust the detail amount
|
||||
F32 detailAdjustBackup = TSShapeInstance::smDetailAdjust;
|
||||
TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust;
|
||||
|
||||
|
||||
if(reflectTarget.isNull())
|
||||
reflectTarget = GFX->allocRenderToTextureTarget();
|
||||
reflectTarget->attachTexture( GFXTextureTarget::Color0, reflectTex );
|
||||
reflectTarget->attachTexture( GFXTextureTarget::DepthStencil, depthBuff );
|
||||
GFX->pushActiveRenderTarget();
|
||||
GFX->setActiveRenderTarget( reflectTarget );
|
||||
|
||||
SceneRenderState reflectRenderState
|
||||
(
|
||||
gClientSceneGraph,
|
||||
SPT_Reflect,
|
||||
SceneCameraState::fromGFX()
|
||||
);
|
||||
|
||||
reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial );
|
||||
reflectRenderState.setDiffuseCameraTransform( params.query->cameraMatrix );
|
||||
reflectRenderState.disableAdvancedLightingBins(true);
|
||||
|
||||
U32 objTypeFlag = -1;
|
||||
LIGHTMGR->registerGlobalLights( &reflectRenderState.getFrustum(), false );
|
||||
|
||||
// Since we can sometime be rendering a reflection for 1 or 2 frames before
|
||||
// it gets updated do to the lag associated with getting the results from
|
||||
// a HOQ we can sometimes see into parts of the reflection texture that
|
||||
// have nothing but clear color ( eg. under the water ).
|
||||
// To make this look less crappy use the ambient color of the sun.
|
||||
//
|
||||
// In the future we may want to fix this instead by having the scatterSky
|
||||
// render a skirt or something in its lower half.
|
||||
//
|
||||
ColorF clearColor = reflectRenderState.getAmbientLightColor();
|
||||
GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, clearColor, 1.0f, 0 );
|
||||
|
||||
gClientSceneGraph->renderSceneNoLights( &reflectRenderState, objTypeFlag );
|
||||
|
||||
LIGHTMGR->unregisterAllLights();
|
||||
|
||||
// Clean up.
|
||||
reflectTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
|
||||
// Restore detail adjust amount.
|
||||
TSShapeInstance::smDetailAdjust = detailAdjustBackup;
|
||||
|
||||
mIsRendering = false;
|
||||
}
|
||||
|
||||
MatrixF PlaneReflector::getCameraReflection( MatrixF &camTrans )
|
||||
{
|
||||
Point3F normal = refplane;
|
||||
|
||||
// Figure out new cam position
|
||||
Point3F camPos = camTrans.getPosition();
|
||||
F32 dist = refplane.distToPlane( camPos );
|
||||
Point3F newCamPos = camPos - normal * dist * 2.0;
|
||||
|
||||
// Figure out new look direction
|
||||
Point3F i, j, k;
|
||||
camTrans.getColumn( 0, &i );
|
||||
camTrans.getColumn( 1, &j );
|
||||
camTrans.getColumn( 2, &k );
|
||||
|
||||
i = MathUtils::reflect( i, normal );
|
||||
j = MathUtils::reflect( j, normal );
|
||||
k = MathUtils::reflect( k, normal );
|
||||
//mCross( i, j, &k );
|
||||
|
||||
|
||||
MatrixF newTrans(true);
|
||||
newTrans.setColumn( 0, i );
|
||||
newTrans.setColumn( 1, j );
|
||||
newTrans.setColumn( 2, k );
|
||||
|
||||
newTrans.setPosition( newCamPos );
|
||||
|
||||
return newTrans;
|
||||
}
|
||||
|
||||
inline float sgn(float a)
|
||||
{
|
||||
if (a > 0.0F) return (1.0F);
|
||||
if (a < 0.0F) return (-1.0F);
|
||||
return (0.0F);
|
||||
}
|
||||
|
||||
MatrixF PlaneReflector::getFrustumClipProj( MatrixF &modelview )
|
||||
{
|
||||
static MatrixF rotMat(EulerF( static_cast<F32>(M_PI / 2.f), 0.0, 0.0));
|
||||
static MatrixF invRotMat(EulerF( -static_cast<F32>(M_PI / 2.f), 0.0, 0.0));
|
||||
|
||||
|
||||
MatrixF revModelview = modelview;
|
||||
revModelview = rotMat * revModelview; // add rotation to modelview because it needs to be removed from projection
|
||||
|
||||
// rotate clip plane into modelview space
|
||||
Point4F clipPlane;
|
||||
Point3F pnt = refplane * -(refplane.d + 0.0 );
|
||||
Point3F norm = refplane;
|
||||
|
||||
revModelview.mulP( pnt );
|
||||
revModelview.mulV( norm );
|
||||
norm.normalize();
|
||||
|
||||
clipPlane.set( norm.x, norm.y, norm.z, -mDot( pnt, norm ) );
|
||||
|
||||
|
||||
// Manipulate projection matrix
|
||||
//------------------------------------------------------------------------
|
||||
MatrixF proj = GFX->getProjectionMatrix();
|
||||
proj.mul( invRotMat ); // reverse rotation imposed by Torque
|
||||
proj.transpose(); // switch to row-major order
|
||||
|
||||
// Calculate the clip-space corner point opposite the clipping plane
|
||||
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
|
||||
// transform it into camera space by multiplying it
|
||||
// by the inverse of the projection matrix
|
||||
Vector4F q;
|
||||
q.x = sgn(clipPlane.x) / proj(0,0);
|
||||
q.y = sgn(clipPlane.y) / proj(1,1);
|
||||
q.z = -1.0F;
|
||||
q.w = ( 1.0F - proj(2,2) ) / proj(3,2);
|
||||
|
||||
F32 a = 1.0 / (clipPlane.x * q.x + clipPlane.y * q.y + clipPlane.z * q.z + clipPlane.w * q.w);
|
||||
|
||||
Vector4F c = clipPlane * a;
|
||||
|
||||
// CodeReview [ags 1/23/08] Come up with a better way to deal with this.
|
||||
if(GFX->getAdapterType() == OpenGL)
|
||||
c.z += 1.0f;
|
||||
|
||||
// Replace the third column of the projection matrix
|
||||
proj.setColumn( 2, c );
|
||||
proj.transpose(); // convert back to column major order
|
||||
proj.mul( rotMat ); // restore Torque rotation
|
||||
|
||||
return proj;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue