mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-22 04:45:31 +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
202
Engine/source/lighting/shadowMap/cubeLightShadowMap.cpp
Normal file
202
Engine/source/lighting/shadowMap/cubeLightShadowMap.cpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/cubeLightShadowMap.h"
|
||||
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "materials/materialDefinition.h"
|
||||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "math/mathUtils.h"
|
||||
|
||||
|
||||
CubeLightShadowMap::CubeLightShadowMap( LightInfo *light )
|
||||
: Parent( light )
|
||||
{
|
||||
}
|
||||
|
||||
bool CubeLightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc )
|
||||
{
|
||||
if ( currTexFlag == Material::DynamicLight )
|
||||
{
|
||||
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
GFX->setCubeTexture( reg, mCubemap );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CubeLightShadowMap::setShaderParameters( GFXShaderConstBuffer *params,
|
||||
LightingShaderConstants *lsc )
|
||||
{
|
||||
if ( lsc->mTapRotationTexSC->isValid() )
|
||||
GFX->setTexture( lsc->mTapRotationTexSC->getSamplerRegister(),
|
||||
SHADOWMGR->getTapRotationTex() );
|
||||
|
||||
ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
|
||||
if ( lsc->mLightParamsSC->isValid() )
|
||||
{
|
||||
Point4F lightParams( mLight->getRange().x,
|
||||
p->overDarkFactor.x,
|
||||
0.0f,
|
||||
0.0f );
|
||||
params->set(lsc->mLightParamsSC, lightParams);
|
||||
}
|
||||
|
||||
// The softness is a factor of the texel size.
|
||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
|
||||
void CubeLightShadowMap::releaseTextures()
|
||||
{
|
||||
Parent::releaseTextures();
|
||||
mCubemap = NULL;
|
||||
}
|
||||
|
||||
void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
PROFILE_SCOPE( CubeLightShadowMap_Render );
|
||||
|
||||
const LightMapParams *lmParams = mLight->getExtended<LightMapParams>();
|
||||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||
|
||||
const U32 texSize = getBestTexSize();
|
||||
|
||||
if ( mCubemap.isNull() ||
|
||||
mTexSize != texSize )
|
||||
{
|
||||
mTexSize = texSize;
|
||||
mCubemap = GFX->createCubemap();
|
||||
mCubemap->initDynamic( mTexSize, LightShadowMap::ShadowMapFormat );
|
||||
}
|
||||
|
||||
// Setup the world to light projection which is used
|
||||
// in the shader to transform the light vector for the
|
||||
// shadow lookup.
|
||||
mWorldToLightProj = mLight->getTransform();
|
||||
mWorldToLightProj.inverse();
|
||||
|
||||
// Set up frustum and visible distance
|
||||
GFXFrustumSaver fsaver;
|
||||
GFXTransformSaver saver;
|
||||
{
|
||||
F32 left, right, top, bottom;
|
||||
MathUtils::makeFrustum( &left, &right, &top, &bottom, M_HALFPI_F, 1.0f, 0.1f );
|
||||
GFX->setFrustum( left, right, bottom, top, 0.1f, mLight->getRange().x );
|
||||
}
|
||||
|
||||
// Render the shadowmap!
|
||||
GFX->pushActiveRenderTarget();
|
||||
|
||||
for( U32 i = 0; i < 6; i++ )
|
||||
{
|
||||
// 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( i )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
GFXDEBUGEVENT_START( CubeLightShadowMap_Render_Face, ColorI::RED );
|
||||
|
||||
// create camera matrix
|
||||
VectorF cross = mCross(vUpVec, vLookatPt);
|
||||
cross.normalizeSafe();
|
||||
|
||||
MatrixF lightMatrix(true);
|
||||
lightMatrix.setColumn(0, cross);
|
||||
lightMatrix.setColumn(1, vLookatPt);
|
||||
lightMatrix.setColumn(2, vUpVec);
|
||||
lightMatrix.setPosition( mLight->getPosition() );
|
||||
lightMatrix.inverse();
|
||||
|
||||
GFX->setWorldMatrix( lightMatrix );
|
||||
|
||||
mTarget->attachTexture(GFXTextureTarget::Color0, mCubemap, i);
|
||||
mTarget->attachTexture(GFXTextureTarget::DepthStencil, _getDepthTarget( mTexSize, mTexSize ));
|
||||
GFX->setActiveRenderTarget(mTarget);
|
||||
GFX->clear( GFXClearTarget | GFXClearStencil | GFXClearZBuffer, ColorI(255,255,255,255), 1.0f, 0 );
|
||||
|
||||
// Create scene state, prep it
|
||||
SceneManager* sceneManager = diffuseState->getSceneManager();
|
||||
|
||||
SceneRenderState shadowRenderState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
shadowRenderState.getMaterialDelegate().bind( this, &LightShadowMap::getShadowMaterial );
|
||||
shadowRenderState.renderNonLightmappedMeshes( true );
|
||||
shadowRenderState.renderLightmappedMeshes( bUseLightmappedGeometry );
|
||||
shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
sceneManager->renderSceneNoLights( &shadowRenderState, SHADOW_TYPEMASK );
|
||||
|
||||
_debugRender( &shadowRenderState );
|
||||
|
||||
// Resolve this face
|
||||
mTarget->resolve();
|
||||
|
||||
GFXDEBUGEVENT_END();
|
||||
}
|
||||
GFX->popActiveRenderTarget();
|
||||
}
|
||||
57
Engine/source/lighting/shadowMap/cubeLightShadowMap.h
Normal file
57
Engine/source/lighting/shadowMap/cubeLightShadowMap.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CUBELIGHTSHADOWMAP_H_
|
||||
#define _CUBELIGHTSHADOWMAP_H_
|
||||
|
||||
#ifndef _LIGHTSHADOWMAP_H_
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#endif
|
||||
#ifndef _GFXCUBEMAP_H_
|
||||
#include "gfx/gfxCubemap.h"
|
||||
#endif
|
||||
|
||||
|
||||
class CubeLightShadowMap : public LightShadowMap
|
||||
{
|
||||
typedef LightShadowMap Parent;
|
||||
|
||||
public:
|
||||
|
||||
CubeLightShadowMap( LightInfo *light );
|
||||
|
||||
// LightShadowMap
|
||||
virtual bool hasShadowTex() const { return mCubemap.isValid(); }
|
||||
virtual ShadowType getShadowType() const { return ShadowType_CubeMap; }
|
||||
virtual void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState );
|
||||
virtual void setShaderParameters( GFXShaderConstBuffer* params, LightingShaderConstants* lsc );
|
||||
virtual void releaseTextures();
|
||||
virtual bool setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc );
|
||||
|
||||
protected:
|
||||
|
||||
/// The shadow cubemap.
|
||||
GFXCubemapHandle mCubemap;
|
||||
|
||||
};
|
||||
|
||||
#endif // _CUBELIGHTSHADOWMAP_H_
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/dualParaboloidLightShadowMap.h"
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "materials/materialDefinition.h"
|
||||
#include "math/util/matrixSet.h"
|
||||
|
||||
DualParaboloidLightShadowMap::DualParaboloidLightShadowMap( LightInfo *light )
|
||||
: Parent( light )
|
||||
{
|
||||
}
|
||||
|
||||
void DualParaboloidLightShadowMap::_render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
PROFILE_SCOPE(DualParaboloidLightShadowMap_render);
|
||||
|
||||
const ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
const LightMapParams *lmParams = mLight->getExtended<LightMapParams>();
|
||||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||
|
||||
const U32 texSize = getBestTexSize( 2 );
|
||||
|
||||
if ( mShadowMapTex.isNull() ||
|
||||
mTexSize != texSize )
|
||||
{
|
||||
mTexSize = texSize;
|
||||
|
||||
mShadowMapTex.set( mTexSize * 2, mTexSize,
|
||||
ShadowMapFormat, &ShadowMapProfile,
|
||||
"DualParaboloidLightShadowMap" );
|
||||
}
|
||||
|
||||
GFXFrustumSaver frustSaver;
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// Set and Clear target
|
||||
GFX->pushActiveRenderTarget();
|
||||
|
||||
mTarget->attachTexture(GFXTextureTarget::Color0, mShadowMapTex);
|
||||
mTarget->attachTexture( GFXTextureTarget::DepthStencil,
|
||||
_getDepthTarget( mShadowMapTex->getWidth(), mShadowMapTex->getHeight() ) );
|
||||
GFX->setActiveRenderTarget(mTarget);
|
||||
GFX->clear(GFXClearTarget | GFXClearStencil | GFXClearZBuffer, ColorI::WHITE, 1.0f, 0);
|
||||
|
||||
const bool bUseSinglePassDPM = (p->shadowType == ShadowType_DualParaboloidSinglePass);
|
||||
|
||||
// Set up matrix and visible distance
|
||||
mWorldToLightProj = mLight->getTransform();
|
||||
mWorldToLightProj.inverse();
|
||||
|
||||
const F32 &lightRadius = mLight->getRange().x;
|
||||
const F32 paraboloidNearPlane = 0.01f;
|
||||
const F32 renderPosOffset = 0.01f;
|
||||
|
||||
// Alter for creation of scene state if this is a single pass map
|
||||
if(bUseSinglePassDPM)
|
||||
{
|
||||
VectorF camDir;
|
||||
MatrixF temp = mLight->getTransform();
|
||||
temp.getColumn(1, &camDir);
|
||||
temp.setPosition(mLight->getPosition() - camDir * (lightRadius + renderPosOffset));
|
||||
temp.inverse();
|
||||
GFX->setWorldMatrix(temp);
|
||||
GFX->setOrtho(-lightRadius, lightRadius, -lightRadius, lightRadius, paraboloidNearPlane, 2.0f * lightRadius, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorF camDir;
|
||||
MatrixF temp = mLight->getTransform();
|
||||
temp.getColumn(1, &camDir);
|
||||
temp.setPosition(mLight->getPosition() - camDir * renderPosOffset);
|
||||
temp.inverse();
|
||||
GFX->setWorldMatrix(temp);
|
||||
|
||||
GFX->setOrtho(-lightRadius, lightRadius, -lightRadius, lightRadius, paraboloidNearPlane, lightRadius, true);
|
||||
}
|
||||
|
||||
SceneManager* sceneManager = diffuseState->getSceneManager();
|
||||
|
||||
// Front map render
|
||||
{
|
||||
SceneRenderState frontMapRenderState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
frontMapRenderState.getMaterialDelegate().bind( this, &LightShadowMap::getShadowMaterial );
|
||||
frontMapRenderState.renderNonLightmappedMeshes( true );
|
||||
frontMapRenderState.renderLightmappedMeshes( bUseLightmappedGeometry );
|
||||
frontMapRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
frontMapRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
if(bUseSinglePassDPM)
|
||||
{
|
||||
GFX->setWorldMatrix(mWorldToLightProj);
|
||||
frontMapRenderState.getRenderPass()->getMatrixSet().setSceneView(mWorldToLightProj);
|
||||
GFX->setOrtho(-lightRadius, lightRadius, -lightRadius, lightRadius, paraboloidNearPlane, lightRadius, true);
|
||||
}
|
||||
|
||||
GFXDEBUGEVENT_SCOPE( DualParaboloidLightShadowMap_Render_FrontFacingParaboloid, ColorI::RED );
|
||||
mShadowMapScale.set(0.5f, 1.0f);
|
||||
mShadowMapOffset.set(-0.5f, 0.0f);
|
||||
sceneManager->renderSceneNoLights( &frontMapRenderState, SHADOW_TYPEMASK );
|
||||
_debugRender( &frontMapRenderState );
|
||||
}
|
||||
|
||||
// Back map render
|
||||
if(!bUseSinglePassDPM)
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( DualParaboloidLightShadowMap_Render_BackFacingParaboloid, ColorI::RED );
|
||||
|
||||
mShadowMapScale.set(0.5f, 1.0f);
|
||||
mShadowMapOffset.set(0.5f, 0.0f);
|
||||
|
||||
// Invert direction on camera matrix
|
||||
VectorF right, forward;
|
||||
MatrixF temp = mLight->getTransform();
|
||||
temp.getColumn( 1, &forward );
|
||||
temp.getColumn( 0, &right );
|
||||
forward *= -1.0f;
|
||||
right *= -1.0f;
|
||||
temp.setColumn( 1, forward );
|
||||
temp.setColumn( 0, right );
|
||||
temp.setPosition(mLight->getPosition() - forward * -renderPosOffset);
|
||||
temp.inverse();
|
||||
GFX->setWorldMatrix(temp);
|
||||
|
||||
// Create an inverted scene state for the back-map
|
||||
|
||||
SceneRenderState backMapRenderState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
backMapRenderState.getMaterialDelegate().bind( this, &LightShadowMap::getShadowMaterial );
|
||||
backMapRenderState.renderNonLightmappedMeshes( true );
|
||||
backMapRenderState.renderLightmappedMeshes( bUseLightmappedGeometry );
|
||||
backMapRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
backMapRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
backMapRenderState.getRenderPass()->getMatrixSet().setSceneView(temp);
|
||||
|
||||
// Draw scene
|
||||
sceneManager->renderSceneNoLights( &backMapRenderState );
|
||||
_debugRender( &backMapRenderState );
|
||||
}
|
||||
|
||||
mTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _DUALPARABOLOIDLIGHTSHADOWMAP_H_
|
||||
#define _DUALPARABOLOIDLIGHTSHADOWMAP_H_
|
||||
|
||||
#ifndef _PARABOLOIDLIGHTSHADOWMAP_H_
|
||||
#include "lighting/shadowMap/paraboloidLightShadowMap.h"
|
||||
#endif
|
||||
|
||||
class DualParaboloidLightShadowMap : public ParaboloidLightShadowMap
|
||||
{
|
||||
typedef ParaboloidLightShadowMap Parent;
|
||||
|
||||
public:
|
||||
DualParaboloidLightShadowMap( LightInfo *light );
|
||||
|
||||
virtual void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState );
|
||||
};
|
||||
|
||||
#endif // _DUALPARABOLOIDLIGHTSHADOWMAP_H_
|
||||
752
Engine/source/lighting/shadowMap/lightShadowMap.cpp
Normal file
752
Engine/source/lighting/shadowMap/lightShadowMap.cpp
Normal file
|
|
@ -0,0 +1,752 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/lightShadowMap.h"
|
||||
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/shadowMap/shadowMatHook.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxTextureManager.h"
|
||||
#include "gfx/gfxOcclusionQuery.h"
|
||||
#include "gfx/gfxCardProfile.h"
|
||||
#include "gfx/sim/debugDraw.h"
|
||||
#include "materials/materialDefinition.h"
|
||||
#include "materials/baseMatInstance.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "scene/zones/SceneZoneSpace.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "shaderGen/shaderGenVars.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "materials/shaderData.h"
|
||||
|
||||
// Used for creation in ShadowMapParams::getOrCreateShadowMap()
|
||||
#include "lighting/shadowMap/singleLightShadowMap.h"
|
||||
#include "lighting/shadowMap/pssmLightShadowMap.h"
|
||||
#include "lighting/shadowMap/cubeLightShadowMap.h"
|
||||
#include "lighting/shadowMap/dualParaboloidLightShadowMap.h"
|
||||
|
||||
// Remove this when the shader constants are reworked better
|
||||
#include "lighting/advanced/advancedLightManager.h"
|
||||
#include "lighting/advanced/advancedLightBinManager.h"
|
||||
|
||||
// TODO: Some cards (Justin's GeForce 7x series) barf on the integer format causing
|
||||
// filtering artifacts. These can (sometimes) be resolved by switching the format
|
||||
// to FP16 instead of Int16.
|
||||
const GFXFormat LightShadowMap::ShadowMapFormat = GFXFormatR32F; // GFXFormatR8G8B8A8;
|
||||
|
||||
bool LightShadowMap::smDebugRenderFrustums;
|
||||
F32 LightShadowMap::smShadowTexScalar = 1.0f;
|
||||
|
||||
Vector<LightShadowMap*> LightShadowMap::smUsedShadowMaps;
|
||||
Vector<LightShadowMap*> LightShadowMap::smShadowMaps;
|
||||
|
||||
GFX_ImplementTextureProfile( ShadowMapProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize |
|
||||
GFXTextureProfile::RenderTarget |
|
||||
GFXTextureProfile::Pooled,
|
||||
GFXTextureProfile::None );
|
||||
|
||||
GFX_ImplementTextureProfile( ShadowMapZProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize |
|
||||
GFXTextureProfile::NoMipmap |
|
||||
GFXTextureProfile::ZTarget |
|
||||
GFXTextureProfile::Pooled,
|
||||
GFXTextureProfile::None );
|
||||
|
||||
|
||||
LightShadowMap::LightShadowMap( LightInfo *light )
|
||||
: mWorldToLightProj( true ),
|
||||
mLight( light ),
|
||||
mTexSize( 0 ),
|
||||
mLastShader( NULL ),
|
||||
mLastUpdate( 0 ),
|
||||
mLastCull( 0 ),
|
||||
mIsViewDependent( false ),
|
||||
mVizQuery( NULL ),
|
||||
mWasOccluded( false ),
|
||||
mLastScreenSize( 0.0f ),
|
||||
mLastPriority( 0.0f )
|
||||
{
|
||||
GFXTextureManager::addEventDelegate( this, &LightShadowMap::_onTextureEvent );
|
||||
|
||||
mTarget = GFX->allocRenderToTextureTarget();
|
||||
mVizQuery = GFX->createOcclusionQuery();
|
||||
|
||||
smShadowMaps.push_back( this );
|
||||
}
|
||||
|
||||
LightShadowMap::~LightShadowMap()
|
||||
{
|
||||
mTarget = NULL;
|
||||
SAFE_DELETE( mVizQuery );
|
||||
|
||||
releaseTextures();
|
||||
|
||||
smShadowMaps.remove( this );
|
||||
smUsedShadowMaps.remove( this );
|
||||
|
||||
GFXTextureManager::removeEventDelegate( this, &LightShadowMap::_onTextureEvent );
|
||||
}
|
||||
|
||||
void LightShadowMap::releaseAllTextures()
|
||||
{
|
||||
PROFILE_SCOPE( LightShadowMap_ReleaseAllTextures );
|
||||
|
||||
for ( U32 i=0; i < smShadowMaps.size(); i++ )
|
||||
smShadowMaps[i]->releaseTextures();
|
||||
}
|
||||
|
||||
U32 LightShadowMap::releaseUnusedTextures()
|
||||
{
|
||||
PROFILE_SCOPE( LightShadowMap_ReleaseUnusedTextures );
|
||||
|
||||
const U32 currTime = Sim::getCurrentTime();
|
||||
const U32 purgeTime = 1000;
|
||||
|
||||
for ( U32 i=0; i < smUsedShadowMaps.size(); )
|
||||
{
|
||||
LightShadowMap *lsm = smUsedShadowMaps[i];
|
||||
|
||||
// If the shadow has not been culled in a while then
|
||||
// release its textures for other shadows to use.
|
||||
if ( currTime > ( lsm->mLastCull + purgeTime ) )
|
||||
{
|
||||
// Internally this will remove the map from the used
|
||||
// list, so don't increment the loop.
|
||||
lsm->releaseTextures();
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return smUsedShadowMaps.size();
|
||||
}
|
||||
|
||||
void LightShadowMap::_onTextureEvent( GFXTexCallbackCode code )
|
||||
{
|
||||
if ( code == GFXZombify )
|
||||
releaseTextures();
|
||||
|
||||
// We don't initialize here as we want the textures
|
||||
// to be reallocated when the shadow becomes visible.
|
||||
}
|
||||
|
||||
void LightShadowMap::calcLightMatrices( MatrixF &outLightMatrix, const Frustum &viewFrustum )
|
||||
{
|
||||
// Create light matrix, set projection
|
||||
|
||||
switch ( mLight->getType() )
|
||||
{
|
||||
case LightInfo::Vector :
|
||||
{
|
||||
const ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
|
||||
// Calculate the bonding box of the shadowed area
|
||||
// we're interested in... this is the shadow box
|
||||
// transformed by the frustum transform.
|
||||
Box3F viewBB( -p->shadowDistance, -p->shadowDistance, -p->shadowDistance,
|
||||
p->shadowDistance, p->shadowDistance, p->shadowDistance );
|
||||
viewFrustum.getTransform().mul( viewBB );
|
||||
|
||||
// Calculate a light "projection" matrix.
|
||||
MatrixF lightMatrix = MathUtils::createOrientFromDir(mLight->getDirection());
|
||||
outLightMatrix = lightMatrix;
|
||||
static MatrixF rotMat(EulerF( (M_PI_F / 2.0f), 0.0f, 0.0f));
|
||||
lightMatrix.mul( rotMat );
|
||||
|
||||
// This is the box in lightspace
|
||||
Box3F lightViewBB(viewBB);
|
||||
lightMatrix.mul(lightViewBB);
|
||||
|
||||
// Now, let's position our light based on the lightViewBB
|
||||
Point3F newLightPos(viewBB.getCenter());
|
||||
F32 sceneDepth = lightViewBB.maxExtents.z - lightViewBB.minExtents.z;
|
||||
newLightPos += mLight->getDirection() * ((-sceneDepth / 2.0f)-1.0f); // -1 for the nearplane
|
||||
outLightMatrix.setPosition(newLightPos);
|
||||
|
||||
// Update light info
|
||||
mLight->setRange( sceneDepth );
|
||||
mLight->setPosition( newLightPos );
|
||||
|
||||
// Set our ortho projection
|
||||
F32 width = (lightViewBB.maxExtents.x - lightViewBB.minExtents.x) / 2.0f;
|
||||
F32 height = (lightViewBB.maxExtents.y - lightViewBB.minExtents.y) / 2.0f;
|
||||
|
||||
width = getMax(width, height);
|
||||
|
||||
GFX->setOrtho(-width, width, -width, width, 1.0f, sceneDepth, true);
|
||||
|
||||
|
||||
// TODO: Width * 2... really isn't that pixels being used as
|
||||
// meters? Is a real physical metric of scene depth better?
|
||||
//SceneManager::setVisibleDistance(width * 2.0f);
|
||||
|
||||
#if 0
|
||||
DebugDrawer::get()->drawFrustum(viewFrustum, ColorF(1.0f, 0.0f, 0.0f));
|
||||
DebugDrawer::get()->drawBox(viewBB.minExtents, viewBB.maxExtents, ColorF(0.0f, 1.0f, 0.0f));
|
||||
DebugDrawer::get()->drawBox(lightViewBB.minExtents, lightViewBB.maxExtents, ColorF(0.0f, 0.0f, 1.0f));
|
||||
DebugDrawer::get()->drawBox(newLightPos - Point3F(1,1,1), newLightPos + Point3F(1,1,1), ColorF(1,1,0));
|
||||
DebugDrawer::get()->drawLine(newLightPos, newLightPos + mLight.mDirection*3.0f, ColorF(0,1,1));
|
||||
|
||||
Point3F a(newLightPos);
|
||||
Point3F b(newLightPos);
|
||||
Point3F offset(width, height,0.0f);
|
||||
a -= offset;
|
||||
b += offset;
|
||||
DebugDrawer::get()->drawBox(a, b, ColorF(0.5f, 0.5f, 0.5f));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case LightInfo::Spot :
|
||||
{
|
||||
outLightMatrix = mLight->getTransform();
|
||||
F32 fov = mDegToRad( mLight->getOuterConeAngle() );
|
||||
F32 farDist = mLight->getRange().x;
|
||||
F32 nearDist = farDist * 0.01f;
|
||||
|
||||
F32 left, right, top, bottom;
|
||||
MathUtils::makeFrustum( &left, &right, &top, &bottom, fov, 1.0f, nearDist );
|
||||
GFX->setFrustum( left, right, bottom, top, nearDist, farDist );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "Unsupported light type!");
|
||||
}
|
||||
}
|
||||
|
||||
void LightShadowMap::releaseTextures()
|
||||
{
|
||||
mShadowMapTex = NULL;
|
||||
mDebugTarget.setTexture( NULL );
|
||||
mLastUpdate = 0;
|
||||
smUsedShadowMaps.remove( this );
|
||||
}
|
||||
|
||||
void LightShadowMap::setDebugTarget( const String &name )
|
||||
{
|
||||
mDebugTarget.registerWithName( name );
|
||||
mDebugTarget.setTexture( mShadowMapTex );
|
||||
}
|
||||
|
||||
GFXTextureObject* LightShadowMap::_getDepthTarget( U32 width, U32 height )
|
||||
{
|
||||
// Get a depth texture target from the pooled profile
|
||||
// which is returned as a temporary.
|
||||
GFXTexHandle depthTex( width, height, GFXFormatD24S8, &ShadowMapZProfile,
|
||||
"LightShadowMap::_getDepthTarget()" );
|
||||
|
||||
return depthTex;
|
||||
}
|
||||
|
||||
bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc )
|
||||
{
|
||||
if ( currTexFlag == Material::DynamicLight )
|
||||
{
|
||||
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, mShadowMapTex);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ( currTexFlag == Material::DynamicLightMask )
|
||||
{
|
||||
S32 reg = lsc->mCookieMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
{
|
||||
ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
|
||||
if ( lsc->mCookieMapSC->getType() == GFXSCT_SamplerCube )
|
||||
GFX->setCubeTexture( reg, p->getCookieCubeTex() );
|
||||
else
|
||||
GFX->setTexture( reg, p->getCookieTex() );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LightShadowMap::render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
mDebugTarget.setTexture( NULL );
|
||||
_render( renderPass, diffuseState );
|
||||
mDebugTarget.setTexture( mShadowMapTex );
|
||||
|
||||
// Add it to the used list unless we're been updated.
|
||||
if ( !mLastUpdate )
|
||||
{
|
||||
AssertFatal( !smUsedShadowMaps.contains( this ), "LightShadowMap::render - Used shadow map inserted twice!" );
|
||||
smUsedShadowMaps.push_back( this );
|
||||
}
|
||||
|
||||
mLastUpdate = Sim::getCurrentTime();
|
||||
}
|
||||
|
||||
void LightShadowMap::preLightRender()
|
||||
{
|
||||
PROFILE_SCOPE( LightShadowMap_prepLightRender );
|
||||
|
||||
if ( mVizQuery )
|
||||
{
|
||||
mWasOccluded = mVizQuery->getStatus( true ) == GFXOcclusionQuery::Occluded;
|
||||
mVizQuery->begin();
|
||||
}
|
||||
}
|
||||
|
||||
void LightShadowMap::postLightRender()
|
||||
{
|
||||
if ( mVizQuery )
|
||||
mVizQuery->end();
|
||||
}
|
||||
|
||||
BaseMatInstance* LightShadowMap::getShadowMaterial( BaseMatInstance *inMat ) const
|
||||
{
|
||||
// See if we have an existing material hook.
|
||||
ShadowMaterialHook *hook = static_cast<ShadowMaterialHook*>( inMat->getHook( ShadowMaterialHook::Type ) );
|
||||
if ( !hook )
|
||||
{
|
||||
// Create a hook and initialize it using the incoming material.
|
||||
hook = new ShadowMaterialHook;
|
||||
hook->init( inMat );
|
||||
inMat->addHook( hook );
|
||||
}
|
||||
|
||||
return hook->getShadowMat( getShadowType() );
|
||||
}
|
||||
|
||||
U32 LightShadowMap::getBestTexSize( U32 scale ) const
|
||||
{
|
||||
const ShadowMapParams *params = mLight->getExtended<ShadowMapParams>();
|
||||
|
||||
// The view dependent shadows don't scale by screen size.
|
||||
U32 texSize;
|
||||
if ( isViewDependent() )
|
||||
texSize = params->texSize;
|
||||
else
|
||||
texSize = params->texSize * getMin( 1.0f, mLastScreenSize );
|
||||
|
||||
// Apply the shadow texture scale and make
|
||||
// sure this is a power of 2.
|
||||
texSize = getNextPow2( texSize * smShadowTexScalar );
|
||||
|
||||
// Get the max texture size this card supports and
|
||||
// scale it down... ensuring the final texSize can
|
||||
// be scaled up that many times and not go over
|
||||
// the card maximum.
|
||||
U32 maxTexSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 2048 );
|
||||
if ( scale > 1 )
|
||||
maxTexSize >>= ( scale - 1 );
|
||||
|
||||
// Never let the shadow texture get smaller than 16x16 as
|
||||
// it just makes the pool bigger and the fillrate savings
|
||||
// are less and leass as we get smaller.
|
||||
texSize = mClamp( texSize, (U32)16, maxTexSize );
|
||||
|
||||
// Return it.
|
||||
return texSize;
|
||||
}
|
||||
|
||||
void LightShadowMap::updatePriority( const SceneRenderState *state, U32 currTimeMs )
|
||||
{
|
||||
PROFILE_SCOPE( LightShadowMap_updatePriority );
|
||||
|
||||
mLastCull = currTimeMs;
|
||||
|
||||
if ( isViewDependent() )
|
||||
{
|
||||
mLastScreenSize = 1.0f;
|
||||
mLastPriority = F32_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
U32 timeSinceLastUpdate = currTimeMs - mLastUpdate;
|
||||
|
||||
const Point3F &camPt = state->getCameraPosition();
|
||||
F32 range = mLight->getRange().x;
|
||||
F32 dist;
|
||||
|
||||
if ( mLight->getType() == LightInfo::Spot )
|
||||
{
|
||||
// We treat the cone as a cylinder to get the
|
||||
// approximate projection distance.
|
||||
|
||||
Point3F endPt = mLight->getPosition() + ( mLight->getDirection() * range );
|
||||
Point3F nearPt = MathUtils::mClosestPointOnSegment( mLight->getPosition(), endPt, camPt );
|
||||
dist = ( camPt - nearPt ).len();
|
||||
|
||||
F32 radius = range * mSin( mDegToRad( mLight->getOuterConeAngle() * 0.5f ) );
|
||||
dist -= radius;
|
||||
}
|
||||
else
|
||||
dist = SphereF( mLight->getPosition(), range ).distanceTo( camPt );
|
||||
|
||||
// Get the approximate screen size of the light.
|
||||
mLastScreenSize = state->projectRadius( dist, range );
|
||||
mLastScreenSize /= state->getViewport().extent.y;
|
||||
|
||||
// Update the priority.
|
||||
mLastPriority = mPow( mLastScreenSize * 50.0f, 2.0f );
|
||||
mLastPriority += timeSinceLastUpdate;
|
||||
mLastPriority *= mLight->getPriority();
|
||||
}
|
||||
|
||||
S32 QSORT_CALLBACK LightShadowMap::cmpPriority( LightShadowMap *const *lsm1, LightShadowMap *const *lsm2 )
|
||||
{
|
||||
F32 diff = (*lsm1)->getLastPriority() - (*lsm2)->getLastPriority();
|
||||
return diff > 0.0f ? -1 : ( diff < 0.0f ? 1 : 0 );
|
||||
}
|
||||
|
||||
void LightShadowMap::_debugRender( SceneRenderState* shadowRenderState )
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
|
||||
// Skip if light does not have debug rendering enabled.
|
||||
if( !getLightInfo()->isDebugRenderingEnabled() )
|
||||
return;
|
||||
|
||||
DebugDrawer* drawer = DebugDrawer::get();
|
||||
if( !drawer )
|
||||
return;
|
||||
|
||||
if( smDebugRenderFrustums )
|
||||
shadowRenderState->getCullingState().debugRenderCullingVolumes();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
LightingShaderConstants::LightingShaderConstants()
|
||||
: mInit( false ),
|
||||
mShader( NULL ),
|
||||
mLightParamsSC(NULL),
|
||||
mLightSpotParamsSC(NULL),
|
||||
mLightPositionSC(NULL),
|
||||
mLightDiffuseSC(NULL),
|
||||
mLightAmbientSC(NULL),
|
||||
mLightInvRadiusSqSC(NULL),
|
||||
mLightSpotDirSC(NULL),
|
||||
mLightSpotAngleSC(NULL),
|
||||
mLightSpotFalloffSC(NULL),
|
||||
mShadowMapSC(NULL),
|
||||
mShadowMapSizeSC(NULL),
|
||||
mCookieMapSC(NULL),
|
||||
mRandomDirsConst(NULL),
|
||||
mShadowSoftnessConst(NULL),
|
||||
mWorldToLightProjSC(NULL),
|
||||
mViewToLightProjSC(NULL),
|
||||
mScaleXSC(NULL),
|
||||
mScaleYSC(NULL),
|
||||
mOffsetXSC(NULL),
|
||||
mOffsetYSC(NULL),
|
||||
mAtlasXOffsetSC(NULL),
|
||||
mAtlasYOffsetSC(NULL),
|
||||
mAtlasScaleSC(NULL),
|
||||
mFadeStartLength(NULL),
|
||||
mFarPlaneScalePSSM(NULL),
|
||||
mOverDarkFactorPSSM(NULL),
|
||||
mTapRotationTexSC(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LightingShaderConstants::~LightingShaderConstants()
|
||||
{
|
||||
if (mShader.isValid())
|
||||
{
|
||||
mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );
|
||||
mShader = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LightingShaderConstants::init(GFXShader* shader)
|
||||
{
|
||||
if (mShader.getPointer() != shader)
|
||||
{
|
||||
if (mShader.isValid())
|
||||
mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );
|
||||
|
||||
mShader = shader;
|
||||
mShader->getReloadSignal().notify( this, &LightingShaderConstants::_onShaderReload );
|
||||
}
|
||||
|
||||
mLightParamsSC = shader->getShaderConstHandle("$lightParams");
|
||||
mLightSpotParamsSC = shader->getShaderConstHandle("$lightSpotParams");
|
||||
|
||||
// NOTE: These are the shader constants used for doing lighting
|
||||
// during the forward pass. Do not confuse these for the prepass
|
||||
// lighting constants which are used from AdvancedLightBinManager.
|
||||
mLightPositionSC = shader->getShaderConstHandle( ShaderGenVars::lightPosition );
|
||||
mLightDiffuseSC = shader->getShaderConstHandle( ShaderGenVars::lightDiffuse );
|
||||
mLightAmbientSC = shader->getShaderConstHandle( ShaderGenVars::lightAmbient );
|
||||
mLightInvRadiusSqSC = shader->getShaderConstHandle( ShaderGenVars::lightInvRadiusSq );
|
||||
mLightSpotDirSC = shader->getShaderConstHandle( ShaderGenVars::lightSpotDir );
|
||||
mLightSpotAngleSC = shader->getShaderConstHandle( ShaderGenVars::lightSpotAngle );
|
||||
mLightSpotFalloffSC = shader->getShaderConstHandle( ShaderGenVars::lightSpotFalloff );
|
||||
|
||||
mShadowMapSC = shader->getShaderConstHandle("$shadowMap");
|
||||
mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize");
|
||||
|
||||
mCookieMapSC = shader->getShaderConstHandle("$cookieMap");
|
||||
|
||||
mShadowSoftnessConst = shader->getShaderConstHandle("$shadowSoftness");
|
||||
|
||||
mWorldToLightProjSC = shader->getShaderConstHandle("$worldToLightProj");
|
||||
mViewToLightProjSC = shader->getShaderConstHandle("$viewToLightProj");
|
||||
|
||||
mScaleXSC = shader->getShaderConstHandle("$scaleX");
|
||||
mScaleYSC = shader->getShaderConstHandle("$scaleY");
|
||||
mOffsetXSC = shader->getShaderConstHandle("$offsetX");
|
||||
mOffsetYSC = shader->getShaderConstHandle("$offsetY");
|
||||
mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset");
|
||||
mAtlasYOffsetSC = shader->getShaderConstHandle("$atlasYOffset");
|
||||
mAtlasScaleSC = shader->getShaderConstHandle("$atlasScale");
|
||||
|
||||
mFadeStartLength = shader->getShaderConstHandle("$fadeStartLength");
|
||||
mFarPlaneScalePSSM = shader->getShaderConstHandle("$farPlaneScalePSSM");
|
||||
|
||||
mOverDarkFactorPSSM = shader->getShaderConstHandle("$overDarkPSSM");
|
||||
|
||||
mTapRotationTexSC = shader->getShaderConstHandle( "$gTapRotationTex" );
|
||||
|
||||
mInit = true;
|
||||
}
|
||||
|
||||
void LightingShaderConstants::_onShaderReload()
|
||||
{
|
||||
if (mShader.isValid())
|
||||
init( mShader );
|
||||
}
|
||||
|
||||
|
||||
const LightInfoExType ShadowMapParams::Type( "ShadowMapParams" );
|
||||
|
||||
ShadowMapParams::ShadowMapParams( LightInfo *light )
|
||||
: mLight( light ),
|
||||
mShadowMap( NULL )
|
||||
{
|
||||
attenuationRatio.set( 0.0f, 1.0f, 1.0f );
|
||||
shadowType = ShadowType_Spot;
|
||||
overDarkFactor.set(2000.0f, 1000.0f, 500.0f, 100.0f);
|
||||
numSplits = 4;
|
||||
logWeight = 0.91f;
|
||||
texSize = 512;
|
||||
shadowDistance = 400.0f;
|
||||
shadowSoftness = 0.15f;
|
||||
fadeStartDist = 0.0f;
|
||||
lastSplitTerrainOnly = false;
|
||||
_validate();
|
||||
}
|
||||
|
||||
ShadowMapParams::~ShadowMapParams()
|
||||
{
|
||||
SAFE_DELETE( mShadowMap );
|
||||
}
|
||||
|
||||
void ShadowMapParams::_validate()
|
||||
{
|
||||
switch ( mLight->getType() )
|
||||
{
|
||||
case LightInfo::Spot:
|
||||
shadowType = ShadowType_Spot;
|
||||
break;
|
||||
|
||||
case LightInfo::Vector:
|
||||
shadowType = ShadowType_PSSM;
|
||||
break;
|
||||
|
||||
case LightInfo::Point:
|
||||
if ( shadowType < ShadowType_Paraboloid )
|
||||
shadowType = ShadowType_DualParaboloidSinglePass;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// The texture sizes for shadows should always
|
||||
// be power of 2 in size.
|
||||
texSize = getNextPow2( texSize );
|
||||
|
||||
// The maximum shadow texture size setting we're
|
||||
// gonna allow... this doesn't use your hardware
|
||||
// settings as you may be on a lower end system
|
||||
// than your target machine.
|
||||
//
|
||||
// We apply the hardware specific limits during
|
||||
// shadow rendering.
|
||||
//
|
||||
U32 maxTexSize = 4096;
|
||||
|
||||
if ( mLight->getType() == LightInfo::Vector )
|
||||
{
|
||||
numSplits = mClamp( numSplits, 1, 4 );
|
||||
|
||||
// Adjust the shadow texture size for the PSSM
|
||||
// based on the split count to keep the total
|
||||
// shadow texture size within 4096.
|
||||
if ( numSplits == 2 || numSplits == 4 )
|
||||
maxTexSize = 2048;
|
||||
if ( numSplits == 3 )
|
||||
maxTexSize = 1024;
|
||||
}
|
||||
else
|
||||
numSplits = 1;
|
||||
|
||||
// Keep it in a valid range... less than 32 is dumb.
|
||||
texSize = mClamp( texSize, 32, maxTexSize );
|
||||
}
|
||||
|
||||
LightShadowMap* ShadowMapParams::getOrCreateShadowMap()
|
||||
{
|
||||
if ( mShadowMap )
|
||||
return mShadowMap;
|
||||
|
||||
if ( !mLight->getCastShadows() )
|
||||
return NULL;
|
||||
|
||||
switch ( mLight->getType() )
|
||||
{
|
||||
case LightInfo::Spot:
|
||||
mShadowMap = new SingleLightShadowMap( mLight );
|
||||
break;
|
||||
|
||||
case LightInfo::Vector:
|
||||
mShadowMap = new PSSMLightShadowMap( mLight );
|
||||
break;
|
||||
|
||||
case LightInfo::Point:
|
||||
|
||||
if ( shadowType == ShadowType_CubeMap )
|
||||
mShadowMap = new CubeLightShadowMap( mLight );
|
||||
else if ( shadowType == ShadowType_Paraboloid )
|
||||
mShadowMap = new ParaboloidLightShadowMap( mLight );
|
||||
else
|
||||
mShadowMap = new DualParaboloidLightShadowMap( mLight );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return mShadowMap;
|
||||
}
|
||||
|
||||
GFXTextureObject* ShadowMapParams::getCookieTex()
|
||||
{
|
||||
if ( cookie.isNotEmpty() &&
|
||||
( mCookieTex.isNull() ||
|
||||
cookie != mCookieTex->getPath() ) )
|
||||
{
|
||||
mCookieTex.set( cookie,
|
||||
&GFXDefaultStaticDiffuseProfile,
|
||||
"ShadowMapParams::getCookieTex()" );
|
||||
}
|
||||
else if ( cookie.isEmpty() )
|
||||
mCookieTex = NULL;
|
||||
|
||||
return mCookieTex.getPointer();
|
||||
}
|
||||
|
||||
GFXCubemap* ShadowMapParams::getCookieCubeTex()
|
||||
{
|
||||
if ( cookie.isNotEmpty() &&
|
||||
( mCookieCubeTex.isNull() ||
|
||||
cookie != mCookieCubeTex->getPath() ) )
|
||||
{
|
||||
mCookieCubeTex.set( cookie );
|
||||
}
|
||||
else if ( cookie.isEmpty() )
|
||||
mCookieCubeTex = NULL;
|
||||
|
||||
return mCookieCubeTex.getPointer();
|
||||
}
|
||||
|
||||
void ShadowMapParams::set( const LightInfoEx *ex )
|
||||
{
|
||||
// TODO: Do we even need this?
|
||||
}
|
||||
|
||||
void ShadowMapParams::packUpdate( BitStream *stream ) const
|
||||
{
|
||||
// HACK: We need to work out proper parameter
|
||||
// validation when any field changes on the light.
|
||||
|
||||
((ShadowMapParams*)this)->_validate();
|
||||
|
||||
stream->writeInt( shadowType, 8 );
|
||||
|
||||
mathWrite( *stream, attenuationRatio );
|
||||
|
||||
stream->write( texSize );
|
||||
|
||||
stream->write( cookie );
|
||||
|
||||
stream->write( numSplits );
|
||||
stream->write( logWeight );
|
||||
|
||||
mathWrite(*stream, overDarkFactor);
|
||||
|
||||
stream->write( fadeStartDist );
|
||||
stream->writeFlag( lastSplitTerrainOnly );
|
||||
|
||||
stream->write( shadowDistance );
|
||||
|
||||
stream->write( shadowSoftness );
|
||||
}
|
||||
|
||||
void ShadowMapParams::unpackUpdate( BitStream *stream )
|
||||
{
|
||||
ShadowType newType = (ShadowType)stream->readInt( 8 );
|
||||
if ( shadowType != newType )
|
||||
{
|
||||
// If the shadow type changes delete the shadow
|
||||
// map so it can be reallocated on the next render.
|
||||
shadowType = newType;
|
||||
SAFE_DELETE( mShadowMap );
|
||||
}
|
||||
|
||||
mathRead( *stream, &attenuationRatio );
|
||||
|
||||
stream->read( &texSize );
|
||||
|
||||
stream->read( &cookie );
|
||||
|
||||
stream->read( &numSplits );
|
||||
stream->read( &logWeight );
|
||||
mathRead(*stream, &overDarkFactor);
|
||||
|
||||
stream->read( &fadeStartDist );
|
||||
lastSplitTerrainOnly = stream->readFlag();
|
||||
|
||||
stream->read( &shadowDistance );
|
||||
|
||||
stream->read( &shadowSoftness );
|
||||
}
|
||||
380
Engine/source/lighting/shadowMap/lightShadowMap.h
Normal file
380
Engine/source/lighting/shadowMap/lightShadowMap.h
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _LIGHTSHADOWMAP_H_
|
||||
#define _LIGHTSHADOWMAP_H_
|
||||
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
#ifndef _GFXCUBEMAP_H_
|
||||
#include "gfx/gfxCubemap.h"
|
||||
#endif
|
||||
#ifndef _GFXTARGET_H_
|
||||
#include "gfx/gfxTarget.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
#ifndef _MATHUTIL_FRUSTUM_H_
|
||||
#include "math/util/frustum.h"
|
||||
#endif
|
||||
#ifndef _MATTEXTURETARGET_H_
|
||||
#include "materials/matTextureTarget.h"
|
||||
#endif
|
||||
#ifndef _SHADOW_COMMON_H_
|
||||
#include "lighting/shadowMap/shadowCommon.h"
|
||||
#endif
|
||||
#ifndef _GFXSHADER_H_
|
||||
#include "gfx/gfxShader.h"
|
||||
#endif
|
||||
|
||||
class ShadowMapManager;
|
||||
class SceneManager;
|
||||
class SceneRenderState;
|
||||
class BaseMatInstance;
|
||||
class MaterialParameters;
|
||||
class SharedShadowMapObjects;
|
||||
struct SceneData;
|
||||
class GFXShaderConstBuffer;
|
||||
class GFXShaderConstHandle;
|
||||
class GFXShader;
|
||||
class GFXOcclusionQuery;
|
||||
class LightManager;
|
||||
class RenderPassManager;
|
||||
|
||||
|
||||
// Shader constant handle lookup
|
||||
// This isn't broken up as much as it could be, we're mixing single light constants
|
||||
// and pssm constants.
|
||||
struct LightingShaderConstants
|
||||
{
|
||||
bool mInit;
|
||||
|
||||
GFXShaderRef mShader;
|
||||
|
||||
GFXShaderConstHandle* mLightParamsSC;
|
||||
GFXShaderConstHandle* mLightSpotParamsSC;
|
||||
|
||||
// NOTE: These are the shader constants used for doing
|
||||
// lighting during the forward pass. Do not confuse
|
||||
// these for the prepass lighting constants which are
|
||||
// used from AdvancedLightBinManager.
|
||||
GFXShaderConstHandle *mLightPositionSC;
|
||||
GFXShaderConstHandle *mLightDiffuseSC;
|
||||
GFXShaderConstHandle *mLightAmbientSC;
|
||||
GFXShaderConstHandle *mLightInvRadiusSqSC;
|
||||
GFXShaderConstHandle *mLightSpotDirSC;
|
||||
GFXShaderConstHandle *mLightSpotAngleSC;
|
||||
GFXShaderConstHandle *mLightSpotFalloffSC;
|
||||
|
||||
GFXShaderConstHandle* mShadowMapSC;
|
||||
GFXShaderConstHandle* mShadowMapSizeSC;
|
||||
|
||||
GFXShaderConstHandle* mCookieMapSC;
|
||||
|
||||
GFXShaderConstHandle* mRandomDirsConst;
|
||||
GFXShaderConstHandle* mShadowSoftnessConst;
|
||||
|
||||
GFXShaderConstHandle* mWorldToLightProjSC;
|
||||
GFXShaderConstHandle* mViewToLightProjSC;
|
||||
|
||||
GFXShaderConstHandle* mScaleXSC;
|
||||
GFXShaderConstHandle* mScaleYSC;
|
||||
GFXShaderConstHandle* mOffsetXSC;
|
||||
GFXShaderConstHandle* mOffsetYSC;
|
||||
GFXShaderConstHandle* mAtlasXOffsetSC;
|
||||
GFXShaderConstHandle* mAtlasYOffsetSC;
|
||||
GFXShaderConstHandle* mAtlasScaleSC;
|
||||
|
||||
// fadeStartLength.x = Distance in eye space to start fading shadows
|
||||
// fadeStartLength.y = 1 / Length of fade
|
||||
GFXShaderConstHandle* mFadeStartLength;
|
||||
GFXShaderConstHandle* mFarPlaneScalePSSM;
|
||||
GFXShaderConstHandle* mOverDarkFactorPSSM;
|
||||
|
||||
GFXShaderConstHandle* mTapRotationTexSC;
|
||||
|
||||
LightingShaderConstants();
|
||||
~LightingShaderConstants();
|
||||
|
||||
void init(GFXShader* buffer);
|
||||
|
||||
void _onShaderReload();
|
||||
};
|
||||
|
||||
typedef Map<GFXShader*, LightingShaderConstants*> LightConstantMap;
|
||||
|
||||
|
||||
/// This represents everything we need to render
|
||||
/// the shadowmap for one light.
|
||||
class LightShadowMap
|
||||
{
|
||||
public:
|
||||
|
||||
const static GFXFormat ShadowMapFormat;
|
||||
|
||||
/// Used to scale the shadow texture size for performance tweaking.
|
||||
static F32 smShadowTexScalar;
|
||||
|
||||
/// Whether to render shadow frustums for lights that have debug
|
||||
/// rendering enabled.
|
||||
static bool smDebugRenderFrustums;
|
||||
|
||||
public:
|
||||
|
||||
LightShadowMap( LightInfo *light );
|
||||
|
||||
virtual ~LightShadowMap();
|
||||
|
||||
void render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState );
|
||||
|
||||
U32 getLastUpdate() const { return mLastUpdate; }
|
||||
|
||||
//U32 getLastVisible() const { return mLastVisible; }
|
||||
|
||||
bool isViewDependent() const { return mIsViewDependent; }
|
||||
|
||||
bool wasOccluded() const { return mWasOccluded; }
|
||||
|
||||
void preLightRender();
|
||||
|
||||
void postLightRender();
|
||||
|
||||
void updatePriority( const SceneRenderState *state, U32 currTimeMs );
|
||||
|
||||
F32 getLastScreenSize() const { return mLastScreenSize; }
|
||||
|
||||
F32 getLastPriority() const { return mLastPriority; }
|
||||
|
||||
virtual bool hasShadowTex() const { return mShadowMapTex.isValid(); }
|
||||
|
||||
virtual bool setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc );
|
||||
|
||||
LightInfo* getLightInfo() { return mLight; }
|
||||
|
||||
virtual void setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc) = 0;
|
||||
|
||||
U32 getTexSize() const { return mTexSize; }
|
||||
|
||||
/// Returns the best texture size based on the user
|
||||
/// texture size, the last light screen size, and
|
||||
/// global shadow tweak parameters.
|
||||
U32 getBestTexSize( U32 scale = 1 ) const;
|
||||
|
||||
const MatrixF& getWorldToLightProj() const { return mWorldToLightProj; }
|
||||
|
||||
static GFXTextureObject* _getDepthTarget( U32 width, U32 height );
|
||||
|
||||
virtual ShadowType getShadowType() const = 0;
|
||||
|
||||
// Cleanup texture resources
|
||||
virtual void releaseTextures();
|
||||
|
||||
///
|
||||
GFXTextureObject* getTexture() const { return mShadowMapTex; }
|
||||
|
||||
///
|
||||
void setDebugTarget( const String &name );
|
||||
|
||||
static void releaseAllTextures();
|
||||
|
||||
/// Releases any shadow maps that have not been culled
|
||||
/// in a while and returns the count of the remaing
|
||||
/// shadow maps in use.
|
||||
static U32 releaseUnusedTextures();
|
||||
|
||||
///
|
||||
static S32 QSORT_CALLBACK cmpPriority( LightShadowMap *const *lsm1, LightShadowMap *const *lsm2 );
|
||||
|
||||
/// Returns the correct shadow material this type of light
|
||||
/// or NULL if no shadow material is possible.
|
||||
BaseMatInstance* getShadowMaterial( BaseMatInstance *inMat ) const;
|
||||
|
||||
protected:
|
||||
|
||||
/// All the shadow maps in the system.
|
||||
static Vector<LightShadowMap*> smShadowMaps;
|
||||
|
||||
/// All the shadow maps that have been recently rendered to.
|
||||
static Vector<LightShadowMap*> smUsedShadowMaps;
|
||||
|
||||
virtual void _render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState ) = 0;
|
||||
|
||||
/// If there is a LightDebugInfo attached to the light that owns this map,
|
||||
/// then update its information from the given render state.
|
||||
///
|
||||
/// @note This method only does something in debug builds.
|
||||
void _debugRender( SceneRenderState* shadowRenderState );
|
||||
|
||||
/// Helper for rendering shadow map for debugging.
|
||||
NamedTexTarget mDebugTarget;
|
||||
|
||||
/// If true the shadow is view dependent and cannot
|
||||
/// be skipped if visible and within active range.
|
||||
bool mIsViewDependent;
|
||||
|
||||
/// The time this shadow was last updated.
|
||||
U32 mLastUpdate;
|
||||
|
||||
/// The time this shadow was last culled and prioritized.
|
||||
U32 mLastCull;
|
||||
|
||||
/// The shadow occlusion query used when the light is
|
||||
/// rendered to determine if any pixel of it is visible.
|
||||
GFXOcclusionQuery *mVizQuery;
|
||||
|
||||
/// If true the light was occluded by geometry the
|
||||
/// last frame it was updated.
|
||||
//the last frame.
|
||||
bool mWasOccluded;
|
||||
|
||||
F32 mLastScreenSize;
|
||||
|
||||
F32 mLastPriority;
|
||||
|
||||
MatrixF mWorldToLightProj;
|
||||
|
||||
GFXTextureTargetRef mTarget;
|
||||
U32 mTexSize;
|
||||
GFXTexHandle mShadowMapTex;
|
||||
|
||||
// The light we are rendering.
|
||||
LightInfo *mLight;
|
||||
|
||||
// Used for blur
|
||||
GFXShader* mLastShader;
|
||||
GFXShaderConstHandle* mBlurBoundaries;
|
||||
|
||||
// Calculate view matrices and set proper projection with GFX
|
||||
void calcLightMatrices( MatrixF& outLightMatrix, const Frustum &viewFrustum );
|
||||
|
||||
/// The callback used to get texture events.
|
||||
/// @see GFXTextureManager::addEventDelegate
|
||||
void _onTextureEvent( GFXTexCallbackCode code );
|
||||
};
|
||||
|
||||
GFX_DeclareTextureProfile( ShadowMapProfile );
|
||||
GFX_DeclareTextureProfile( ShadowMapZProfile );
|
||||
|
||||
|
||||
class ShadowMapParams : public LightInfoEx
|
||||
{
|
||||
public:
|
||||
|
||||
ShadowMapParams( LightInfo *light );
|
||||
virtual ~ShadowMapParams();
|
||||
|
||||
/// The LightInfoEx hook type.
|
||||
static const LightInfoExType Type;
|
||||
|
||||
// LightInfoEx
|
||||
virtual void set( const LightInfoEx *ex );
|
||||
virtual const LightInfoExType& getType() const { return Type; }
|
||||
virtual void packUpdate( BitStream *stream ) const;
|
||||
virtual void unpackUpdate( BitStream *stream );
|
||||
|
||||
LightShadowMap* getShadowMap() const { return mShadowMap; }
|
||||
|
||||
LightShadowMap* getOrCreateShadowMap();
|
||||
|
||||
bool hasCookieTex() const { return cookie.isNotEmpty(); }
|
||||
|
||||
GFXTextureObject* getCookieTex();
|
||||
|
||||
GFXCubemap* getCookieCubeTex();
|
||||
|
||||
// Validates the parameters after a field is changed.
|
||||
void _validate();
|
||||
|
||||
protected:
|
||||
|
||||
void _initShadowMap();
|
||||
|
||||
///
|
||||
LightShadowMap *mShadowMap;
|
||||
|
||||
LightInfo *mLight;
|
||||
|
||||
GFXTexHandle mCookieTex;
|
||||
|
||||
GFXCubemapHandle mCookieCubeTex;
|
||||
|
||||
public:
|
||||
|
||||
// We're leaving these public for easy access
|
||||
// for console protected fields.
|
||||
|
||||
/// @name Shadow Map
|
||||
/// @{
|
||||
|
||||
///
|
||||
U32 texSize;
|
||||
|
||||
///
|
||||
FileName cookie;
|
||||
|
||||
/// @}
|
||||
|
||||
Point3F attenuationRatio;
|
||||
|
||||
/// @name Point Lights
|
||||
/// @{
|
||||
|
||||
///
|
||||
ShadowType shadowType;
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Exponential Shadow Map Parameters
|
||||
/// @{
|
||||
Point4F overDarkFactor;
|
||||
/// @}
|
||||
|
||||
/// @name Parallel Split Shadow Map
|
||||
/// @{
|
||||
|
||||
///
|
||||
F32 shadowDistance;
|
||||
|
||||
///
|
||||
F32 shadowSoftness;
|
||||
|
||||
/// The number of splits in the shadow map.
|
||||
U32 numSplits;
|
||||
|
||||
///
|
||||
F32 logWeight;
|
||||
|
||||
/// At what distance do we start fading the shadows out completely.
|
||||
F32 fadeStartDist;
|
||||
|
||||
/// This toggles only terrain being visible in the last
|
||||
/// split of a PSSM shadow map.
|
||||
bool lastSplitTerrainOnly;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
#endif // _LIGHTSHADOWMAP_H_
|
||||
141
Engine/source/lighting/shadowMap/paraboloidLightShadowMap.cpp
Normal file
141
Engine/source/lighting/shadowMap/paraboloidLightShadowMap.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/paraboloidLightShadowMap.h"
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
//#include "scene/sceneReflectPass.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "materials/materialDefinition.h"
|
||||
#include "gui/controls/guiBitmapCtrl.h"
|
||||
|
||||
ParaboloidLightShadowMap::ParaboloidLightShadowMap( LightInfo *light )
|
||||
: Parent( light ),
|
||||
mShadowMapScale( 1, 1 ),
|
||||
mShadowMapOffset( 0, 0 )
|
||||
{
|
||||
}
|
||||
|
||||
ParaboloidLightShadowMap::~ParaboloidLightShadowMap()
|
||||
{
|
||||
releaseTextures();
|
||||
}
|
||||
|
||||
ShadowType ParaboloidLightShadowMap::getShadowType() const
|
||||
{
|
||||
const ShadowMapParams *params = mLight->getExtended<ShadowMapParams>();
|
||||
return params->shadowType;
|
||||
}
|
||||
|
||||
void ParaboloidLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc)
|
||||
{
|
||||
if ( lsc->mTapRotationTexSC->isValid() )
|
||||
GFX->setTexture( lsc->mTapRotationTexSC->getSamplerRegister(),
|
||||
SHADOWMGR->getTapRotationTex() );
|
||||
|
||||
ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
if ( lsc->mLightParamsSC->isValid() )
|
||||
{
|
||||
Point4F lightParams( mLight->getRange().x, p->overDarkFactor.x, 0.0f, 0.0f);
|
||||
params->set( lsc->mLightParamsSC, lightParams );
|
||||
}
|
||||
|
||||
// Atlasing parameters (only used in the dual case, set here to use same shaders)
|
||||
params->setSafe( lsc->mAtlasScaleSC, mShadowMapScale );
|
||||
params->setSafe( lsc->mAtlasXOffsetSC, mShadowMapOffset );
|
||||
|
||||
// The softness is a factor of the texel size.
|
||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
|
||||
void ParaboloidLightShadowMap::_render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
PROFILE_SCOPE(ParaboloidLightShadowMap_render);
|
||||
|
||||
const LightMapParams *lmParams = mLight->getExtended<LightMapParams>();
|
||||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||
|
||||
const U32 texSize = getBestTexSize();
|
||||
|
||||
if ( mShadowMapTex.isNull() ||
|
||||
mTexSize != texSize )
|
||||
{
|
||||
mTexSize = texSize;
|
||||
|
||||
mShadowMapTex.set( mTexSize, mTexSize,
|
||||
ShadowMapFormat, &ShadowMapProfile,
|
||||
"ParaboloidLightShadowMap" );
|
||||
}
|
||||
|
||||
GFXFrustumSaver frustSaver;
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// Render the shadowmap!
|
||||
GFX->pushActiveRenderTarget();
|
||||
|
||||
// Calc matrix and set up visible distance
|
||||
mWorldToLightProj = mLight->getTransform();
|
||||
mWorldToLightProj.inverse();
|
||||
GFX->setWorldMatrix(mWorldToLightProj);
|
||||
|
||||
const F32 &lightRadius = mLight->getRange().x;
|
||||
GFX->setOrtho(-lightRadius, lightRadius, -lightRadius, lightRadius, 1.0f, lightRadius, true);
|
||||
|
||||
// Set up target
|
||||
mTarget->attachTexture( GFXTextureTarget::Color0, mShadowMapTex );
|
||||
mTarget->attachTexture( GFXTextureTarget::DepthStencil,
|
||||
_getDepthTarget( mShadowMapTex->getWidth(), mShadowMapTex->getHeight() ) );
|
||||
GFX->setActiveRenderTarget(mTarget);
|
||||
GFX->clear(GFXClearTarget | GFXClearStencil | GFXClearZBuffer, ColorI(255,255,255,255), 1.0f, 0);
|
||||
|
||||
// Create scene state, prep it
|
||||
SceneManager* sceneManager = diffuseState->getSceneManager();
|
||||
|
||||
SceneRenderState shadowRenderState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
shadowRenderState.getMaterialDelegate().bind( this, &LightShadowMap::getShadowMaterial );
|
||||
shadowRenderState.renderNonLightmappedMeshes( true );
|
||||
shadowRenderState.renderLightmappedMeshes( bUseLightmappedGeometry );
|
||||
shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
sceneManager->renderSceneNoLights( &shadowRenderState, SHADOW_TYPEMASK );
|
||||
|
||||
_debugRender( &shadowRenderState );
|
||||
|
||||
mTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
}
|
||||
48
Engine/source/lighting/shadowMap/paraboloidLightShadowMap.h
Normal file
48
Engine/source/lighting/shadowMap/paraboloidLightShadowMap.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PARABOLOIDLIGHTSHADOWMAP_H_
|
||||
#define _PARABOLOIDLIGHTSHADOWMAP_H_
|
||||
|
||||
#ifndef _LIGHTSHADOWMAP_H_
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#endif
|
||||
|
||||
|
||||
class ParaboloidLightShadowMap : public LightShadowMap
|
||||
{
|
||||
typedef LightShadowMap Parent;
|
||||
public:
|
||||
ParaboloidLightShadowMap( LightInfo *light );
|
||||
~ParaboloidLightShadowMap();
|
||||
|
||||
// LightShadowMap
|
||||
virtual ShadowType getShadowType() const;
|
||||
virtual void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState );
|
||||
virtual void setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc);
|
||||
|
||||
protected:
|
||||
Point2F mShadowMapScale;
|
||||
Point2F mShadowMapOffset;
|
||||
};
|
||||
|
||||
#endif
|
||||
459
Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp
Normal file
459
Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/pssmLightShadowMap.h"
|
||||
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "console/console.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "gui/controls/guiBitmapCtrl.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "materials/shaderData.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
{
|
||||
Con::addVariable( "$pref::PSSM::detailAdjustScale",
|
||||
TypeF32, &PSSMLightShadowMap::smDetailAdjustScale,
|
||||
"@brief Scales the model LOD when rendering into the PSSM shadow.\n"
|
||||
"Use this to reduce the draw calls when rendering the shadow by having "
|
||||
"meshes LOD out nearer to the camera than normal.\n"
|
||||
"@see $pref::TS::detailAdjust\n"
|
||||
"@ingroup AdvancedLighting" );
|
||||
|
||||
Con::addVariable( "$pref::PSSM::smallestVisiblePixelSize",
|
||||
TypeF32, &PSSMLightShadowMap::smSmallestVisiblePixelSize,
|
||||
"@brief The smallest pixel size an object can be and still be rendered into the PSSM shadow.\n"
|
||||
"Use this to force culling of small objects which contribute little to the final shadow.\n"
|
||||
"@see $pref::TS::smallestVisiblePixelSize\n"
|
||||
"@ingroup AdvancedLighting" );
|
||||
}
|
||||
|
||||
F32 PSSMLightShadowMap::smDetailAdjustScale = 0.85f;
|
||||
F32 PSSMLightShadowMap::smSmallestVisiblePixelSize = 25.0f;
|
||||
|
||||
|
||||
PSSMLightShadowMap::PSSMLightShadowMap( LightInfo *light )
|
||||
: LightShadowMap( light ),
|
||||
mNumSplits( 0 )
|
||||
{
|
||||
mIsViewDependent = true;
|
||||
}
|
||||
|
||||
void PSSMLightShadowMap::_setNumSplits( U32 numSplits, U32 texSize )
|
||||
{
|
||||
AssertFatal( numSplits > 0 && numSplits <= MAX_SPLITS,
|
||||
"PSSMLightShadowMap::_setNumSplits() - Splits must be between 1 and 4!" );
|
||||
|
||||
releaseTextures();
|
||||
|
||||
mNumSplits = numSplits;
|
||||
mTexSize = texSize;
|
||||
F32 texWidth, texHeight;
|
||||
|
||||
// If the split count is less than 4 then do a
|
||||
// 1xN layout of shadow maps...
|
||||
if ( mNumSplits < 4 )
|
||||
{
|
||||
texHeight = texSize;
|
||||
texWidth = texSize * mNumSplits;
|
||||
|
||||
for ( U32 i = 0; i < 4; i++ )
|
||||
{
|
||||
mViewports[i].extent.set(texSize, texSize);
|
||||
mViewports[i].point.set(texSize*i, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ... with 4 splits do a 2x2.
|
||||
texWidth = texHeight = texSize * 2;
|
||||
|
||||
for ( U32 i = 0; i < 4; i++ )
|
||||
{
|
||||
F32 xOff = (i == 1 || i == 3) ? 0.5f : 0.0f;
|
||||
F32 yOff = (i > 1) ? 0.5f : 0.0f;
|
||||
mViewports[i].extent.set( texSize, texSize );
|
||||
mViewports[i].point.set( xOff * texWidth, yOff * texHeight );
|
||||
}
|
||||
}
|
||||
|
||||
mShadowMapTex.set( texWidth, texHeight,
|
||||
ShadowMapFormat, &ShadowMapProfile,
|
||||
"PSSMLightShadowMap" );
|
||||
}
|
||||
|
||||
void PSSMLightShadowMap::_calcSplitPos(const Frustum& currFrustum)
|
||||
{
|
||||
const F32 nearDist = 0.01f; // TODO: Should this be adjustable or different?
|
||||
const F32 farDist = currFrustum.getFarDist();
|
||||
|
||||
for ( U32 i = 1; i < mNumSplits; i++ )
|
||||
{
|
||||
F32 step = (F32) i / (F32) mNumSplits;
|
||||
F32 logSplit = nearDist * mPow(farDist / nearDist, step);
|
||||
F32 linearSplit = nearDist + (farDist - nearDist) * step;
|
||||
mSplitDist[i] = mLerp( linearSplit, logSplit, mClampF( mLogWeight, 0.0f, 1.0f ) );
|
||||
}
|
||||
|
||||
mSplitDist[0] = nearDist;
|
||||
mSplitDist[mNumSplits] = farDist;
|
||||
}
|
||||
|
||||
Box3F PSSMLightShadowMap::_calcClipSpaceAABB(const Frustum& f, const MatrixF& transform, F32 farDist)
|
||||
{
|
||||
// Calculate frustum center
|
||||
Point3F center(0,0,0);
|
||||
for (U32 i = 0; i < 8; i++)
|
||||
{
|
||||
const Point3F& pt = f.getPoints()[i];
|
||||
center += pt;
|
||||
}
|
||||
center /= 8;
|
||||
|
||||
// Calculate frustum bounding sphere radius
|
||||
F32 radius = 0.0f;
|
||||
for (U32 i = 0; i < 8; i++)
|
||||
radius = getMax(radius, (f.getPoints()[i] - center).lenSquared());
|
||||
radius = mFloor( mSqrt(radius) );
|
||||
|
||||
// Now build box for sphere
|
||||
Box3F result;
|
||||
Point3F radiusBox(radius, radius, radius);
|
||||
result.minExtents = center - radiusBox;
|
||||
result.maxExtents = center + radiusBox;
|
||||
|
||||
// Transform to light projection space
|
||||
transform.mul(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// This "rounds" the projection matrix to remove subtexel movement during shadow map
|
||||
// rasterization. This is here to reduce shadow shimmering.
|
||||
void PSSMLightShadowMap::_roundProjection(const MatrixF& lightMat, const MatrixF& cropMatrix, Point3F &offset, U32 splitNum)
|
||||
{
|
||||
// Round to the nearest shadowmap texel, this helps reduce shimmering
|
||||
MatrixF currentProj = GFX->getProjectionMatrix();
|
||||
currentProj = cropMatrix * currentProj * lightMat;
|
||||
|
||||
// Project origin to screen.
|
||||
Point4F originShadow4F(0,0,0,1);
|
||||
currentProj.mul(originShadow4F);
|
||||
Point2F originShadow(originShadow4F.x / originShadow4F.w, originShadow4F.y / originShadow4F.w);
|
||||
|
||||
// Convert to texture space (0..shadowMapSize)
|
||||
F32 t = mNumSplits < 4 ? mShadowMapTex->getWidth() / mNumSplits : mShadowMapTex->getWidth() / 2;
|
||||
Point2F texelsToTexture(t / 2.0f, mShadowMapTex->getHeight() / 2.0f);
|
||||
if (mNumSplits >= 4) texelsToTexture.y *= 0.5f;
|
||||
originShadow.convolve(texelsToTexture);
|
||||
|
||||
// Clamp to texel boundary
|
||||
Point2F originRounded;
|
||||
originRounded.x = mFloor(originShadow.x + 0.5f);
|
||||
originRounded.y = mFloor(originShadow.y + 0.5f);
|
||||
|
||||
// Subtract origin to get an offset to recenter everything on texel boundaries
|
||||
originRounded -= originShadow;
|
||||
|
||||
// Convert back to texels (0..1) and offset
|
||||
originRounded.convolveInverse(texelsToTexture);
|
||||
offset.x += originRounded.x;
|
||||
offset.y += originRounded.y;
|
||||
}
|
||||
|
||||
void PSSMLightShadowMap::_render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
PROFILE_SCOPE(PSSMLightShadowMap_render);
|
||||
|
||||
const ShadowMapParams *params = mLight->getExtended<ShadowMapParams>();
|
||||
const LightMapParams *lmParams = mLight->getExtended<LightMapParams>();
|
||||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||
|
||||
const U32 texSize = getBestTexSize( params->numSplits < 4 ? params->numSplits : 2 );
|
||||
|
||||
if ( mShadowMapTex.isNull() ||
|
||||
mNumSplits != params->numSplits ||
|
||||
mTexSize != texSize )
|
||||
_setNumSplits( params->numSplits, texSize );
|
||||
mLogWeight = params->logWeight;
|
||||
|
||||
Frustum fullFrustum( diffuseState->getFrustum() );
|
||||
fullFrustum.cropNearFar(fullFrustum.getNearDist(), params->shadowDistance);
|
||||
|
||||
GFXFrustumSaver frustSaver;
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// Set our render target
|
||||
GFX->pushActiveRenderTarget();
|
||||
mTarget->attachTexture( GFXTextureTarget::Color0, mShadowMapTex );
|
||||
mTarget->attachTexture( GFXTextureTarget::DepthStencil,
|
||||
_getDepthTarget( mShadowMapTex->getWidth(), mShadowMapTex->getHeight() ) );
|
||||
GFX->setActiveRenderTarget( mTarget );
|
||||
GFX->clear( GFXClearStencil | GFXClearZBuffer | GFXClearTarget, ColorI(255,255,255), 1.0f, 0 );
|
||||
|
||||
// Calculate our standard light matrices
|
||||
MatrixF lightMatrix;
|
||||
calcLightMatrices( lightMatrix, diffuseState->getFrustum() );
|
||||
lightMatrix.inverse();
|
||||
MatrixF lightViewProj = GFX->getProjectionMatrix() * lightMatrix;
|
||||
|
||||
// TODO: This is just retrieving the near and far calculated
|
||||
// in calcLightMatrices... we should make that clear.
|
||||
F32 pnear, pfar;
|
||||
GFX->getFrustum( NULL, NULL, NULL, NULL, &pnear, &pfar, NULL );
|
||||
|
||||
// Set our view up
|
||||
GFX->setWorldMatrix(lightMatrix);
|
||||
MatrixF toLightSpace = lightMatrix; // * invCurrentView;
|
||||
|
||||
_calcSplitPos(fullFrustum);
|
||||
|
||||
mWorldToLightProj = GFX->getProjectionMatrix() * toLightSpace;
|
||||
|
||||
// Apply the PSSM
|
||||
const F32 savedSmallestVisible = TSShapeInstance::smSmallestVisiblePixelSize;
|
||||
const F32 savedDetailAdjust = TSShapeInstance::smDetailAdjust;
|
||||
TSShapeInstance::smDetailAdjust *= smDetailAdjustScale;
|
||||
TSShapeInstance::smSmallestVisiblePixelSize = smSmallestVisiblePixelSize;
|
||||
|
||||
for (U32 i = 0; i < mNumSplits; i++)
|
||||
{
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// Calculate a sub-frustum
|
||||
Frustum subFrustum(fullFrustum);
|
||||
subFrustum.cropNearFar(mSplitDist[i], mSplitDist[i+1]);
|
||||
|
||||
// Calculate our AABB in the light's clip space.
|
||||
Box3F clipAABB = _calcClipSpaceAABB(subFrustum, lightViewProj, fullFrustum.getFarDist());
|
||||
|
||||
// Calculate our crop matrix
|
||||
Point3F scale(2.0f / (clipAABB.maxExtents.x - clipAABB.minExtents.x),
|
||||
2.0f / (clipAABB.maxExtents.y - clipAABB.minExtents.y),
|
||||
1.0f);
|
||||
|
||||
// TODO: This seems to produce less "pops" of the
|
||||
// shadow resolution as the camera spins around and
|
||||
// it should produce pixels that are closer to being
|
||||
// square.
|
||||
//
|
||||
// Still is it the right thing to do?
|
||||
//
|
||||
scale.y = scale.x = ( getMin( scale.x, scale.y ) );
|
||||
//scale.x = mFloor(scale.x);
|
||||
//scale.y = mFloor(scale.y);
|
||||
|
||||
Point3F offset( -0.5f * (clipAABB.maxExtents.x + clipAABB.minExtents.x) * scale.x,
|
||||
-0.5f * (clipAABB.maxExtents.y + clipAABB.minExtents.y) * scale.y,
|
||||
0.0f );
|
||||
|
||||
MatrixF cropMatrix(true);
|
||||
cropMatrix.scale(scale);
|
||||
cropMatrix.setPosition(offset);
|
||||
|
||||
_roundProjection(lightMatrix, cropMatrix, offset, i);
|
||||
|
||||
cropMatrix.setPosition(offset);
|
||||
|
||||
// Save scale/offset for shader computations
|
||||
mScaleProj[i].set(scale);
|
||||
mOffsetProj[i].set(offset);
|
||||
|
||||
// Adjust the far plane to the max z we got (maybe add a little to deal with split overlap)
|
||||
bool isOrtho;
|
||||
{
|
||||
F32 left, right, bottom, top, nearDist, farDist;
|
||||
GFX->getFrustum(&left, &right, &bottom, &top, &nearDist, &farDist,&isOrtho);
|
||||
// BTRTODO: Fix me!
|
||||
farDist = clipAABB.maxExtents.z;
|
||||
if (!isOrtho)
|
||||
GFX->setFrustum(left, right, bottom, top, nearDist, farDist);
|
||||
else
|
||||
{
|
||||
// Calculate a new far plane, add a fudge factor to avoid bringing
|
||||
// the far plane in too close.
|
||||
F32 newFar = pfar * clipAABB.maxExtents.z + 1.0f;
|
||||
mFarPlaneScalePSSM[i] = (pfar - pnear) / (newFar - pnear);
|
||||
GFX->setOrtho(left, right, bottom, top, pnear, newFar, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Crop matrix multiply needs to be post-projection.
|
||||
MatrixF alightProj = GFX->getProjectionMatrix();
|
||||
alightProj = cropMatrix * alightProj;
|
||||
|
||||
// Set our new projection
|
||||
GFX->setProjectionMatrix(alightProj);
|
||||
|
||||
// Render into the quad of the shadow map we are using.
|
||||
GFX->setViewport(mViewports[i]);
|
||||
|
||||
SceneManager* sceneManager = diffuseState->getSceneManager();
|
||||
|
||||
// The frustum is currently the full size and has not had
|
||||
// cropping applied.
|
||||
//
|
||||
// We make that adjustment here.
|
||||
|
||||
const Frustum& uncroppedFrustum = GFX->getFrustum();
|
||||
Frustum croppedFrustum;
|
||||
scale *= 0.5f;
|
||||
croppedFrustum.set(
|
||||
isOrtho,
|
||||
uncroppedFrustum.getNearLeft() / scale.x,
|
||||
uncroppedFrustum.getNearRight() / scale.x,
|
||||
uncroppedFrustum.getNearTop() / scale.y,
|
||||
uncroppedFrustum.getNearBottom() / scale.y,
|
||||
uncroppedFrustum.getNearDist(),
|
||||
uncroppedFrustum.getFarDist(),
|
||||
uncroppedFrustum.getTransform()
|
||||
);
|
||||
|
||||
MatrixF camera = GFX->getWorldMatrix();
|
||||
camera.inverse();
|
||||
croppedFrustum.setTransform( camera );
|
||||
|
||||
// Setup the scene state and use the diffuse state
|
||||
// camera position and screen metrics values so that
|
||||
// lod is done the same as in the diffuse pass.
|
||||
|
||||
SceneRenderState shadowRenderState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState( diffuseState->getViewport(), croppedFrustum,
|
||||
GFX->getWorldMatrix(), GFX->getProjectionMatrix() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
shadowRenderState.getMaterialDelegate().bind( this, &LightShadowMap::getShadowMaterial );
|
||||
shadowRenderState.renderNonLightmappedMeshes( true );
|
||||
shadowRenderState.renderLightmappedMeshes( bUseLightmappedGeometry );
|
||||
|
||||
shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
U32 objectMask = SHADOW_TYPEMASK;
|
||||
if ( i == mNumSplits-1 && params->lastSplitTerrainOnly )
|
||||
objectMask = TerrainObjectType;
|
||||
|
||||
sceneManager->renderSceneNoLights( &shadowRenderState, objectMask );
|
||||
|
||||
_debugRender( &shadowRenderState );
|
||||
}
|
||||
|
||||
// Restore the original TS lod settings.
|
||||
TSShapeInstance::smSmallestVisiblePixelSize = savedSmallestVisible;
|
||||
TSShapeInstance::smDetailAdjust = savedDetailAdjust;
|
||||
|
||||
// Release our render target
|
||||
mTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
}
|
||||
|
||||
void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc)
|
||||
{
|
||||
PROFILE_SCOPE( PSSMLightShadowMap_setShaderParameters );
|
||||
|
||||
if ( lsc->mTapRotationTexSC->isValid() )
|
||||
GFX->setTexture( lsc->mTapRotationTexSC->getSamplerRegister(),
|
||||
SHADOWMGR->getTapRotationTex() );
|
||||
|
||||
const ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
|
||||
Point4F sx(Point4F::Zero),
|
||||
sy(Point4F::Zero),
|
||||
ox(Point4F::Zero),
|
||||
oy(Point4F::Zero),
|
||||
aXOff(Point4F::Zero),
|
||||
aYOff(Point4F::Zero);
|
||||
|
||||
for (U32 i = 0; i < mNumSplits; i++)
|
||||
{
|
||||
sx[i] = mScaleProj[i].x;
|
||||
sy[i] = mScaleProj[i].y;
|
||||
ox[i] = mOffsetProj[i].x;
|
||||
oy[i] = mOffsetProj[i].y;
|
||||
}
|
||||
|
||||
Point2F shadowMapAtlas;
|
||||
if (mNumSplits < 4)
|
||||
{
|
||||
shadowMapAtlas.x = 1.0f / (F32)mNumSplits;
|
||||
shadowMapAtlas.y = 1.0f;
|
||||
|
||||
// 1xmNumSplits
|
||||
for (U32 i = 0; i < mNumSplits; i++)
|
||||
aXOff[i] = (F32)i * shadowMapAtlas.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
shadowMapAtlas.set(0.5f, 0.5f);
|
||||
|
||||
// 2x2
|
||||
for (U32 i = 0; i < mNumSplits; i++)
|
||||
{
|
||||
if (i == 1 || i == 3)
|
||||
aXOff[i] = 0.5f;
|
||||
if (i > 1)
|
||||
aYOff[i] = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
params->setSafe(lsc->mScaleXSC, sx);
|
||||
params->setSafe(lsc->mScaleYSC, sy);
|
||||
params->setSafe(lsc->mOffsetXSC, ox);
|
||||
params->setSafe(lsc->mOffsetYSC, oy);
|
||||
params->setSafe(lsc->mAtlasXOffsetSC, aXOff);
|
||||
params->setSafe(lsc->mAtlasYOffsetSC, aYOff);
|
||||
params->setSafe(lsc->mAtlasScaleSC, shadowMapAtlas);
|
||||
|
||||
Point4F lightParams( mLight->getRange().x, p->overDarkFactor.x, 0.0f, 0.0f );
|
||||
params->setSafe( lsc->mLightParamsSC, lightParams );
|
||||
|
||||
params->setSafe( lsc->mFarPlaneScalePSSM, mFarPlaneScalePSSM);
|
||||
|
||||
Point2F fadeStartLength(p->fadeStartDist, 0.0f);
|
||||
if (fadeStartLength.x == 0.0f)
|
||||
{
|
||||
// By default, lets fade the last half of the last split.
|
||||
fadeStartLength.x = (mSplitDist[mNumSplits-1] + mSplitDist[mNumSplits]) / 2.0f;
|
||||
}
|
||||
fadeStartLength.y = 1.0f / (mSplitDist[mNumSplits] - fadeStartLength.x);
|
||||
params->setSafe( lsc->mFadeStartLength, fadeStartLength);
|
||||
|
||||
params->setSafe( lsc->mOverDarkFactorPSSM, p->overDarkFactor);
|
||||
|
||||
// The softness is a factor of the texel size.
|
||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
71
Engine/source/lighting/shadowMap/pssmLightShadowMap.h
Normal file
71
Engine/source/lighting/shadowMap/pssmLightShadowMap.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _PSSMLIGHTSHADOWMAP_H_
|
||||
#define _PSSMLIGHTSHADOWMAP_H_
|
||||
|
||||
#ifndef _LIGHTSHADOWMAP_H_
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#endif
|
||||
#ifndef _MATHUTIL_FRUSTUM_H_
|
||||
#include "math/util/frustum.h"
|
||||
#endif
|
||||
|
||||
|
||||
class PSSMLightShadowMap : public LightShadowMap
|
||||
{
|
||||
typedef LightShadowMap Parent;
|
||||
public:
|
||||
PSSMLightShadowMap( LightInfo *light );
|
||||
|
||||
// LightShadowMap
|
||||
virtual ShadowType getShadowType() const { return ShadowType_PSSM; }
|
||||
virtual void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState );
|
||||
virtual void setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc);
|
||||
|
||||
/// Used to scale TSShapeInstance::smDetailAdjust to have
|
||||
/// objects lod quicker when in the PSSM shadow.
|
||||
/// @see TSShapeInstance::smDetailAdjust
|
||||
static F32 smDetailAdjustScale;
|
||||
|
||||
/// Like TSShapeInstance::smSmallestVisiblePixelSize this is used
|
||||
/// to define the smallest LOD to render.
|
||||
/// @see TSShapeInstance::smSmallestVisiblePixelSize
|
||||
static F32 smSmallestVisiblePixelSize;
|
||||
|
||||
protected:
|
||||
|
||||
void _setNumSplits( U32 numSplits, U32 texSize );
|
||||
void _calcSplitPos(const Frustum& currFrustum);
|
||||
Box3F _calcClipSpaceAABB(const Frustum& f, const MatrixF& transform, F32 farDist);
|
||||
void _roundProjection(const MatrixF& lightMat, const MatrixF& cropMatrix, Point3F &offset, U32 splitNum);
|
||||
|
||||
static const int MAX_SPLITS = 4;
|
||||
U32 mNumSplits;
|
||||
F32 mSplitDist[MAX_SPLITS+1]; // +1 because we store a cap
|
||||
RectI mViewports[MAX_SPLITS];
|
||||
Point3F mScaleProj[MAX_SPLITS];
|
||||
Point3F mOffsetProj[MAX_SPLITS];
|
||||
Point4F mFarPlaneScalePSSM;
|
||||
F32 mLogWeight;
|
||||
};
|
||||
|
||||
#endif
|
||||
62
Engine/source/lighting/shadowMap/shadowCommon.h
Normal file
62
Engine/source/lighting/shadowMap/shadowCommon.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SHADOW_COMMON_H_
|
||||
#define _SHADOW_COMMON_H_
|
||||
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
|
||||
|
||||
///
|
||||
enum ShadowType
|
||||
{
|
||||
ShadowType_None = -1,
|
||||
|
||||
ShadowType_Spot,
|
||||
ShadowType_PSSM,
|
||||
|
||||
ShadowType_Paraboloid,
|
||||
ShadowType_DualParaboloidSinglePass,
|
||||
ShadowType_DualParaboloid,
|
||||
ShadowType_CubeMap,
|
||||
|
||||
ShadowType_Count,
|
||||
};
|
||||
|
||||
DefineEnumType( ShadowType );
|
||||
|
||||
|
||||
/// The different shadow filter modes used when rendering
|
||||
/// shadowed lights.
|
||||
/// @see setShadowFilterMode
|
||||
enum ShadowFilterMode
|
||||
{
|
||||
ShadowFilterMode_None,
|
||||
ShadowFilterMode_SoftShadow,
|
||||
ShadowFilterMode_SoftShadowHighQuality
|
||||
};
|
||||
|
||||
DefineEnumType( ShadowFilterMode );
|
||||
|
||||
#endif // _SHADOW_COMMON_H_
|
||||
192
Engine/source/lighting/shadowMap/shadowMapManager.cpp
Normal file
192
Engine/source/lighting/shadowMap/shadowMapManager.cpp
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/shadowMapManager.h"
|
||||
|
||||
#include "lighting/shadowMap/shadowMapPass.h"
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "gfx/gfxTextureManager.h"
|
||||
#include "core/module.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
GFX_ImplementTextureProfile(ShadowMapTexProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize | GFXTextureProfile::Dynamic ,
|
||||
GFXTextureProfile::None);
|
||||
|
||||
|
||||
MODULE_BEGIN( ShadowMapManager )
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
ManagedSingleton< ShadowMapManager >::createSingleton();
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
ManagedSingleton< ShadowMapManager >::deleteSingleton();
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
{
|
||||
Con::addVariable( "$pref::Shadows::textureScalar",
|
||||
TypeF32, &LightShadowMap::smShadowTexScalar,
|
||||
"@brief Used to scale the shadow texture sizes.\n"
|
||||
"This can reduce the shadow quality and texture memory overhead or increase them.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
Con::NotifyDelegate callabck( &LightShadowMap::releaseAllTextures );
|
||||
Con::addVariableNotify( "$pref::Shadows::textureScalar", callabck );
|
||||
|
||||
Con::addVariable( "$pref::Shadows::disable",
|
||||
TypeBool, &ShadowMapPass::smDisableShadowsPref,
|
||||
"Used to disable all shadow rendering.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$Shadows::disable",
|
||||
TypeBool, &ShadowMapPass::smDisableShadowsEditor,
|
||||
"Used by the editor to disable all shadow rendering.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::NotifyDelegate shadowCallback( &ShadowMapManager::updateShadowDisable );
|
||||
Con::addVariableNotify( "$pref::Shadows::disable", shadowCallback );
|
||||
Con::addVariableNotify( "$Shadows::disable", shadowCallback );
|
||||
}
|
||||
|
||||
Signal<void(void)> ShadowMapManager::smShadowDeactivateSignal;
|
||||
|
||||
|
||||
ShadowMapManager::ShadowMapManager()
|
||||
: mShadowMapPass(NULL),
|
||||
mCurrentShadowMap(NULL),
|
||||
mIsActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
ShadowMapManager::~ShadowMapManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ShadowMapManager::setLightShadowMapForLight( LightInfo *light )
|
||||
{
|
||||
ShadowMapParams *params = light->getExtended<ShadowMapParams>();
|
||||
if ( params )
|
||||
mCurrentShadowMap = params->getShadowMap();
|
||||
else
|
||||
mCurrentShadowMap = NULL;
|
||||
}
|
||||
|
||||
void ShadowMapManager::activate()
|
||||
{
|
||||
ShadowManager::activate();
|
||||
|
||||
if (!getSceneManager())
|
||||
{
|
||||
Con::errorf("This world has no scene manager! Shadow manager not activating!");
|
||||
return;
|
||||
}
|
||||
|
||||
mShadowMapPass = new ShadowMapPass(LIGHTMGR, this);
|
||||
|
||||
getSceneManager()->getPreRenderSignal().notify( this, &ShadowMapManager::_onPreRender, 0.01f );
|
||||
GFXTextureManager::addEventDelegate( this, &ShadowMapManager::_onTextureEvent );
|
||||
|
||||
mIsActive = true;
|
||||
}
|
||||
|
||||
void ShadowMapManager::deactivate()
|
||||
{
|
||||
GFXTextureManager::removeEventDelegate( this, &ShadowMapManager::_onTextureEvent );
|
||||
getSceneManager()->getPreRenderSignal().remove( this, &ShadowMapManager::_onPreRender );
|
||||
|
||||
SAFE_DELETE(mShadowMapPass);
|
||||
mTapRotationTex = NULL;
|
||||
|
||||
// Clean up our shadow texture memory.
|
||||
LightShadowMap::releaseAllTextures();
|
||||
TEXMGR->cleanupPool();
|
||||
|
||||
mIsActive = false;
|
||||
|
||||
ShadowManager::deactivate();
|
||||
}
|
||||
|
||||
void ShadowMapManager::_onPreRender( SceneManager *sg, const SceneRenderState *state )
|
||||
{
|
||||
if ( mShadowMapPass && state->isDiffusePass() )
|
||||
mShadowMapPass->render( sg, state, (U32)-1 );
|
||||
}
|
||||
|
||||
void ShadowMapManager::_onTextureEvent( GFXTexCallbackCode code )
|
||||
{
|
||||
if ( code == GFXZombify )
|
||||
mTapRotationTex = NULL;
|
||||
}
|
||||
|
||||
GFXTextureObject* ShadowMapManager::getTapRotationTex()
|
||||
{
|
||||
if ( mTapRotationTex.isValid() )
|
||||
return mTapRotationTex;
|
||||
|
||||
mTapRotationTex.set( 64, 64, GFXFormatR8G8B8A8, &ShadowMapTexProfile,
|
||||
"ShadowMapManager::getTapRotationTex" );
|
||||
|
||||
GFXLockedRect *rect = mTapRotationTex.lock();
|
||||
U8 *f = rect->bits;
|
||||
F32 angle;
|
||||
for( U32 i = 0; i < 64*64; i++, f += 4 )
|
||||
{
|
||||
// We only pack the rotations into the red
|
||||
// and green channels... the rest are empty.
|
||||
angle = M_2PI_F * gRandGen.randF();
|
||||
f[0] = U8_MAX * ( ( 1.0f + mSin( angle ) ) * 0.5f );
|
||||
f[1] = U8_MAX * ( ( 1.0f + mCos( angle ) ) * 0.5f );
|
||||
f[2] = 0;
|
||||
f[3] = 0;
|
||||
}
|
||||
|
||||
mTapRotationTex.unlock();
|
||||
|
||||
return mTapRotationTex;
|
||||
}
|
||||
|
||||
void ShadowMapManager::updateShadowDisable()
|
||||
{
|
||||
bool disable = false;
|
||||
|
||||
if ( ShadowMapPass::smDisableShadowsEditor || ShadowMapPass::smDisableShadowsPref )
|
||||
disable = true;
|
||||
|
||||
if ( disable != ShadowMapPass::smDisableShadows)
|
||||
{
|
||||
ShadowMapPass::smDisableShadows = disable;
|
||||
smShadowDeactivateSignal.trigger();
|
||||
}
|
||||
}
|
||||
108
Engine/source/lighting/shadowMap/shadowMapManager.h
Normal file
108
Engine/source/lighting/shadowMap/shadowMapManager.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SHADOWMAPMANAGER_H_
|
||||
#define _SHADOWMAPMANAGER_H_
|
||||
|
||||
#ifndef _TSINGLETON_H_
|
||||
#include "core/util/tSingleton.h"
|
||||
#endif
|
||||
#ifndef _SHADOWMANAGER_H_
|
||||
#include "lighting/shadowManager.h"
|
||||
#endif
|
||||
#ifndef _GFXENUMS_H_
|
||||
#include "gfx/gfxEnums.h"
|
||||
#endif
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
#ifndef _MPOINT4_H_
|
||||
#include "math/mPoint4.h"
|
||||
#endif
|
||||
|
||||
class LightShadowMap;
|
||||
class ShadowMapPass;
|
||||
class LightInfo;
|
||||
|
||||
class SceneManager;
|
||||
class SceneRenderState;
|
||||
|
||||
|
||||
class ShadowMapManager : public ShadowManager
|
||||
{
|
||||
typedef ShadowManager Parent;
|
||||
|
||||
friend class ShadowMapPass;
|
||||
|
||||
public:
|
||||
|
||||
ShadowMapManager();
|
||||
virtual ~ShadowMapManager();
|
||||
|
||||
/// Sets the current shadowmap (used in setLightInfo/setTextureStage calls)
|
||||
void setLightShadowMap( LightShadowMap *lm ) { mCurrentShadowMap = lm; }
|
||||
|
||||
/// Looks up the shadow map for the light then sets it.
|
||||
void setLightShadowMapForLight( LightInfo *light );
|
||||
|
||||
/// Return the current shadow map
|
||||
LightShadowMap* getCurrentShadowMap() const { return mCurrentShadowMap; }
|
||||
|
||||
ShadowMapPass* getShadowMapPass() const { return mShadowMapPass; }
|
||||
|
||||
// Shadow manager
|
||||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
|
||||
GFXTextureObject* getTapRotationTex();
|
||||
|
||||
/// The shadow map deactivation signal.
|
||||
static Signal<void(void)> smShadowDeactivateSignal;
|
||||
|
||||
static void updateShadowDisable();
|
||||
|
||||
protected:
|
||||
|
||||
void _onTextureEvent( GFXTexCallbackCode code );
|
||||
|
||||
void _onPreRender( SceneManager *sg, const SceneRenderState* state );
|
||||
|
||||
ShadowMapPass *mShadowMapPass;
|
||||
LightShadowMap *mCurrentShadowMap;
|
||||
|
||||
///
|
||||
GFXTexHandle mTapRotationTex;
|
||||
|
||||
bool mIsActive;
|
||||
|
||||
public:
|
||||
// For ManagedSingleton.
|
||||
static const char* getSingletonName() { return "ShadowMapManager"; }
|
||||
};
|
||||
|
||||
|
||||
/// Returns the ShadowMapManager singleton.
|
||||
#define SHADOWMGR ManagedSingleton<ShadowMapManager>::instance()
|
||||
|
||||
GFX_DeclareTextureProfile( ShadowMapTexProfile );
|
||||
|
||||
#endif // _SHADOWMAPMANAGER_H_
|
||||
250
Engine/source/lighting/shadowMap/shadowMapPass.cpp
Normal file
250
Engine/source/lighting/shadowMap/shadowMapPass.cpp
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/shadowMapPass.h"
|
||||
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "renderInstance/renderObjectMgr.h"
|
||||
#include "renderInstance/renderMeshMgr.h"
|
||||
#include "renderInstance/renderTerrainMgr.h"
|
||||
#include "renderInstance/renderImposterMgr.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "platform/platformTimer.h"
|
||||
|
||||
|
||||
const String ShadowMapPass::PassTypeName("ShadowMap");
|
||||
|
||||
U32 ShadowMapPass::smActiveShadowMaps = 0;
|
||||
U32 ShadowMapPass::smUpdatedShadowMaps = 0;
|
||||
U32 ShadowMapPass::smNearShadowMaps = 0;
|
||||
U32 ShadowMapPass::smShadowMapsDrawCalls = 0;
|
||||
U32 ShadowMapPass::smShadowMapPolyCount = 0;
|
||||
U32 ShadowMapPass::smRenderTargetChanges = 0;
|
||||
U32 ShadowMapPass::smShadowPoolTexturesCount = 0.;
|
||||
F32 ShadowMapPass::smShadowPoolMemory = 0.0f;
|
||||
|
||||
bool ShadowMapPass::smDisableShadows = false;
|
||||
bool ShadowMapPass::smDisableShadowsEditor = false;
|
||||
bool ShadowMapPass::smDisableShadowsPref = false;
|
||||
|
||||
/// We have a default 8ms render budget for shadow rendering.
|
||||
U32 ShadowMapPass::smRenderBudgetMs = 8;
|
||||
|
||||
ShadowMapPass::ShadowMapPass(LightManager* lightManager, ShadowMapManager* shadowManager)
|
||||
{
|
||||
mLightManager = lightManager;
|
||||
mShadowManager = shadowManager;
|
||||
mShadowRPM = new ShadowRenderPassManager();
|
||||
mShadowRPM->assignName( "ShadowRenderPassManager" );
|
||||
mShadowRPM->registerObject();
|
||||
Sim::getRootGroup()->addObject( mShadowRPM );
|
||||
|
||||
// Setup our render pass manager
|
||||
|
||||
mShadowRPM->addManager( new RenderMeshMgr(RenderPassManager::RIT_Mesh, 0.3f, 0.3f) );
|
||||
mShadowRPM->addManager( new RenderMeshMgr( RenderPassManager::RIT_Interior, 0.4f, 0.4f ) );
|
||||
//mShadowRPM->addManager( new RenderObjectMgr() );
|
||||
mShadowRPM->addManager( new RenderTerrainMgr( 0.5f, 0.5f ) );
|
||||
mShadowRPM->addManager( new RenderImposterMgr( 0.6f, 0.6f ) );
|
||||
|
||||
mActiveLights = 0;
|
||||
|
||||
mTimer = PlatformTimer::create();
|
||||
|
||||
Con::addVariable( "$ShadowStats::activeMaps", TypeS32, &smActiveShadowMaps,
|
||||
"The shadow stats showing the active number of shadow maps.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::updatedMaps", TypeS32, &smUpdatedShadowMaps,
|
||||
"The shadow stats showing the number of shadow maps updated this frame.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::nearMaps", TypeS32, &smNearShadowMaps,
|
||||
"The shadow stats showing the number of shadow maps that are close enough to be updated very frame.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::drawCalls", TypeS32, &smShadowMapsDrawCalls,
|
||||
"The shadow stats showing the number of draw calls in shadow map renders for this frame.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::polyCount", TypeS32, &smShadowMapPolyCount,
|
||||
"The shadow stats showing the number of triangles in shadow map renders for this frame.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::rtChanges", TypeS32, &smRenderTargetChanges,
|
||||
"The shadow stats showing the number of render target changes for shadow maps in this frame.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::poolTexCount", TypeS32, &smShadowPoolTexturesCount,
|
||||
"The shadow stats showing the number of shadow textures in the shadow texture pool.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$ShadowStats::poolTexMemory", TypeF32, &smShadowPoolMemory,
|
||||
"The shadow stats showing the approximate texture memory usage of the shadow map texture pool.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
}
|
||||
|
||||
ShadowMapPass::~ShadowMapPass()
|
||||
{
|
||||
SAFE_DELETE( mTimer );
|
||||
|
||||
if ( mShadowRPM )
|
||||
mShadowRPM->deleteObject();
|
||||
}
|
||||
|
||||
void ShadowMapPass::render( SceneManager *sceneManager,
|
||||
const SceneRenderState *diffuseState,
|
||||
U32 objectMask )
|
||||
{
|
||||
PROFILE_SCOPE( ShadowMapPass_Render );
|
||||
|
||||
// Prep some shadow rendering stats.
|
||||
smActiveShadowMaps = 0;
|
||||
smUpdatedShadowMaps = 0;
|
||||
smNearShadowMaps = 0;
|
||||
GFXDeviceStatistics stats;
|
||||
stats.start( GFX->getDeviceStatistics() );
|
||||
|
||||
// NOTE: The lights were already registered by SceneManager.
|
||||
|
||||
// Update mLights
|
||||
mLights.clear();
|
||||
mLightManager->getAllUnsortedLights( &mLights );
|
||||
mActiveLights = mLights.size();
|
||||
|
||||
// Use the per-frame incremented time for
|
||||
// priority updates and to track when the
|
||||
// shadow was last updated.
|
||||
const U32 currTime = Sim::getCurrentTime();
|
||||
|
||||
// First do a loop thru the lights setting up the shadow
|
||||
// info array for this pass.
|
||||
Vector<LightShadowMap*> shadowMaps;
|
||||
shadowMaps.reserve( mActiveLights );
|
||||
for ( U32 i = 0; i < mActiveLights; i++ )
|
||||
{
|
||||
ShadowMapParams *params = mLights[i]->getExtended<ShadowMapParams>();
|
||||
|
||||
// Before we do anything... skip lights without shadows.
|
||||
if ( !mLights[i]->getCastShadows() || smDisableShadows )
|
||||
continue;
|
||||
|
||||
LightShadowMap *lsm = params->getOrCreateShadowMap();
|
||||
|
||||
// First check the visiblity query... if it wasn't
|
||||
// visible skip it.
|
||||
if ( lsm->wasOccluded() )
|
||||
continue;
|
||||
|
||||
// Any shadow that is visible is counted as being
|
||||
// active regardless if we update it or not.
|
||||
++smActiveShadowMaps;
|
||||
|
||||
// Do a priority update for this shadow.
|
||||
lsm->updatePriority( diffuseState, currTime );
|
||||
|
||||
shadowMaps.push_back( lsm );
|
||||
}
|
||||
|
||||
// Now sort the shadow info by priority.
|
||||
shadowMaps.sort( LightShadowMap::cmpPriority );
|
||||
|
||||
GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render, ColorI::RED );
|
||||
|
||||
// Use a timer for tracking our shadow rendering
|
||||
// budget to ensure a high precision results.
|
||||
mTimer->getElapsedMs();
|
||||
mTimer->reset();
|
||||
|
||||
for ( U32 i = 0; i < shadowMaps.size(); i++ )
|
||||
{
|
||||
LightShadowMap *lsm = shadowMaps[i];
|
||||
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render_Shadow, ColorI::RED );
|
||||
|
||||
mShadowManager->setLightShadowMap( lsm );
|
||||
lsm->render( mShadowRPM, diffuseState );
|
||||
++smUpdatedShadowMaps;
|
||||
}
|
||||
|
||||
// View dependent shadows or ones that are covering the entire
|
||||
// screen are updated every frame no matter the time left in
|
||||
// our shadow rendering budget.
|
||||
if ( lsm->isViewDependent() || lsm->getLastScreenSize() >= 1.0f )
|
||||
{
|
||||
++smNearShadowMaps;
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if we're over our frame budget for shadow
|
||||
// updates... give up completely in that case.
|
||||
if ( mTimer->getElapsedMs() > smRenderBudgetMs )
|
||||
break;
|
||||
}
|
||||
|
||||
// Cleanup old unused textures.
|
||||
LightShadowMap::releaseUnusedTextures();
|
||||
|
||||
// Update the stats.
|
||||
stats.end( GFX->getDeviceStatistics() );
|
||||
smShadowMapsDrawCalls = stats.mDrawCalls;
|
||||
smShadowMapPolyCount = stats.mPolyCount;
|
||||
smRenderTargetChanges = stats.mRenderTargetChanges;
|
||||
smShadowPoolTexturesCount = ShadowMapProfile.getStats().activeCount;
|
||||
smShadowPoolMemory = ( ShadowMapProfile.getStats().activeBytes / 1024.0f ) / 1024.0f;
|
||||
|
||||
// The NULL here is importaint as having it around
|
||||
// will cause extra work in AdvancedLightManager::setLightInfo().
|
||||
mShadowManager->setLightShadowMap( NULL );
|
||||
}
|
||||
|
||||
void ShadowRenderPassManager::addInst( RenderInst *inst )
|
||||
{
|
||||
PROFILE_SCOPE(ShadowRenderPassManager_addInst);
|
||||
|
||||
if ( inst->type == RIT_Mesh || inst->type == RIT_Interior )
|
||||
{
|
||||
MeshRenderInst *meshRI = static_cast<MeshRenderInst*>( inst );
|
||||
if ( !meshRI->matInst )
|
||||
return;
|
||||
|
||||
const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
|
||||
if ( !mat->castsShadows() || mat->isTranslucent() )
|
||||
{
|
||||
// Do not add this instance, return here and avoid the default behavior
|
||||
// of calling up to Parent::addInst()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Parent::addInst(inst);
|
||||
}
|
||||
120
Engine/source/lighting/shadowMap/shadowMapPass.h
Normal file
120
Engine/source/lighting/shadowMap/shadowMapPass.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SHADOWMAPPASS_H_
|
||||
#define _SHADOWMAPPASS_H_
|
||||
|
||||
#ifndef _RENDERPASSMANAGER_H_
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#endif
|
||||
#ifndef _RENDERMESHMGR_H_
|
||||
#include "renderInstance/renderMeshMgr.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
#ifndef _SHADOW_COMMON_H_
|
||||
#include "lighting/shadowMap/shadowCommon.h"
|
||||
#endif
|
||||
|
||||
class RenderMeshMgr;
|
||||
class LightShadowMap;
|
||||
class LightManager;
|
||||
class ShadowMapManager;
|
||||
class BaseMatInstance;
|
||||
class RenderObjectMgr;
|
||||
class RenderTerrainMgr;
|
||||
class PlatformTimer;
|
||||
class ShadowRenderPassManager;
|
||||
|
||||
/// ShadowMapPass, this is plugged into the SceneManager to generate
|
||||
/// ShadowMaps for the scene.
|
||||
class ShadowMapPass
|
||||
{
|
||||
public:
|
||||
|
||||
ShadowMapPass() {} // Only called by ConsoleSystem
|
||||
ShadowMapPass(LightManager* LightManager, ShadowMapManager* ShadowManager);
|
||||
virtual ~ShadowMapPass();
|
||||
|
||||
//
|
||||
// SceneRenderPass interface
|
||||
//
|
||||
|
||||
/// Called to render a scene.
|
||||
void render( SceneManager *sceneGraph,
|
||||
const SceneRenderState *diffuseState,
|
||||
U32 objectMask );
|
||||
|
||||
/// Return the type of pass this is
|
||||
virtual const String& getPassType() const { return PassTypeName; };
|
||||
|
||||
/// Return our sort value. (Go first in order to have shadow maps available for RIT_Objects)
|
||||
virtual F32 getSortValue() const { return 0.0f; }
|
||||
|
||||
virtual bool geometryOnly() const { return true; }
|
||||
|
||||
static const String PassTypeName;
|
||||
|
||||
|
||||
/// Used to for debugging performance by disabling
|
||||
/// shadow updates and rendering.
|
||||
static bool smDisableShadows;
|
||||
|
||||
static bool smDisableShadowsEditor;
|
||||
static bool smDisableShadowsPref;
|
||||
|
||||
private:
|
||||
|
||||
static U32 smActiveShadowMaps;
|
||||
static U32 smUpdatedShadowMaps;
|
||||
static U32 smNearShadowMaps;
|
||||
static U32 smShadowMapsDrawCalls;
|
||||
static U32 smShadowMapPolyCount;
|
||||
static U32 smRenderTargetChanges;
|
||||
static U32 smShadowPoolTexturesCount;
|
||||
static F32 smShadowPoolMemory;
|
||||
|
||||
/// The milliseconds alotted for shadow map updates
|
||||
/// on a per frame basis.
|
||||
static U32 smRenderBudgetMs;
|
||||
|
||||
PlatformTimer *mTimer;
|
||||
|
||||
LightInfoList mLights;
|
||||
U32 mActiveLights;
|
||||
SimObjectPtr<ShadowRenderPassManager> mShadowRPM;
|
||||
LightManager* mLightManager;
|
||||
ShadowMapManager* mShadowManager;
|
||||
};
|
||||
|
||||
class ShadowRenderPassManager : public RenderPassManager
|
||||
{
|
||||
typedef RenderPassManager Parent;
|
||||
public:
|
||||
ShadowRenderPassManager() : Parent() {}
|
||||
|
||||
/// Add a RenderInstance to the list
|
||||
virtual void addInst( RenderInst *inst );
|
||||
};
|
||||
|
||||
#endif // _SHADOWMAPPASS_H_
|
||||
224
Engine/source/lighting/shadowMap/shadowMatHook.cpp
Normal file
224
Engine/source/lighting/shadowMap/shadowMatHook.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/shadowMatHook.h"
|
||||
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/customMaterialDefinition.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "materials/materialFeatureData.h"
|
||||
#include "shaderGen/featureType.h"
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "terrain/terrFeatureTypes.h"
|
||||
|
||||
|
||||
const MatInstanceHookType ShadowMaterialHook::Type( "ShadowMap" );
|
||||
|
||||
ShadowMaterialHook::ShadowMaterialHook()
|
||||
{
|
||||
dMemset( mShadowMat, 0, sizeof( mShadowMat ) );
|
||||
}
|
||||
|
||||
ShadowMaterialHook::~ShadowMaterialHook()
|
||||
{
|
||||
for ( U32 i = 0; i < ShadowType_Count; i++ )
|
||||
SAFE_DELETE( mShadowMat[i] );
|
||||
}
|
||||
|
||||
void ShadowMaterialHook::init( BaseMatInstance *inMat )
|
||||
{
|
||||
if( !inMat->isValid() )
|
||||
return;
|
||||
|
||||
// Tweak the feature data to include just what we need.
|
||||
FeatureSet features;
|
||||
features.addFeature( MFT_VertTransform );
|
||||
features.addFeature( MFT_DiffuseMap );
|
||||
features.addFeature( MFT_TexAnim );
|
||||
features.addFeature( MFT_AlphaTest );
|
||||
features.addFeature( MFT_Visibility );
|
||||
|
||||
// Actually we want to include features from the inMat
|
||||
// if they operate on the preTransform verts so things
|
||||
// like wind/deformation effects will also affect the shadow.
|
||||
const FeatureSet &inFeatures = inMat->getFeatures();
|
||||
for ( U32 i = 0; i < inFeatures.getCount(); i++ )
|
||||
{
|
||||
const FeatureType& ft = inFeatures.getAt(i);
|
||||
|
||||
if ( ft.getGroup() == MFG_PreTransform )
|
||||
features.addFeature( ft );
|
||||
}
|
||||
|
||||
// Do instancing in shadows if we can.
|
||||
if ( inFeatures.hasFeature( MFT_UseInstancing ) )
|
||||
features.addFeature( MFT_UseInstancing );
|
||||
|
||||
Material *shadowMat = (Material*)inMat->getMaterial();
|
||||
if ( dynamic_cast<CustomMaterial*>( shadowMat ) )
|
||||
{
|
||||
// This is a custom material... who knows what it really does, but
|
||||
// if it wasn't already filtered out of the shadow render then just
|
||||
// give it some default depth out material.
|
||||
shadowMat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" );
|
||||
}
|
||||
|
||||
// By default we want to disable some states
|
||||
// that the material might enable for us.
|
||||
GFXStateBlockDesc forced;
|
||||
forced.setBlend( false );
|
||||
forced.setAlphaTest( false );
|
||||
|
||||
// We should force on zwrite as the prepass
|
||||
// will disable it by default.
|
||||
forced.setZReadWrite( true, true );
|
||||
|
||||
// TODO: Should we render backfaces for
|
||||
// shadows or does the ESM take care of
|
||||
// all our acne issues?
|
||||
//forced.setCullMode( GFXCullCW );
|
||||
|
||||
// Vector, and spotlights use the same shadow material.
|
||||
BaseMatInstance *newMat = new ShadowMatInstance( shadowMat );
|
||||
newMat->setUserObject( inMat->getUserObject() );
|
||||
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
||||
newMat->addStateBlockDesc( forced );
|
||||
if( !newMat->init( features, inMat->getVertexFormat() ) )
|
||||
{
|
||||
SAFE_DELETE( newMat );
|
||||
newMat = MATMGR->createWarningMatInstance();
|
||||
}
|
||||
|
||||
mShadowMat[ShadowType_Spot] = newMat;
|
||||
|
||||
newMat = new ShadowMatInstance( shadowMat );
|
||||
newMat->setUserObject( inMat->getUserObject() );
|
||||
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
||||
forced.setCullMode( GFXCullCW );
|
||||
newMat->addStateBlockDesc( forced );
|
||||
forced.cullDefined = false;
|
||||
newMat->addShaderMacro( "CUBE_SHADOW_MAP", "" );
|
||||
newMat->init( features, inMat->getVertexFormat() );
|
||||
mShadowMat[ShadowType_CubeMap] = newMat;
|
||||
|
||||
// A dual paraboloid shadow rendered in a single draw call.
|
||||
features.addFeature( MFT_ParaboloidVertTransform );
|
||||
features.addFeature( MFT_IsSinglePassParaboloid );
|
||||
features.removeFeature( MFT_VertTransform );
|
||||
newMat = new ShadowMatInstance( shadowMat );
|
||||
newMat->setUserObject( inMat->getUserObject() );
|
||||
GFXStateBlockDesc noCull( forced );
|
||||
noCull.setCullMode( GFXCullNone );
|
||||
newMat->addStateBlockDesc( noCull );
|
||||
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
||||
newMat->init( features, inMat->getVertexFormat() );
|
||||
mShadowMat[ShadowType_DualParaboloidSinglePass] = newMat;
|
||||
|
||||
// Regular dual paraboloid shadow.
|
||||
features.addFeature( MFT_ParaboloidVertTransform );
|
||||
features.removeFeature( MFT_IsSinglePassParaboloid );
|
||||
features.removeFeature( MFT_VertTransform );
|
||||
newMat = new ShadowMatInstance( shadowMat );
|
||||
newMat->setUserObject( inMat->getUserObject() );
|
||||
newMat->addStateBlockDesc( forced );
|
||||
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
||||
newMat->init( features, inMat->getVertexFormat() );
|
||||
mShadowMat[ShadowType_DualParaboloid] = newMat;
|
||||
|
||||
/*
|
||||
// A single paraboloid shadow.
|
||||
newMat = new ShadowMatInstance( startMatInstance );
|
||||
GFXStateBlockDesc noCull;
|
||||
noCull.setCullMode( GFXCullNone );
|
||||
newMat->addStateBlockDesc( noCull );
|
||||
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
||||
newMat->init( features, globalFeatures, inMat->getVertexFormat() );
|
||||
mShadowMat[ShadowType_DualParaboloidSinglePass] = newMat;
|
||||
*/
|
||||
}
|
||||
|
||||
BaseMatInstance* ShadowMaterialHook::getShadowMat( ShadowType type ) const
|
||||
{
|
||||
AssertFatal( type < ShadowType_Count, "ShadowMaterialHook::getShadowMat() - Bad light type!" );
|
||||
|
||||
// The cubemap and pssm shadows use the same
|
||||
// spotlight material for shadows.
|
||||
if ( type == ShadowType_Spot ||
|
||||
type == ShadowType_PSSM )
|
||||
return mShadowMat[ShadowType_Spot];
|
||||
|
||||
// Get the specialized shadow material.
|
||||
return mShadowMat[type];
|
||||
}
|
||||
|
||||
void ShadowMaterialHook::_overrideFeatures( ProcessedMaterial *mat,
|
||||
U32 stageNum,
|
||||
MaterialFeatureData &fd,
|
||||
const FeatureSet &features )
|
||||
{
|
||||
if ( stageNum != 0 )
|
||||
{
|
||||
fd.features.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the base texture if we don't
|
||||
// have alpha test enabled.
|
||||
if ( !fd.features[ MFT_AlphaTest ] )
|
||||
{
|
||||
fd.features.removeFeature( MFT_TexAnim );
|
||||
fd.features.removeFeature( MFT_DiffuseMap );
|
||||
}
|
||||
|
||||
// HACK: Need to figure out how to enable these
|
||||
// suckers without this override call!
|
||||
|
||||
fd.features.setFeature( MFT_ParaboloidVertTransform,
|
||||
features.hasFeature( MFT_ParaboloidVertTransform ) );
|
||||
fd.features.setFeature( MFT_IsSinglePassParaboloid,
|
||||
features.hasFeature( MFT_IsSinglePassParaboloid ) );
|
||||
|
||||
// The paraboloid transform outputs linear depth, so
|
||||
// it needs to use the plain depth out feature.
|
||||
if ( fd.features.hasFeature( MFT_ParaboloidVertTransform ) )
|
||||
fd.features.addFeature( MFT_DepthOut );
|
||||
else
|
||||
fd.features.addFeature( MFT_EyeSpaceDepthOut );
|
||||
}
|
||||
|
||||
ShadowMatInstance::ShadowMatInstance( Material *mat )
|
||||
: MatInstance( *mat )
|
||||
{
|
||||
mLightmappedMaterial = mMaterial->isLightmapped();
|
||||
}
|
||||
|
||||
bool ShadowMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData )
|
||||
{
|
||||
// Respect SceneRenderState render flags
|
||||
if( (mLightmappedMaterial && !state->renderLightmappedMeshes()) ||
|
||||
(!mLightmappedMaterial && !state->renderNonLightmappedMeshes()) )
|
||||
return false;
|
||||
|
||||
return Parent::setupPass(state, sgData);
|
||||
}
|
||||
81
Engine/source/lighting/shadowMap/shadowMatHook.h
Normal file
81
Engine/source/lighting/shadowMap/shadowMatHook.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SHADOWMATHOOK_H_
|
||||
#define _SHADOWMATHOOK_H_
|
||||
|
||||
#ifndef _MATINSTANCEHOOK_H_
|
||||
#include "materials/matInstanceHook.h"
|
||||
#endif
|
||||
#ifndef _MATINSTANCE_H_
|
||||
#include "materials/matInstance.h"
|
||||
#endif
|
||||
|
||||
// TODO: Move ShadowType enum to somewhere
|
||||
// with less dependancies.
|
||||
#ifndef _SHADOWMAPPASS_H_
|
||||
#include "lighting/shadowMap/shadowMapPass.h"
|
||||
#endif
|
||||
|
||||
class ShadowMatInstance : public MatInstance
|
||||
{
|
||||
typedef MatInstance Parent;
|
||||
|
||||
bool mLightmappedMaterial;
|
||||
public:
|
||||
ShadowMatInstance( Material *mat );
|
||||
virtual ~ShadowMatInstance() {}
|
||||
|
||||
virtual bool setupPass( SceneRenderState *state, const SceneData &sgData );
|
||||
};
|
||||
|
||||
class ShadowMaterialHook : public MatInstanceHook
|
||||
{
|
||||
public:
|
||||
|
||||
ShadowMaterialHook();
|
||||
|
||||
// MatInstanceHook
|
||||
virtual ~ShadowMaterialHook();
|
||||
virtual const MatInstanceHookType& getType() const { return Type; }
|
||||
|
||||
/// The material hook type.
|
||||
static const MatInstanceHookType Type;
|
||||
|
||||
BaseMatInstance* getShadowMat( ShadowType type ) const;
|
||||
|
||||
void init( BaseMatInstance *mat );
|
||||
|
||||
protected:
|
||||
|
||||
static void _overrideFeatures( ProcessedMaterial *mat,
|
||||
U32 stageNum,
|
||||
MaterialFeatureData &fd,
|
||||
const FeatureSet &features );
|
||||
|
||||
///
|
||||
BaseMatInstance* mShadowMat[ShadowType_Count];
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // _SHADOWMATHOOK_H_
|
||||
128
Engine/source/lighting/shadowMap/singleLightShadowMap.cpp
Normal file
128
Engine/source/lighting/shadowMap/singleLightShadowMap.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/shadowMap/singleLightShadowMap.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "console/console.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
//#include "scene/sceneReflectPass.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
|
||||
SingleLightShadowMap::SingleLightShadowMap( LightInfo *light )
|
||||
: LightShadowMap( light )
|
||||
{
|
||||
}
|
||||
|
||||
SingleLightShadowMap::~SingleLightShadowMap()
|
||||
{
|
||||
releaseTextures();
|
||||
}
|
||||
|
||||
void SingleLightShadowMap::_render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
PROFILE_SCOPE(SingleLightShadowMap_render);
|
||||
|
||||
const LightMapParams *lmParams = mLight->getExtended<LightMapParams>();
|
||||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||
|
||||
const U32 texSize = getBestTexSize();
|
||||
|
||||
if ( mShadowMapTex.isNull() ||
|
||||
mTexSize != texSize )
|
||||
{
|
||||
mTexSize = texSize;
|
||||
|
||||
mShadowMapTex.set( mTexSize, mTexSize,
|
||||
ShadowMapFormat, &ShadowMapProfile,
|
||||
"SingleLightShadowMap" );
|
||||
}
|
||||
|
||||
GFXFrustumSaver frustSaver;
|
||||
GFXTransformSaver saver;
|
||||
|
||||
MatrixF lightMatrix;
|
||||
calcLightMatrices( lightMatrix, diffuseState->getFrustum() );
|
||||
lightMatrix.inverse();
|
||||
GFX->setWorldMatrix(lightMatrix);
|
||||
|
||||
const MatrixF& lightProj = GFX->getProjectionMatrix();
|
||||
mWorldToLightProj = lightProj * lightMatrix;
|
||||
|
||||
// Render the shadowmap!
|
||||
GFX->pushActiveRenderTarget();
|
||||
mTarget->attachTexture( GFXTextureTarget::Color0, mShadowMapTex );
|
||||
mTarget->attachTexture( GFXTextureTarget::DepthStencil,
|
||||
_getDepthTarget( mShadowMapTex->getWidth(), mShadowMapTex->getHeight() ) );
|
||||
GFX->setActiveRenderTarget(mTarget);
|
||||
GFX->clear(GFXClearStencil | GFXClearZBuffer | GFXClearTarget, ColorI(255,255,255), 1.0f, 0);
|
||||
|
||||
SceneManager* sceneManager = diffuseState->getSceneManager();
|
||||
|
||||
SceneRenderState shadowRenderState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
shadowRenderState.getMaterialDelegate().bind( this, &LightShadowMap::getShadowMaterial );
|
||||
shadowRenderState.renderNonLightmappedMeshes( true );
|
||||
shadowRenderState.renderLightmappedMeshes( bUseLightmappedGeometry );
|
||||
shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
sceneManager->renderSceneNoLights( &shadowRenderState, SHADOW_TYPEMASK );
|
||||
|
||||
_debugRender( &shadowRenderState );
|
||||
|
||||
mTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
}
|
||||
|
||||
void SingleLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc)
|
||||
{
|
||||
if ( lsc->mTapRotationTexSC->isValid() )
|
||||
GFX->setTexture( lsc->mTapRotationTexSC->getSamplerRegister(),
|
||||
SHADOWMGR->getTapRotationTex() );
|
||||
|
||||
ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
|
||||
|
||||
if ( lsc->mLightParamsSC->isValid() )
|
||||
{
|
||||
Point4F lightParams( mLight->getRange().x,
|
||||
p->overDarkFactor.x,
|
||||
0.0f,
|
||||
0.0f );
|
||||
params->set(lsc->mLightParamsSC, lightParams);
|
||||
}
|
||||
|
||||
// The softness is a factor of the texel size.
|
||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
46
Engine/source/lighting/shadowMap/singleLightShadowMap.h
Normal file
46
Engine/source/lighting/shadowMap/singleLightShadowMap.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _SINGLELIGHTSHADOWMAP_H_
|
||||
#define _SINGLELIGHTSHADOWMAP_H_
|
||||
|
||||
#ifndef _LIGHTSHADOWMAP_H_
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#endif
|
||||
|
||||
//
|
||||
// SingleLightShadowMap, holds the shadow map and various other things for a light.
|
||||
//
|
||||
// This represents everything we need to render the shadowmap for one light.
|
||||
class SingleLightShadowMap : public LightShadowMap
|
||||
{
|
||||
public:
|
||||
SingleLightShadowMap( LightInfo *light );
|
||||
~SingleLightShadowMap();
|
||||
|
||||
// LightShadowMap
|
||||
virtual ShadowType getShadowType() const { return ShadowType_Spot; }
|
||||
virtual void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState );
|
||||
virtual void setShaderParameters(GFXShaderConstBuffer* params, LightingShaderConstants* lsc);
|
||||
};
|
||||
|
||||
|
||||
#endif // _SINGLELIGHTSHADOWMAP_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue