mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-11 22:54:34 +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
855
Engine/source/lighting/advanced/advancedLightBinManager.cpp
Normal file
855
Engine/source/lighting/advanced/advancedLightBinManager.cpp
Normal file
|
|
@ -0,0 +1,855 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/advancedLightBinManager.h"
|
||||
|
||||
#include "lighting/advanced/advancedLightManager.h"
|
||||
#include "lighting/advanced/advancedLightBufferConditioner.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/shadowMap/shadowMapPass.h"
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/sceneData.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "core/util/rgb2luv.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "math/util/matrixSet.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
const RenderInstType AdvancedLightBinManager::RIT_LightInfo( "LightInfo" );
|
||||
const String AdvancedLightBinManager::smBufferName( "lightinfo" );
|
||||
|
||||
ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_SoftShadowHighQuality;
|
||||
bool AdvancedLightBinManager::smPSSMDebugRender = false;
|
||||
bool AdvancedLightBinManager::smUseSSAOMask = false;
|
||||
|
||||
|
||||
ImplementEnumType( ShadowFilterMode,
|
||||
"The shadow filtering modes for Advanced Lighting shadows.\n"
|
||||
"@ingroup AdvancedLighting" )
|
||||
|
||||
{ ShadowFilterMode_None, "None",
|
||||
"@brief Simple point sampled filtering.\n"
|
||||
"This is the fastest and lowest quality mode." },
|
||||
|
||||
{ ShadowFilterMode_SoftShadow, "SoftShadow",
|
||||
"@brief A variable tap rotated poisson disk soft shadow filter.\n"
|
||||
"It performs 4 taps to classify the point as in shadow, out of shadow, or along a "
|
||||
"shadow edge. Samples on the edge get an additional 8 taps to soften them." },
|
||||
|
||||
{ ShadowFilterMode_SoftShadowHighQuality, "SoftShadowHighQuality",
|
||||
"@brief A 12 tap rotated poisson disk soft shadow filter.\n"
|
||||
"It performs all the taps for every point without any early rejection." },
|
||||
|
||||
EndImplementEnumType;
|
||||
|
||||
// NOTE: The order here matches that of the LightInfo::Type enum.
|
||||
const String AdvancedLightBinManager::smLightMatNames[] =
|
||||
{
|
||||
"AL_PointLightMaterial", // LightInfo::Point
|
||||
"AL_SpotLightMaterial", // LightInfo::Spot
|
||||
"AL_VectorLightMaterial", // LightInfo::Vector
|
||||
"", // LightInfo::Ambient
|
||||
};
|
||||
|
||||
// NOTE: The order here matches that of the LightInfo::Type enum.
|
||||
const GFXVertexFormat* AdvancedLightBinManager::smLightMatVertex[] =
|
||||
{
|
||||
getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Point
|
||||
getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Spot
|
||||
getGFXVertexFormat<FarFrustumQuadVert>(), // LightInfo::Vector
|
||||
NULL, // LightInfo::Ambient
|
||||
};
|
||||
|
||||
// NOTE: The order here matches that of the ShadowType enum.
|
||||
const String AdvancedLightBinManager::smShadowTypeMacro[] =
|
||||
{
|
||||
"", // ShadowType_Spot
|
||||
"", // ShadowType_PSSM,
|
||||
"SHADOW_PARABOLOID", // ShadowType_Paraboloid,
|
||||
"SHADOW_DUALPARABOLOID_SINGLE_PASS", // ShadowType_DualParaboloidSinglePass,
|
||||
"SHADOW_DUALPARABOLOID", // ShadowType_DualParaboloid,
|
||||
"SHADOW_CUBE", // ShadowType_CubeMap,
|
||||
};
|
||||
|
||||
AdvancedLightBinManager::RenderSignal &AdvancedLightBinManager::getRenderSignal()
|
||||
{
|
||||
static RenderSignal theSignal;
|
||||
return theSignal;
|
||||
}
|
||||
|
||||
IMPLEMENT_CONOBJECT(AdvancedLightBinManager);
|
||||
|
||||
ConsoleDocClass( AdvancedLightBinManager,
|
||||
"@brief Rendering Manager responsible for lighting, shadows, and global variables affecing both.\n\n"
|
||||
|
||||
"Should not be exposed to TorqueScript as a game object, meant for internal use only\n\n"
|
||||
|
||||
"@ingroup Lighting"
|
||||
);
|
||||
|
||||
AdvancedLightBinManager::AdvancedLightBinManager( AdvancedLightManager *lm /* = NULL */,
|
||||
ShadowMapManager *sm /* = NULL */,
|
||||
GFXFormat lightBufferFormat /* = GFXFormatR8G8B8A8 */ )
|
||||
: RenderTexTargetBinManager( RIT_LightInfo, 1.0f, 1.0f, lightBufferFormat ),
|
||||
mNumLightsCulled(0),
|
||||
mLightManager(lm),
|
||||
mShadowManager(sm),
|
||||
mConditioner(NULL)
|
||||
{
|
||||
// Create an RGB conditioner
|
||||
mConditioner = new AdvancedLightBufferConditioner( getTargetFormat(),
|
||||
AdvancedLightBufferConditioner::RGB );
|
||||
mNamedTarget.setConditioner( mConditioner );
|
||||
mNamedTarget.registerWithName( smBufferName );
|
||||
|
||||
// We want a full-resolution buffer
|
||||
mTargetSizeType = RenderTexTargetBinManager::WindowSize;
|
||||
|
||||
mMRTLightmapsDuringPrePass = false;
|
||||
|
||||
Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );
|
||||
Con::addVariableNotify( "$pref::Shadows::filterMode", callback );
|
||||
Con::addVariableNotify( "$AL::PSSMDebugRender", callback );
|
||||
Con::addVariableNotify( "$AL::UseSSAOMask", callback );
|
||||
}
|
||||
|
||||
|
||||
AdvancedLightBinManager::~AdvancedLightBinManager()
|
||||
{
|
||||
_deleteLightMaterials();
|
||||
|
||||
SAFE_DELETE(mConditioner);
|
||||
|
||||
Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );
|
||||
Con::removeVariableNotify( "$pref::shadows::filterMode", callback );
|
||||
Con::removeVariableNotify( "$AL::PSSMDebugRender", callback );
|
||||
Con::removeVariableNotify( "$AL::UseSSAOMask", callback );
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
Con::addVariable( "$pref::shadows::filterMode",
|
||||
TYPEID<ShadowFilterMode>(), &smShadowFilterMode,
|
||||
"The filter mode to use for shadows.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$AL::UseSSAOMask", TypeBool, &smUseSSAOMask,
|
||||
"Used by the SSAO PostEffect to toggle the sampling of ssaomask "
|
||||
"texture by the light shaders.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
|
||||
Con::addVariable( "$AL::PSSMDebugRender", TypeBool, &smPSSMDebugRender,
|
||||
"Enables debug rendering of the PSSM shadows.\n"
|
||||
"@ingroup AdvancedLighting\n" );
|
||||
}
|
||||
|
||||
bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize)
|
||||
{
|
||||
bool ret = Parent::setTargetSize( newTargetSize );
|
||||
|
||||
// We require the viewport to match the default.
|
||||
mNamedTarget.setViewport( GFX->getViewport() );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::addLight( LightInfo *light )
|
||||
{
|
||||
// Get the light type.
|
||||
const LightInfo::Type lightType = light->getType();
|
||||
|
||||
AssertFatal( lightType == LightInfo::Point ||
|
||||
lightType == LightInfo::Spot, "Bogus light type." );
|
||||
|
||||
// Find a shadow map for this light, if it has one
|
||||
ShadowMapParams *lsp = light->getExtended<ShadowMapParams>();
|
||||
LightShadowMap *lsm = lsp->getShadowMap();
|
||||
|
||||
// Get the right shadow type.
|
||||
ShadowType shadowType = ShadowType_None;
|
||||
if ( light->getCastShadows() &&
|
||||
lsm && lsm->hasShadowTex() &&
|
||||
!ShadowMapPass::smDisableShadows )
|
||||
shadowType = lsm->getShadowType();
|
||||
|
||||
// Add the entry
|
||||
LightBinEntry lEntry;
|
||||
lEntry.lightInfo = light;
|
||||
lEntry.shadowMap = lsm;
|
||||
lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() );
|
||||
|
||||
if( lightType == LightInfo::Spot )
|
||||
lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer );
|
||||
else
|
||||
lEntry.vertBuffer = mLightManager->getSphereMesh( lEntry.numPrims, lEntry.primBuffer );
|
||||
|
||||
// If it's a point light, push front, spot
|
||||
// light, push back. This helps batches.
|
||||
Vector<LightBinEntry> &curBin = mLightBin;
|
||||
if ( light->getType() == LightInfo::Point )
|
||||
curBin.push_front( lEntry );
|
||||
else
|
||||
curBin.push_back( lEntry );
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::clear()
|
||||
{
|
||||
Con::setIntVariable("lightMetrics::activeLights", mLightBin.size());
|
||||
Con::setIntVariable("lightMetrics::culledLights", mNumLightsCulled);
|
||||
|
||||
mLightBin.clear();
|
||||
mNumLightsCulled = 0;
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::render( SceneRenderState *state )
|
||||
{
|
||||
PROFILE_SCOPE( AdvancedLightManager_Render );
|
||||
|
||||
// Take a look at the SceneRenderState and see if we should skip drawing the pre-pass
|
||||
if( state->disableAdvancedLightingBins() )
|
||||
return;
|
||||
|
||||
// Automagically save & restore our viewport and transforms.
|
||||
GFXTransformSaver saver;
|
||||
|
||||
if( !mLightManager )
|
||||
return;
|
||||
|
||||
// Get the sunlight. If there's no sun, and no lights in the bins, no draw
|
||||
LightInfo *sunLight = mLightManager->getSpecialLight( LightManager::slSunLightType );
|
||||
if( !sunLight && mLightBin.empty() )
|
||||
return;
|
||||
|
||||
GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render, ColorI::RED );
|
||||
|
||||
// Tell the superclass we're about to render
|
||||
if ( !_onPreRender( state ) )
|
||||
return;
|
||||
|
||||
// Clear as long as there isn't MRT population of light buffer with lightmap data
|
||||
if ( !MRTLightmapsDuringPrePass() )
|
||||
GFX->clear(GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0);
|
||||
|
||||
// Restore transforms
|
||||
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
|
||||
matrixSet.restoreSceneViewProjection();
|
||||
|
||||
const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera();
|
||||
|
||||
// Set up the SG Data
|
||||
SceneData sgData;
|
||||
sgData.init( state );
|
||||
|
||||
// There are cases where shadow rendering is disabled.
|
||||
const bool disableShadows = state->isReflectPass() || ShadowMapPass::smDisableShadows;
|
||||
|
||||
// Pick the right material for rendering the sunlight... we only
|
||||
// cast shadows when its enabled and we're not in a reflection.
|
||||
LightMaterialInfo *vectorMatInfo;
|
||||
if ( sunLight &&
|
||||
sunLight->getCastShadows() &&
|
||||
!disableShadows &&
|
||||
sunLight->getExtended<ShadowMapParams>() )
|
||||
vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false );
|
||||
else
|
||||
vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false );
|
||||
|
||||
// Initialize and set the per-frame parameters after getting
|
||||
// the vector light material as we use lazy creation.
|
||||
_setupPerFrameParameters( state );
|
||||
|
||||
// Draw sunlight/ambient
|
||||
if ( sunLight && vectorMatInfo )
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Sunlight, ColorI::RED );
|
||||
|
||||
// Set up SG data
|
||||
setupSGData( sgData, state, sunLight );
|
||||
vectorMatInfo->setLightParameters( sunLight, state, worldToCameraXfm );
|
||||
|
||||
// Set light holds the active shadow map.
|
||||
mShadowManager->setLightShadowMapForLight( sunLight );
|
||||
|
||||
// Set geometry
|
||||
GFX->setVertexBuffer( mFarFrustumQuadVerts );
|
||||
GFX->setPrimitiveBuffer( NULL );
|
||||
|
||||
// Render the material passes
|
||||
while( vectorMatInfo->matInstance->setupPass( state, sgData ) )
|
||||
{
|
||||
vectorMatInfo->matInstance->setSceneInfo( state, sgData );
|
||||
vectorMatInfo->matInstance->setTransforms( matrixSet, state );
|
||||
GFX->drawPrimitive( GFXTriangleFan, 0, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
// Blend the lights in the bin to the light buffer
|
||||
for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ )
|
||||
{
|
||||
LightBinEntry& curEntry = *itr;
|
||||
LightInfo *curLightInfo = curEntry.lightInfo;
|
||||
LightMaterialInfo *curLightMat = curEntry.lightMaterial;
|
||||
const U32 numPrims = curEntry.numPrims;
|
||||
const U32 numVerts = curEntry.vertBuffer->mNumVerts;
|
||||
|
||||
// Skip lights which won't affect the scene.
|
||||
if ( !curLightMat || curLightInfo->getBrightness() <= 0.001f )
|
||||
continue;
|
||||
|
||||
GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED );
|
||||
|
||||
setupSGData( sgData, state, curLightInfo );
|
||||
curLightMat->setLightParameters( curLightInfo, state, worldToCameraXfm );
|
||||
mShadowManager->setLightShadowMap( curEntry.shadowMap );
|
||||
|
||||
// Let the shadow know we're about to render from it.
|
||||
if ( curEntry.shadowMap )
|
||||
curEntry.shadowMap->preLightRender();
|
||||
|
||||
// Set geometry
|
||||
GFX->setVertexBuffer( curEntry.vertBuffer );
|
||||
GFX->setPrimitiveBuffer( curEntry.primBuffer );
|
||||
|
||||
// Render the material passes
|
||||
while( curLightMat->matInstance->setupPass( state, sgData ) )
|
||||
{
|
||||
// Set transforms
|
||||
matrixSet.setWorld(*sgData.objTrans);
|
||||
curLightMat->matInstance->setTransforms(matrixSet, state);
|
||||
curLightMat->matInstance->setSceneInfo(state, sgData);
|
||||
|
||||
if(curEntry.primBuffer)
|
||||
GFX->drawIndexedPrimitive(GFXTriangleList, 0, 0, numVerts, 0, numPrims);
|
||||
else
|
||||
GFX->drawPrimitive(GFXTriangleList, 0, numPrims);
|
||||
}
|
||||
|
||||
// Tell it we're done rendering.
|
||||
if ( curEntry.shadowMap )
|
||||
curEntry.shadowMap->postLightRender();
|
||||
}
|
||||
|
||||
// Set NULL for active shadow map (so nothing gets confused)
|
||||
mShadowManager->setLightShadowMap(NULL);
|
||||
GFX->setVertexBuffer( NULL );
|
||||
GFX->setPrimitiveBuffer( NULL );
|
||||
|
||||
// Fire off a signal to let others know that light-bin rendering is ending now
|
||||
getRenderSignal().trigger(state, this);
|
||||
|
||||
// Finish up the rendering
|
||||
_onPostRender();
|
||||
}
|
||||
|
||||
AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial( LightInfo::Type lightType,
|
||||
ShadowType shadowType,
|
||||
bool useCookieTex )
|
||||
{
|
||||
PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial );
|
||||
|
||||
// Build the key.
|
||||
const LightMatKey key( lightType, shadowType, useCookieTex );
|
||||
|
||||
// See if we've already built this one.
|
||||
LightMatTable::Iterator iter = mLightMaterials.find( key );
|
||||
if ( iter != mLightMaterials.end() )
|
||||
return iter->value;
|
||||
|
||||
// If we got here we need to build a material for
|
||||
// this light+shadow combination.
|
||||
|
||||
LightMaterialInfo *info = NULL;
|
||||
|
||||
// First get the light material name and make sure
|
||||
// this light has a material in the first place.
|
||||
const String &lightMatName = smLightMatNames[ lightType ];
|
||||
if ( lightMatName.isNotEmpty() )
|
||||
{
|
||||
Vector<GFXShaderMacro> shadowMacros;
|
||||
|
||||
// Setup the shadow type macros for this material.
|
||||
if ( shadowType == ShadowType_None )
|
||||
shadowMacros.push_back( GFXShaderMacro( "NO_SHADOW" ) );
|
||||
else
|
||||
{
|
||||
shadowMacros.push_back( GFXShaderMacro( smShadowTypeMacro[ shadowType ] ) );
|
||||
|
||||
// Do we need to do shadow filtering?
|
||||
if ( smShadowFilterMode != ShadowFilterMode_None )
|
||||
{
|
||||
shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW" ) );
|
||||
|
||||
const F32 SM = GFX->getPixelShaderVersion();
|
||||
if ( SM >= 3.0f && smShadowFilterMode == ShadowFilterMode_SoftShadowHighQuality )
|
||||
shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW_HIGH_QUALITY" ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( useCookieTex )
|
||||
shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) );
|
||||
|
||||
// Its safe to add the PSSM debug macro to all the materials.
|
||||
if ( smPSSMDebugRender )
|
||||
shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) );
|
||||
|
||||
// If its a vector light see if we can enable SSAO.
|
||||
if ( lightType == LightInfo::Vector && smUseSSAOMask )
|
||||
shadowMacros.push_back( GFXShaderMacro( "USE_SSAO_MASK" ) );
|
||||
|
||||
// Now create the material info object.
|
||||
info = new LightMaterialInfo( lightMatName, smLightMatVertex[ lightType ], shadowMacros );
|
||||
}
|
||||
|
||||
// Push this into the map and return it.
|
||||
mLightMaterials.insertUnique( key, info );
|
||||
return info;
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::_deleteLightMaterials()
|
||||
{
|
||||
LightMatTable::Iterator iter = mLightMaterials.begin();
|
||||
for ( ; iter != mLightMaterials.end(); iter++ )
|
||||
delete iter->value;
|
||||
|
||||
mLightMaterials.clear();
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *state )
|
||||
{
|
||||
PROFILE_SCOPE( AdvancedLightBinManager_SetupPerFrameParameters );
|
||||
const Frustum &frustum = state->getFrustum();
|
||||
|
||||
MatrixF invCam( frustum.getTransform() );
|
||||
invCam.inverse();
|
||||
|
||||
const Point3F *wsFrustumPoints = frustum.getPoints();
|
||||
const Point3F& cameraPos = frustum.getPosition();
|
||||
|
||||
// Now build the quad for drawing full-screen vector light
|
||||
// passes.... this is a volatile VB and updates every frame.
|
||||
FarFrustumQuadVert verts[4];
|
||||
{
|
||||
verts[0].point.set( wsFrustumPoints[Frustum::FarBottomLeft] - cameraPos );
|
||||
invCam.mulP( wsFrustumPoints[Frustum::FarBottomLeft], &verts[0].normal );
|
||||
verts[0].texCoord.set( -1.0, -1.0 );
|
||||
|
||||
verts[1].point.set( wsFrustumPoints[Frustum::FarTopLeft] - cameraPos );
|
||||
invCam.mulP( wsFrustumPoints[Frustum::FarTopLeft], &verts[1].normal );
|
||||
verts[1].texCoord.set( -1.0, 1.0 );
|
||||
|
||||
verts[2].point.set( wsFrustumPoints[Frustum::FarTopRight] - cameraPos );
|
||||
invCam.mulP( wsFrustumPoints[Frustum::FarTopRight], &verts[2].normal );
|
||||
verts[2].texCoord.set( 1.0, 1.0 );
|
||||
|
||||
verts[3].point.set( wsFrustumPoints[Frustum::FarBottomRight] - cameraPos );
|
||||
invCam.mulP( wsFrustumPoints[Frustum::FarBottomRight], &verts[3].normal );
|
||||
verts[3].texCoord.set( 1.0, -1.0 );
|
||||
}
|
||||
mFarFrustumQuadVerts.set( GFX, 4 );
|
||||
dMemcpy( mFarFrustumQuadVerts.lock(), verts, sizeof( verts ) );
|
||||
mFarFrustumQuadVerts.unlock();
|
||||
|
||||
PlaneF farPlane(wsFrustumPoints[Frustum::FarBottomLeft], wsFrustumPoints[Frustum::FarTopLeft], wsFrustumPoints[Frustum::FarTopRight]);
|
||||
PlaneF vsFarPlane(verts[0].normal, verts[1].normal, verts[2].normal);
|
||||
|
||||
// Parameters calculated, assign them to the materials
|
||||
LightMatTable::Iterator iter = mLightMaterials.begin();
|
||||
for ( ; iter != mLightMaterials.end(); iter++ )
|
||||
{
|
||||
if ( iter->value )
|
||||
iter->value->setViewParameters( frustum.getNearDist(),
|
||||
frustum.getFarDist(),
|
||||
frustum.getPosition(),
|
||||
farPlane,
|
||||
vsFarPlane);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light )
|
||||
{
|
||||
PROFILE_SCOPE( AdvancedLightBinManager_setupSGData );
|
||||
|
||||
data.lights[0] = light;
|
||||
data.ambientLightColor = state->getAmbientLightColor();
|
||||
data.objTrans = &MatrixF::Identity;
|
||||
|
||||
if ( light )
|
||||
{
|
||||
if ( light->getType() == LightInfo::Point )
|
||||
{
|
||||
// The point light volume gets some flat spots along
|
||||
// the perimiter mostly visible in the constant and
|
||||
// quadradic falloff modes.
|
||||
//
|
||||
// To account for them slightly increase the scale
|
||||
// instead of greatly increasing the polycount.
|
||||
|
||||
mLightMat = light->getTransform();
|
||||
mLightMat.scale( light->getRange() * 1.01f );
|
||||
data.objTrans = &mLightMat;
|
||||
}
|
||||
else if ( light->getType() == LightInfo::Spot )
|
||||
{
|
||||
mLightMat = light->getTransform();
|
||||
|
||||
// Rotate it to face down the -y axis.
|
||||
MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) );
|
||||
|
||||
// Calculate the radius based on the range and angle.
|
||||
F32 range = light->getRange().x;
|
||||
F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f );
|
||||
|
||||
// NOTE: This fudge makes the cone a little bigger
|
||||
// to remove the facet egde of the cone geometry.
|
||||
radius *= 1.1f;
|
||||
|
||||
// Use the scale to distort the cone to
|
||||
// match our radius and range.
|
||||
scaleRotateTranslate.scale( Point3F( radius, radius, range ) );
|
||||
|
||||
// Apply the transform and set the position.
|
||||
mLightMat *= scaleRotateTranslate;
|
||||
mLightMat.setPosition( light->getPosition() );
|
||||
|
||||
data.objTrans = &mLightMat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::MRTLightmapsDuringPrePass( bool val )
|
||||
{
|
||||
// Do not enable if the GFX device can't do MRT's
|
||||
if ( GFX->getNumRenderTargets() < 2 )
|
||||
val = false;
|
||||
|
||||
if ( mMRTLightmapsDuringPrePass != val )
|
||||
{
|
||||
mMRTLightmapsDuringPrePass = val;
|
||||
|
||||
// Reload materials to cause a feature recalculation on prepass materials
|
||||
if(mLightManager->isActive())
|
||||
MATMGR->flushAndReInitInstances();
|
||||
|
||||
RenderPrePassMgr *prepass;
|
||||
if ( Sim::findObject( "AL_PrePassBin", prepass ) && prepass->getTargetTexture( 0 ) )
|
||||
prepass->updateTargets();
|
||||
}
|
||||
}
|
||||
|
||||
AdvancedLightBinManager::LightMaterialInfo::LightMaterialInfo( const String &matName,
|
||||
const GFXVertexFormat *vertexFormat,
|
||||
const Vector<GFXShaderMacro> ¯os )
|
||||
: matInstance(NULL),
|
||||
zNearFarInvNearFar(NULL),
|
||||
farPlane(NULL),
|
||||
vsFarPlane(NULL),
|
||||
negFarPlaneDotEye(NULL),
|
||||
lightPosition(NULL),
|
||||
lightDirection(NULL),
|
||||
lightColor(NULL),
|
||||
lightAttenuation(NULL),
|
||||
lightRange(NULL),
|
||||
lightAmbient(NULL),
|
||||
lightTrilight(NULL),
|
||||
lightSpotParams(NULL)
|
||||
{
|
||||
Material *mat = MATMGR->getMaterialDefinitionByName( matName );
|
||||
if ( !mat )
|
||||
return;
|
||||
|
||||
matInstance = new LightMatInstance( *mat );
|
||||
|
||||
for ( U32 i=0; i < macros.size(); i++ )
|
||||
matInstance->addShaderMacro( macros[i].name, macros[i].value );
|
||||
|
||||
matInstance->init( MATMGR->getDefaultFeatures(), vertexFormat );
|
||||
|
||||
lightDirection = matInstance->getMaterialParameterHandle("$lightDirection");
|
||||
lightAmbient = matInstance->getMaterialParameterHandle("$lightAmbient");
|
||||
lightTrilight = matInstance->getMaterialParameterHandle("$lightTrilight");
|
||||
lightSpotParams = matInstance->getMaterialParameterHandle("$lightSpotParams");
|
||||
lightAttenuation = matInstance->getMaterialParameterHandle("$lightAttenuation");
|
||||
lightRange = matInstance->getMaterialParameterHandle("$lightRange");
|
||||
lightPosition = matInstance->getMaterialParameterHandle("$lightPosition");
|
||||
farPlane = matInstance->getMaterialParameterHandle("$farPlane");
|
||||
vsFarPlane = matInstance->getMaterialParameterHandle("$vsFarPlane");
|
||||
negFarPlaneDotEye = matInstance->getMaterialParameterHandle("$negFarPlaneDotEye");
|
||||
zNearFarInvNearFar = matInstance->getMaterialParameterHandle("$zNearFarInvNearFar");
|
||||
lightColor = matInstance->getMaterialParameterHandle("$lightColor");
|
||||
lightBrightness = matInstance->getMaterialParameterHandle("$lightBrightness");
|
||||
}
|
||||
|
||||
AdvancedLightBinManager::LightMaterialInfo::~LightMaterialInfo()
|
||||
{
|
||||
SAFE_DELETE(matInstance);
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::LightMaterialInfo::setViewParameters( const F32 _zNear,
|
||||
const F32 _zFar,
|
||||
const Point3F &_eyePos,
|
||||
const PlaneF &_farPlane,
|
||||
const PlaneF &_vsFarPlane)
|
||||
{
|
||||
MaterialParameters *matParams = matInstance->getMaterialParameters();
|
||||
|
||||
matParams->setSafe( farPlane, *((const Point4F *)&_farPlane) );
|
||||
|
||||
matParams->setSafe( vsFarPlane, *((const Point4F *)&_vsFarPlane) );
|
||||
|
||||
if ( negFarPlaneDotEye->isValid() )
|
||||
{
|
||||
// -dot( farPlane, eyePos )
|
||||
const F32 negFarPlaneDotEyeVal = -( mDot( *((const Point3F *)&_farPlane), _eyePos ) + _farPlane.d );
|
||||
matParams->set( negFarPlaneDotEye, negFarPlaneDotEyeVal );
|
||||
}
|
||||
|
||||
matParams->setSafe( zNearFarInvNearFar, Point4F( _zNear, _zFar, 1.0f / _zNear, 1.0f / _zFar ) );
|
||||
}
|
||||
|
||||
void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState, const MatrixF &worldViewOnly )
|
||||
{
|
||||
MaterialParameters *matParams = matInstance->getMaterialParameters();
|
||||
|
||||
// Set color in the right format, set alpha to the luminance value for the color.
|
||||
ColorF col = lightInfo->getColor();
|
||||
|
||||
// TODO: The specularity control of the light
|
||||
// is being scaled by the overall lumiance.
|
||||
//
|
||||
// Not sure if this may be the source of our
|
||||
// bad specularity results maybe?
|
||||
//
|
||||
|
||||
const Point3F colorToLumiance( 0.3576f, 0.7152f, 0.1192f );
|
||||
F32 lumiance = mDot(*((const Point3F *)&lightInfo->getColor()), colorToLumiance );
|
||||
col.alpha *= lumiance;
|
||||
|
||||
matParams->setSafe( lightColor, col );
|
||||
matParams->setSafe( lightBrightness, lightInfo->getBrightness() );
|
||||
|
||||
switch( lightInfo->getType() )
|
||||
{
|
||||
case LightInfo::Vector:
|
||||
{
|
||||
VectorF lightDir = lightInfo->getDirection();
|
||||
worldViewOnly.mulV(lightDir);
|
||||
lightDir.normalize();
|
||||
matParams->setSafe( lightDirection, lightDir );
|
||||
|
||||
// Set small number for alpha since it represents existing specular in
|
||||
// the vector light. This prevents a divide by zero.
|
||||
ColorF ambientColor = renderState->getAmbientLightColor();
|
||||
ambientColor.alpha = 0.00001f;
|
||||
matParams->setSafe( lightAmbient, ambientColor );
|
||||
|
||||
// If no alt color is specified, set it to the average of
|
||||
// the ambient and main color to avoid artifacts.
|
||||
//
|
||||
// TODO: Trilight disabled until we properly implement it
|
||||
// in the light info!
|
||||
//
|
||||
//ColorF lightAlt = lightInfo->getAltColor();
|
||||
ColorF lightAlt( ColorF::BLACK ); // = lightInfo->getAltColor();
|
||||
if ( lightAlt.red == 0.0f && lightAlt.green == 0.0f && lightAlt.blue == 0.0f )
|
||||
lightAlt = (lightInfo->getColor() + renderState->getAmbientLightColor()) / 2.0f;
|
||||
|
||||
ColorF trilightColor = lightAlt;
|
||||
matParams->setSafe(lightTrilight, trilightColor);
|
||||
}
|
||||
break;
|
||||
|
||||
case LightInfo::Spot:
|
||||
{
|
||||
const F32 outerCone = lightInfo->getOuterConeAngle();
|
||||
const F32 innerCone = getMin( lightInfo->getInnerConeAngle(), outerCone );
|
||||
const F32 outerCos = mCos( mDegToRad( outerCone / 2.0f ) );
|
||||
const F32 innerCos = mCos( mDegToRad( innerCone / 2.0f ) );
|
||||
Point4F spotParams( outerCos,
|
||||
innerCos - outerCos,
|
||||
mCos( mDegToRad( outerCone ) ),
|
||||
0.0f );
|
||||
|
||||
matParams->setSafe( lightSpotParams, spotParams );
|
||||
|
||||
VectorF lightDir = lightInfo->getDirection();
|
||||
worldViewOnly.mulV(lightDir);
|
||||
lightDir.normalize();
|
||||
matParams->setSafe( lightDirection, lightDir );
|
||||
}
|
||||
// Fall through
|
||||
|
||||
case LightInfo::Point:
|
||||
{
|
||||
const F32 radius = lightInfo->getRange().x;
|
||||
matParams->setSafe( lightRange, radius );
|
||||
|
||||
Point3F lightPos;
|
||||
worldViewOnly.mulP(lightInfo->getPosition(), &lightPos);
|
||||
matParams->setSafe( lightPosition, lightPos );
|
||||
|
||||
// Get the attenuation falloff ratio and normalize it.
|
||||
Point3F attenRatio = lightInfo->getExtended<ShadowMapParams>()->attenuationRatio;
|
||||
F32 total = attenRatio.x + attenRatio.y + attenRatio.z;
|
||||
if ( total > 0.0f )
|
||||
attenRatio /= total;
|
||||
|
||||
Point2F attenParams( ( 1.0f / radius ) * attenRatio.y,
|
||||
( 1.0f / ( radius * radius ) ) * attenRatio.z );
|
||||
|
||||
matParams->setSafe( lightAttenuation, attenParams );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
AssertFatal( false, "Bad light type!" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData )
|
||||
{
|
||||
// Go no further if the material failed to initialize properly.
|
||||
if ( !mProcessedMaterial ||
|
||||
mProcessedMaterial->getNumPasses() == 0 )
|
||||
return false;
|
||||
|
||||
// Fetch the lightmap params
|
||||
const LightMapParams *lmParams = sgData.lights[0]->getExtended<LightMapParams>();
|
||||
|
||||
// If no Lightmap params, let parent handle it
|
||||
if(lmParams == NULL)
|
||||
return Parent::setupPass(state, sgData);
|
||||
|
||||
// Defaults
|
||||
bool bRetVal = true;
|
||||
|
||||
// What render pass is this...
|
||||
if(mCurPass == -1)
|
||||
{
|
||||
// First pass, reset this flag
|
||||
mInternalPass = false;
|
||||
|
||||
// Pass call to parent
|
||||
bRetVal = Parent::setupPass(state, sgData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this light is represented in a lightmap, it has already done it's
|
||||
// job for non-lightmapped geometry. Now render the lightmapped geometry
|
||||
// pass (specular + shadow-darkening)
|
||||
if(!mInternalPass && lmParams->representedInLightmap)
|
||||
mInternalPass = true;
|
||||
else
|
||||
return Parent::setupPass(state, sgData);
|
||||
}
|
||||
|
||||
// Set up the shader constants we need to...
|
||||
if(mLightMapParamsSC->isValid())
|
||||
{
|
||||
// If this is an internal pass, special case the parameters
|
||||
if(mInternalPass)
|
||||
{
|
||||
AssertFatal( lmParams->shadowDarkenColor.alpha == -1.0f, "Assumption failed, check unpack code!" );
|
||||
getMaterialParameters()->set( mLightMapParamsSC, lmParams->shadowDarkenColor );
|
||||
}
|
||||
else
|
||||
getMaterialParameters()->set( mLightMapParamsSC, ColorF::WHITE );
|
||||
}
|
||||
|
||||
// Now override stateblock with our own
|
||||
if(!mInternalPass)
|
||||
{
|
||||
// If this is not an internal pass, and this light is represented in lightmaps
|
||||
// than only effect non-lightmapped geometry for this pass
|
||||
if(lmParams->representedInLightmap)
|
||||
GFX->setStateBlock(mLitState[StaticLightNonLMGeometry]);
|
||||
else // This is a normal, dynamic light.
|
||||
GFX->setStateBlock(mLitState[DynamicLight]);
|
||||
|
||||
}
|
||||
else // Internal pass, this is the add-specular/multiply-darken-color pass
|
||||
GFX->setStateBlock(mLitState[StaticLightLMGeometry]);
|
||||
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *vertexFormat )
|
||||
{
|
||||
bool success = Parent::init(features, vertexFormat);
|
||||
|
||||
// If the initialization failed don't continue.
|
||||
if ( !success || !mProcessedMaterial || mProcessedMaterial->getNumPasses() == 0 )
|
||||
return false;
|
||||
|
||||
mLightMapParamsSC = getMaterialParameterHandle("$lightMapParams");
|
||||
|
||||
// Grab the state block for the first render pass (since this mat instance
|
||||
// inserts a pass after the first pass)
|
||||
AssertFatal(mProcessedMaterial->getNumPasses() > 0, "No passes created! Ohnoes");
|
||||
const RenderPassData *rpd = mProcessedMaterial->getPass(0);
|
||||
AssertFatal(rpd, "No render pass data!");
|
||||
AssertFatal(rpd->mRenderStates[0], "No render state 0!");
|
||||
|
||||
// Get state block desc for normal (not wireframe, not translucent, not glow, etc)
|
||||
// render state
|
||||
GFXStateBlockDesc litState = rpd->mRenderStates[0]->getDesc();
|
||||
|
||||
// Create state blocks for each of the 3 possible combos in setupPass
|
||||
|
||||
//DynamicLight State: This will effect lightmapped and non-lightmapped geometry
|
||||
// in the same way.
|
||||
litState.separateAlphaBlendDefined = true;
|
||||
litState.separateAlphaBlendEnable = false;
|
||||
litState.stencilMask = RenderPrePassMgr::OpaqueDynamicLitMask | RenderPrePassMgr::OpaqueStaticLitMask;
|
||||
mLitState[DynamicLight] = GFX->createStateBlock(litState);
|
||||
|
||||
// StaticLightNonLMGeometry State: This will treat non-lightmapped geometry
|
||||
// in the usual way, but will not effect lightmapped geometry.
|
||||
litState.separateAlphaBlendDefined = true;
|
||||
litState.separateAlphaBlendEnable = false;
|
||||
litState.stencilMask = RenderPrePassMgr::OpaqueDynamicLitMask;
|
||||
mLitState[StaticLightNonLMGeometry] = GFX->createStateBlock(litState);
|
||||
|
||||
// StaticLightLMGeometry State: This will add specular information (alpha) but
|
||||
// multiply-darken color information.
|
||||
litState.blendDest = GFXBlendSrcColor;
|
||||
litState.blendSrc = GFXBlendZero;
|
||||
litState.stencilMask = RenderPrePassMgr::OpaqueStaticLitMask;
|
||||
litState.separateAlphaBlendDefined = true;
|
||||
litState.separateAlphaBlendEnable = true;
|
||||
litState.separateAlphaBlendSrc = GFXBlendOne;
|
||||
litState.separateAlphaBlendDest = GFXBlendOne;
|
||||
litState.separateAlphaBlendOp = GFXBlendOpAdd;
|
||||
mLitState[StaticLightLMGeometry] = GFX->createStateBlock(litState);
|
||||
|
||||
return true;
|
||||
}
|
||||
234
Engine/source/lighting/advanced/advancedLightBinManager.h
Normal file
234
Engine/source/lighting/advanced/advancedLightBinManager.h
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _ADVANCEDLIGHTBINMANAGER_H_
|
||||
#define _ADVANCEDLIGHTBINMANAGER_H_
|
||||
|
||||
#ifndef _TEXTARGETBIN_MGR_H_
|
||||
#include "renderInstance/renderTexTargetBinManager.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
#ifndef _MATHUTIL_FRUSTUM_H_
|
||||
#include "math/util/frustum.h"
|
||||
#endif
|
||||
#ifndef _MATINSTANCE_H_
|
||||
#include "materials/matInstance.h"
|
||||
#endif
|
||||
#ifndef _SHADOW_COMMON_H_
|
||||
#include "lighting/shadowMap/shadowCommon.h"
|
||||
#endif
|
||||
|
||||
|
||||
class AdvancedLightManager;
|
||||
class ShadowMapManager;
|
||||
class LightShadowMap;
|
||||
class AdvancedLightBufferConditioner;
|
||||
class LightMapParams;
|
||||
|
||||
|
||||
class LightMatInstance : public MatInstance
|
||||
{
|
||||
typedef MatInstance Parent;
|
||||
protected:
|
||||
MaterialParameterHandle *mLightMapParamsSC;
|
||||
bool mInternalPass;
|
||||
|
||||
enum
|
||||
{
|
||||
DynamicLight = 0,
|
||||
StaticLightNonLMGeometry,
|
||||
StaticLightLMGeometry,
|
||||
NUM_LIT_STATES
|
||||
};
|
||||
GFXStateBlockRef mLitState[NUM_LIT_STATES];
|
||||
|
||||
public:
|
||||
LightMatInstance(Material &mat) : Parent(mat), mLightMapParamsSC(NULL), mInternalPass(false) {}
|
||||
|
||||
virtual bool init( const FeatureSet &features, const GFXVertexFormat *vertexFormat );
|
||||
virtual bool setupPass( SceneRenderState *state, const SceneData &sgData );
|
||||
};
|
||||
|
||||
|
||||
class AdvancedLightBinManager : public RenderTexTargetBinManager
|
||||
{
|
||||
typedef RenderTexTargetBinManager Parent;
|
||||
|
||||
public:
|
||||
|
||||
// Light info Render Inst Type
|
||||
static const RenderInstType RIT_LightInfo;
|
||||
|
||||
// registered buffer name
|
||||
static const String smBufferName;
|
||||
|
||||
/// The shadow filter mode to use on shadowed light materials.
|
||||
static ShadowFilterMode smShadowFilterMode;
|
||||
|
||||
/// Used to toggle the PSSM debug rendering mode.
|
||||
static bool smPSSMDebugRender;
|
||||
|
||||
/// Set by the SSAO post effect to tell the vector
|
||||
/// light to compile in the SSAO mask.
|
||||
static bool smUseSSAOMask;
|
||||
|
||||
// Used for console init
|
||||
AdvancedLightBinManager( AdvancedLightManager *lm = NULL,
|
||||
ShadowMapManager *sm = NULL,
|
||||
GFXFormat lightBufferFormat = GFXFormatR8G8B8A8 );
|
||||
virtual ~AdvancedLightBinManager();
|
||||
|
||||
// ConsoleObject
|
||||
static void consoleInit();
|
||||
|
||||
// RenderBinManager
|
||||
virtual void render(SceneRenderState *);
|
||||
virtual void clear();
|
||||
virtual void sort() {}
|
||||
|
||||
// Add a light to the bins
|
||||
void addLight( LightInfo *light );
|
||||
|
||||
virtual bool setTargetSize(const Point2I &newTargetSize);
|
||||
|
||||
// ConsoleObject interface
|
||||
DECLARE_CONOBJECT(AdvancedLightBinManager);
|
||||
|
||||
bool MRTLightmapsDuringPrePass() const { return mMRTLightmapsDuringPrePass; }
|
||||
void MRTLightmapsDuringPrePass(bool val);
|
||||
|
||||
|
||||
typedef Signal<void(SceneRenderState *, AdvancedLightBinManager *)> RenderSignal;
|
||||
static RenderSignal &getRenderSignal();
|
||||
|
||||
AdvancedLightManager *getManager() { return mLightManager; }
|
||||
|
||||
protected:
|
||||
|
||||
/// Frees all the currently allocated light materials.
|
||||
void _deleteLightMaterials();
|
||||
|
||||
// Track a light material and associated data
|
||||
struct LightMaterialInfo
|
||||
{
|
||||
LightMatInstance *matInstance;
|
||||
|
||||
// { zNear, zFar, 1/zNear, 1/zFar }
|
||||
MaterialParameterHandle *zNearFarInvNearFar;
|
||||
|
||||
// Far frustum plane (World Space)
|
||||
MaterialParameterHandle *farPlane;
|
||||
|
||||
// Far frustum plane (View Space)
|
||||
MaterialParameterHandle *vsFarPlane;
|
||||
|
||||
// -dot( farPlane, eyePos )
|
||||
MaterialParameterHandle *negFarPlaneDotEye;
|
||||
|
||||
// Light Parameters
|
||||
MaterialParameterHandle *lightPosition;
|
||||
MaterialParameterHandle *lightDirection;
|
||||
MaterialParameterHandle *lightColor;
|
||||
MaterialParameterHandle *lightBrightness;
|
||||
MaterialParameterHandle *lightAttenuation;
|
||||
MaterialParameterHandle *lightRange;
|
||||
MaterialParameterHandle *lightAmbient;
|
||||
MaterialParameterHandle *lightTrilight;
|
||||
MaterialParameterHandle *lightSpotParams;
|
||||
|
||||
LightMaterialInfo( const String &matName,
|
||||
const GFXVertexFormat *vertexFormat,
|
||||
const Vector<GFXShaderMacro> ¯os = Vector<GFXShaderMacro>() );
|
||||
|
||||
virtual ~LightMaterialInfo();
|
||||
|
||||
|
||||
void setViewParameters( const F32 zNear,
|
||||
const F32 zFar,
|
||||
const Point3F &eyePos,
|
||||
const PlaneF &farPlane,
|
||||
const PlaneF &_vsFarPlane );
|
||||
|
||||
void setLightParameters( const LightInfo *light, const SceneRenderState* renderState, const MatrixF &worldViewOnly );
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
struct LightBinEntry
|
||||
{
|
||||
LightInfo* lightInfo;
|
||||
LightShadowMap* shadowMap;
|
||||
LightMaterialInfo* lightMaterial;
|
||||
GFXPrimitiveBuffer* primBuffer;
|
||||
GFXVertexBuffer* vertBuffer;
|
||||
U32 numPrims;
|
||||
};
|
||||
|
||||
Vector<LightBinEntry> mLightBin;
|
||||
typedef Vector<LightBinEntry>::iterator LightBinIterator;
|
||||
|
||||
bool mMRTLightmapsDuringPrePass;
|
||||
|
||||
/// Used in setupSGData to set the object transform.
|
||||
MatrixF mLightMat;
|
||||
|
||||
U32 mNumLightsCulled;
|
||||
AdvancedLightManager *mLightManager;
|
||||
ShadowMapManager *mShadowManager;
|
||||
|
||||
static const String smLightMatNames[LightInfo::Count];
|
||||
|
||||
static const String smShadowTypeMacro[ShadowType_Count];
|
||||
|
||||
static const GFXVertexFormat* smLightMatVertex[LightInfo::Count];
|
||||
|
||||
typedef CompoundKey3<LightInfo::Type,ShadowType,bool> LightMatKey;
|
||||
|
||||
typedef HashTable<LightMatKey,LightMaterialInfo*> LightMatTable;
|
||||
|
||||
/// The fixed table of light material info.
|
||||
LightMatTable mLightMaterials;
|
||||
|
||||
LightMaterialInfo* _getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, bool useCookieTex );
|
||||
|
||||
///
|
||||
void _onShadowFilterChanged();
|
||||
|
||||
AdvancedLightBufferConditioner *mConditioner;
|
||||
|
||||
typedef GFXVertexPNT FarFrustumQuadVert;
|
||||
GFXVertexBufferHandle<FarFrustumQuadVert> mFarFrustumQuadVerts;
|
||||
|
||||
|
||||
//void _createMaterials();
|
||||
|
||||
void _setupPerFrameParameters( const SceneRenderState *state );
|
||||
|
||||
void setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light );
|
||||
};
|
||||
|
||||
#endif // _ADVANCEDLIGHTBINMANAGER_H_
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/advancedLightBufferConditioner.h"
|
||||
|
||||
#include "shaderGen/shaderOp.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
|
||||
|
||||
AdvancedLightBufferConditioner::~AdvancedLightBufferConditioner()
|
||||
{
|
||||
}
|
||||
|
||||
Var *AdvancedLightBufferConditioner::_conditionOutput( Var *unconditionedOutput, MultiLine *meta )
|
||||
{
|
||||
Var *conditionedOutput = new Var;
|
||||
|
||||
if(GFX->getAdapterType() == OpenGL)
|
||||
conditionedOutput->setType("vec4");
|
||||
else
|
||||
conditionedOutput->setType("float4");
|
||||
|
||||
DecOp *outputDecl = new DecOp(conditionedOutput);
|
||||
if(mColorFormat == RGB)
|
||||
{
|
||||
conditionedOutput->setName("rgbLightInfoOut");
|
||||
|
||||
// If this is a 16 bit integer format, scale up/down the values. All other
|
||||
// formats just write out the full 0..1
|
||||
if(getBufferFormat() == GFXFormatR16G16B16A16)
|
||||
meta->addStatement( new GenOp( " @ = max(4.0, (float4(lightColor, specular) * NL_att + float4(bufferSample.rgb, 0.0)) / 4.0);\r\n", outputDecl ) );
|
||||
else
|
||||
meta->addStatement( new GenOp( " @ = float4(lightColor, specular) * NL_att + float4(bufferSample.rgb, 0.0);\r\n", outputDecl ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input u'v' assumed to be scaled
|
||||
conditionedOutput->setName("luvLightInfoOut");
|
||||
meta->addStatement( new GenOp( " @ = float4( lerp(bufferSample.xy, lightColor.xy, saturate(NL_att / bufferSample.z) * 0.5),\r\n", outputDecl ) );
|
||||
meta->addStatement( new GenOp( " bufferSample.z + NL_att, bufferSample.w + saturate(specular * NL_att) );\r\n" ) );
|
||||
}
|
||||
|
||||
return conditionedOutput;
|
||||
}
|
||||
|
||||
Var *AdvancedLightBufferConditioner::_unconditionInput( Var *conditionedInput, MultiLine *meta )
|
||||
{
|
||||
if(mColorFormat == RGB)
|
||||
{
|
||||
if(getBufferFormat() == GFXFormatR16G16B16A16)
|
||||
meta->addStatement( new GenOp( " lightColor = @.rgb * 4.0;\r\n", conditionedInput ) );
|
||||
else
|
||||
meta->addStatement( new GenOp( " lightColor = @.rgb;\r\n", conditionedInput ) );
|
||||
meta->addStatement( new GenOp( " NL_att = dot(@.rgb, float3(0.3576, 0.7152, 0.1192));\r\n", conditionedInput ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
meta->addStatement( new GenOp( " // TODO: This clamps HDR values.\r\n" ) );
|
||||
meta->addStatement( new GenOp( " NL_att = @.b;\r\n", conditionedInput ) );
|
||||
meta->addStatement( new GenOp( " lightColor = DecodeLuv(float3(saturate(NL_att), @.rg * 0.62));\r\n", conditionedInput ) );
|
||||
}
|
||||
meta->addStatement( new GenOp( " specular = max(@.a / NL_att, 0.00001f);\r\n", conditionedInput ) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Var *AdvancedLightBufferConditioner::printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta )
|
||||
{
|
||||
Var *methodVar = new Var;
|
||||
methodVar->setName(methodName);
|
||||
DecOp *methodDecl = new DecOp(methodVar);
|
||||
|
||||
Var *lightColor = new Var;
|
||||
lightColor->setName("lightColor");
|
||||
DecOp *lightColorDecl = new DecOp(lightColor);
|
||||
|
||||
Var *NLAtt = new Var;
|
||||
NLAtt->setName("NL_att");
|
||||
DecOp *NLAttDecl = new DecOp(NLAtt);
|
||||
|
||||
Var *specular = new Var;
|
||||
specular->setName("specular");
|
||||
DecOp *specularDecl = new DecOp(specular);
|
||||
|
||||
Var *bufferSample = new Var;
|
||||
bufferSample->setName("bufferSample");
|
||||
DecOp *bufferSampleDecl = new DecOp(bufferSample);
|
||||
|
||||
const bool isCondition = ( methodType == ConditionerFeature::ConditionMethod );
|
||||
|
||||
if(GFX->getAdapterType() == OpenGL)
|
||||
{
|
||||
methodVar->setType(avar("%s", isCondition ? "vec4" : "void"));
|
||||
lightColor->setType(avar("%s vec3", isCondition ? "in" : "out"));
|
||||
NLAtt->setType(avar("%s float", isCondition ? "in" : "out"));
|
||||
specular->setType(avar("%s float", isCondition ? "in" : "out"));
|
||||
bufferSample->setType("in vec4");
|
||||
}
|
||||
else
|
||||
{
|
||||
methodVar->setType(avar("inline %s", isCondition ? "float4" : "void"));
|
||||
lightColor->setType(avar("%s float3", isCondition ? "in" : "out"));
|
||||
NLAtt->setType(avar("%s float", isCondition ? "in" : "out"));
|
||||
specular->setType(avar("%s float", isCondition ? "in" : "out"));
|
||||
bufferSample->setType("in float4");
|
||||
}
|
||||
|
||||
// If this is LUV, print methods to convert RGB<->LUV as needed
|
||||
if(mColorFormat == LUV)
|
||||
{
|
||||
if(!isCondition)
|
||||
{
|
||||
meta->addStatement( new GenOp( "float3 DecodeLuv(float3 Luv)\r\n{\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float2 xy = float2(9.0f, 4.0f) * Luv.yz / (dot(Luv.yz, float2(6.0f, -16.0f)) + 12.0f);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float Ld = Luv.x;\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float3 XYZ = float3(xy.x, Ld, 1.0f - xy.x - xy.y);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " XYZ.xz = XYZ.xz * Ld / xy.y;\r\n" ) );
|
||||
meta->addStatement( new GenOp( " const float3x3 XYZ2RGB =\r\n" ) );
|
||||
meta->addStatement( new GenOp( " {\r\n" ) );
|
||||
meta->addStatement( new GenOp( " 2.5651f, -1.1665f, -0.3986f,\r\n" ) );
|
||||
meta->addStatement( new GenOp( " -1.0217f, 1.9777f, 0.0439f,\r\n" ) );
|
||||
meta->addStatement( new GenOp( " 0.0753f, -0.2543f, 1.1892f\r\n" ) );
|
||||
meta->addStatement( new GenOp( " };\r\n" ) );
|
||||
meta->addStatement( new GenOp( " return mul(XYZ2RGB, XYZ);\r\n" ) );
|
||||
meta->addStatement( new GenOp( "}\r\n\r\n" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shouldn't need this
|
||||
}
|
||||
}
|
||||
|
||||
// Method header and opening bracket
|
||||
if(isCondition)
|
||||
{
|
||||
// All parameters are input parameters, and the return value is float4.
|
||||
// If this is an LUV buffer format, than the previous pixel value is needed
|
||||
// for interpolation.
|
||||
meta->addStatement( new GenOp( "@(@, @, @, @)\r\n", methodDecl, lightColorDecl, NLAttDecl, specularDecl, bufferSampleDecl ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sample as input, parameters as output. Void return.
|
||||
meta->addStatement( new GenOp( "@(@, @, @, @)\r\n", methodDecl, bufferSampleDecl, lightColorDecl, NLAttDecl, specularDecl ) );
|
||||
}
|
||||
|
||||
meta->addStatement( new GenOp( "{\r\n" ) );
|
||||
|
||||
// We don't use this way of passing var's around, so this should cause a crash
|
||||
// if something uses this improperly
|
||||
return ( isCondition ? NULL : bufferSample );
|
||||
}
|
||||
|
||||
void AdvancedLightBufferConditioner::printMethodFooter( ConditionerFeature::MethodType methodType, Var *retVar, Stream &stream, MultiLine *meta )
|
||||
{
|
||||
// Return and closing bracket
|
||||
if(methodType == ConditionerFeature::ConditionMethod)
|
||||
meta->addStatement( new GenOp( "\r\n return @;\r\n", retVar ) );
|
||||
|
||||
// Uncondition will assign output parameters
|
||||
meta->addStatement( new GenOp( "}\r\n" ) );
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _ADVANCED_LIGHTBUFFER_CONDITIONER_H_
|
||||
#define _ADVANCED_LIGHTBUFFER_CONDITIONER_H_
|
||||
|
||||
#ifndef _CONDITIONER_BASE_H_
|
||||
#include "shaderGen/conditionerFeature.h"
|
||||
#endif
|
||||
|
||||
|
||||
class AdvancedLightBufferConditioner : public ConditionerFeature
|
||||
{
|
||||
typedef ConditionerFeature Parent;
|
||||
|
||||
public:
|
||||
enum ColorFormat
|
||||
{
|
||||
RGB,
|
||||
LUV
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
AdvancedLightBufferConditioner(const GFXFormat bufferFormat, const ColorFormat colorFormat)
|
||||
: Parent(bufferFormat), mColorFormat(colorFormat)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~AdvancedLightBufferConditioner();
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return String("Light Buffer Conditioner ") + String( mColorFormat == RGB ? "[RGB]" : "[LUV]" );
|
||||
}
|
||||
|
||||
protected:
|
||||
ColorFormat mColorFormat;
|
||||
|
||||
virtual Var *_conditionOutput( Var *unconditionedOutput, MultiLine *meta );
|
||||
virtual Var *_unconditionInput( Var *conditionedInput, MultiLine *meta );
|
||||
virtual Var *printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta );
|
||||
virtual void printMethodFooter( MethodType methodType, Var *retVar, Stream &stream, MultiLine *meta );
|
||||
};
|
||||
|
||||
#endif // _ADVANCED_LIGHTBUFFER_CONDITIONER_H_
|
||||
671
Engine/source/lighting/advanced/advancedLightManager.cpp
Normal file
671
Engine/source/lighting/advanced/advancedLightManager.cpp
Normal file
|
|
@ -0,0 +1,671 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/advancedLightManager.h"
|
||||
|
||||
#include "lighting/advanced/advancedLightBinManager.h"
|
||||
#include "lighting/advanced/advancedLightingFeatures.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#include "lighting/common/sceneLighting.h"
|
||||
#include "lighting/common/lightMapParams.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "math/util/sphereMesh.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
|
||||
|
||||
ImplementEnumType( ShadowType,
|
||||
"\n\n"
|
||||
"@ingroup AdvancedLighting" )
|
||||
{ ShadowType_Spot, "Spot" },
|
||||
{ ShadowType_PSSM, "PSSM" },
|
||||
{ ShadowType_Paraboloid, "Paraboloid" },
|
||||
{ ShadowType_DualParaboloidSinglePass, "DualParaboloidSinglePass" },
|
||||
{ ShadowType_DualParaboloid, "DualParaboloid" },
|
||||
{ ShadowType_CubeMap, "CubeMap" },
|
||||
EndImplementEnumType;
|
||||
|
||||
|
||||
AdvancedLightManager AdvancedLightManager::smSingleton;
|
||||
|
||||
|
||||
AdvancedLightManager::AdvancedLightManager()
|
||||
: LightManager( "Advanced Lighting", "ADVLM" )
|
||||
{
|
||||
mLightBinManager = NULL;
|
||||
mLastShader = NULL;
|
||||
mAvailableSLInterfaces = NULL;
|
||||
}
|
||||
|
||||
AdvancedLightManager::~AdvancedLightManager()
|
||||
{
|
||||
mLastShader = NULL;
|
||||
mLastConstants = NULL;
|
||||
|
||||
for (LightConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++)
|
||||
{
|
||||
if (i->value)
|
||||
SAFE_DELETE(i->value);
|
||||
}
|
||||
mConstantLookup.clear();
|
||||
}
|
||||
|
||||
bool AdvancedLightManager::isCompatible() const
|
||||
{
|
||||
// TODO: We need at least 3.0 shaders at the moment
|
||||
// but this should be relaxed to 2.0 soon.
|
||||
if ( GFX->getPixelShaderVersion() < 3.0 )
|
||||
return false;
|
||||
|
||||
// TODO: Test for the necessary texture formats!
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdvancedLightManager::activate( SceneManager *sceneManager )
|
||||
{
|
||||
Parent::activate( sceneManager );
|
||||
|
||||
GFXShader::addGlobalMacro( "TORQUE_ADVANCED_LIGHTING" );
|
||||
|
||||
sceneManager->setPostEffectFog( true );
|
||||
|
||||
SHADOWMGR->activate();
|
||||
|
||||
// Find a target format that supports blending...
|
||||
// we prefer the floating point format if it works.
|
||||
Vector<GFXFormat> formats;
|
||||
formats.push_back( GFXFormatR16G16B16A16F );
|
||||
formats.push_back( GFXFormatR16G16B16A16 );
|
||||
GFXFormat blendTargetFormat = GFX->selectSupportedFormat( &GFXDefaultRenderTargetProfile,
|
||||
formats,
|
||||
true,
|
||||
true,
|
||||
false );
|
||||
|
||||
mLightBinManager = new AdvancedLightBinManager( this, SHADOWMGR, blendTargetFormat );
|
||||
mLightBinManager->assignName( "AL_LightBinMgr" );
|
||||
|
||||
// First look for the prepass bin...
|
||||
RenderPrePassMgr *prePassBin = _findPrePassRenderBin();
|
||||
|
||||
// If we didn't find the prepass bin then add one.
|
||||
if ( !prePassBin )
|
||||
{
|
||||
prePassBin = new RenderPrePassMgr( true, blendTargetFormat );
|
||||
prePassBin->assignName( "AL_PrePassBin" );
|
||||
prePassBin->registerObject();
|
||||
getSceneManager()->getDefaultRenderPass()->addManager( prePassBin );
|
||||
mPrePassRenderBin = prePassBin;
|
||||
}
|
||||
|
||||
// Tell the material manager that prepass is enabled.
|
||||
MATMGR->setPrePassEnabled( true );
|
||||
|
||||
// Insert our light bin manager.
|
||||
mLightBinManager->setRenderOrder( prePassBin->getRenderOrder() + 0.01f );
|
||||
getSceneManager()->getDefaultRenderPass()->addManager( mLightBinManager );
|
||||
|
||||
AdvancedLightingFeatures::registerFeatures(mPrePassRenderBin->getTargetFormat(), mLightBinManager->getTargetFormat());
|
||||
|
||||
// Last thing... let everyone know we're active.
|
||||
smActivateSignal.trigger( getId(), true );
|
||||
}
|
||||
|
||||
void AdvancedLightManager::deactivate()
|
||||
{
|
||||
Parent::deactivate();
|
||||
|
||||
GFXShader::removeGlobalMacro( "TORQUE_ADVANCED_LIGHTING" );
|
||||
|
||||
// Release our bin manager... it will take care of
|
||||
// removing itself from the render passes.
|
||||
if( mLightBinManager )
|
||||
{
|
||||
mLightBinManager->MRTLightmapsDuringPrePass(false);
|
||||
mLightBinManager->deleteObject();
|
||||
}
|
||||
mLightBinManager = NULL;
|
||||
|
||||
if ( mPrePassRenderBin )
|
||||
mPrePassRenderBin->deleteObject();
|
||||
mPrePassRenderBin = NULL;
|
||||
|
||||
SHADOWMGR->deactivate();
|
||||
|
||||
mLastShader = NULL;
|
||||
mLastConstants = NULL;
|
||||
|
||||
for (LightConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++)
|
||||
{
|
||||
if (i->value)
|
||||
SAFE_DELETE(i->value);
|
||||
}
|
||||
mConstantLookup.clear();
|
||||
|
||||
mSphereGeometry = NULL;
|
||||
mSphereIndices = NULL;
|
||||
mConeGeometry = NULL;
|
||||
mConeIndices = NULL;
|
||||
|
||||
AdvancedLightingFeatures::unregisterFeatures();
|
||||
|
||||
// Now let everyone know we've deactivated.
|
||||
smActivateSignal.trigger( getId(), false );
|
||||
}
|
||||
|
||||
void AdvancedLightManager::_addLightInfoEx( LightInfo *lightInfo )
|
||||
{
|
||||
lightInfo->addExtended( new ShadowMapParams( lightInfo ) );
|
||||
lightInfo->addExtended( new LightMapParams( lightInfo ) );
|
||||
}
|
||||
|
||||
|
||||
void AdvancedLightManager::_initLightFields()
|
||||
{
|
||||
#define DEFINE_LIGHT_FIELD( var, type, enum_ ) \
|
||||
static inline const char* _get##var##Field( void *obj, const char *data ) \
|
||||
{ \
|
||||
ShadowMapParams *p = _getShadowMapParams( obj ); \
|
||||
if ( p ) \
|
||||
return Con::getData( type, &p->var, 0, enum_ ); \
|
||||
else \
|
||||
return ""; \
|
||||
} \
|
||||
\
|
||||
static inline bool _set##var##Field( void *object, const char *index, const char *data ) \
|
||||
{ \
|
||||
ShadowMapParams *p = _getShadowMapParams( object ); \
|
||||
if ( p ) \
|
||||
{ \
|
||||
Con::setData( type, &p->var, 0, 1, &data, enum_ ); \
|
||||
p->_validate(); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define DEFINE_LIGHTMAP_FIELD( var, type, enum_ ) \
|
||||
static inline const char* _get##var##Field( void *obj, const char *data ) \
|
||||
{ \
|
||||
LightMapParams *p = _getLightMapParams( obj ); \
|
||||
if ( p ) \
|
||||
return Con::getData( type, &p->var, 0, enum_ ); \
|
||||
else \
|
||||
return ""; \
|
||||
} \
|
||||
\
|
||||
static inline bool _set##var##Field( void *object, const char *index, const char *data ) \
|
||||
{ \
|
||||
LightMapParams *p = _getLightMapParams( object ); \
|
||||
if ( p ) \
|
||||
{ \
|
||||
Con::setData( type, &p->var, 0, 1, &data, enum_ ); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define ADD_LIGHT_FIELD( field, type, var, desc ) \
|
||||
ConsoleObject::addProtectedField( field, type, 0, \
|
||||
&Dummy::_set##var##Field, &Dummy::_get##var##Field, desc )
|
||||
|
||||
// Our dummy adaptor class which we hide in here
|
||||
// to keep from poluting the global namespace.
|
||||
class Dummy
|
||||
{
|
||||
protected:
|
||||
|
||||
static inline ShadowMapParams* _getShadowMapParams( void *obj )
|
||||
{
|
||||
ISceneLight *sceneLight = dynamic_cast<ISceneLight*>( (SimObject*)obj );
|
||||
if ( sceneLight )
|
||||
{
|
||||
LightInfo *lightInfo = sceneLight->getLight();
|
||||
if ( lightInfo )
|
||||
return lightInfo->getExtended<ShadowMapParams>();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline LightMapParams* _getLightMapParams( void *obj )
|
||||
{
|
||||
ISceneLight *sceneLight = dynamic_cast<ISceneLight*>( (SimObject*)obj );
|
||||
if ( sceneLight )
|
||||
{
|
||||
LightInfo *lightInfo = sceneLight->getLight();
|
||||
if ( lightInfo )
|
||||
return lightInfo->getExtended<LightMapParams>();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
DEFINE_LIGHT_FIELD( attenuationRatio, TypePoint3F, NULL );
|
||||
DEFINE_LIGHT_FIELD( shadowType, TYPEID< ShadowType >(), ConsoleBaseType::getType( TYPEID< ShadowType >() )->getEnumTable() );
|
||||
DEFINE_LIGHT_FIELD( texSize, TypeS32, NULL );
|
||||
DEFINE_LIGHT_FIELD( cookie, TypeStringFilename, NULL );
|
||||
DEFINE_LIGHT_FIELD( numSplits, TypeS32, NULL );
|
||||
DEFINE_LIGHT_FIELD( logWeight, TypeF32, NULL );
|
||||
DEFINE_LIGHT_FIELD( overDarkFactor, TypePoint4F, NULL);
|
||||
DEFINE_LIGHT_FIELD( shadowDistance, TypeF32, NULL );
|
||||
DEFINE_LIGHT_FIELD( shadowSoftness, TypeF32, NULL );
|
||||
DEFINE_LIGHT_FIELD( fadeStartDist, TypeF32, NULL );
|
||||
DEFINE_LIGHT_FIELD( lastSplitTerrainOnly, TypeBool, NULL );
|
||||
|
||||
DEFINE_LIGHTMAP_FIELD( representedInLightmap, TypeBool, NULL );
|
||||
DEFINE_LIGHTMAP_FIELD( shadowDarkenColor, TypeColorF, NULL );
|
||||
DEFINE_LIGHTMAP_FIELD( includeLightmappedGeometryInShadow, TypeBool, NULL );
|
||||
};
|
||||
|
||||
ConsoleObject::addGroup( "Advanced Lighting" );
|
||||
|
||||
ADD_LIGHT_FIELD( "attenuationRatio", TypePoint3F, attenuationRatio,
|
||||
"The proportions of constant, linear, and quadratic attenuation to use for "
|
||||
"the falloff for point and spot lights." );
|
||||
|
||||
ADD_LIGHT_FIELD( "shadowType", TYPEID< ShadowType >(), shadowType,
|
||||
"The type of shadow to use on this light." );
|
||||
|
||||
ADD_LIGHT_FIELD( "cookie", TypeStringFilename, cookie,
|
||||
"A custom pattern texture which is projected from the light." );
|
||||
|
||||
ADD_LIGHT_FIELD( "texSize", TypeS32, texSize,
|
||||
"The texture size of the shadow map." );
|
||||
|
||||
ADD_LIGHT_FIELD( "overDarkFactor", TypePoint4F, overDarkFactor,
|
||||
"The ESM shadow darkening factor");
|
||||
|
||||
ADD_LIGHT_FIELD( "shadowDistance", TypeF32, shadowDistance,
|
||||
"The distance from the camera to extend the PSSM shadow." );
|
||||
|
||||
ADD_LIGHT_FIELD( "shadowSoftness", TypeF32, shadowSoftness,
|
||||
"" );
|
||||
|
||||
ADD_LIGHT_FIELD( "numSplits", TypeS32, numSplits,
|
||||
"The logrithmic PSSM split distance factor." );
|
||||
|
||||
ADD_LIGHT_FIELD( "logWeight", TypeF32, logWeight,
|
||||
"The logrithmic PSSM split distance factor." );
|
||||
|
||||
ADD_LIGHT_FIELD( "fadeStartDistance", TypeF32, fadeStartDist,
|
||||
"Start fading shadows out at this distance. 0 = auto calculate this distance.");
|
||||
|
||||
ADD_LIGHT_FIELD( "lastSplitTerrainOnly", TypeBool, lastSplitTerrainOnly,
|
||||
"This toggles only terrain being rendered to the last split of a PSSM shadow map.");
|
||||
|
||||
ConsoleObject::endGroup( "Advanced Lighting" );
|
||||
|
||||
ConsoleObject::addGroup( "Advanced Lighting Lightmap" );
|
||||
|
||||
ADD_LIGHT_FIELD( "representedInLightmap", TypeBool, representedInLightmap,
|
||||
"This light is represented in lightmaps (static light, default: false)");
|
||||
|
||||
ADD_LIGHT_FIELD( "shadowDarkenColor", TypeColorF, shadowDarkenColor,
|
||||
"The color that should be used to multiply-blend dynamic shadows onto lightmapped geometry (ignored if 'representedInLightmap' is false)");
|
||||
|
||||
ADD_LIGHT_FIELD( "includeLightmappedGeometryInShadow", TypeBool, includeLightmappedGeometryInShadow,
|
||||
"This light should render lightmapped geometry during its shadow-map update (ignored if 'representedInLightmap' is false)");
|
||||
|
||||
ConsoleObject::endGroup( "Advanced Lighting Lightmap" );
|
||||
|
||||
#undef DEFINE_LIGHT_FIELD
|
||||
#undef ADD_LIGHT_FIELD
|
||||
}
|
||||
|
||||
void AdvancedLightManager::setLightInfo( ProcessedMaterial *pmat,
|
||||
const Material *mat,
|
||||
const SceneData &sgData,
|
||||
const SceneRenderState *state,
|
||||
U32 pass,
|
||||
GFXShaderConstBuffer *shaderConsts)
|
||||
{
|
||||
// Skip this if we're rendering from the prepass bin.
|
||||
if ( sgData.binType == SceneData::PrePassBin )
|
||||
return;
|
||||
|
||||
PROFILE_SCOPE(AdvancedLightManager_setLightInfo);
|
||||
|
||||
LightingShaderConstants *lsc = getLightingShaderConstants(shaderConsts);
|
||||
|
||||
LightShadowMap *lsm = SHADOWMGR->getCurrentShadowMap();
|
||||
|
||||
LightInfo *light;
|
||||
if ( lsm )
|
||||
light = lsm->getLightInfo();
|
||||
else
|
||||
{
|
||||
light = sgData.lights[0];
|
||||
if ( !light )
|
||||
light = getDefaultLight();
|
||||
}
|
||||
|
||||
// NOTE: If you encounter a crash from this point forward
|
||||
// while setting a shader constant its probably because the
|
||||
// mConstantLookup has bad shaders/constants in it.
|
||||
//
|
||||
// This is a known crash bug that can occur if materials/shaders
|
||||
// are reloaded and the light manager is not reset.
|
||||
//
|
||||
// We should look to fix this by clearing the table.
|
||||
|
||||
// Update the forward shading light constants.
|
||||
_update4LightConsts( sgData,
|
||||
lsc->mLightPositionSC,
|
||||
lsc->mLightDiffuseSC,
|
||||
lsc->mLightAmbientSC,
|
||||
lsc->mLightInvRadiusSqSC,
|
||||
lsc->mLightSpotDirSC,
|
||||
lsc->mLightSpotAngleSC,
|
||||
lsc->mLightSpotFalloffSC,
|
||||
shaderConsts );
|
||||
|
||||
if ( lsm && light->getCastShadows() )
|
||||
{
|
||||
if ( lsc->mWorldToLightProjSC->isValid() )
|
||||
shaderConsts->set( lsc->mWorldToLightProjSC,
|
||||
lsm->getWorldToLightProj(),
|
||||
lsc->mWorldToLightProjSC->getType() );
|
||||
|
||||
if ( lsc->mViewToLightProjSC->isValid() )
|
||||
{
|
||||
// TODO: Should probably cache these results and
|
||||
// not do this mul here on every material that needs
|
||||
// this transform.
|
||||
|
||||
shaderConsts->set( lsc->mViewToLightProjSC,
|
||||
lsm->getWorldToLightProj() * state->getCameraTransform(),
|
||||
lsc->mViewToLightProjSC->getType() );
|
||||
}
|
||||
|
||||
shaderConsts->setSafe( lsc->mShadowMapSizeSC, 1.0f / (F32)lsm->getTexSize() );
|
||||
|
||||
// Do this last so that overrides can properly override parameters previously set
|
||||
lsm->setShaderParameters(shaderConsts, lsc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( lsc->mViewToLightProjSC->isValid() )
|
||||
{
|
||||
// TODO: Should probably cache these results and
|
||||
// not do this mul here on every material that needs
|
||||
// this transform.
|
||||
MatrixF proj;
|
||||
light->getWorldToLightProj( &proj );
|
||||
|
||||
shaderConsts->set( lsc->mViewToLightProjSC,
|
||||
proj * state->getCameraTransform(),
|
||||
lsc->mViewToLightProjSC->getType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedLightManager::registerGlobalLight(LightInfo *light, SimObject *obj)
|
||||
{
|
||||
Parent::registerGlobalLight( light, obj );
|
||||
|
||||
// Pass the volume lights to the bin manager.
|
||||
if ( mLightBinManager &&
|
||||
( light->getType() == LightInfo::Point ||
|
||||
light->getType() == LightInfo::Spot ) )
|
||||
mLightBinManager->addLight( light );
|
||||
}
|
||||
|
||||
void AdvancedLightManager::unregisterAllLights()
|
||||
{
|
||||
Parent::unregisterAllLights();
|
||||
|
||||
if ( mLightBinManager )
|
||||
mLightBinManager->clear();
|
||||
}
|
||||
|
||||
bool AdvancedLightManager::setTextureStage( const SceneData &sgData,
|
||||
const U32 currTexFlag,
|
||||
const U32 textureSlot,
|
||||
GFXShaderConstBuffer *shaderConsts,
|
||||
ShaderConstHandles *handles )
|
||||
{
|
||||
LightShadowMap* lsm = SHADOWMGR->getCurrentShadowMap();
|
||||
|
||||
// Assign Shadowmap, if it exists
|
||||
LightingShaderConstants* lsc = getLightingShaderConstants(shaderConsts);
|
||||
if ( !lsc )
|
||||
return false;
|
||||
|
||||
if ( lsm && lsm->getLightInfo()->getCastShadows() )
|
||||
return lsm->setTextureStage( currTexFlag, lsc );
|
||||
|
||||
|
||||
if ( currTexFlag == Material::DynamicLight )
|
||||
{
|
||||
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, GFXTexHandle::ONE );
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ( currTexFlag == Material::DynamicLightMask )
|
||||
{
|
||||
S32 reg = lsc->mCookieMapSC->getSamplerRegister();
|
||||
if ( reg != -1 && sgData.lights[0] )
|
||||
{
|
||||
ShadowMapParams *p = sgData.lights[0]->getExtended<ShadowMapParams>();
|
||||
|
||||
if ( lsc->mCookieMapSC->getType() == GFXSCT_SamplerCube )
|
||||
GFX->setCubeTexture( reg, p->getCookieCubeTex() );
|
||||
else
|
||||
GFX->setTexture( reg, p->getCookieTex() );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LightingShaderConstants* AdvancedLightManager::getLightingShaderConstants(GFXShaderConstBuffer* buffer)
|
||||
{
|
||||
if ( !buffer )
|
||||
return NULL;
|
||||
|
||||
PROFILE_SCOPE( AdvancedLightManager_GetLightingShaderConstants );
|
||||
|
||||
GFXShader* shader = buffer->getShader();
|
||||
|
||||
// Check to see if this is the same shader, we'll get hit repeatedly by
|
||||
// the same one due to the render bin loops.
|
||||
if ( mLastShader.getPointer() != shader )
|
||||
{
|
||||
LightConstantMap::Iterator iter = mConstantLookup.find(shader);
|
||||
if ( iter != mConstantLookup.end() )
|
||||
{
|
||||
mLastConstants = iter->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LightingShaderConstants* lsc = new LightingShaderConstants();
|
||||
mConstantLookup[shader] = lsc;
|
||||
|
||||
mLastConstants = lsc;
|
||||
}
|
||||
|
||||
// Set our new shader
|
||||
mLastShader = shader;
|
||||
}
|
||||
|
||||
// Make sure that our current lighting constants are initialized
|
||||
if (!mLastConstants->mInit)
|
||||
mLastConstants->init(shader);
|
||||
|
||||
return mLastConstants;
|
||||
}
|
||||
|
||||
GFXVertexBufferHandle<AdvancedLightManager::LightVertex> AdvancedLightManager::getSphereMesh(U32 &outNumPrimitives, GFXPrimitiveBuffer *&outPrimitives)
|
||||
{
|
||||
static SphereMesh sSphereMesh;
|
||||
|
||||
if( mSphereGeometry.isNull() )
|
||||
{
|
||||
const SphereMesh::TriangleMesh * sphereMesh = sSphereMesh.getMesh(3);
|
||||
S32 numPoly = sphereMesh->numPoly;
|
||||
mSpherePrimitiveCount = 0;
|
||||
mSphereGeometry.set(GFX, numPoly*3, GFXBufferTypeStatic);
|
||||
mSphereGeometry.lock();
|
||||
S32 vertexIndex = 0;
|
||||
|
||||
for (S32 i=0; i<numPoly; i++)
|
||||
{
|
||||
mSpherePrimitiveCount++;
|
||||
|
||||
mSphereGeometry[vertexIndex].point = sphereMesh->poly[i].pnt[0];
|
||||
mSphereGeometry[vertexIndex].color = ColorI::WHITE;
|
||||
vertexIndex++;
|
||||
|
||||
mSphereGeometry[vertexIndex].point = sphereMesh->poly[i].pnt[1];
|
||||
mSphereGeometry[vertexIndex].color = ColorI::WHITE;
|
||||
vertexIndex++;
|
||||
|
||||
mSphereGeometry[vertexIndex].point = sphereMesh->poly[i].pnt[2];
|
||||
mSphereGeometry[vertexIndex].color = ColorI::WHITE;
|
||||
vertexIndex++;
|
||||
}
|
||||
mSphereGeometry.unlock();
|
||||
}
|
||||
|
||||
outNumPrimitives = mSpherePrimitiveCount;
|
||||
outPrimitives = NULL; // For now
|
||||
return mSphereGeometry;
|
||||
}
|
||||
|
||||
GFXVertexBufferHandle<AdvancedLightManager::LightVertex> AdvancedLightManager::getConeMesh(U32 &outNumPrimitives, GFXPrimitiveBuffer *&outPrimitives )
|
||||
{
|
||||
static const Point2F circlePoints[] =
|
||||
{
|
||||
Point2F(0.707107f, 0.707107f),
|
||||
Point2F(0.923880f, 0.382683f),
|
||||
Point2F(1.000000f, 0.000000f),
|
||||
Point2F(0.923880f, -0.382684f),
|
||||
Point2F(0.707107f, -0.707107f),
|
||||
Point2F(0.382683f, -0.923880f),
|
||||
Point2F(0.000000f, -1.000000f),
|
||||
Point2F(-0.382683f, -0.923880f),
|
||||
Point2F(-0.707107f, -0.707107f),
|
||||
Point2F(-0.923880f, -0.382684f),
|
||||
Point2F(-1.000000f, 0.000000f),
|
||||
Point2F(-0.923879f, 0.382684f),
|
||||
Point2F(-0.707107f, 0.707107f),
|
||||
Point2F(-0.382683f, 0.923880f),
|
||||
Point2F(0.000000f, 1.000000f),
|
||||
Point2F(0.382684f, 0.923879f)
|
||||
};
|
||||
const S32 numPoints = sizeof(circlePoints)/sizeof(Point2F);
|
||||
|
||||
if ( mConeGeometry.isNull() )
|
||||
{
|
||||
mConeGeometry.set(GFX, numPoints + 1, GFXBufferTypeStatic);
|
||||
mConeGeometry.lock();
|
||||
|
||||
mConeGeometry[0].point = Point3F(0.0f,0.0f,0.0f);
|
||||
|
||||
for (S32 i=1; i<numPoints + 1; i++)
|
||||
{
|
||||
S32 imod = (i - 1) % numPoints;
|
||||
mConeGeometry[i].point = Point3F(circlePoints[imod].x,circlePoints[imod].y, -1.0f);
|
||||
mConeGeometry[i].color = ColorI::WHITE;
|
||||
}
|
||||
mConeGeometry.unlock();
|
||||
|
||||
mConePrimitiveCount = numPoints * 2 - 1;
|
||||
|
||||
// Now build the index buffer
|
||||
mConeIndices.set(GFX, mConePrimitiveCount * 3, mConePrimitiveCount, GFXBufferTypeStatic);
|
||||
|
||||
U16 *idx = NULL;
|
||||
mConeIndices.lock( &idx );
|
||||
// Build the cone
|
||||
U32 idxIdx = 0;
|
||||
for( int i = 1; i < numPoints + 1; i++ )
|
||||
{
|
||||
idx[idxIdx++] = 0; // Triangles on cone start at top point
|
||||
idx[idxIdx++] = i;
|
||||
idx[idxIdx++] = ( i + 1 > numPoints ) ? 1 : i + 1;
|
||||
}
|
||||
|
||||
// Build the bottom of the cone (reverse winding order)
|
||||
for( int i = 1; i < numPoints - 1; i++ )
|
||||
{
|
||||
idx[idxIdx++] = 1;
|
||||
idx[idxIdx++] = i + 2;
|
||||
idx[idxIdx++] = i + 1;
|
||||
}
|
||||
mConeIndices.unlock();
|
||||
}
|
||||
|
||||
outNumPrimitives = mConePrimitiveCount;
|
||||
outPrimitives = mConeIndices.getPointer();
|
||||
return mConeGeometry;
|
||||
}
|
||||
|
||||
LightShadowMap* AdvancedLightManager::findShadowMapForObject( SimObject *object )
|
||||
{
|
||||
if ( !object )
|
||||
return NULL;
|
||||
|
||||
ISceneLight *sceneLight = dynamic_cast<ISceneLight*>( object );
|
||||
if ( !sceneLight || !sceneLight->getLight() )
|
||||
return NULL;
|
||||
|
||||
return sceneLight->getLight()->getExtended<ShadowMapParams>()->getShadowMap();
|
||||
}
|
||||
|
||||
ConsoleFunction( setShadowVizLight, const char*, 2, 2, "" )
|
||||
{
|
||||
static const String DebugTargetName( "AL_ShadowVizTexture" );
|
||||
|
||||
NamedTexTarget *target = NamedTexTarget::find( DebugTargetName );
|
||||
if ( target )
|
||||
target->unregister();
|
||||
|
||||
AdvancedLightManager *lm = dynamic_cast<AdvancedLightManager*>( LIGHTMGR );
|
||||
if ( !lm )
|
||||
return 0;
|
||||
|
||||
SimObject *object;
|
||||
Sim::findObject( argv[1], object );
|
||||
LightShadowMap *lightShadowMap = lm->findShadowMapForObject( object );
|
||||
if ( !lightShadowMap || !lightShadowMap->getTexture() )
|
||||
return 0;
|
||||
|
||||
lightShadowMap->setDebugTarget( DebugTargetName );
|
||||
|
||||
GFXTextureObject *texObject = lightShadowMap->getTexture();
|
||||
const Point3I &size = texObject->getSize();
|
||||
F32 aspect = (F32)size.x / (F32)size.y;
|
||||
|
||||
char *result = Con::getReturnBuffer( 64 );
|
||||
dSprintf( result, 64, "%d %d %g", size.x, size.y, aspect );
|
||||
return result;
|
||||
}
|
||||
|
||||
143
Engine/source/lighting/advanced/advancedLightManager.h
Normal file
143
Engine/source/lighting/advanced/advancedLightManager.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _ADVANCEDLIGHTMANAGER_H_
|
||||
#define _ADVANCEDLIGHTMANAGER_H_
|
||||
|
||||
#ifndef _SIMOBJECT_H_
|
||||
#include "console/simObject.h"
|
||||
#endif
|
||||
#ifndef _LIGHTMANAGER_H_
|
||||
#include "lighting/lightManager.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
#ifndef _GFXTARGET_H_
|
||||
#include "gfx/gfxTarget.h"
|
||||
#endif
|
||||
#ifndef _TDICTIONARY_H_
|
||||
#include "core/util/tDictionary.h"
|
||||
#endif
|
||||
#ifndef _LIGHTSHADOWMAP_H_
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
#endif
|
||||
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
#ifndef _GFXVERTEXBUFFER_H_
|
||||
#include "gfx/gfxVertexBuffer.h"
|
||||
#endif
|
||||
|
||||
|
||||
class AvailableSLInterfaces;
|
||||
class AdvancedLightBinManager;
|
||||
class RenderPrePassMgr;
|
||||
class BaseMatInstance;
|
||||
class MaterialParameters;
|
||||
class MaterialParameterHandle;
|
||||
class GFXShader;
|
||||
class GFXShaderConstHandle;
|
||||
class ShadowMapManager;
|
||||
|
||||
|
||||
class AdvancedLightManager : public LightManager
|
||||
{
|
||||
typedef LightManager Parent;
|
||||
|
||||
public:
|
||||
|
||||
/// Return the lightBinManager for this light manager.
|
||||
AdvancedLightBinManager* getLightBinManager() { return mLightBinManager; }
|
||||
|
||||
// LightManager
|
||||
virtual bool isCompatible() const;
|
||||
virtual void activate( SceneManager *sceneManager );
|
||||
virtual void deactivate();
|
||||
virtual void registerGlobalLight(LightInfo *light, SimObject *obj);
|
||||
virtual void unregisterAllLights();
|
||||
virtual void setLightInfo( ProcessedMaterial *pmat,
|
||||
const Material *mat,
|
||||
const SceneData &sgData,
|
||||
const SceneRenderState *state,
|
||||
U32 pass,
|
||||
GFXShaderConstBuffer *shaderConsts );
|
||||
virtual bool setTextureStage( const SceneData &sgData,
|
||||
const U32 currTexFlag,
|
||||
const U32 textureSlot,
|
||||
GFXShaderConstBuffer *shaderConsts,
|
||||
ShaderConstHandles *handles );
|
||||
|
||||
typedef GFXVertexPC LightVertex;
|
||||
|
||||
GFXVertexBufferHandle<LightVertex> getSphereMesh(U32 &outNumPrimitives, GFXPrimitiveBuffer *&outPrimitives );
|
||||
GFXVertexBufferHandle<LightVertex> getConeMesh(U32 &outNumPrimitives, GFXPrimitiveBuffer *&outPrimitives );
|
||||
|
||||
LightShadowMap* findShadowMapForObject( SimObject *object );
|
||||
|
||||
protected:
|
||||
|
||||
// LightManager
|
||||
virtual void _addLightInfoEx( LightInfo *lightInfo );
|
||||
virtual void _initLightFields();
|
||||
|
||||
/// A simple protected singleton. Use LightManager::findByName()
|
||||
/// to access this light manager.
|
||||
/// @see LightManager::findByName()
|
||||
static AdvancedLightManager smSingleton;
|
||||
|
||||
// These are protected because we're a singleton and
|
||||
// no one else should be creating us!
|
||||
AdvancedLightManager();
|
||||
virtual ~AdvancedLightManager();
|
||||
|
||||
SimObjectPtr<AdvancedLightBinManager> mLightBinManager;
|
||||
|
||||
SimObjectPtr<RenderPrePassMgr> mPrePassRenderBin;
|
||||
|
||||
LightConstantMap mConstantLookup;
|
||||
|
||||
GFXShaderRef mLastShader;
|
||||
|
||||
LightingShaderConstants* mLastConstants;
|
||||
|
||||
// Convex geometry for lights
|
||||
GFXVertexBufferHandle<LightVertex> mSphereGeometry;
|
||||
|
||||
GFXPrimitiveBufferHandle mSphereIndices;
|
||||
|
||||
U32 mSpherePrimitiveCount;
|
||||
|
||||
GFXVertexBufferHandle<LightVertex> mConeGeometry;
|
||||
|
||||
GFXPrimitiveBufferHandle mConeIndices;
|
||||
|
||||
U32 mConePrimitiveCount;
|
||||
|
||||
LightingShaderConstants* getLightingShaderConstants(GFXShaderConstBuffer* shader);
|
||||
|
||||
};
|
||||
|
||||
#endif // _ADVANCEDLIGHTMANAGER_H_
|
||||
101
Engine/source/lighting/advanced/advancedLightingFeatures.cpp
Normal file
101
Engine/source/lighting/advanced/advancedLightingFeatures.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/advancedLightingFeatures.h"
|
||||
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "gfx/gfxStringEnumTranslate.h"
|
||||
#include "materials/materialParameters.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "materials/matTextureTarget.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
|
||||
#ifndef TORQUE_OS_MAC
|
||||
# include "lighting/advanced/hlsl/gBufferConditionerHLSL.h"
|
||||
# include "lighting/advanced/hlsl/advancedLightingFeaturesHLSL.h"
|
||||
#else
|
||||
# include "lighting/advanced/glsl/gBufferConditionerGLSL.h"
|
||||
# include "lighting/advanced/glsl/advancedLightingFeaturesGLSL.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
bool AdvancedLightingFeatures::smFeaturesRegistered = false;
|
||||
|
||||
void AdvancedLightingFeatures::registerFeatures( const GFXFormat &prepassTargetFormat, const GFXFormat &lightInfoTargetFormat )
|
||||
{
|
||||
AssertFatal( !smFeaturesRegistered, "AdvancedLightingFeatures::registerFeatures() - Features already registered. Bad!" );
|
||||
|
||||
// If we ever need this...
|
||||
TORQUE_UNUSED(lightInfoTargetFormat);
|
||||
|
||||
ConditionerFeature *cond = NULL;
|
||||
|
||||
if(GFX->getAdapterType() == OpenGL)
|
||||
{
|
||||
#ifdef TORQUE_OS_MAC
|
||||
cond = new GBufferConditionerGLSL( prepassTargetFormat );
|
||||
FEATUREMGR->registerFeature(MFT_PrePassConditioner, cond);
|
||||
FEATUREMGR->registerFeature(MFT_RTLighting, new DeferredRTLightingFeatGLSL());
|
||||
FEATUREMGR->registerFeature(MFT_NormalMap, new DeferredBumpFeatGLSL());
|
||||
FEATUREMGR->registerFeature(MFT_PixSpecular, new DeferredPixelSpecularGLSL());
|
||||
FEATUREMGR->registerFeature(MFT_MinnaertShading, new DeferredMinnaertGLSL());
|
||||
FEATUREMGR->registerFeature(MFT_SubSurface, new DeferredSubSurfaceGLSL());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef TORQUE_OS_MAC
|
||||
cond = new GBufferConditionerHLSL( prepassTargetFormat, GBufferConditionerHLSL::ViewSpace );
|
||||
FEATUREMGR->registerFeature(MFT_PrePassConditioner, cond);
|
||||
FEATUREMGR->registerFeature(MFT_RTLighting, new DeferredRTLightingFeatHLSL());
|
||||
FEATUREMGR->registerFeature(MFT_NormalMap, new DeferredBumpFeatHLSL());
|
||||
FEATUREMGR->registerFeature(MFT_PixSpecular, new DeferredPixelSpecularHLSL());
|
||||
FEATUREMGR->registerFeature(MFT_MinnaertShading, new DeferredMinnaertHLSL());
|
||||
FEATUREMGR->registerFeature(MFT_SubSurface, new DeferredSubSurfaceHLSL());
|
||||
#endif
|
||||
}
|
||||
|
||||
NamedTexTarget *target = NamedTexTarget::find( "prepass" );
|
||||
if ( target )
|
||||
target->setConditioner( cond );
|
||||
|
||||
smFeaturesRegistered = true;
|
||||
}
|
||||
|
||||
void AdvancedLightingFeatures::unregisterFeatures()
|
||||
{
|
||||
NamedTexTarget *target = NamedTexTarget::find( "prepass" );
|
||||
if ( target )
|
||||
target->setConditioner( NULL );
|
||||
|
||||
FEATUREMGR->unregisterFeature(MFT_PrePassConditioner);
|
||||
FEATUREMGR->unregisterFeature(MFT_RTLighting);
|
||||
FEATUREMGR->unregisterFeature(MFT_NormalMap);
|
||||
FEATUREMGR->unregisterFeature(MFT_PixSpecular);
|
||||
FEATUREMGR->unregisterFeature(MFT_MinnaertShading);
|
||||
FEATUREMGR->unregisterFeature(MFT_SubSurface);
|
||||
|
||||
smFeaturesRegistered = false;
|
||||
}
|
||||
42
Engine/source/lighting/advanced/advancedLightingFeatures.h
Normal file
42
Engine/source/lighting/advanced/advancedLightingFeatures.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _ADVANCEDLIGHTINGFEATURES_H_
|
||||
#define _ADVANCEDLIGHTINGFEATURES_H_
|
||||
|
||||
#ifndef _GFXENUMS_H_
|
||||
#include "gfx/gfxEnums.h"
|
||||
#endif
|
||||
|
||||
|
||||
class AdvancedLightingFeatures
|
||||
{
|
||||
public:
|
||||
|
||||
static void registerFeatures( const GFXFormat &prepassTargetFormat, const GFXFormat &lightInfoTargetFormat );
|
||||
static void unregisterFeatures();
|
||||
|
||||
private:
|
||||
|
||||
static bool smFeaturesRegistered;
|
||||
};
|
||||
|
||||
#endif // _ADVANCEDLIGHTINGFEATURES_H_
|
||||
|
|
@ -0,0 +1,725 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/glsl/advancedLightingFeaturesGLSL.h"
|
||||
|
||||
#include "lighting/advanced/advancedLightBinManager.h"
|
||||
#include "shaderGen/langElement.h"
|
||||
#include "shaderGen/shaderOp.h"
|
||||
#include "shaderGen/conditionerFeature.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
#include "materials/processedMaterial.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
|
||||
|
||||
void DeferredRTLightingFeatGLSL::processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
/// TODO: This needs to be done via some sort of material
|
||||
/// feature and not just allow all translucent elements to
|
||||
/// read from the light prepass.
|
||||
/*
|
||||
if ( fd.features[MFT_IsTranslucent] )
|
||||
{
|
||||
Parent::processPixMacros( macros, fd );
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// Pull in the uncondition method for the light info buffer
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find( AdvancedLightBinManager::smBufferName );
|
||||
if ( texTarget && texTarget->getConditioner() )
|
||||
{
|
||||
ConditionerMethodDependency *unconditionMethod = texTarget->getConditioner()->getConditionerMethodDependency(ConditionerFeature::UnconditionMethod);
|
||||
unconditionMethod->createMethodMacro( String::ToLower( AdvancedLightBinManager::smBufferName ) + "Uncondition", macros );
|
||||
addDependency(unconditionMethod);
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredRTLightingFeatGLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
/// TODO: This needs to be done via some sort of material
|
||||
/// feature and not just allow all translucent elements to
|
||||
/// read from the light prepass.
|
||||
/*
|
||||
if ( fd.features[MFT_IsTranslucent] )
|
||||
{
|
||||
Parent::processVert( componentList, fd );
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// Pass screen space position to pixel shader to compute a full screen buffer uv
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *ssPos = connectComp->getElement( RT_TEXCOORD );
|
||||
ssPos->setName( "screenspacePos" );
|
||||
ssPos->setType( "vec4" );
|
||||
|
||||
// Var *outPosition = (Var*) LangElement::find( "hpos" );
|
||||
// AssertFatal( outPosition, "No hpos, ohnoes." );
|
||||
|
||||
output = new GenOp( " @ = gl_Position;\r\n", ssPos );
|
||||
}
|
||||
|
||||
void DeferredRTLightingFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
/// TODO: This needs to be done via some sort of material
|
||||
/// feature and not just allow all translucent elements to
|
||||
/// read from the light prepass.
|
||||
/*
|
||||
if ( fd.features[MFT_IsTranslucent] )
|
||||
{
|
||||
Parent::processPix( componentList, fd );
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *ssPos = connectComp->getElement( RT_TEXCOORD );
|
||||
ssPos->setName( "screenspacePos" );
|
||||
ssPos->setType( "vec4" );
|
||||
|
||||
Var *uvScene = new Var;
|
||||
uvScene->setType( "vec2" );
|
||||
uvScene->setName( "uvScene" );
|
||||
LangElement *uvSceneDecl = new DecOp( uvScene );
|
||||
|
||||
Var *rtParams = (Var*) LangElement::find( "renderTargetParams" );
|
||||
if( !rtParams )
|
||||
{
|
||||
rtParams = new Var;
|
||||
rtParams->setType( "vec4" );
|
||||
rtParams->setName( "renderTargetParams" );
|
||||
rtParams->uniform = true;
|
||||
rtParams->constSortPos = cspPass;
|
||||
}
|
||||
|
||||
meta->addStatement( new GenOp( " @ = @.xy / @.w;\r\n", uvSceneDecl, ssPos, ssPos ) ); // get the screen coord... its -1 to +1
|
||||
meta->addStatement( new GenOp( " @ = ( @ + 1.0 ) / 2.0;\r\n", uvScene, uvScene ) ); // get the screen coord to 0 to 1
|
||||
meta->addStatement( new GenOp( " @ = ( @ * @.zw ) + @.xy;\r\n", uvScene, uvScene, rtParams, rtParams) ); // scale it down and offset it to the rt size
|
||||
|
||||
Var *lightInfoSamp = new Var;
|
||||
lightInfoSamp->setType( "vec4" );
|
||||
lightInfoSamp->setName( "lightInfoSample" );
|
||||
|
||||
// create texture var
|
||||
Var *lightInfoBuffer = new Var;
|
||||
lightInfoBuffer->setType( "sampler2D" );
|
||||
lightInfoBuffer->setName( "lightInfoBuffer" );
|
||||
lightInfoBuffer->uniform = true;
|
||||
lightInfoBuffer->sampler = true;
|
||||
lightInfoBuffer->constNum = Var::getTexUnitNum(); // used as texture unit num here
|
||||
|
||||
String unconditionLightInfo = String::ToLower( AdvancedLightBinManager::smBufferName ) + "Uncondition";
|
||||
|
||||
meta->addStatement( new GenOp( " vec3 d_lightcolor;\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float d_NL_Att;\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float d_specular;\r\n" ) );
|
||||
meta->addStatement( new GenOp( avar( " %s(texture2D(@, @), d_lightcolor, d_NL_Att, d_specular);\r\n", unconditionLightInfo.c_str() ),
|
||||
lightInfoBuffer, uvScene ) );
|
||||
|
||||
Var *rtShading = new Var;
|
||||
rtShading->setType( "vec4" );
|
||||
rtShading->setName( "rtShading" );
|
||||
LangElement *rtShadingDecl = new DecOp( rtShading );
|
||||
meta->addStatement( new GenOp( " @ = vec4( d_lightcolor, 1.0 );\r\n", rtShadingDecl ) );
|
||||
|
||||
// This is kind of weak sauce
|
||||
if( !fd.features[MFT_SubSurface] && !fd.features[MFT_ToneMap] && !fd.features[MFT_LightMap] )
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( rtShading, Material::Mul ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources DeferredRTLightingFeatGLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
/// TODO: This needs to be done via some sort of material
|
||||
/// feature and not just allow all translucent elements to
|
||||
/// read from the light prepass.
|
||||
/*
|
||||
if( fd.features[MFT_IsTranslucent] )
|
||||
return Parent::getResources( fd );
|
||||
*/
|
||||
|
||||
Resources res;
|
||||
res.numTex = 1;
|
||||
res.numTexReg = 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
void DeferredRTLightingFeatGLSL::setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex )
|
||||
{
|
||||
/// TODO: This needs to be done via some sort of material
|
||||
/// feature and not just allow all translucent elements to
|
||||
/// read from the light prepass.
|
||||
/*
|
||||
if( fd.features[MFT_IsTranslucent] )
|
||||
{
|
||||
Parent::setTexData( stageDat, fd, passData, texIndex );
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find( AdvancedLightBinManager::smBufferName );
|
||||
if( texTarget )
|
||||
{
|
||||
passData.mTexType[ texIndex ] = Material::TexTarget;
|
||||
passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeferredBumpFeatGLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_PrePassConditioner] )
|
||||
{
|
||||
// There is an output conditioner active, so we need to supply a transform
|
||||
// to the pixel shader.
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
// setup texture space matrix
|
||||
Var *texSpaceMat = (Var*) LangElement::find( "objToTangentSpace" );
|
||||
if( !texSpaceMat )
|
||||
{
|
||||
LangElement * texSpaceSetup = setupTexSpaceMat( componentList, &texSpaceMat );
|
||||
meta->addStatement( texSpaceSetup );
|
||||
texSpaceMat = (Var*) LangElement::find( "objToTangentSpace" );
|
||||
}
|
||||
|
||||
// turn obj->tangent into world->tangent
|
||||
Var *worldToTangent = new Var;
|
||||
worldToTangent->setType( "mat3" );
|
||||
worldToTangent->setName( "worldToTangent" );
|
||||
LangElement *worldToTangentDecl = new DecOp( worldToTangent );
|
||||
|
||||
// Get the world->obj transform
|
||||
Var *worldToObj = new Var;
|
||||
worldToObj->setType( "mat4" );
|
||||
worldToObj->setName( "worldToObj" );
|
||||
worldToObj->uniform = true;
|
||||
worldToObj->constSortPos = cspPrimitive;
|
||||
|
||||
Var *mat3Conversion = new Var;
|
||||
mat3Conversion->setType( "mat3" );
|
||||
mat3Conversion->setName( "worldToObjMat3" );
|
||||
LangElement* mat3Lang = new DecOp(mat3Conversion);
|
||||
meta->addStatement( new GenOp( " @ = mat3(@[0].xyz, @[1].xyz, @[2].xyz);\r\n ", mat3Lang, worldToObj, worldToObj, worldToObj) );
|
||||
|
||||
// assign world->tangent transform
|
||||
meta->addStatement( new GenOp( " @ = @ * @;\r\n", worldToTangentDecl, texSpaceMat, mat3Conversion ) );
|
||||
|
||||
// send transform to pixel shader
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
|
||||
Var *worldToTangentR1 = connectComp->getElement( RT_TEXCOORD );
|
||||
worldToTangentR1->setName( "worldToTangentR1" );
|
||||
worldToTangentR1->setType( "vec3" );
|
||||
meta->addStatement( new GenOp( " @ = @[0];\r\n", worldToTangentR1, worldToTangent ) );
|
||||
|
||||
Var *worldToTangentR2 = connectComp->getElement( RT_TEXCOORD );
|
||||
worldToTangentR2->setName( "worldToTangentR2" );
|
||||
worldToTangentR2->setType( "vec3" );
|
||||
meta->addStatement( new GenOp( " @ = @[1];\r\n", worldToTangentR2, worldToTangent ) );
|
||||
|
||||
Var *worldToTangentR3 = connectComp->getElement( RT_TEXCOORD );
|
||||
worldToTangentR3->setName( "worldToTangentR3" );
|
||||
worldToTangentR3->setType( "vec3" );
|
||||
meta->addStatement( new GenOp( " @ = @[2];\r\n", worldToTangentR3, worldToTangent ) );
|
||||
|
||||
// Make sure there are texcoords
|
||||
if( !fd.features[MFT_DiffuseMap] )
|
||||
{
|
||||
// find incoming texture var
|
||||
Var *inTex = getVertTexCoord( "texCoord" );
|
||||
|
||||
// grab connector texcoord register
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *outTex = connectComp->getElement( RT_TEXCOORD );
|
||||
outTex->setName( "outTexCoord" );
|
||||
outTex->setType( "vec2" );
|
||||
outTex->mapsToSampler = true;
|
||||
|
||||
if( fd.features[MFT_TexAnim] )
|
||||
{
|
||||
inTex->setType( "vec4" );
|
||||
|
||||
// create texture mat var
|
||||
Var *texMat = new Var;
|
||||
texMat->setType( "mat4" );
|
||||
texMat->setName( "texMat" );
|
||||
texMat->uniform = true;
|
||||
texMat->constSortPos = cspPotentialPrimitive;
|
||||
|
||||
meta->addStatement( new GenOp( " @ = @ * @;\r\n", outTex, texMat, inTex ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// setup language elements to output incoming tex coords to output
|
||||
meta->addStatement( new GenOp( " @ = @;\r\n", outTex, inTex ) );
|
||||
}
|
||||
}
|
||||
|
||||
output = meta;
|
||||
}
|
||||
else if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_IsTranslucent] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processVert( componentList, fd );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
output = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredBumpFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// NULL output in case nothing gets handled
|
||||
output = NULL;
|
||||
|
||||
if( fd.features[MFT_PrePassConditioner] )
|
||||
{
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
// Pull the world->tangent transform from the vertex shader
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
|
||||
Var *worldToTangentR1 = connectComp->getElement( RT_TEXCOORD );
|
||||
worldToTangentR1->setName( "worldToTangentR1" );
|
||||
worldToTangentR1->setType( "vec3" );
|
||||
|
||||
Var *worldToTangentR2 = connectComp->getElement( RT_TEXCOORD );
|
||||
worldToTangentR2->setName( "worldToTangentR2" );
|
||||
worldToTangentR2->setType( "vec3" );
|
||||
|
||||
Var *worldToTangentR3 = connectComp->getElement( RT_TEXCOORD );
|
||||
worldToTangentR3->setName( "worldToTangentR3" );
|
||||
worldToTangentR3->setType( "vec3" );
|
||||
|
||||
Var *worldToTangent = new Var;
|
||||
worldToTangent->setType( "mat3" );
|
||||
worldToTangent->setName( "worldToTangent" );
|
||||
LangElement *worldToTangentDecl = new DecOp( worldToTangent );
|
||||
|
||||
// Build world->tangent matrix
|
||||
meta->addStatement( new GenOp( " @;\r\n", worldToTangentDecl ) );
|
||||
meta->addStatement( new GenOp( " @[0] = @;\r\n", worldToTangent, worldToTangentR1 ) );
|
||||
meta->addStatement( new GenOp( " @[1] = @;\r\n", worldToTangent, worldToTangentR2 ) );
|
||||
meta->addStatement( new GenOp( " @[2] = @;\r\n", worldToTangent, worldToTangentR3 ) );
|
||||
|
||||
// create texture var
|
||||
Var *bumpMap = new Var;
|
||||
bumpMap->setType( "sampler2D" );
|
||||
bumpMap->setName( "bumpMap" );
|
||||
bumpMap->uniform = true;
|
||||
bumpMap->sampler = true;
|
||||
bumpMap->constNum = Var::getTexUnitNum(); // used as texture unit num here
|
||||
|
||||
Var *texCoord = (Var*) LangElement::find( "outTexCoord" );
|
||||
if( !texCoord )
|
||||
{
|
||||
// grab connector texcoord register
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
texCoord = connectComp->getElement( RT_TEXCOORD );
|
||||
texCoord->setName( "outTexCoord" );
|
||||
texCoord->setType( "vec2" );
|
||||
texCoord->mapsToSampler = true;
|
||||
}
|
||||
|
||||
LangElement * texOp = new GenOp( "texture2D(@, @)", bumpMap, texCoord );
|
||||
|
||||
// create bump normal
|
||||
Var *bumpNorm = new Var;
|
||||
bumpNorm->setName( "bumpNormal" );
|
||||
bumpNorm->setType( "vec4" );
|
||||
|
||||
LangElement *bumpNormDecl = new DecOp( bumpNorm );
|
||||
meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) );
|
||||
|
||||
// This var is read from GBufferConditionerHLSL and
|
||||
// used in the prepass output.
|
||||
Var *gbNormal = new Var;
|
||||
gbNormal->setName( "gbNormal" );
|
||||
gbNormal->setType( "vec3" );
|
||||
LangElement *gbNormalDecl = new DecOp( gbNormal );
|
||||
|
||||
// Normalize is done later...
|
||||
// Note: The reverse mul order is intentional. Affine matrix.
|
||||
meta->addStatement( new GenOp( " @ = @.xyz * @;\r\n", gbNormalDecl, bumpNorm, worldToTangent ) );
|
||||
|
||||
output = meta;
|
||||
return;
|
||||
}
|
||||
else if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_IsTranslucent] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processPix( componentList, fd );
|
||||
return;
|
||||
}
|
||||
else if ( fd.features[MFT_PixSpecular] )
|
||||
{
|
||||
Var *bumpSample = (Var *)LangElement::find( "bumpSample" );
|
||||
if( bumpSample == NULL )
|
||||
{
|
||||
Var *texCoord = (Var*) LangElement::find( "outTexCoord" );
|
||||
if( !texCoord )
|
||||
{
|
||||
// grab connector texcoord register
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
texCoord = connectComp->getElement( RT_TEXCOORD );
|
||||
texCoord->setName( "outTexCoord" );
|
||||
texCoord->setType( "vec2" );
|
||||
texCoord->mapsToSampler = true;
|
||||
}
|
||||
|
||||
Var *bumpMap = new Var;
|
||||
bumpMap->setType( "sampler2D" );
|
||||
bumpMap->setName( "bumpMap" );
|
||||
bumpMap->uniform = true;
|
||||
bumpMap->sampler = true;
|
||||
bumpMap->constNum = Var::getTexUnitNum(); // used as texture unit num here
|
||||
|
||||
bumpSample = new Var;
|
||||
bumpSample->setType( "vec4" );
|
||||
bumpSample->setName( "bumpSample" );
|
||||
LangElement *bumpSampleDecl = new DecOp( bumpSample );
|
||||
|
||||
output = new GenOp( " @ = texture2D(@, @);\r\n", bumpSampleDecl, bumpMap, texCoord );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
output = NULL;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources DeferredBumpFeatGLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_IsTranslucent] ||
|
||||
fd.features[MFT_Parallax] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
return Parent::getResources( fd );
|
||||
|
||||
Resources res;
|
||||
if(!fd.features[MFT_SpecularMap])
|
||||
{
|
||||
res.numTex = 1;
|
||||
res.numTexReg = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void DeferredBumpFeatGLSL::setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex )
|
||||
{
|
||||
if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_IsTranslucent] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::setTexData( stageDat, fd, passData, texIndex );
|
||||
return;
|
||||
}
|
||||
|
||||
GFXTextureObject *normalMap = stageDat.getTex( MFT_NormalMap );
|
||||
if ( !fd.features[MFT_Parallax] && !fd.features[MFT_SpecularMap] &&
|
||||
( fd.features[MFT_PrePassConditioner] ||
|
||||
fd.features[MFT_PixSpecular] ) &&
|
||||
normalMap )
|
||||
{
|
||||
passData.mTexType[ texIndex ] = Material::Bump;
|
||||
passData.mTexSlot[ texIndex++ ].texObject = normalMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeferredPixelSpecularGLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_IsTranslucent] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processVert( componentList, fd );
|
||||
return;
|
||||
}
|
||||
output = NULL;
|
||||
}
|
||||
|
||||
void DeferredPixelSpecularGLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_IsTranslucent] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processPix( componentList, fd );
|
||||
return;
|
||||
}
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
Var *specular = new Var;
|
||||
specular->setType( "float" );
|
||||
specular->setName( "specular" );
|
||||
LangElement * specDecl = new DecOp( specular );
|
||||
|
||||
Var *specCol = (Var*)LangElement::find( "specularColor" );
|
||||
if(specCol == NULL)
|
||||
{
|
||||
specCol = new Var;
|
||||
specCol->setType( "vec4" );
|
||||
specCol->setName( "specularColor" );
|
||||
specCol->uniform = true;
|
||||
specCol->constSortPos = cspPotentialPrimitive;
|
||||
}
|
||||
|
||||
Var *specPow = new Var;
|
||||
specPow->setType( "float" );
|
||||
specPow->setName( "specularPower" );
|
||||
|
||||
// If the gloss map flag is set, than the specular power is in the alpha
|
||||
// channel of the specular map
|
||||
if( fd.features[ MFT_GlossMap ] )
|
||||
meta->addStatement( new GenOp( " @ = @.a * 255;\r\n", new DecOp( specPow ), specCol ) );
|
||||
else
|
||||
{
|
||||
specPow->uniform = true;
|
||||
specPow->constSortPos = cspPotentialPrimitive;
|
||||
}
|
||||
|
||||
Var *constSpecPow = new Var;
|
||||
constSpecPow->setType( "float" );
|
||||
constSpecPow->setName( "constantSpecularPower" );
|
||||
constSpecPow->uniform = true;
|
||||
constSpecPow->constSortPos = cspPass;
|
||||
|
||||
Var *lightInfoSamp = (Var *)LangElement::find( "lightInfoSample" );
|
||||
AssertFatal( lightInfoSamp, "Something hosed the deferred features! Can't find lightInfoSample" );
|
||||
|
||||
// (a^m)^n = a^(m*n)
|
||||
meta->addStatement( new GenOp( " @ = pow(d_specular, ceil(@ / @)) * d_NL_Att;\r\n", specDecl, specPow, constSpecPow ) );
|
||||
|
||||
LangElement *specMul = new GenOp( "@ * @", specCol, specular );
|
||||
LangElement *final = specMul;
|
||||
|
||||
// We we have a normal map then mask the specular
|
||||
if( !fd.features[MFT_SpecularMap] && fd.features[MFT_NormalMap] )
|
||||
{
|
||||
Var *bumpSample = (Var*)LangElement::find( "bumpSample" );
|
||||
final = new GenOp( "@ * @.a", final, bumpSample );
|
||||
}
|
||||
|
||||
// add to color
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( final, Material::Add ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources DeferredPixelSpecularGLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_IsTranslucent] || !fd.features[MFT_RTLighting] )
|
||||
return Parent::getResources( fd );
|
||||
|
||||
Resources res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ShaderFeature::Resources DeferredMinnaertGLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
Resources res;
|
||||
if( !fd.features[MFT_IsTranslucent] && fd.features[MFT_RTLighting] )
|
||||
{
|
||||
res.numTex = 1;
|
||||
res.numTexReg = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void DeferredMinnaertGLSL::setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex )
|
||||
{
|
||||
if( !fd.features[MFT_IsTranslucent] && fd.features[MFT_RTLighting] )
|
||||
{
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find(RenderPrePassMgr::BufferName);
|
||||
if ( texTarget )
|
||||
{
|
||||
passData.mTexType[ texIndex ] = Material::TexTarget;
|
||||
passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredMinnaertGLSL::processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( !fd.features[MFT_IsTranslucent] && fd.features[MFT_RTLighting] )
|
||||
{
|
||||
// Pull in the uncondition method for the g buffer
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find( RenderPrePassMgr::BufferName );
|
||||
if ( texTarget && texTarget->getConditioner() )
|
||||
{
|
||||
ConditionerMethodDependency *unconditionMethod = texTarget->getConditioner()->getConditionerMethodDependency(ConditionerFeature::UnconditionMethod);
|
||||
unconditionMethod->createMethodMacro( String::ToLower(RenderPrePassMgr::BufferName) + "Uncondition", macros );
|
||||
addDependency(unconditionMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredMinnaertGLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If there is no deferred information, bail on this feature
|
||||
if( fd.features[MFT_IsTranslucent] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
output = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// grab incoming vert position
|
||||
Var *inVertPos = (Var*) LangElement::find( "position" );
|
||||
AssertFatal( inVertPos, "Something went bad with ShaderGen. The vertex position should be already defined." );
|
||||
|
||||
// grab output for gbuffer normal
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *outWSEyeVec= connectComp->getElement( RT_TEXCOORD );
|
||||
outWSEyeVec->setName( "outWSViewVec" );
|
||||
outWSEyeVec->setType( "vec4" );
|
||||
|
||||
// create objToWorld variable
|
||||
Var *objToWorld = (Var*) LangElement::find( "objTrans" );
|
||||
if( !objToWorld )
|
||||
{
|
||||
objToWorld = new Var;
|
||||
objToWorld->setType( "mat4x4" );
|
||||
objToWorld->setName( "objTrans" );
|
||||
objToWorld->uniform = true;
|
||||
objToWorld->constSortPos = cspPrimitive;
|
||||
}
|
||||
|
||||
// Eye Pos world
|
||||
Var *eyePosWorld = (Var*) LangElement::find( "eyePosWorld" );
|
||||
if( !eyePosWorld )
|
||||
{
|
||||
eyePosWorld = new Var;
|
||||
eyePosWorld->setType( "vec3" );
|
||||
eyePosWorld->setName( "eyePosWorld" );
|
||||
eyePosWorld->uniform = true;
|
||||
eyePosWorld->constSortPos = cspPass;
|
||||
}
|
||||
|
||||
// Kick out the world-space normal
|
||||
LangElement *statement = new GenOp( " @ = vec4(@, @) - vec4(@, 0.0);\r\n",
|
||||
outWSEyeVec, objToWorld, inVertPos, eyePosWorld );
|
||||
output = statement;
|
||||
}
|
||||
|
||||
void DeferredMinnaertGLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If there is no deferred information, bail on this feature
|
||||
if( fd.features[MFT_IsTranslucent] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
output = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
Var *minnaertConstant = new Var;
|
||||
minnaertConstant->setType( "float" );
|
||||
minnaertConstant->setName( "minnaertConstant" );
|
||||
minnaertConstant->uniform = true;
|
||||
minnaertConstant->constSortPos = cspPotentialPrimitive;
|
||||
|
||||
// create texture var
|
||||
Var *prepassBuffer = new Var;
|
||||
prepassBuffer->setType( "sampler2D" );
|
||||
prepassBuffer->setName( "prepassBuffer" );
|
||||
prepassBuffer->uniform = true;
|
||||
prepassBuffer->sampler = true;
|
||||
prepassBuffer->constNum = Var::getTexUnitNum(); // used as texture unit num here
|
||||
|
||||
// Texture coord
|
||||
Var *uvScene = (Var*) LangElement::find( "uvScene" );
|
||||
AssertFatal(uvScene != NULL, "Unable to find UVScene, no RTLighting feature?");
|
||||
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *wsViewVec = (Var*) LangElement::find( "wsPos" );
|
||||
if( !wsViewVec )
|
||||
{
|
||||
wsViewVec = connectComp->getElement( RT_TEXCOORD );
|
||||
wsViewVec->setName( "outWSViewVec" );
|
||||
wsViewVec->setType( "vec4" );
|
||||
wsViewVec->mapsToSampler = false;
|
||||
wsViewVec->uniform = false;
|
||||
}
|
||||
|
||||
String unconditionPrePassMethod = String::ToLower(RenderPrePassMgr::BufferName) + "Uncondition";
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
meta->addStatement( new GenOp( avar( " vec4 normalDepth = %s(texture2D(@, @));\r\n", unconditionPrePassMethod.c_str() ), prepassBuffer, uvScene ) );
|
||||
meta->addStatement( new GenOp( " vec3 worldViewVec = normalize(@.xyz / @.w);\r\n", wsViewVec, wsViewVec ) );
|
||||
meta->addStatement( new GenOp( " float vDotN = dot(normalDepth.xyz, worldViewVec);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float Minnaert = pow(d_NL_Att, @) * pow(vDotN, 1.0 - @);\r\n", minnaertConstant, minnaertConstant ) );
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( new GenOp( "vec4(Minnaert, Minnaert, Minnaert, 1.0)" ), Material::Mul ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
|
||||
void DeferredSubSurfaceGLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If there is no deferred information, bail on this feature
|
||||
if( fd.features[MFT_IsTranslucent] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
output = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
Var *subSurfaceParams = new Var;
|
||||
subSurfaceParams->setType( "vec4" );
|
||||
subSurfaceParams->setName( "subSurfaceParams" );
|
||||
subSurfaceParams->uniform = true;
|
||||
subSurfaceParams->constSortPos = cspPotentialPrimitive;
|
||||
|
||||
Var *inColor = (Var*) LangElement::find( "rtShading" );
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
meta->addStatement( new GenOp( " float subLamb = smoothstep(-@.a, 1.0, d_NL_Att) - smoothstep(0.0, 1.0, d_NL_Att);\r\n", subSurfaceParams ) );
|
||||
meta->addStatement( new GenOp( " subLamb = max(0.0, subLamb);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( new GenOp( "vec4(@.rgb + (subLamb * @.rgb), 1.0)", inColor, subSurfaceParams ), Material::Mul ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _DEFERREDFEATURESGLSL_H_
|
||||
#define _DEFERREDFEATURESGLSL_H_
|
||||
|
||||
#include "shaderGen/GLSL/shaderFeatureGLSL.h"
|
||||
#include "shaderGen/GLSL/bumpGLSL.h"
|
||||
#include "shaderGen/GLSL/pixSpecularGLSL.h"
|
||||
|
||||
class ConditionerMethodDependency;
|
||||
|
||||
|
||||
/// Lights the pixel by sampling from the light prepass buffer. It will
|
||||
/// fall back to default vertex lighting functionality if
|
||||
class DeferredRTLightingFeatGLSL : public RTLightingFeatGLSL
|
||||
{
|
||||
typedef RTLightingFeatGLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Material::BlendOp getBlendOp(){ return Material::None; }
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual void setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Deferred RT Lighting Feature";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Used to write the normals during the depth/normal prepass.
|
||||
class DeferredBumpFeatGLSL : public BumpFeatGLSL
|
||||
{
|
||||
typedef BumpFeatGLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Material::BlendOp getBlendOp() { return Material::LerpAlpha; }
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual void setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Bumpmap [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Generates specular highlights in the forward pass
|
||||
/// from the light prepass buffer.
|
||||
class DeferredPixelSpecularGLSL : public PixelSpecularGLSL
|
||||
{
|
||||
typedef PixelSpecularGLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Pixel Specular [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
class DeferredMinnaertGLSL : public ShaderFeatureGLSL
|
||||
{
|
||||
typedef ShaderFeatureGLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual void setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Minnaert Shading [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
class DeferredSubSurfaceGLSL : public ShaderFeatureGLSL
|
||||
{
|
||||
typedef ShaderFeatureGLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Sub-Surface Approximation [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _DEFERREDFEATURESGLSL_H_
|
||||
320
Engine/source/lighting/advanced/glsl/gBufferConditionerGLSL.cpp
Normal file
320
Engine/source/lighting/advanced/glsl/gBufferConditionerGLSL.cpp
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/glsl/gBufferConditionerGLSL.h"
|
||||
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "gfx/gfxStringEnumTranslate.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "materials/materialFeatureData.h"
|
||||
|
||||
|
||||
GBufferConditionerGLSL::GBufferConditionerGLSL( const GFXFormat bufferFormat ) :
|
||||
Parent( bufferFormat )
|
||||
{
|
||||
// Figure out how we should store the normal data. These are the defaults.
|
||||
mCanWriteNegativeValues = false;
|
||||
mNormalStorageType = CartesianXYZ;
|
||||
|
||||
// Note: We clear to a depth 1 (the w component) so
|
||||
// that the unrendered parts of the scene end up
|
||||
// farthest to the camera.
|
||||
|
||||
switch(bufferFormat)
|
||||
{
|
||||
case GFXFormatR8G8B8A8:
|
||||
// TODO: Some kind of logic here. Spherical is better, but is more
|
||||
// expensive.
|
||||
mNormalStorageType = Spherical;
|
||||
mBitsPerChannel = 8;
|
||||
break;
|
||||
|
||||
case GFXFormatR16G16B16A16F:
|
||||
// Floating point buffers don't need to encode negative values
|
||||
mCanWriteNegativeValues = true;
|
||||
mNormalStorageType = Spherical;
|
||||
mBitsPerChannel = 16;
|
||||
break;
|
||||
|
||||
// Store a 32bit depth with a sperical normal in the
|
||||
// integer 16 format. This gives us perfect depth
|
||||
// precision and high quality normals within a 64bit
|
||||
// buffer format.
|
||||
case GFXFormatR16G16B16A16:
|
||||
mNormalStorageType = Spherical;
|
||||
mBitsPerChannel = 16;
|
||||
break;
|
||||
|
||||
case GFXFormatR32G32B32A32F:
|
||||
mCanWriteNegativeValues = true;
|
||||
mNormalStorageType = CartesianXYZ;
|
||||
mBitsPerChannel = 32;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Unsupported G-Buffer format");
|
||||
}
|
||||
}
|
||||
|
||||
GBufferConditionerGLSL::~GBufferConditionerGLSL()
|
||||
{
|
||||
}
|
||||
|
||||
void GBufferConditionerGLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
output = NULL;
|
||||
|
||||
if( !fd.features[MFT_NormalMap] )
|
||||
{
|
||||
// grab incoming vert normal
|
||||
Var *inNormal = (Var*) LangElement::find( "normal" );
|
||||
AssertFatal( inNormal, "Something went bad with ShaderGen. The normal should be already defined." );
|
||||
|
||||
// grab output for gbuffer normal
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *outNormal = connectComp->getElement( RT_TEXCOORD );
|
||||
outNormal->setName( "gbNormal" );
|
||||
outNormal->setType( "vec3" );
|
||||
|
||||
// create objToWorld variable
|
||||
Var *objToWorld = (Var*) LangElement::find( "objTrans" );
|
||||
if( !objToWorld )
|
||||
{
|
||||
objToWorld = new Var;
|
||||
objToWorld->setType( "mat4" );
|
||||
objToWorld->setName( "objTrans" );
|
||||
objToWorld->uniform = true;
|
||||
objToWorld->constSortPos = cspPrimitive;
|
||||
}
|
||||
|
||||
// Kick out the world-space normal
|
||||
LangElement *statement = new GenOp( " @ = vec3(@ * vec4(normalize(@), 0.0));\r\n", outNormal, objToWorld, inNormal );
|
||||
output = statement;
|
||||
}
|
||||
}
|
||||
|
||||
void GBufferConditionerGLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// sanity
|
||||
AssertFatal( fd.features[MFT_EyeSpaceDepthOut], "No depth-out feature enabled! Bad news!" );
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
// grab connector normal
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *gbNormal = (Var*) LangElement::find( "gbNormal" );
|
||||
if( !gbNormal )
|
||||
{
|
||||
gbNormal = connectComp->getElement( RT_TEXCOORD );
|
||||
gbNormal->setName( "gbNormal" );
|
||||
gbNormal->setType( "vec3" );
|
||||
gbNormal->mapsToSampler = false;
|
||||
gbNormal->uniform = false;
|
||||
}
|
||||
|
||||
// find depth
|
||||
ShaderFeature *depthFeat = FEATUREMGR->getByType( MFT_EyeSpaceDepthOut );
|
||||
AssertFatal( depthFeat != NULL, "No eye space depth feature found!" );
|
||||
|
||||
Var *depth = (Var*) LangElement::find(depthFeat->getOutputVarName());
|
||||
AssertFatal( depth, "Something went bad with ShaderGen. The depth should be already generated by the EyeSpaceDepthOut feature." );
|
||||
|
||||
|
||||
Var *unconditionedOut = new Var;
|
||||
unconditionedOut->setType("vec4");
|
||||
unconditionedOut->setName("normal_depth");
|
||||
|
||||
LangElement *outputDecl = new DecOp( unconditionedOut );
|
||||
|
||||
// NOTE: We renormalize the normal here as they
|
||||
// will not stay normalized during interpolation.
|
||||
meta->addStatement( new GenOp(" @ = @;", outputDecl, new GenOp( "vec4(normalize(@), @)", gbNormal, depth ) ) );
|
||||
meta->addStatement( assignOutput( unconditionedOut ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources GBufferConditionerGLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
Resources res;
|
||||
|
||||
// Passing from VS->PS:
|
||||
// - world space normal (gbNormal)
|
||||
res.numTexReg = 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Var* GBufferConditionerGLSL::printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta )
|
||||
{
|
||||
const bool isCondition = ( methodType == ConditionerFeature::ConditionMethod );
|
||||
|
||||
Var *retVal = NULL;
|
||||
|
||||
// The uncondition method inputs are changed
|
||||
if( isCondition )
|
||||
retVal = Parent::printMethodHeader( methodType, methodName, stream, meta );
|
||||
else
|
||||
{
|
||||
Var *methodVar = new Var;
|
||||
methodVar->setName(methodName);
|
||||
methodVar->setType("vec4");
|
||||
DecOp *methodDecl = new DecOp(methodVar);
|
||||
|
||||
Var *prepassSampler = new Var;
|
||||
prepassSampler->setName("prepassSamplerVar");
|
||||
prepassSampler->setType("sampler2D");
|
||||
DecOp *prepassSamplerDecl = new DecOp(prepassSampler);
|
||||
|
||||
Var *screenUV = new Var;
|
||||
screenUV->setName("screenUVVar");
|
||||
screenUV->setType("vec2");
|
||||
DecOp *screenUVDecl = new DecOp(screenUV);
|
||||
|
||||
Var *bufferSample = new Var;
|
||||
bufferSample->setName("bufferSample");
|
||||
bufferSample->setType("vec4");
|
||||
DecOp *bufferSampleDecl = new DecOp(bufferSample);
|
||||
|
||||
meta->addStatement( new GenOp( "@(@, @)\r\n", methodDecl, prepassSamplerDecl, screenUVDecl ) );
|
||||
|
||||
meta->addStatement( new GenOp( "{\r\n" ) );
|
||||
|
||||
meta->addStatement( new GenOp( " // Sampler g-buffer\r\n" ) );
|
||||
|
||||
// The gbuffer has no mipmaps, so use tex2dlod when
|
||||
// so that the shader compiler can optimize.
|
||||
meta->addStatement( new GenOp( " @ = texture2DLod(@, @, 0.0);\r\n", bufferSampleDecl, prepassSampler, screenUV ) );
|
||||
|
||||
// We don't use this way of passing var's around, so this should cause a crash
|
||||
// if something uses this improperly
|
||||
retVal = bufferSample;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
GenOp* GBufferConditionerGLSL::_posnegEncode( GenOp *val )
|
||||
{
|
||||
return mCanWriteNegativeValues ? val : new GenOp("0.5 * (@ + 1.0)", val);
|
||||
}
|
||||
|
||||
GenOp* GBufferConditionerGLSL::_posnegDecode( GenOp *val )
|
||||
{
|
||||
return mCanWriteNegativeValues ? val : new GenOp("@ * 2.0 - 1.0", val);
|
||||
}
|
||||
|
||||
Var* GBufferConditionerGLSL::_conditionOutput( Var *unconditionedOutput, MultiLine *meta )
|
||||
{
|
||||
Var *retVar = new Var;
|
||||
retVar->setType("vec4");
|
||||
retVar->setName("_gbConditionedOutput");
|
||||
LangElement *outputDecl = new DecOp( retVar );
|
||||
|
||||
switch(mNormalStorageType)
|
||||
{
|
||||
case CartesianXYZ:
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.xyz, depth)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl,
|
||||
_posnegEncode(new GenOp("@.xyz", unconditionedOutput)), unconditionedOutput ) );
|
||||
break;
|
||||
|
||||
case CartesianXY:
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = vec4(@, @.a);", outputDecl,
|
||||
_posnegEncode(new GenOp("vec3(@.xy, sign(@.z))", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) );
|
||||
break;
|
||||
|
||||
case Spherical:
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = vec4(@, 0.0, @.a);\r\n", outputDecl,
|
||||
_posnegEncode(new GenOp("vec2(atan2(@.y, @.x) / 3.14159265358979323846f, @.z)", unconditionedOutput, unconditionedOutput, unconditionedOutput ) ),
|
||||
unconditionedOutput ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Encode depth into two channels
|
||||
if(mNormalStorageType != CartesianXYZ)
|
||||
{
|
||||
const U64 maxValPerChannel = 1 << mBitsPerChannel;
|
||||
const U64 extraVal = (maxValPerChannel * maxValPerChannel - 1) - (maxValPerChannel - 1) * 2;
|
||||
meta->addStatement( new GenOp( " \r\n // Encode depth into hi/lo\r\n" ) );
|
||||
meta->addStatement( new GenOp( avar( " vec3 _tempDepth = fract(@.a * vec3(1.0, %llu.0, %llu.0));\r\n", maxValPerChannel - 1, extraVal ),
|
||||
unconditionedOutput ) );
|
||||
meta->addStatement( new GenOp( avar( " @.zw = _tempDepth.xy - _tempDepth.yz * vec2(1.0/%llu.0, 1.0/%llu.0);\r\n\r\n", maxValPerChannel - 1, maxValPerChannel - 1 ),
|
||||
retVar ) );
|
||||
}
|
||||
|
||||
AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) );
|
||||
return retVar;
|
||||
}
|
||||
|
||||
Var* GBufferConditionerGLSL::_unconditionInput( Var *conditionedInput, MultiLine *meta )
|
||||
{
|
||||
Var *retVar = new Var;
|
||||
retVar->setType("vec4");
|
||||
retVar->setName("_gbUnconditionedInput");
|
||||
LangElement *outputDecl = new DecOp( retVar );
|
||||
|
||||
switch(mNormalStorageType)
|
||||
{
|
||||
case CartesianXYZ:
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: vec4(normal.xyz, depth)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl,
|
||||
_posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) );
|
||||
break;
|
||||
|
||||
case CartesianXY:
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: vec4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl,
|
||||
_posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) );
|
||||
meta->addStatement( new GenOp( " @.z *= sqrt(1.0 - dot(@.xy, @.xy));\r\n", retVar, retVar, retVar ) );
|
||||
break;
|
||||
|
||||
case Spherical:
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: vec4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " vec2 spGPUAngles = @;\r\n", _posnegDecode(new GenOp("@.xy", conditionedInput)) ) );
|
||||
meta->addStatement( new GenOp( " vec2 sincosTheta;\r\n" ) );
|
||||
meta->addStatement( new GenOp( " sincosTheta.x = sin(spGPUAngles.x * 3.14159265358979323846);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " sincosTheta.y = cos(spGPUAngles.x * 3.14159265358979323846);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " vec2 sincosPhi = vec2(sqrt(1.0 - spGPUAngles.y * spGPUAngles.y), spGPUAngles.y);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = vec4(sincosTheta.y * sincosPhi.x, sincosTheta.x * sincosPhi.x, sincosPhi.y, @.a);\r\n", outputDecl, conditionedInput ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Recover depth from encoding
|
||||
if(mNormalStorageType != CartesianXYZ)
|
||||
{
|
||||
const U64 maxValPerChannel = 1 << mBitsPerChannel;
|
||||
meta->addStatement( new GenOp( " \r\n // Decode depth\r\n" ) );
|
||||
meta->addStatement( new GenOp( avar( " @.w = dot( @.zw, vec2(1.0, 1.0/%llu.0));\r\n", maxValPerChannel - 1 ),
|
||||
retVar, conditionedInput ) );
|
||||
}
|
||||
|
||||
|
||||
AssertFatal( retVar != NULL, avar( "Cannot uncondition input from buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) );
|
||||
return retVar;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _GBUFFER_CONDITIONER_GLSL_H_
|
||||
#define _GBUFFER_CONDITIONER_GLSL_H_
|
||||
|
||||
#ifndef _CONDITIONER_BASE_H_
|
||||
#include "shaderGen/conditionerFeature.h"
|
||||
#endif
|
||||
#ifndef _SHADEROP_H_
|
||||
#include "shaderGen/shaderOp.h"
|
||||
#endif
|
||||
|
||||
|
||||
///
|
||||
class GBufferConditionerGLSL : public ConditionerFeature
|
||||
{
|
||||
typedef ConditionerFeature Parent;
|
||||
|
||||
public:
|
||||
enum NormalStorage
|
||||
{
|
||||
CartesianXYZ,
|
||||
CartesianXY,
|
||||
Spherical,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
NormalStorage mNormalStorageType;
|
||||
bool mCanWriteNegativeValues;
|
||||
U32 mBitsPerChannel;
|
||||
|
||||
public:
|
||||
|
||||
GBufferConditionerGLSL( const GFXFormat bufferFormat );
|
||||
virtual ~GBufferConditionerGLSL();
|
||||
|
||||
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd );
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd );
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
virtual String getName() { return "GBuffer Conditioner"; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual Var *printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta );
|
||||
|
||||
virtual GenOp* _posnegEncode( GenOp *val );
|
||||
virtual GenOp* _posnegDecode( GenOp *val );
|
||||
virtual Var* _conditionOutput( Var *unconditionedOutput, MultiLine *meta );
|
||||
virtual Var* _unconditionInput( Var *conditionedInput, MultiLine *meta );
|
||||
};
|
||||
|
||||
#endif // _GBUFFER_CONDITIONER_GLSL_H_
|
||||
|
|
@ -0,0 +1,636 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/hlsl/advancedLightingFeaturesHLSL.h"
|
||||
|
||||
#include "lighting/advanced/advancedLightBinManager.h"
|
||||
#include "shaderGen/langElement.h"
|
||||
#include "shaderGen/shaderOp.h"
|
||||
#include "shaderGen/conditionerFeature.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
#include "materials/processedMaterial.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
|
||||
|
||||
void DeferredRTLightingFeatHLSL::processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// Skip deferred features, and use forward shading instead
|
||||
if ( fd.features[MFT_ForwardShading] )
|
||||
{
|
||||
Parent::processPixMacros( macros, fd );
|
||||
return;
|
||||
}
|
||||
|
||||
// Pull in the uncondition method for the light info buffer
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find( AdvancedLightBinManager::smBufferName );
|
||||
if ( texTarget && texTarget->getConditioner() )
|
||||
{
|
||||
ConditionerMethodDependency *unconditionMethod = texTarget->getConditioner()->getConditionerMethodDependency(ConditionerFeature::UnconditionMethod);
|
||||
unconditionMethod->createMethodMacro( String::ToLower( AdvancedLightBinManager::smBufferName ) + "Uncondition", macros );
|
||||
addDependency(unconditionMethod);
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredRTLightingFeatHLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// Skip deferred features, and use forward shading instead
|
||||
if ( fd.features[MFT_ForwardShading] )
|
||||
{
|
||||
Parent::processVert( componentList, fd );
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass screen space position to pixel shader to compute a full screen buffer uv
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *ssPos = connectComp->getElement( RT_TEXCOORD );
|
||||
ssPos->setName( "screenspacePos" );
|
||||
ssPos->setStructName( "OUT" );
|
||||
ssPos->setType( "float4" );
|
||||
|
||||
Var *outPosition = (Var*) LangElement::find( "hpos" );
|
||||
AssertFatal( outPosition, "No hpos, ohnoes." );
|
||||
|
||||
output = new GenOp( " @ = @;\r\n", ssPos, outPosition );
|
||||
}
|
||||
|
||||
void DeferredRTLightingFeatHLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// Skip deferred features, and use forward shading instead
|
||||
if ( fd.features[MFT_ForwardShading] )
|
||||
{
|
||||
Parent::processPix( componentList, fd );
|
||||
return;
|
||||
}
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *ssPos = connectComp->getElement( RT_TEXCOORD );
|
||||
ssPos->setName( "screenspacePos" );
|
||||
ssPos->setStructName( "IN" );
|
||||
ssPos->setType( "float4" );
|
||||
|
||||
Var *uvScene = new Var;
|
||||
uvScene->setType( "float2" );
|
||||
uvScene->setName( "uvScene" );
|
||||
LangElement *uvSceneDecl = new DecOp( uvScene );
|
||||
|
||||
String rtParamName = String::ToString( "rtParams%d", mLastTexIndex );
|
||||
Var *rtParams = (Var*) LangElement::find( rtParamName );
|
||||
if( !rtParams )
|
||||
{
|
||||
rtParams = new Var;
|
||||
rtParams->setType( "float4" );
|
||||
rtParams->setName( rtParamName );
|
||||
rtParams->uniform = true;
|
||||
rtParams->constSortPos = cspPass;
|
||||
}
|
||||
|
||||
meta->addStatement( new GenOp( " @ = @.xy / @.w;\r\n", uvSceneDecl, ssPos, ssPos ) ); // get the screen coord... its -1 to +1
|
||||
meta->addStatement( new GenOp( " @ = ( @ + 1.0 ) / 2.0;\r\n", uvScene, uvScene ) ); // get the screen coord to 0 to 1
|
||||
meta->addStatement( new GenOp( " @.y = 1.0 - @.y;\r\n", uvScene, uvScene ) ); // flip the y axis
|
||||
meta->addStatement( new GenOp( " @ = ( @ * @.zw ) + @.xy;\r\n", uvScene, uvScene, rtParams, rtParams) ); // scale it down and offset it to the rt size
|
||||
|
||||
Var *lightInfoSamp = new Var;
|
||||
lightInfoSamp->setType( "float4" );
|
||||
lightInfoSamp->setName( "lightInfoSample" );
|
||||
|
||||
// create texture var
|
||||
Var *lightInfoBuffer = new Var;
|
||||
lightInfoBuffer->setType( "sampler2D" );
|
||||
lightInfoBuffer->setName( "lightInfoBuffer" );
|
||||
lightInfoBuffer->uniform = true;
|
||||
lightInfoBuffer->sampler = true;
|
||||
lightInfoBuffer->constNum = Var::getTexUnitNum(); // used as texture unit num here
|
||||
|
||||
// Declare the RTLighting variables in this feature, they will either be assigned
|
||||
// in this feature, or in the tonemap/lightmap feature
|
||||
Var *d_lightcolor = new Var( "d_lightcolor", "float3" );
|
||||
meta->addStatement( new GenOp( " @;\r\n", new DecOp( d_lightcolor ) ) );
|
||||
|
||||
Var *d_NL_Att = new Var( "d_NL_Att", "float" );
|
||||
meta->addStatement( new GenOp( " @;\r\n", new DecOp( d_NL_Att ) ) );
|
||||
|
||||
Var *d_specular = new Var( "d_specular", "float" );
|
||||
meta->addStatement( new GenOp( " @;\r\n", new DecOp( d_specular ) ) );
|
||||
|
||||
|
||||
// Perform the uncondition here.
|
||||
String unconditionLightInfo = String::ToLower( AdvancedLightBinManager::smBufferName ) + "Uncondition";
|
||||
meta->addStatement( new GenOp( avar( " %s(tex2D(@, @), @, @, @);\r\n",
|
||||
unconditionLightInfo.c_str() ), lightInfoBuffer, uvScene, d_lightcolor, d_NL_Att, d_specular ) );
|
||||
|
||||
// If this has an interlaced pre-pass, do averaging here
|
||||
if( fd.features[MFT_InterlacedPrePass] )
|
||||
{
|
||||
Var *oneOverTargetSize = (Var*) LangElement::find( "oneOverTargetSize" );
|
||||
if( !oneOverTargetSize )
|
||||
{
|
||||
oneOverTargetSize = new Var;
|
||||
oneOverTargetSize->setType( "float2" );
|
||||
oneOverTargetSize->setName( "oneOverTargetSize" );
|
||||
oneOverTargetSize->uniform = true;
|
||||
oneOverTargetSize->constSortPos = cspPass;
|
||||
}
|
||||
|
||||
meta->addStatement( new GenOp( " float id_NL_Att, id_specular;\r\n float3 id_lightcolor;\r\n" ) );
|
||||
meta->addStatement( new GenOp( avar( " %s(tex2D(@, @ + float2(0.0, @.y)), id_lightcolor, id_NL_Att, id_specular);\r\n",
|
||||
unconditionLightInfo.c_str() ), lightInfoBuffer, uvScene, oneOverTargetSize ) );
|
||||
|
||||
meta->addStatement( new GenOp(" @ = lerp(@, id_lightcolor, 0.5);\r\n", d_lightcolor, d_lightcolor ) );
|
||||
meta->addStatement( new GenOp(" @ = lerp(@, id_NL_Att, 0.5);\r\n", d_NL_Att, d_NL_Att ) );
|
||||
meta->addStatement( new GenOp(" @ = lerp(@, id_specular, 0.5);\r\n", d_specular, d_specular ) );
|
||||
}
|
||||
|
||||
// This is kind of weak sauce
|
||||
if( !fd.features[MFT_VertLit] && !fd.features[MFT_ToneMap] && !fd.features[MFT_LightMap] && !fd.features[MFT_SubSurface] )
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( new GenOp( "float4(@, 1.0)", d_lightcolor ), Material::Mul ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources DeferredRTLightingFeatHLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
// Skip deferred features, and use forward shading instead
|
||||
if ( fd.features[MFT_ForwardShading] )
|
||||
return Parent::getResources( fd );
|
||||
|
||||
// HACK: See DeferredRTLightingFeatHLSL::setTexData.
|
||||
mLastTexIndex = 0;
|
||||
|
||||
Resources res;
|
||||
res.numTex = 1;
|
||||
res.numTexReg = 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
void DeferredRTLightingFeatHLSL::setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex )
|
||||
{
|
||||
// Skip deferred features, and use forward shading instead
|
||||
if ( fd.features[MFT_ForwardShading] )
|
||||
{
|
||||
Parent::setTexData( stageDat, fd, passData, texIndex );
|
||||
return;
|
||||
}
|
||||
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find( AdvancedLightBinManager::smBufferName );
|
||||
if( texTarget )
|
||||
{
|
||||
// HACK: We store this for use in DeferredRTLightingFeatHLSL::processPix()
|
||||
// which cannot deduce the texture unit itself.
|
||||
mLastTexIndex = texIndex;
|
||||
|
||||
passData.mTexType[ texIndex ] = Material::TexTarget;
|
||||
passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeferredBumpFeatHLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_PrePassConditioner] )
|
||||
{
|
||||
// There is an output conditioner active, so we need to supply a transform
|
||||
// to the pixel shader.
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
// We need the view to tangent space transform in the pixel shader.
|
||||
getOutViewToTangent( componentList, meta, fd );
|
||||
|
||||
// Make sure there are texcoords
|
||||
if( !fd.features[MFT_Parallax] && !fd.features[MFT_DiffuseMap] )
|
||||
{
|
||||
const bool useTexAnim = fd.features[MFT_TexAnim];
|
||||
|
||||
getOutTexCoord( "texCoord",
|
||||
"float2",
|
||||
true,
|
||||
useTexAnim,
|
||||
meta,
|
||||
componentList );
|
||||
|
||||
if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
|
||||
addOutDetailTexCoord( componentList,
|
||||
meta,
|
||||
useTexAnim );
|
||||
}
|
||||
|
||||
output = meta;
|
||||
}
|
||||
else if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_ForwardShading] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processVert( componentList, fd );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
output = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredBumpFeatHLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// NULL output in case nothing gets handled
|
||||
output = NULL;
|
||||
|
||||
if( fd.features[MFT_PrePassConditioner] )
|
||||
{
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
Var *viewToTangent = getInViewToTangent( componentList );
|
||||
|
||||
// create texture var
|
||||
Var *bumpMap = getNormalMapTex();
|
||||
Var *texCoord = getInTexCoord( "texCoord", "float2", true, componentList );
|
||||
LangElement *texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
|
||||
|
||||
// create bump normal
|
||||
Var *bumpNorm = new Var;
|
||||
bumpNorm->setName( "bumpNormal" );
|
||||
bumpNorm->setType( "float4" );
|
||||
|
||||
LangElement *bumpNormDecl = new DecOp( bumpNorm );
|
||||
meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) );
|
||||
|
||||
// If we have a detail normal map we add the xy coords of
|
||||
// it to the base normal map. This gives us the effect we
|
||||
// want with few instructions and minial artifacts.
|
||||
if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
|
||||
{
|
||||
bumpMap = new Var;
|
||||
bumpMap->setType( "sampler2D" );
|
||||
bumpMap->setName( "detailBumpMap" );
|
||||
bumpMap->uniform = true;
|
||||
bumpMap->sampler = true;
|
||||
bumpMap->constNum = Var::getTexUnitNum();
|
||||
|
||||
texCoord = getInTexCoord( "detCoord", "float2", true, componentList );
|
||||
texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
|
||||
|
||||
Var *detailBump = new Var;
|
||||
detailBump->setName( "detailBump" );
|
||||
detailBump->setType( "float4" );
|
||||
meta->addStatement( expandNormalMap( texOp, new DecOp( detailBump ), detailBump, fd ) );
|
||||
|
||||
Var *detailBumpScale = new Var;
|
||||
detailBumpScale->setType( "float" );
|
||||
detailBumpScale->setName( "detailBumpStrength" );
|
||||
detailBumpScale->uniform = true;
|
||||
detailBumpScale->constSortPos = cspPass;
|
||||
meta->addStatement( new GenOp( " @.xy += @.xy * @;\r\n", bumpNorm, detailBump, detailBumpScale ) );
|
||||
}
|
||||
|
||||
// This var is read from GBufferConditionerHLSL and
|
||||
// used in the prepass output.
|
||||
//
|
||||
// By using the 'half' type here we get a bunch of partial
|
||||
// precision optimized code on further operations on the normal
|
||||
// which helps alot on older Geforce cards.
|
||||
//
|
||||
Var *gbNormal = new Var;
|
||||
gbNormal->setName( "gbNormal" );
|
||||
gbNormal->setType( "half3" );
|
||||
LangElement *gbNormalDecl = new DecOp( gbNormal );
|
||||
|
||||
// Normalize is done later...
|
||||
// Note: The reverse mul order is intentional. Affine matrix.
|
||||
meta->addStatement( new GenOp( " @ = (half3)mul( @.xyz, @ );\r\n", gbNormalDecl, bumpNorm, viewToTangent ) );
|
||||
|
||||
output = meta;
|
||||
return;
|
||||
}
|
||||
else if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_ForwardShading] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processPix( componentList, fd );
|
||||
return;
|
||||
}
|
||||
else if ( fd.features[MFT_PixSpecular] && !fd.features[MFT_SpecularMap] )
|
||||
{
|
||||
Var *bumpSample = (Var *)LangElement::find( "bumpSample" );
|
||||
if( bumpSample == NULL )
|
||||
{
|
||||
Var *texCoord = getInTexCoord( "texCoord", "float2", true, componentList );
|
||||
|
||||
Var *bumpMap = getNormalMapTex();
|
||||
|
||||
bumpSample = new Var;
|
||||
bumpSample->setType( "float4" );
|
||||
bumpSample->setName( "bumpSample" );
|
||||
LangElement *bumpSampleDecl = new DecOp( bumpSample );
|
||||
|
||||
output = new GenOp( " @ = tex2D(@, @);\r\n", bumpSampleDecl, bumpMap, texCoord );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
output = NULL;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources DeferredBumpFeatHLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_ForwardShading] ||
|
||||
fd.features[MFT_Parallax] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
return Parent::getResources( fd );
|
||||
|
||||
Resources res;
|
||||
if(!fd.features[MFT_SpecularMap])
|
||||
{
|
||||
res.numTex = 1;
|
||||
res.numTexReg = 1;
|
||||
|
||||
if ( fd.features[MFT_PrePassConditioner] &&
|
||||
fd.features.hasFeature( MFT_DetailNormalMap ) )
|
||||
{
|
||||
res.numTex += 1;
|
||||
if ( !fd.features.hasFeature( MFT_DetailMap ) )
|
||||
res.numTexReg += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void DeferredBumpFeatHLSL::setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex )
|
||||
{
|
||||
if ( fd.materialFeatures[MFT_NormalsOut] ||
|
||||
fd.features[MFT_ForwardShading] ||
|
||||
!fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::setTexData( stageDat, fd, passData, texIndex );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !fd.features[MFT_Parallax] && !fd.features[MFT_SpecularMap] &&
|
||||
( fd.features[MFT_PrePassConditioner] ||
|
||||
fd.features[MFT_PixSpecular] ) )
|
||||
{
|
||||
passData.mTexType[ texIndex ] = Material::Bump;
|
||||
passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap );
|
||||
|
||||
if ( fd.features[MFT_PrePassConditioner] &&
|
||||
fd.features.hasFeature( MFT_DetailNormalMap ) )
|
||||
{
|
||||
passData.mTexType[ texIndex ] = Material::DetailBump;
|
||||
passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeferredPixelSpecularHLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_ForwardShading] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processVert( componentList, fd );
|
||||
return;
|
||||
}
|
||||
output = NULL;
|
||||
}
|
||||
|
||||
void DeferredPixelSpecularHLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_ForwardShading] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
Parent::processPix( componentList, fd );
|
||||
return;
|
||||
}
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
Var *specular = new Var;
|
||||
specular->setType( "float" );
|
||||
specular->setName( "specular" );
|
||||
LangElement * specDecl = new DecOp( specular );
|
||||
|
||||
Var *specCol = (Var*)LangElement::find( "specularColor" );
|
||||
if(specCol == NULL)
|
||||
{
|
||||
specCol = new Var;
|
||||
specCol->setType( "float4" );
|
||||
specCol->setName( "specularColor" );
|
||||
specCol->uniform = true;
|
||||
specCol->constSortPos = cspPotentialPrimitive;
|
||||
}
|
||||
|
||||
Var *specPow = new Var;
|
||||
specPow->setType( "float" );
|
||||
specPow->setName( "specularPower" );
|
||||
|
||||
// If the gloss map flag is set, than the specular power is in the alpha
|
||||
// channel of the specular map
|
||||
if( fd.features[ MFT_GlossMap ] )
|
||||
meta->addStatement( new GenOp( " @ = @.a * 255;\r\n", new DecOp( specPow ), specCol ) );
|
||||
else
|
||||
{
|
||||
specPow->uniform = true;
|
||||
specPow->constSortPos = cspPotentialPrimitive;
|
||||
}
|
||||
|
||||
Var *lightInfoSamp = (Var *)LangElement::find( "lightInfoSample" );
|
||||
Var *d_specular = (Var*)LangElement::find( "d_specular" );
|
||||
Var *d_NL_Att = (Var*)LangElement::find( "d_NL_Att" );
|
||||
|
||||
AssertFatal( lightInfoSamp && d_specular && d_NL_Att,
|
||||
"DeferredPixelSpecularHLSL::processPix - Something hosed the deferred features!" );
|
||||
|
||||
// (a^m)^n = a^(m*n)
|
||||
meta->addStatement( new GenOp( " @ = pow( @, ceil(@ / AL_ConstantSpecularPower)) * @;\r\n",
|
||||
specDecl, d_specular, specPow, d_NL_Att ) );
|
||||
|
||||
LangElement *specMul = new GenOp( "float4( @.rgb, 0 ) * @", specCol, specular );
|
||||
LangElement *final = specMul;
|
||||
|
||||
// We we have a normal map then mask the specular
|
||||
if( !fd.features[MFT_SpecularMap] && fd.features[MFT_NormalMap] )
|
||||
{
|
||||
Var *bumpSample = (Var*)LangElement::find( "bumpSample" );
|
||||
final = new GenOp( "@ * @.a", final, bumpSample );
|
||||
}
|
||||
|
||||
// add to color
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( final, Material::Add ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources DeferredPixelSpecularHLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
if( fd.features[MFT_ForwardShading] || !fd.features[MFT_RTLighting] )
|
||||
return Parent::getResources( fd );
|
||||
|
||||
Resources res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ShaderFeature::Resources DeferredMinnaertHLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
Resources res;
|
||||
if( !fd.features[MFT_ForwardShading] && fd.features[MFT_RTLighting] )
|
||||
{
|
||||
res.numTex = 1;
|
||||
res.numTexReg = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void DeferredMinnaertHLSL::setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex )
|
||||
{
|
||||
if( !fd.features[MFT_ForwardShading] && fd.features[MFT_RTLighting] )
|
||||
{
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find(RenderPrePassMgr::BufferName);
|
||||
if ( texTarget )
|
||||
{
|
||||
passData.mTexType[ texIndex ] = Material::TexTarget;
|
||||
passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredMinnaertHLSL::processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
if( !fd.features[MFT_ForwardShading] && fd.features[MFT_RTLighting] )
|
||||
{
|
||||
// Pull in the uncondition method for the g buffer
|
||||
NamedTexTarget *texTarget = NamedTexTarget::find( RenderPrePassMgr::BufferName );
|
||||
if ( texTarget && texTarget->getConditioner() )
|
||||
{
|
||||
ConditionerMethodDependency *unconditionMethod = texTarget->getConditioner()->getConditionerMethodDependency(ConditionerFeature::UnconditionMethod);
|
||||
unconditionMethod->createMethodMacro( String::ToLower(RenderPrePassMgr::BufferName) + "Uncondition", macros );
|
||||
addDependency(unconditionMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredMinnaertHLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If there is no deferred information, bail on this feature
|
||||
if( fd.features[MFT_ForwardShading] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
output = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we pass the world space position to the
|
||||
// pixel shader so we can calculate a view vector.
|
||||
MultiLine *meta = new MultiLine;
|
||||
addOutWsPosition( componentList, fd.features[MFT_UseInstancing], meta );
|
||||
output = meta;
|
||||
}
|
||||
|
||||
void DeferredMinnaertHLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If there is no deferred information, bail on this feature
|
||||
if( fd.features[MFT_ForwardShading] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
output = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
Var *minnaertConstant = new Var;
|
||||
minnaertConstant->setType( "float" );
|
||||
minnaertConstant->setName( "minnaertConstant" );
|
||||
minnaertConstant->uniform = true;
|
||||
minnaertConstant->constSortPos = cspPotentialPrimitive;
|
||||
|
||||
// create texture var
|
||||
Var *prepassBuffer = new Var;
|
||||
prepassBuffer->setType( "sampler2D" );
|
||||
prepassBuffer->setName( "prepassBuffer" );
|
||||
prepassBuffer->uniform = true;
|
||||
prepassBuffer->sampler = true;
|
||||
prepassBuffer->constNum = Var::getTexUnitNum(); // used as texture unit num here
|
||||
|
||||
// Texture coord
|
||||
Var *uvScene = (Var*) LangElement::find( "uvScene" );
|
||||
AssertFatal(uvScene != NULL, "Unable to find UVScene, no RTLighting feature?");
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
// Get the world space view vector.
|
||||
Var *wsViewVec = getWsView( getInWsPosition( componentList ), meta );
|
||||
|
||||
String unconditionPrePassMethod = String::ToLower(RenderPrePassMgr::BufferName) + "Uncondition";
|
||||
|
||||
Var *d_NL_Att = (Var*)LangElement::find( "d_NL_Att" );
|
||||
|
||||
meta->addStatement( new GenOp( avar( " float4 normalDepth = %s(@, @);\r\n", unconditionPrePassMethod.c_str() ), prepassBuffer, uvScene ) );
|
||||
meta->addStatement( new GenOp( " float vDotN = dot(normalDepth.xyz, @);\r\n", wsViewVec ) );
|
||||
meta->addStatement( new GenOp( " float Minnaert = pow( @, @) * pow(vDotN, 1.0 - @);\r\n", d_NL_Att, minnaertConstant, minnaertConstant ) );
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( new GenOp( "float4(Minnaert, Minnaert, Minnaert, 1.0)" ), Material::Mul ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
|
||||
void DeferredSubSurfaceHLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If there is no deferred information, bail on this feature
|
||||
if( fd.features[MFT_ForwardShading] || !fd.features[MFT_RTLighting] )
|
||||
{
|
||||
output = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
Var *subSurfaceParams = new Var;
|
||||
subSurfaceParams->setType( "float4" );
|
||||
subSurfaceParams->setName( "subSurfaceParams" );
|
||||
subSurfaceParams->uniform = true;
|
||||
subSurfaceParams->constSortPos = cspPotentialPrimitive;
|
||||
|
||||
Var *d_lightcolor = (Var*)LangElement::find( "d_lightcolor" );
|
||||
Var *d_NL_Att = (Var*)LangElement::find( "d_NL_Att" );
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
meta->addStatement( new GenOp( " float subLamb = smoothstep(-@.a, 1.0, @) - smoothstep(0.0, 1.0, @);\r\n", subSurfaceParams, d_NL_Att, d_NL_Att ) );
|
||||
meta->addStatement( new GenOp( " subLamb = max(0.0, subLamb);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @;\r\n", assignColor( new GenOp( "float4(@ + (subLamb * @.rgb), 1.0)", d_lightcolor, subSurfaceParams ), Material::Mul ) ) );
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _DEFERREDFEATURESHLSL_H_
|
||||
#define _DEFERREDFEATURESHLSL_H_
|
||||
|
||||
#include "shaderGen/HLSL/shaderFeatureHLSL.h"
|
||||
#include "shaderGen/HLSL/bumpHLSL.h"
|
||||
#include "shaderGen/HLSL/pixSpecularHLSL.h"
|
||||
|
||||
class ConditionerMethodDependency;
|
||||
|
||||
|
||||
/// Lights the pixel by sampling from the light prepass
|
||||
/// buffer. It will fall back to forward lighting
|
||||
/// functionality for non-deferred rendered surfaces.
|
||||
///
|
||||
/// Also note that this feature is only used in the
|
||||
/// forward rendering pass. It is not used during the
|
||||
/// prepass step.
|
||||
///
|
||||
class DeferredRTLightingFeatHLSL : public RTLightingFeatHLSL
|
||||
{
|
||||
typedef RTLightingFeatHLSL Parent;
|
||||
|
||||
protected:
|
||||
|
||||
/// @see DeferredRTLightingFeatHLSL::processPix()
|
||||
U32 mLastTexIndex;
|
||||
|
||||
public:
|
||||
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Material::BlendOp getBlendOp(){ return Material::None; }
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual void setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Deferred RT Lighting";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// This is used during the
|
||||
class DeferredBumpFeatHLSL : public BumpFeatHLSL
|
||||
{
|
||||
typedef BumpFeatHLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Material::BlendOp getBlendOp() { return Material::LerpAlpha; }
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual void setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Bumpmap [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Generates specular highlights in the forward pass
|
||||
/// from the light prepass buffer.
|
||||
class DeferredPixelSpecularHLSL : public PixelSpecularHLSL
|
||||
{
|
||||
typedef PixelSpecularHLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Pixel Specular [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
class DeferredMinnaertHLSL : public ShaderFeatureHLSL
|
||||
{
|
||||
typedef ShaderFeatureHLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual void processPixMacros( Vector<GFXShaderMacro> ¯os,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
|
||||
virtual void setTexData( Material::StageData &stageDat,
|
||||
const MaterialFeatureData &fd,
|
||||
RenderPassData &passData,
|
||||
U32 &texIndex );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Minnaert Shading [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
class DeferredSubSurfaceHLSL : public ShaderFeatureHLSL
|
||||
{
|
||||
typedef ShaderFeatureHLSL Parent;
|
||||
|
||||
public:
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd );
|
||||
|
||||
virtual String getName()
|
||||
{
|
||||
return "Sub-Surface Approximation [Deferred]";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _DEFERREDFEATURESHLSL_H_
|
||||
404
Engine/source/lighting/advanced/hlsl/gBufferConditionerHLSL.cpp
Normal file
404
Engine/source/lighting/advanced/hlsl/gBufferConditionerHLSL.cpp
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/advanced/hlsl/gBufferConditionerHLSL.h"
|
||||
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "gfx/gfxStringEnumTranslate.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "materials/materialFeatureData.h"
|
||||
#include "shaderGen/hlsl/shaderFeatureHLSL.h"
|
||||
|
||||
|
||||
GBufferConditionerHLSL::GBufferConditionerHLSL( const GFXFormat bufferFormat, const NormalSpace nrmSpace ) :
|
||||
Parent( bufferFormat )
|
||||
{
|
||||
// Figure out how we should store the normal data. These are the defaults.
|
||||
mCanWriteNegativeValues = false;
|
||||
mNormalStorageType = CartesianXYZ;
|
||||
|
||||
// Note: We clear to a depth 1 (the w component) so
|
||||
// that the unrendered parts of the scene end up
|
||||
// farthest to the camera.
|
||||
const NormalStorage &twoCmpNrmStorageType = ( nrmSpace == WorldSpace ? Spherical : LambertAzimuthal );
|
||||
switch(bufferFormat)
|
||||
{
|
||||
case GFXFormatR8G8B8A8:
|
||||
mNormalStorageType = twoCmpNrmStorageType;
|
||||
mBitsPerChannel = 8;
|
||||
break;
|
||||
|
||||
case GFXFormatR16G16B16A16F:
|
||||
// Floating point buffers don't need to encode negative values
|
||||
mCanWriteNegativeValues = true;
|
||||
mNormalStorageType = twoCmpNrmStorageType;
|
||||
mBitsPerChannel = 16;
|
||||
break;
|
||||
|
||||
// Store a 32bit depth with a sperical normal in the
|
||||
// integer 16 format. This gives us perfect depth
|
||||
// precision and high quality normals within a 64bit
|
||||
// buffer format.
|
||||
case GFXFormatR16G16B16A16:
|
||||
mNormalStorageType = twoCmpNrmStorageType;
|
||||
mBitsPerChannel = 16;
|
||||
break;
|
||||
|
||||
case GFXFormatR32G32B32A32F:
|
||||
mCanWriteNegativeValues = true;
|
||||
mNormalStorageType = CartesianXYZ;
|
||||
mBitsPerChannel = 32;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Unsupported G-Buffer format");
|
||||
}
|
||||
}
|
||||
|
||||
GBufferConditionerHLSL::~GBufferConditionerHLSL()
|
||||
{
|
||||
}
|
||||
|
||||
void GBufferConditionerHLSL::processVert( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// If we have a normal map then that feature will
|
||||
// take care of passing gbNormal to the pixel shader.
|
||||
if ( fd.features[MFT_NormalMap] )
|
||||
return;
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
output = meta;
|
||||
|
||||
// grab incoming vert normal
|
||||
Var *inNormal = (Var*) LangElement::find( "normal" );
|
||||
AssertFatal( inNormal, "Something went bad with ShaderGen. The normal should be already defined." );
|
||||
|
||||
// grab output for gbuffer normal
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *outNormal = connectComp->getElement( RT_TEXCOORD );
|
||||
outNormal->setName( "gbNormal" );
|
||||
outNormal->setStructName( "OUT" );
|
||||
outNormal->setType( "float3" );
|
||||
|
||||
if( !fd.features[MFT_ParticleNormal] )
|
||||
{
|
||||
// Kick out the view-space normal
|
||||
|
||||
// TODO: Total hack because Conditioner is directly derived
|
||||
// from ShaderFeature and not from ShaderFeatureHLSL.
|
||||
NamedFeatureHLSL dummy( String::EmptyString );
|
||||
dummy.mInstancingFormat = mInstancingFormat;
|
||||
Var *worldViewOnly = dummy.getWorldView( componentList, fd.features[MFT_UseInstancing], meta );
|
||||
|
||||
meta->addStatement( new GenOp(" @ = mul(@, float4( normalize(@), 0.0 ) ).xyz;\r\n",
|
||||
outNormal, worldViewOnly, inNormal ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume the particle normal generator has already put this in view space
|
||||
// and normalized it
|
||||
meta->addStatement( new GenOp( " @ = @;\r\n", outNormal, inNormal ) );
|
||||
}
|
||||
}
|
||||
|
||||
void GBufferConditionerHLSL::processPix( Vector<ShaderComponent*> &componentList,
|
||||
const MaterialFeatureData &fd )
|
||||
{
|
||||
// sanity
|
||||
AssertFatal( fd.features[MFT_EyeSpaceDepthOut], "No depth-out feature enabled! Bad news!" );
|
||||
|
||||
MultiLine *meta = new MultiLine;
|
||||
|
||||
// grab connector normal
|
||||
ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
|
||||
Var *gbNormal = (Var*) LangElement::find( "gbNormal" );
|
||||
if( !gbNormal )
|
||||
{
|
||||
gbNormal = connectComp->getElement( RT_TEXCOORD );
|
||||
gbNormal->setName( "gbNormal" );
|
||||
gbNormal->setStructName( "IN" );
|
||||
gbNormal->setType( "float3" );
|
||||
gbNormal->mapsToSampler = false;
|
||||
gbNormal->uniform = false;
|
||||
}
|
||||
|
||||
// find depth
|
||||
ShaderFeature *depthFeat = FEATUREMGR->getByType( MFT_EyeSpaceDepthOut );
|
||||
AssertFatal( depthFeat != NULL, "No eye space depth feature found!" );
|
||||
|
||||
Var *depth = (Var*) LangElement::find(depthFeat->getOutputVarName());
|
||||
AssertFatal( depth, "Something went bad with ShaderGen. The depth should be already generated by the EyeSpaceDepthOut feature." );
|
||||
|
||||
|
||||
Var *unconditionedOut = new Var;
|
||||
unconditionedOut->setType("float4");
|
||||
unconditionedOut->setName("normal_depth");
|
||||
|
||||
LangElement *outputDecl = new DecOp( unconditionedOut );
|
||||
|
||||
// If we're doing prepass blending then we need
|
||||
// to steal away the alpha channel before the
|
||||
// conditioner stomps on it.
|
||||
Var *alphaVal = NULL;
|
||||
if ( fd.features[ MFT_IsTranslucentZWrite ] )
|
||||
{
|
||||
alphaVal = new Var( "outAlpha", "float" );
|
||||
meta->addStatement( new GenOp( " @ = OUT.col.a; // MFT_IsTranslucentZWrite\r\n", new DecOp( alphaVal ) ) );
|
||||
}
|
||||
|
||||
// If using interlaced normals, invert the normal
|
||||
if(fd.features[MFT_InterlacedPrePass])
|
||||
{
|
||||
// NOTE: Its safe to not call ShaderFeatureHLSL::addOutVpos() in the vertex
|
||||
// shader as for SM 3.0 nothing is needed there.
|
||||
Var *Vpos = ShaderFeatureHLSL::getInVpos( meta, componentList );
|
||||
|
||||
Var *iGBNormal = new Var( "interlacedGBNormal", "float3" );
|
||||
meta->addStatement(new GenOp(" @ = (frac(@.y * 0.5) < 0.1 ? reflect(@, float3(0.0, -1.0, 0.0)) : @);\r\n", new DecOp(iGBNormal), Vpos, gbNormal, gbNormal));
|
||||
gbNormal = iGBNormal;
|
||||
}
|
||||
|
||||
// NOTE: We renormalize the normal here as they
|
||||
// will not stay normalized during interpolation.
|
||||
meta->addStatement( new GenOp(" @ = @;", outputDecl, new GenOp( "float4(normalize(@), @)", gbNormal, depth ) ) );
|
||||
meta->addStatement( assignOutput( unconditionedOut ) );
|
||||
|
||||
// If we have an alpha var then we're doing prepass lerp blending.
|
||||
if ( alphaVal )
|
||||
{
|
||||
Var *outColor = (Var*)LangElement::find( getOutputTargetVarName( DefaultTarget ) );
|
||||
meta->addStatement( new GenOp( " @.ba = float2( 0, @ ); // MFT_IsTranslucentZWrite\r\n", outColor, alphaVal ) );
|
||||
}
|
||||
|
||||
output = meta;
|
||||
}
|
||||
|
||||
ShaderFeature::Resources GBufferConditionerHLSL::getResources( const MaterialFeatureData &fd )
|
||||
{
|
||||
Resources res;
|
||||
|
||||
// Passing from VS->PS:
|
||||
// - world space normal (gbNormal)
|
||||
res.numTexReg = 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Var* GBufferConditionerHLSL::printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta )
|
||||
{
|
||||
const bool isCondition = ( methodType == ConditionerFeature::ConditionMethod );
|
||||
|
||||
Var *retVal = NULL;
|
||||
|
||||
// The uncondition method inputs are changed
|
||||
if( isCondition )
|
||||
retVal = Parent::printMethodHeader( methodType, methodName, stream, meta );
|
||||
else
|
||||
{
|
||||
Var *methodVar = new Var;
|
||||
methodVar->setName(methodName);
|
||||
methodVar->setType("inline float4");
|
||||
DecOp *methodDecl = new DecOp(methodVar);
|
||||
|
||||
Var *prepassSampler = new Var;
|
||||
prepassSampler->setName("prepassSamplerVar");
|
||||
prepassSampler->setType("sampler2D");
|
||||
DecOp *prepassSamplerDecl = new DecOp(prepassSampler);
|
||||
|
||||
Var *screenUV = new Var;
|
||||
screenUV->setName("screenUVVar");
|
||||
screenUV->setType("float2");
|
||||
DecOp *screenUVDecl = new DecOp(screenUV);
|
||||
|
||||
Var *bufferSample = new Var;
|
||||
bufferSample->setName("bufferSample");
|
||||
bufferSample->setType("float4");
|
||||
DecOp *bufferSampleDecl = new DecOp(bufferSample);
|
||||
|
||||
meta->addStatement( new GenOp( "@(@, @)\r\n", methodDecl, prepassSamplerDecl, screenUVDecl ) );
|
||||
|
||||
meta->addStatement( new GenOp( "{\r\n" ) );
|
||||
|
||||
meta->addStatement( new GenOp( " // Sampler g-buffer\r\n" ) );
|
||||
|
||||
#ifdef TORQUE_OS_XENON
|
||||
meta->addStatement( new GenOp( " @;\r\n", bufferSampleDecl ) );
|
||||
meta->addStatement( new GenOp( " asm { tfetch2D @, @, @, MagFilter = point, MinFilter = point, MipFilter = point };\r\n", bufferSample, screenUV, prepassSampler ) );
|
||||
#else
|
||||
// The gbuffer has no mipmaps, so use tex2dlod when
|
||||
// possible so that the shader compiler can optimize.
|
||||
meta->addStatement( new GenOp( " #if TORQUE_SM >= 30\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = tex2Dlod(@, float4(@,0,0));\r\n", bufferSampleDecl, prepassSampler, screenUV ) );
|
||||
meta->addStatement( new GenOp( " #else\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = tex2D(@, @);\r\n", bufferSampleDecl, prepassSampler, screenUV ) );
|
||||
meta->addStatement( new GenOp( " #endif\r\n\r\n" ) );
|
||||
#endif
|
||||
|
||||
// We don't use this way of passing var's around, so this should cause a crash
|
||||
// if something uses this improperly
|
||||
retVal = bufferSample;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
GenOp* GBufferConditionerHLSL::_posnegEncode( GenOp *val )
|
||||
{
|
||||
if(mNormalStorageType == LambertAzimuthal)
|
||||
return mCanWriteNegativeValues ? val : new GenOp(avar("(%f * (@ + %f))", 1.0f/(M_SQRT2_F * 2.0f), M_SQRT2_F), val);
|
||||
else
|
||||
return mCanWriteNegativeValues ? val : new GenOp("(0.5 * (@ + 1.0))", val);
|
||||
}
|
||||
|
||||
GenOp* GBufferConditionerHLSL::_posnegDecode( GenOp *val )
|
||||
{
|
||||
if(mNormalStorageType == LambertAzimuthal)
|
||||
return mCanWriteNegativeValues ? val : new GenOp(avar("(@ * %f - %f)", M_SQRT2_F * 2.0f, M_SQRT2_F), val);
|
||||
else
|
||||
return mCanWriteNegativeValues ? val : new GenOp("(@ * 2.0 - 1.0)", val);
|
||||
}
|
||||
|
||||
Var* GBufferConditionerHLSL::_conditionOutput( Var *unconditionedOutput, MultiLine *meta )
|
||||
{
|
||||
Var *retVar = new Var;
|
||||
retVar->setType("float4");
|
||||
retVar->setName("_gbConditionedOutput");
|
||||
LangElement *outputDecl = new DecOp( retVar );
|
||||
|
||||
switch(mNormalStorageType)
|
||||
{
|
||||
case CartesianXYZ:
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.xyz, depth)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl,
|
||||
_posnegEncode(new GenOp("@.xyz", unconditionedOutput)), unconditionedOutput ) );
|
||||
break;
|
||||
|
||||
case CartesianXY:
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(@, @.a);", outputDecl,
|
||||
_posnegEncode(new GenOp("float3(@.xy, sign(@.z))", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) );
|
||||
break;
|
||||
|
||||
case Spherical:
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(@, 0.0, @.a);\r\n", outputDecl,
|
||||
_posnegEncode(new GenOp("float2(atan2(@.y, @.x) / 3.14159265358979323846f, @.z)", unconditionedOutput, unconditionedOutput, unconditionedOutput ) ),
|
||||
unconditionedOutput ) );
|
||||
|
||||
// HACK: This fixes the noise present when using a floating point
|
||||
// gbuffer on Geforce cards and the "flat areas unlit" issues.
|
||||
//
|
||||
// We need work around atan2() above to fix this issue correctly
|
||||
// without the extra overhead of this test.
|
||||
//
|
||||
meta->addStatement( new GenOp( " if ( abs( dot( @.xyz, float3( 0.0, 0.0, 1.0 ) ) ) > 0.999f ) @ = float4( 0, 1 * sign( @.z ), 0, @.a );\r\n",
|
||||
unconditionedOutput, retVar, unconditionedOutput, unconditionedOutput ) );
|
||||
break;
|
||||
|
||||
case LambertAzimuthal:
|
||||
//http://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
|
||||
//
|
||||
// Note we're casting to half to use partial precision
|
||||
// sqrt which is much faster on older Geforces while
|
||||
// still being acceptable for normals.
|
||||
//
|
||||
meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.X, normal.Y, depth Hi, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(@, 0.0, @.a);\r\n", outputDecl,
|
||||
_posnegEncode(new GenOp("sqrt(half(2.0/(1.0 - @.y))) * half2(@.xz)", unconditionedOutput, unconditionedOutput)),
|
||||
unconditionedOutput ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Encode depth into two channels
|
||||
if(mNormalStorageType != CartesianXYZ)
|
||||
{
|
||||
const U64 maxValPerChannel = 1 << mBitsPerChannel;
|
||||
meta->addStatement( new GenOp( " \r\n // Encode depth into hi/lo\r\n" ) );
|
||||
meta->addStatement( new GenOp( avar( " float2 _tempDepth = frac(@.a * float2(1.0, %llu.0));\r\n", maxValPerChannel - 1 ),
|
||||
unconditionedOutput ) );
|
||||
meta->addStatement( new GenOp( avar( " @.zw = _tempDepth.xy - _tempDepth.yy * float2(1.0/%llu.0, 0.0);\r\n\r\n", maxValPerChannel - 1 ),
|
||||
retVar ) );
|
||||
}
|
||||
|
||||
AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) );
|
||||
return retVar;
|
||||
}
|
||||
|
||||
Var* GBufferConditionerHLSL::_unconditionInput( Var *conditionedInput, MultiLine *meta )
|
||||
{
|
||||
Var *retVar = new Var;
|
||||
retVar->setType("float4");
|
||||
retVar->setName("_gbUnconditionedInput");
|
||||
LangElement *outputDecl = new DecOp( retVar );
|
||||
|
||||
switch(mNormalStorageType)
|
||||
{
|
||||
case CartesianXYZ:
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.xyz, depth)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl,
|
||||
_posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) );
|
||||
break;
|
||||
|
||||
case CartesianXY:
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl,
|
||||
_posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) );
|
||||
meta->addStatement( new GenOp( " @.z *= sqrt(1.0 - dot(@.xy, @.xy));\r\n", retVar, retVar, retVar ) );
|
||||
break;
|
||||
|
||||
case Spherical:
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float2 spGPUAngles = @;\r\n", _posnegDecode(new GenOp("@.xy", conditionedInput)) ) );
|
||||
meta->addStatement( new GenOp( " float2 sincosTheta;\r\n" ) );
|
||||
meta->addStatement( new GenOp( " sincos(spGPUAngles.x * 3.14159265358979323846f, sincosTheta.x, sincosTheta.y);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float2 sincosPhi = float2(sqrt(1.0 - spGPUAngles.y * spGPUAngles.y), spGPUAngles.y);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4(sincosTheta.y * sincosPhi.x, sincosTheta.x * sincosPhi.x, sincosPhi.y, @.a);\r\n", outputDecl, conditionedInput ) );
|
||||
break;
|
||||
|
||||
case LambertAzimuthal:
|
||||
// Note we're casting to half to use partial precision
|
||||
// sqrt which is much faster on older Geforces while
|
||||
// still being acceptable for normals.
|
||||
//
|
||||
meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.X, normal.Y, depth Hi, depth Lo)\r\n" ) );
|
||||
meta->addStatement( new GenOp( " float2 _inpXY = @;\r\n", _posnegDecode(new GenOp("@.xy", conditionedInput)) ) );
|
||||
meta->addStatement( new GenOp( " float _xySQ = dot(_inpXY, _inpXY);\r\n" ) );
|
||||
meta->addStatement( new GenOp( " @ = float4( sqrt(half(1.0 - (_xySQ / 4.0))) * _inpXY, -1.0 + (_xySQ / 2.0), @.a).xzyw;\r\n", outputDecl, conditionedInput ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Recover depth from encoding
|
||||
if(mNormalStorageType != CartesianXYZ)
|
||||
{
|
||||
const U64 maxValPerChannel = 1 << mBitsPerChannel;
|
||||
meta->addStatement( new GenOp( " \r\n // Decode depth\r\n" ) );
|
||||
meta->addStatement( new GenOp( avar( " @.w = dot( @.zw, float2(1.0, 1.0/%llu.0));\r\n", maxValPerChannel - 1 ),
|
||||
retVar, conditionedInput ) );
|
||||
}
|
||||
|
||||
|
||||
AssertFatal( retVar != NULL, avar( "Cannot uncondition input from buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) );
|
||||
return retVar;
|
||||
}
|
||||
|
||||
|
|
@ -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 _GBUFFER_CONDITIONER_HLSL_H_
|
||||
#define _GBUFFER_CONDITIONER_HLSL_H_
|
||||
|
||||
#ifndef _CONDITIONER_BASE_H_
|
||||
#include "shaderGen/conditionerFeature.h"
|
||||
#endif
|
||||
#ifndef _SHADEROP_H_
|
||||
#include "shaderGen/shaderOp.h"
|
||||
#endif
|
||||
|
||||
|
||||
///
|
||||
class GBufferConditionerHLSL : public ConditionerFeature
|
||||
{
|
||||
typedef ConditionerFeature Parent;
|
||||
|
||||
public:
|
||||
enum NormalStorage
|
||||
{
|
||||
CartesianXYZ,
|
||||
CartesianXY,
|
||||
Spherical,
|
||||
LambertAzimuthal,
|
||||
};
|
||||
|
||||
enum NormalSpace
|
||||
{
|
||||
WorldSpace,
|
||||
ViewSpace,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
NormalStorage mNormalStorageType;
|
||||
bool mCanWriteNegativeValues;
|
||||
U32 mBitsPerChannel;
|
||||
|
||||
public:
|
||||
|
||||
GBufferConditionerHLSL( const GFXFormat bufferFormat, const NormalSpace nrmSpace );
|
||||
virtual ~GBufferConditionerHLSL();
|
||||
|
||||
|
||||
virtual void processVert( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd );
|
||||
virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd );
|
||||
virtual Resources getResources( const MaterialFeatureData &fd );
|
||||
virtual String getName() { return "GBuffer Conditioner"; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual Var *printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta );
|
||||
|
||||
virtual GenOp* _posnegEncode( GenOp *val );
|
||||
virtual GenOp* _posnegDecode( GenOp *val );
|
||||
virtual Var* _conditionOutput( Var *unconditionedOutput, MultiLine *meta );
|
||||
virtual Var* _unconditionInput( Var *conditionedInput, MultiLine *meta );
|
||||
};
|
||||
|
||||
#endif // _GBUFFER_CONDITIONER_HLSL_H_
|
||||
412
Engine/source/lighting/basic/basicLightManager.cpp
Normal file
412
Engine/source/lighting/basic/basicLightManager.cpp
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/basic/basicLightManager.h"
|
||||
|
||||
#include "platform/platformTimer.h"
|
||||
#include "console/simSet.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/module.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "materials/processedMaterial.h"
|
||||
#include "shaderGen/shaderFeature.h"
|
||||
#include "lighting/basic/basicSceneObjectLightingPlugin.h"
|
||||
#include "shaderGen/shaderGenVars.h"
|
||||
#include "gfx/gfxShader.h"
|
||||
#include "materials/sceneData.h"
|
||||
#include "materials/materialParameters.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "math/util/frustum.h"
|
||||
#include "scene/sceneObject.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "shaderGen/HLSL/shaderFeatureHLSL.h"
|
||||
#include "shaderGen/HLSL/bumpHLSL.h"
|
||||
#include "shaderGen/HLSL/pixSpecularHLSL.h"
|
||||
#include "lighting/basic/blInteriorSystem.h"
|
||||
#include "lighting/basic/blTerrainSystem.h"
|
||||
#include "lighting/common/projectedShadow.h"
|
||||
|
||||
|
||||
#ifdef TORQUE_OS_MAC
|
||||
#include "shaderGen/GLSL/shaderFeatureGLSL.h"
|
||||
#include "shaderGen/GLSL/bumpGLSL.h"
|
||||
#include "shaderGen/GLSL/pixSpecularGLSL.h"
|
||||
#endif
|
||||
|
||||
|
||||
MODULE_BEGIN( BasicLightManager )
|
||||
|
||||
MODULE_SHUTDOWN_AFTER( Scene )
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
ManagedSingleton< BasicLightManager >::createSingleton();
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
ManagedSingleton< BasicLightManager >::deleteSingleton();
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
|
||||
U32 BasicLightManager::smActiveShadowPlugins = 0;
|
||||
U32 BasicLightManager::smShadowsUpdated = 0;
|
||||
U32 BasicLightManager::smElapsedUpdateMs = 0;
|
||||
|
||||
F32 BasicLightManager::smProjectedShadowFilterDistance = 40.0f;
|
||||
|
||||
static S32 QSORT_CALLBACK comparePluginScores( const void *a, const void *b )
|
||||
{
|
||||
const BasicSceneObjectLightingPlugin *A = *((BasicSceneObjectLightingPlugin**)a);
|
||||
const BasicSceneObjectLightingPlugin *B = *((BasicSceneObjectLightingPlugin**)b);
|
||||
|
||||
F32 dif = B->getScore() - A->getScore();
|
||||
return (S32)mFloor( dif );
|
||||
}
|
||||
|
||||
BasicLightManager::BasicLightManager()
|
||||
: LightManager( "Basic Lighting", "BLM" ),
|
||||
mLastShader(NULL),
|
||||
mLastConstants(NULL)
|
||||
{
|
||||
mTimer = PlatformTimer::create();
|
||||
|
||||
mInteriorSystem = new blInteriorSystem;
|
||||
mTerrainSystem = new blTerrainSystem;
|
||||
|
||||
getSceneLightingInterface()->registerSystem( mInteriorSystem );
|
||||
getSceneLightingInterface()->registerSystem( mTerrainSystem );
|
||||
|
||||
Con::addVariable( "$BasicLightManagerStats::activePlugins",
|
||||
TypeS32, &smActiveShadowPlugins,
|
||||
"The number of active Basic Lighting SceneObjectLightingPlugin objects this frame.\n"
|
||||
"@ingroup BasicLighting\n" );
|
||||
|
||||
Con::addVariable( "$BasicLightManagerStats::shadowsUpdated",
|
||||
TypeS32, &smShadowsUpdated,
|
||||
"The number of Basic Lighting shadows updated this frame.\n"
|
||||
"@ingroup BasicLighting\n" );
|
||||
|
||||
Con::addVariable( "$BasicLightManagerStats::elapsedUpdateMs",
|
||||
TypeS32, &smElapsedUpdateMs,
|
||||
"The number of milliseconds spent this frame updating Basic Lighting shadows.\n"
|
||||
"@ingroup BasicLighting\n" );
|
||||
|
||||
Con::addVariable( "$BasicLightManager::shadowFilterDistance",
|
||||
TypeF32, &smProjectedShadowFilterDistance,
|
||||
"The maximum distance in meters that projected shadows will get soft filtering.\n"
|
||||
"@ingroup BasicLighting\n" );
|
||||
|
||||
Con::addVariable( "$pref::ProjectedShadow::fadeStartPixelSize",
|
||||
TypeF32, &ProjectedShadow::smFadeStartPixelSize,
|
||||
"A size in pixels at which BL shadows begin to fade out. "
|
||||
"This should be a larger value than fadeEndPixelSize.\n"
|
||||
"@see DecalData\n"
|
||||
"@ingroup BasicLighting\n" );
|
||||
|
||||
Con::addVariable( "$pref::ProjectedShadow::fadeEndPixelSize",
|
||||
TypeF32, &ProjectedShadow::smFadeEndPixelSize,
|
||||
"A size in pixels at which BL shadows are fully faded out. "
|
||||
"This should be a smaller value than fadeStartPixelSize.\n"
|
||||
"@see DecalData\n"
|
||||
"@ingroup BasicLighting\n" );
|
||||
}
|
||||
|
||||
BasicLightManager::~BasicLightManager()
|
||||
{
|
||||
mLastShader = NULL;
|
||||
mLastConstants = NULL;
|
||||
|
||||
for (LightConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++)
|
||||
{
|
||||
if (i->value)
|
||||
SAFE_DELETE(i->value);
|
||||
}
|
||||
mConstantLookup.clear();
|
||||
|
||||
if (mTimer)
|
||||
SAFE_DELETE( mTimer );
|
||||
|
||||
SAFE_DELETE( mTerrainSystem );
|
||||
SAFE_DELETE( mInteriorSystem );
|
||||
}
|
||||
|
||||
bool BasicLightManager::isCompatible() const
|
||||
{
|
||||
// As long as we have some shaders this works.
|
||||
return GFX->getPixelShaderVersion() > 1.0;
|
||||
}
|
||||
|
||||
void BasicLightManager::activate( SceneManager *sceneManager )
|
||||
{
|
||||
Parent::activate( sceneManager );
|
||||
|
||||
if( GFX->getAdapterType() == OpenGL )
|
||||
{
|
||||
#ifdef TORQUE_OS_MAC
|
||||
FEATUREMGR->registerFeature( MFT_LightMap, new LightmapFeatGLSL );
|
||||
FEATUREMGR->registerFeature( MFT_ToneMap, new TonemapFeatGLSL );
|
||||
FEATUREMGR->registerFeature( MFT_NormalMap, new BumpFeatGLSL );
|
||||
FEATUREMGR->registerFeature( MFT_RTLighting, new RTLightingFeatGLSL );
|
||||
FEATUREMGR->registerFeature( MFT_PixSpecular, new PixelSpecularGLSL );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef TORQUE_OS_MAC
|
||||
FEATUREMGR->registerFeature( MFT_LightMap, new LightmapFeatHLSL );
|
||||
FEATUREMGR->registerFeature( MFT_ToneMap, new TonemapFeatHLSL );
|
||||
FEATUREMGR->registerFeature( MFT_NormalMap, new BumpFeatHLSL );
|
||||
FEATUREMGR->registerFeature( MFT_RTLighting, new RTLightingFeatHLSL );
|
||||
FEATUREMGR->registerFeature( MFT_PixSpecular, new PixelSpecularHLSL );
|
||||
#endif
|
||||
}
|
||||
|
||||
FEATUREMGR->unregisterFeature( MFT_MinnaertShading );
|
||||
FEATUREMGR->unregisterFeature( MFT_SubSurface );
|
||||
|
||||
// First look for the prepass bin...
|
||||
RenderPrePassMgr *prePassBin = _findPrePassRenderBin();
|
||||
|
||||
/*
|
||||
// If you would like to use forward shading, and have a linear depth pre-pass
|
||||
// than un-comment this code block.
|
||||
if ( !prePassBin )
|
||||
{
|
||||
Vector<GFXFormat> formats;
|
||||
formats.push_back( GFXFormatR32F );
|
||||
formats.push_back( GFXFormatR16F );
|
||||
formats.push_back( GFXFormatR8G8B8A8 );
|
||||
GFXFormat linearDepthFormat = GFX->selectSupportedFormat( &GFXDefaultRenderTargetProfile,
|
||||
formats,
|
||||
true,
|
||||
false );
|
||||
|
||||
// Uncomment this for a no-color-write z-fill pass.
|
||||
//linearDepthFormat = GFXFormat_COUNT;
|
||||
|
||||
prePassBin = new RenderPrePassMgr( linearDepthFormat != GFXFormat_COUNT, linearDepthFormat );
|
||||
prePassBin->registerObject();
|
||||
rpm->addManager( prePassBin );
|
||||
}
|
||||
*/
|
||||
mPrePassRenderBin = prePassBin;
|
||||
|
||||
// If there is a prepass bin
|
||||
MATMGR->setPrePassEnabled( mPrePassRenderBin.isValid() );
|
||||
sceneManager->setPostEffectFog( mPrePassRenderBin.isValid() && mPrePassRenderBin->getTargetChainLength() > 0 );
|
||||
|
||||
// Tell the material manager that we don't use prepass.
|
||||
MATMGR->setPrePassEnabled( false );
|
||||
|
||||
GFXShader::addGlobalMacro( "TORQUE_BASIC_LIGHTING" );
|
||||
|
||||
// Hook into the SceneManager prerender signal.
|
||||
sceneManager->getPreRenderSignal().notify( this, &BasicLightManager::_onPreRender );
|
||||
|
||||
// Last thing... let everyone know we're active.
|
||||
smActivateSignal.trigger( getId(), true );
|
||||
}
|
||||
|
||||
void BasicLightManager::deactivate()
|
||||
{
|
||||
Parent::deactivate();
|
||||
|
||||
mLastShader = NULL;
|
||||
mLastConstants = NULL;
|
||||
|
||||
for (LightConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++)
|
||||
{
|
||||
if (i->value)
|
||||
SAFE_DELETE(i->value);
|
||||
}
|
||||
mConstantLookup.clear();
|
||||
|
||||
if ( mPrePassRenderBin )
|
||||
mPrePassRenderBin->deleteObject();
|
||||
mPrePassRenderBin = NULL;
|
||||
|
||||
GFXShader::removeGlobalMacro( "TORQUE_BASIC_LIGHTING" );
|
||||
|
||||
// Remove us from the prerender signal.
|
||||
getSceneManager()->getPreRenderSignal().remove( this, &BasicLightManager::_onPreRender );
|
||||
|
||||
// Now let everyone know we've deactivated.
|
||||
smActivateSignal.trigger( getId(), false );
|
||||
}
|
||||
|
||||
void BasicLightManager::_onPreRender( SceneManager *sceneManger, const SceneRenderState *state )
|
||||
{
|
||||
// Update all our shadow plugins here!
|
||||
Vector<BasicSceneObjectLightingPlugin*> *pluginInsts = BasicSceneObjectLightingPlugin::getPluginInstances();
|
||||
|
||||
Vector<BasicSceneObjectLightingPlugin*>::const_iterator pluginIter = (*pluginInsts).begin();
|
||||
for ( ; pluginIter != (*pluginInsts).end(); pluginIter++ )
|
||||
{
|
||||
BasicSceneObjectLightingPlugin *plugin = *pluginIter;
|
||||
plugin->updateShadow( (SceneRenderState*)state );
|
||||
}
|
||||
|
||||
U32 pluginCount = (*pluginInsts).size();
|
||||
|
||||
// Sort them by the score.
|
||||
dQsort( (*pluginInsts).address(), pluginCount, sizeof(BasicSceneObjectLightingPlugin*), comparePluginScores );
|
||||
|
||||
mTimer->getElapsedMs();
|
||||
mTimer->reset();
|
||||
U32 numUpdated = 0;
|
||||
U32 targetMs = 5;
|
||||
|
||||
S32 updateMs = 0;
|
||||
|
||||
pluginIter = (*pluginInsts).begin();
|
||||
for ( ; pluginIter != (*pluginInsts).end(); pluginIter++ )
|
||||
{
|
||||
BasicSceneObjectLightingPlugin *plugin = *pluginIter;
|
||||
|
||||
// If we run out of update time then stop.
|
||||
updateMs = mTimer->getElapsedMs();
|
||||
if ( updateMs >= targetMs )
|
||||
break;
|
||||
|
||||
// NOTE! Fix this all up to past const SceneRenderState!
|
||||
plugin->renderShadow( (SceneRenderState*)state );
|
||||
numUpdated++;
|
||||
}
|
||||
|
||||
smShadowsUpdated = numUpdated;
|
||||
smActiveShadowPlugins = pluginCount;
|
||||
smElapsedUpdateMs = updateMs;
|
||||
}
|
||||
|
||||
BasicLightManager::LightingShaderConstants::LightingShaderConstants()
|
||||
: mInit( false ),
|
||||
mShader( NULL ),
|
||||
mLightPosition( NULL ),
|
||||
mLightDiffuse( NULL ),
|
||||
mLightAmbient( NULL ),
|
||||
mLightInvRadiusSq( NULL ),
|
||||
mLightSpotDir( NULL ),
|
||||
mLightSpotAngle( NULL ),
|
||||
mLightSpotFalloff( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
BasicLightManager::LightingShaderConstants::~LightingShaderConstants()
|
||||
{
|
||||
if (mShader.isValid())
|
||||
{
|
||||
mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );
|
||||
mShader = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void BasicLightManager::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 );
|
||||
}
|
||||
|
||||
mLightPosition = shader->getShaderConstHandle( ShaderGenVars::lightPosition );
|
||||
mLightDiffuse = shader->getShaderConstHandle( ShaderGenVars::lightDiffuse);
|
||||
mLightInvRadiusSq = shader->getShaderConstHandle( ShaderGenVars::lightInvRadiusSq );
|
||||
mLightAmbient = shader->getShaderConstHandle( ShaderGenVars::lightAmbient );
|
||||
mLightSpotDir = shader->getShaderConstHandle( ShaderGenVars::lightSpotDir );
|
||||
mLightSpotAngle = shader->getShaderConstHandle( ShaderGenVars::lightSpotAngle );
|
||||
mLightSpotFalloff = shader->getShaderConstHandle( ShaderGenVars::lightSpotFalloff );
|
||||
|
||||
mInit = true;
|
||||
}
|
||||
|
||||
void BasicLightManager::LightingShaderConstants::_onShaderReload()
|
||||
{
|
||||
if (mShader.isValid())
|
||||
init( mShader );
|
||||
}
|
||||
|
||||
void BasicLightManager::setLightInfo( ProcessedMaterial* pmat,
|
||||
const Material* mat,
|
||||
const SceneData& sgData,
|
||||
const SceneRenderState *state,
|
||||
U32 pass,
|
||||
GFXShaderConstBuffer* shaderConsts )
|
||||
{
|
||||
PROFILE_SCOPE( BasicLightManager_SetLightInfo );
|
||||
|
||||
GFXShader *shader = shaderConsts->getShader();
|
||||
|
||||
// Check to see if this is the same shader. Since we
|
||||
// sort by material we should get hit repeatedly by the
|
||||
// same one. This optimization should save us many
|
||||
// hash table lookups.
|
||||
if ( mLastShader.getPointer() != shader )
|
||||
{
|
||||
LightConstantMap::Iterator iter = mConstantLookup.find(shader);
|
||||
if ( iter != mConstantLookup.end() )
|
||||
{
|
||||
mLastConstants = iter->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LightingShaderConstants* lsc = new LightingShaderConstants();
|
||||
mConstantLookup[shader] = lsc;
|
||||
|
||||
mLastConstants = lsc;
|
||||
}
|
||||
|
||||
// Set our new shader
|
||||
mLastShader = shader;
|
||||
}
|
||||
|
||||
// Make sure that our current lighting constants are initialized
|
||||
if (!mLastConstants->mInit)
|
||||
mLastConstants->init(shader);
|
||||
|
||||
// NOTE: If you encounter a crash from this point forward
|
||||
// while setting a shader constant its probably because the
|
||||
// mConstantLookup has bad shaders/constants in it.
|
||||
//
|
||||
// This is a known crash bug that can occur if materials/shaders
|
||||
// are reloaded and the light manager is not reset.
|
||||
//
|
||||
// We should look to fix this by clearing the table.
|
||||
|
||||
_update4LightConsts( sgData,
|
||||
mLastConstants->mLightPosition,
|
||||
mLastConstants->mLightDiffuse,
|
||||
mLastConstants->mLightAmbient,
|
||||
mLastConstants->mLightInvRadiusSq,
|
||||
mLastConstants->mLightSpotDir,
|
||||
mLastConstants->mLightSpotAngle,
|
||||
mLastConstants->mLightSpotFalloff,
|
||||
shaderConsts );
|
||||
}
|
||||
134
Engine/source/lighting/basic/basicLightManager.h
Normal file
134
Engine/source/lighting/basic/basicLightManager.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _BASICLIGHTMANAGER_H_
|
||||
#define _BASICLIGHTMANAGER_H_
|
||||
|
||||
#ifndef _LIGHTMANAGER_H_
|
||||
#include "lighting/lightManager.h"
|
||||
#endif
|
||||
#ifndef _TDICTIONARY_H_
|
||||
#include "core/util/tDictionary.h"
|
||||
#endif
|
||||
#ifndef _GFXSHADER_H_
|
||||
#include "gfx/gfxShader.h"
|
||||
#endif
|
||||
#ifndef _SIMOBJECT_H_
|
||||
#include "console/simObject.h"
|
||||
#endif
|
||||
#ifndef _TSINGLETON_H_
|
||||
#include "core/util/tSingleton.h"
|
||||
#endif
|
||||
|
||||
class AvailableSLInterfaces;
|
||||
class GFXShaderConstHandle;
|
||||
class RenderPrePassMgr;
|
||||
class PlatformTimer;
|
||||
|
||||
class blInteriorSystem;
|
||||
class blTerrainSystem;
|
||||
|
||||
class BasicLightManager : public LightManager
|
||||
{
|
||||
typedef LightManager Parent;
|
||||
|
||||
// For access to protected constructor.
|
||||
friend class ManagedSingleton<BasicLightManager>;
|
||||
|
||||
public:
|
||||
|
||||
// LightManager
|
||||
virtual bool isCompatible() const;
|
||||
virtual void activate( SceneManager *sceneManager );
|
||||
virtual void deactivate();
|
||||
virtual void setLightInfo(ProcessedMaterial* pmat, const Material* mat, const SceneData& sgData, const SceneRenderState *state, U32 pass, GFXShaderConstBuffer* shaderConsts);
|
||||
virtual bool setTextureStage(const SceneData& sgData, const U32 currTexFlag, const U32 textureSlot, GFXShaderConstBuffer* shaderConsts, ShaderConstHandles* handles) { return false; }
|
||||
|
||||
static F32 getShadowFilterDistance() { return smProjectedShadowFilterDistance; }
|
||||
|
||||
protected:
|
||||
|
||||
// LightManager
|
||||
virtual void _addLightInfoEx( LightInfo *lightInfo ) { }
|
||||
virtual void _initLightFields() { }
|
||||
|
||||
void _onPreRender( SceneManager *sceneManger, const SceneRenderState *state );
|
||||
|
||||
// These are protected because we're a singleton and
|
||||
// no one else should be creating us!
|
||||
BasicLightManager();
|
||||
virtual ~BasicLightManager();
|
||||
|
||||
SimObjectPtr<RenderPrePassMgr> mPrePassRenderBin;
|
||||
|
||||
struct LightingShaderConstants
|
||||
{
|
||||
bool mInit;
|
||||
|
||||
GFXShaderRef mShader;
|
||||
|
||||
GFXShaderConstHandle *mLightPosition;
|
||||
GFXShaderConstHandle *mLightDiffuse;
|
||||
GFXShaderConstHandle *mLightAmbient;
|
||||
GFXShaderConstHandle *mLightInvRadiusSq;
|
||||
GFXShaderConstHandle *mLightSpotDir;
|
||||
GFXShaderConstHandle *mLightSpotAngle;
|
||||
GFXShaderConstHandle *mLightSpotFalloff;
|
||||
|
||||
LightingShaderConstants();
|
||||
~LightingShaderConstants();
|
||||
|
||||
void init( GFXShader *shader );
|
||||
|
||||
void _onShaderReload();
|
||||
};
|
||||
|
||||
typedef Map<GFXShader*, LightingShaderConstants*> LightConstantMap;
|
||||
|
||||
LightConstantMap mConstantLookup;
|
||||
GFXShaderRef mLastShader;
|
||||
LightingShaderConstants* mLastConstants;
|
||||
|
||||
/// Statics used for light manager/projected shadow metrics.
|
||||
static U32 smActiveShadowPlugins;
|
||||
static U32 smShadowsUpdated;
|
||||
static U32 smElapsedUpdateMs;
|
||||
|
||||
/// This is used to determine the distance
|
||||
/// at which the shadow filtering PostEffect
|
||||
/// will be enabled for ProjectedShadow.
|
||||
static F32 smProjectedShadowFilterDistance;
|
||||
|
||||
/// A timer used for tracking update time.
|
||||
PlatformTimer *mTimer;
|
||||
|
||||
blInteriorSystem* mInteriorSystem;
|
||||
blTerrainSystem* mTerrainSystem;
|
||||
|
||||
public:
|
||||
// For ManagedSingleton.
|
||||
static const char* getSingletonName() { return "BasicLightManager"; }
|
||||
};
|
||||
|
||||
#define BLM ManagedSingleton<BasicLightManager>::instance()
|
||||
|
||||
#endif // _BASICLIGHTMANAGER_H_
|
||||
230
Engine/source/lighting/basic/basicSceneObjectLightingPlugin.cpp
Normal file
230
Engine/source/lighting/basic/basicSceneObjectLightingPlugin.cpp
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/basic/basicSceneObjectLightingPlugin.h"
|
||||
|
||||
#include "lighting/lightManager.h"
|
||||
#include "lighting/shadowMap/shadowMapPass.h"
|
||||
#include "lighting/shadowMap/shadowMapManager.h"
|
||||
#include "lighting/common/projectedShadow.h"
|
||||
#include "T3D/shapeBase.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "ts/tsRenderState.h"
|
||||
#include "gfx/sim/cubemapData.h"
|
||||
#include "scene/reflector.h"
|
||||
#include "T3D/decal/decalManager.h"
|
||||
#include "core/module.h"
|
||||
|
||||
|
||||
MODULE_BEGIN( BasicSceneObjectLightingPlugin )
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
BasicSceneObjectPluginFactory::createSingleton();
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
BasicSceneObjectPluginFactory::deleteSingleton();
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
|
||||
static const U32 shadowObjectTypeMask = PlayerObjectType | CorpseObjectType | ItemObjectType | VehicleObjectType;
|
||||
Vector<BasicSceneObjectLightingPlugin*> BasicSceneObjectLightingPlugin::smPluginInstances( __FILE__, __LINE__ );
|
||||
|
||||
BasicSceneObjectLightingPlugin::BasicSceneObjectLightingPlugin(SceneObject* parent)
|
||||
: mParentObject( parent )
|
||||
{
|
||||
mShadow = NULL;
|
||||
|
||||
// Stick us on the list.
|
||||
smPluginInstances.push_back( this );
|
||||
}
|
||||
|
||||
BasicSceneObjectLightingPlugin::~BasicSceneObjectLightingPlugin()
|
||||
{
|
||||
SAFE_DELETE( mShadow );
|
||||
|
||||
// Delete us from the list.
|
||||
smPluginInstances.remove( this );
|
||||
}
|
||||
|
||||
void BasicSceneObjectLightingPlugin::reset()
|
||||
{
|
||||
SAFE_DELETE( mShadow );
|
||||
}
|
||||
|
||||
void BasicSceneObjectLightingPlugin::cleanupPluginInstances()
|
||||
{
|
||||
for (U32 i = 0; i < smPluginInstances.size(); i++)
|
||||
{
|
||||
BasicSceneObjectLightingPlugin *plug = smPluginInstances[i];
|
||||
smPluginInstances.remove( plug );
|
||||
delete plug;
|
||||
i--;
|
||||
}
|
||||
|
||||
smPluginInstances.clear();
|
||||
}
|
||||
|
||||
void BasicSceneObjectLightingPlugin::resetAll()
|
||||
{
|
||||
for( U32 i = 0, num = smPluginInstances.size(); i < num; ++ i )
|
||||
smPluginInstances[ i ]->reset();
|
||||
}
|
||||
|
||||
const F32 BasicSceneObjectLightingPlugin::getScore() const
|
||||
{
|
||||
return mShadow ? mShadow->getScore() : 0.0f;
|
||||
}
|
||||
|
||||
void BasicSceneObjectLightingPlugin::updateShadow( SceneRenderState *state )
|
||||
{
|
||||
if ( !mShadow )
|
||||
mShadow = new ProjectedShadow( mParentObject );
|
||||
|
||||
mShadow->update( state );
|
||||
}
|
||||
|
||||
void BasicSceneObjectLightingPlugin::renderShadow( SceneRenderState *state )
|
||||
{
|
||||
// hack until new scenegraph in place
|
||||
GFXTransformSaver ts;
|
||||
|
||||
TSRenderState rstate;
|
||||
rstate.setSceneState(state);
|
||||
|
||||
F32 camDist = (state->getCameraPosition() - mParentObject->getRenderPosition()).len();
|
||||
|
||||
// Make sure the shadow wants to be rendered
|
||||
if( mShadow->shouldRender( state ) )
|
||||
{
|
||||
// Render! (and note the time)
|
||||
mShadow->render( camDist, rstate );
|
||||
}
|
||||
}
|
||||
|
||||
BasicSceneObjectPluginFactory::BasicSceneObjectPluginFactory()
|
||||
: mEnabled( false )
|
||||
{
|
||||
LightManager::smActivateSignal.notify( this, &BasicSceneObjectPluginFactory::_onLMActivate );
|
||||
|
||||
ShadowMapManager::smShadowDeactivateSignal.notify( this, &BasicSceneObjectPluginFactory::_setEnabled );
|
||||
}
|
||||
|
||||
BasicSceneObjectPluginFactory::~BasicSceneObjectPluginFactory()
|
||||
{
|
||||
LightManager::smActivateSignal.remove( this, &BasicSceneObjectPluginFactory::_onLMActivate );
|
||||
|
||||
ShadowMapManager::smShadowDeactivateSignal.remove( this, &BasicSceneObjectPluginFactory::_setEnabled );
|
||||
}
|
||||
|
||||
void BasicSceneObjectPluginFactory::_onLMActivate( const char *lm, bool enable )
|
||||
{
|
||||
_setEnabled();
|
||||
}
|
||||
|
||||
void BasicSceneObjectPluginFactory::_setEnabled()
|
||||
{
|
||||
bool enable = false;
|
||||
|
||||
// Enabled if using basic lighting.
|
||||
LightManager *lm = LightManager::getActiveLM();
|
||||
if ( lm && dStricmp( lm->getName(), "Basic Lighting" ) == 0 )
|
||||
enable = true;
|
||||
|
||||
// Disabled if all shadows are explictly disabled.
|
||||
if ( ShadowMapPass::smDisableShadows )
|
||||
enable = false;
|
||||
|
||||
// Already at the desired state.
|
||||
if ( enable == mEnabled )
|
||||
return;
|
||||
|
||||
if ( enable )
|
||||
{
|
||||
SceneObject::smSceneObjectAdd.notify(this, &BasicSceneObjectPluginFactory::addLightPlugin);
|
||||
SceneObject::smSceneObjectRemove.notify(this, &BasicSceneObjectPluginFactory::removeLightPlugin);
|
||||
|
||||
if( gDecalManager )
|
||||
gDecalManager->getClearDataSignal().notify( this, &BasicSceneObjectPluginFactory::_onDecalManagerClear );
|
||||
|
||||
addToExistingObjects();
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneObject::smSceneObjectAdd.remove(this, &BasicSceneObjectPluginFactory::addLightPlugin);
|
||||
SceneObject::smSceneObjectRemove.remove(this, &BasicSceneObjectPluginFactory::removeLightPlugin);
|
||||
|
||||
if( gDecalManager )
|
||||
gDecalManager->getClearDataSignal().remove( this, &BasicSceneObjectPluginFactory::_onDecalManagerClear );
|
||||
|
||||
BasicSceneObjectLightingPlugin::cleanupPluginInstances();
|
||||
}
|
||||
|
||||
mEnabled = enable;
|
||||
}
|
||||
|
||||
void BasicSceneObjectPluginFactory::_onDecalManagerClear()
|
||||
{
|
||||
BasicSceneObjectLightingPlugin::resetAll();
|
||||
}
|
||||
|
||||
void BasicSceneObjectPluginFactory::removeLightPlugin( SceneObject *obj )
|
||||
{
|
||||
// Grab the plugin instance.
|
||||
SceneObjectLightingPlugin *lightPlugin = obj->getLightingPlugin();
|
||||
|
||||
// Delete it, which will also remove it
|
||||
// from the static list of plugin instances.
|
||||
if ( lightPlugin )
|
||||
{
|
||||
delete lightPlugin;
|
||||
obj->setLightingPlugin( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
void BasicSceneObjectPluginFactory::addLightPlugin(SceneObject* obj)
|
||||
{
|
||||
bool serverObj = obj->isServerObject();
|
||||
bool isShadowType = (obj->getTypeMask() & shadowObjectTypeMask);
|
||||
|
||||
if ( !isShadowType || serverObj )
|
||||
return;
|
||||
|
||||
obj->setLightingPlugin(new BasicSceneObjectLightingPlugin(obj));
|
||||
}
|
||||
|
||||
// Some objects may not get cleaned up during mission load/free, so add our
|
||||
// plugin to existing scene objects
|
||||
void BasicSceneObjectPluginFactory::addToExistingObjects()
|
||||
{
|
||||
SimpleQueryList sql;
|
||||
gClientContainer.findObjects( shadowObjectTypeMask, SimpleQueryList::insertionCallback, &sql);
|
||||
for (SceneObject** i = sql.mList.begin(); i != sql.mList.end(); i++)
|
||||
addLightPlugin(*i);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _BASICSCENEOBJECTLIGHTINGPLUGIN_H_
|
||||
#define _BASICSCENEOBJECTLIGHTINGPLUGIN_H_
|
||||
|
||||
#ifndef _SCENEOBJECTLIGHTINGPLUGIN_H_
|
||||
#include "scene/sceneObjectLightingPlugin.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _TSINGLETON_H_
|
||||
#include "core/util/tSingleton.h"
|
||||
#endif
|
||||
|
||||
|
||||
class ShadowBase;
|
||||
|
||||
class BasicSceneObjectLightingPlugin : public SceneObjectLightingPlugin
|
||||
{
|
||||
private:
|
||||
|
||||
ShadowBase* mShadow;
|
||||
SceneObject* mParentObject;
|
||||
|
||||
static Vector<BasicSceneObjectLightingPlugin*> smPluginInstances;
|
||||
|
||||
public:
|
||||
BasicSceneObjectLightingPlugin(SceneObject* parent);
|
||||
~BasicSceneObjectLightingPlugin();
|
||||
|
||||
static Vector<BasicSceneObjectLightingPlugin*>* getPluginInstances() { return &smPluginInstances; }
|
||||
|
||||
static void cleanupPluginInstances();
|
||||
static void resetAll();
|
||||
|
||||
const F32 getScore() const;
|
||||
|
||||
// Called from BasicLightManager
|
||||
virtual void updateShadow( SceneRenderState *state );
|
||||
virtual void renderShadow( SceneRenderState *state );
|
||||
|
||||
// Called by statics
|
||||
virtual U32 packUpdate(SceneObject* obj, U32 checkMask, NetConnection *conn, U32 mask, BitStream *stream) { return 0; }
|
||||
virtual void unpackUpdate(SceneObject* obj, NetConnection *conn, BitStream *stream) { }
|
||||
|
||||
virtual void reset();
|
||||
};
|
||||
|
||||
class BasicSceneObjectPluginFactory : public ManagedSingleton< BasicSceneObjectPluginFactory >
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Called from the light manager on activation.
|
||||
/// @see LightManager::addActivateCallback
|
||||
void _onLMActivate( const char *lm, bool enable );
|
||||
|
||||
void _onDecalManagerClear();
|
||||
|
||||
void removeLightPlugin(SceneObject* obj);
|
||||
void addLightPlugin(SceneObject* obj);
|
||||
void addToExistingObjects();
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
public:
|
||||
|
||||
BasicSceneObjectPluginFactory();
|
||||
~BasicSceneObjectPluginFactory();
|
||||
|
||||
// For ManagedSingleton.
|
||||
static const char* getSingletonName() { return "BasicSceneObjectPluginFactory"; }
|
||||
|
||||
void _setEnabled();
|
||||
};
|
||||
|
||||
#endif // !_BASICSCENEOBJECTLIGHTINGPLUGIN_H_
|
||||
1472
Engine/source/lighting/basic/blInteriorSystem.cpp
Normal file
1472
Engine/source/lighting/basic/blInteriorSystem.cpp
Normal file
File diff suppressed because it is too large
Load diff
57
Engine/source/lighting/basic/blInteriorSystem.h
Normal file
57
Engine/source/lighting/basic/blInteriorSystem.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 _BLINTERIOSYSTEM_H_
|
||||
#define _BLINTERIOSYSTEM_H_
|
||||
|
||||
#ifndef _SCENELIGHTING_H_
|
||||
#include "lighting/common/sceneLighting.h"
|
||||
#endif
|
||||
#ifndef _SG_SYSTEM_INTERFACE_H
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Lighting system interface
|
||||
//
|
||||
class blInteriorSystem : public SceneLightingInterface
|
||||
{
|
||||
public:
|
||||
static bool smUseVertexLighting;
|
||||
|
||||
virtual SceneLighting::ObjectProxy* createObjectProxy(SceneObject* obj, SceneLighting::ObjectProxyList* sceneObjects);
|
||||
virtual PersistInfo::PersistChunk* createPersistChunk(const U32 chunkType);
|
||||
virtual bool createPersistChunkFromProxy(SceneLighting::ObjectProxy* objproxy, PersistInfo::PersistChunk **ret);
|
||||
|
||||
virtual void init();
|
||||
virtual U32 addObjectType();
|
||||
virtual U32 addToClippingMask();
|
||||
|
||||
virtual void processLightingBegin();
|
||||
virtual void processLightingCompleted(bool success);
|
||||
|
||||
// Given a ray, this will return the color from the lightmap of this object, return true if handled
|
||||
virtual bool getColorFromRayInfo(RayInfo collision, ColorF& result);
|
||||
};
|
||||
|
||||
#endif // !_BLINTERIOSYSTEM_H_
|
||||
715
Engine/source/lighting/basic/blTerrainSystem.cpp
Normal file
715
Engine/source/lighting/basic/blTerrainSystem.cpp
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/basic/blTerrainSystem.h"
|
||||
|
||||
#include "core/bitVector.h"
|
||||
#include "lighting/common/shadowVolumeBSP.h"
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "lighting/basic/basicLightManager.h"
|
||||
#include "lighting/common/sceneLighting.h"
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "collision/collision.h"
|
||||
|
||||
extern SceneLighting* gLighting;
|
||||
|
||||
|
||||
struct blTerrainChunk : public PersistInfo::PersistChunk
|
||||
{
|
||||
typedef PersistInfo::PersistChunk Parent;
|
||||
|
||||
blTerrainChunk();
|
||||
~blTerrainChunk();
|
||||
|
||||
GBitmap *mLightmap;
|
||||
|
||||
bool read(Stream &);
|
||||
bool write(Stream &);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class SceneLighting::TerrainChunk
|
||||
//------------------------------------------------------------------------------
|
||||
blTerrainChunk::blTerrainChunk()
|
||||
{
|
||||
mChunkType = PersistChunk::TerrainChunkType;
|
||||
mLightmap = NULL;
|
||||
}
|
||||
|
||||
blTerrainChunk::~blTerrainChunk()
|
||||
{
|
||||
if(mLightmap)
|
||||
delete mLightmap;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool blTerrainChunk::read(Stream & stream)
|
||||
{
|
||||
if(!Parent::read(stream))
|
||||
return(false);
|
||||
|
||||
mLightmap = new GBitmap();
|
||||
return mLightmap->readBitmap("png",stream);
|
||||
}
|
||||
|
||||
bool blTerrainChunk::write(Stream & stream)
|
||||
{
|
||||
if(!Parent::write(stream))
|
||||
return(false);
|
||||
|
||||
if(!mLightmap)
|
||||
return(false);
|
||||
|
||||
if(!mLightmap->writeBitmap("png",stream))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
class blTerrainProxy : public SceneLighting::ObjectProxy
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef ObjectProxy Parent;
|
||||
|
||||
BitVector mShadowMask;
|
||||
ShadowVolumeBSP * mShadowVolume;
|
||||
ColorF * mLightmap;
|
||||
|
||||
/// The dimension of the lightmap in pixels.
|
||||
const U32 mLightMapSize;
|
||||
|
||||
/// The dimension of the terrain height map sample array.
|
||||
const U32 mTerrainBlockSize;
|
||||
|
||||
ColorF *sgBakedLightmap;
|
||||
Vector<LightInfo *> sgLights;
|
||||
bool sgMarkStaticShadow(void *terrainproxy, SceneObject *sceneobject, LightInfo *light);
|
||||
//void postLight(bool lastLight);
|
||||
|
||||
void lightVector(LightInfo *);
|
||||
|
||||
struct SquareStackNode
|
||||
{
|
||||
U8 mLevel;
|
||||
U16 mClipFlags;
|
||||
Point2I mPos;
|
||||
};
|
||||
|
||||
S32 testSquare(const Point3F &, const Point3F &, S32, F32, const Vector<PlaneF> &);
|
||||
bool markObjectShadow(ObjectProxy *);
|
||||
bool sgIsCorrectStaticObjectType(SceneObject *obj);
|
||||
|
||||
inline ColorF _getValue( S32 row, S32 column );
|
||||
|
||||
public:
|
||||
|
||||
blTerrainProxy(SceneObject * obj);
|
||||
~blTerrainProxy();
|
||||
TerrainBlock * operator->() {return(static_cast<TerrainBlock*>(static_cast<SceneObject*>(mObj)));}
|
||||
TerrainBlock * getObject() {return(static_cast<TerrainBlock*>(static_cast<SceneObject*>(mObj)));}
|
||||
|
||||
bool getShadowedSquares(const Vector<PlaneF> &, Vector<U16> &);
|
||||
|
||||
// lighting
|
||||
void init();
|
||||
bool preLight(LightInfo *);
|
||||
void light(LightInfo *);
|
||||
|
||||
// persist
|
||||
U32 getResourceCRC();
|
||||
bool setPersistInfo(PersistInfo::PersistChunk *);
|
||||
bool getPersistInfo(PersistInfo::PersistChunk *);
|
||||
|
||||
virtual bool supportsShadowVolume();
|
||||
virtual void getClipPlanes(Vector<PlaneF>& planes);
|
||||
virtual void addToShadowVolume(ShadowVolumeBSP * shadowVolume, LightInfo * light, S32 level);
|
||||
|
||||
// events
|
||||
//virtual void processTGELightProcessEvent(U32 curr, U32 max, LightInfo* currlight);
|
||||
//virtual void processSGObjectProcessEvent(LightInfo* currLight);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Class SceneLighting::TerrainProxy:
|
||||
//-------------------------------------------------------------------------------
|
||||
blTerrainProxy::blTerrainProxy( SceneObject *obj ) :
|
||||
Parent( obj ),
|
||||
mLightMapSize( getObject()->getLightMapSize() ),
|
||||
mTerrainBlockSize( getObject()->getBlockSize() ),
|
||||
mLightmap( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
blTerrainProxy::~blTerrainProxy()
|
||||
{
|
||||
delete [] mLightmap;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
void blTerrainProxy::init()
|
||||
{
|
||||
mLightmap = new ColorF[ mLightMapSize * mLightMapSize ];
|
||||
dMemset(mLightmap, 0, mLightMapSize * mLightMapSize * sizeof(ColorF));
|
||||
mShadowMask.setSize( mTerrainBlockSize * mTerrainBlockSize );
|
||||
}
|
||||
|
||||
bool blTerrainProxy::preLight(LightInfo * light)
|
||||
{
|
||||
if(!bool(mObj))
|
||||
return(false);
|
||||
|
||||
if(light->getType() != LightInfo::Vector)
|
||||
return(false);
|
||||
|
||||
mShadowMask.clear();
|
||||
return(true);
|
||||
}
|
||||
|
||||
inline ColorF blTerrainProxy::_getValue( S32 row, S32 column )
|
||||
{
|
||||
while( row < 0 )
|
||||
row += mLightMapSize;
|
||||
row = row % mLightMapSize;
|
||||
|
||||
while( column < 0 )
|
||||
column += mLightMapSize;
|
||||
column = column % mLightMapSize;
|
||||
|
||||
U32 offset = row * mLightMapSize + column;
|
||||
|
||||
return mLightmap[offset];
|
||||
}
|
||||
|
||||
bool blTerrainProxy::markObjectShadow(ObjectProxy * proxy)
|
||||
{
|
||||
if (!proxy->supportsShadowVolume())
|
||||
return false;
|
||||
|
||||
// setup the clip planes
|
||||
Vector<PlaneF> clipPlanes;
|
||||
proxy->getClipPlanes(clipPlanes);
|
||||
|
||||
Vector<U16> shadowList;
|
||||
if(!getShadowedSquares(clipPlanes, shadowList))
|
||||
return(false);
|
||||
|
||||
// set the correct bit
|
||||
for(U32 i = 0; i < shadowList.size(); i++)
|
||||
mShadowMask.set(shadowList[i]);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void blTerrainProxy::light(LightInfo * light)
|
||||
{
|
||||
// If we don't have terrain or its not a directional
|
||||
// light then skip processing.
|
||||
TerrainBlock * terrain = getObject();
|
||||
if ( !terrain || light->getType() != LightInfo::Vector )
|
||||
return;
|
||||
|
||||
S32 time = Platform::getRealMilliseconds();
|
||||
|
||||
// reset
|
||||
mShadowVolume = new ShadowVolumeBSP;
|
||||
|
||||
// build interior shadow volume
|
||||
for(ObjectProxy ** itr = gLighting->mLitObjects.begin(); itr != gLighting->mLitObjects.end(); itr++)
|
||||
{
|
||||
ObjectProxy* objproxy = *itr;
|
||||
if (markObjectShadow(objproxy))
|
||||
objproxy->addToShadowVolume(mShadowVolume, light, SceneLighting::SHADOW_DETAIL);
|
||||
}
|
||||
|
||||
lightVector(light);
|
||||
|
||||
// set the lightmap...
|
||||
terrain->clearLightMap();
|
||||
|
||||
// Blur...
|
||||
F32 kernel[3][3] = { {1, 2, 1},
|
||||
{2, 3, 2},
|
||||
{1, 2, 1} };
|
||||
|
||||
F32 modifier = 1;
|
||||
F32 divisor = 0;
|
||||
|
||||
|
||||
for( U32 i=0; i<3; i++ )
|
||||
{
|
||||
for( U32 j=0; j<3; j++ )
|
||||
{
|
||||
if( i==1 && j==1 )
|
||||
{
|
||||
kernel[i][j] = 1 + kernel[i][j] * modifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
kernel[i][j] = kernel[i][j] * modifier;
|
||||
}
|
||||
|
||||
divisor += kernel[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for( U32 i=0; i < mLightMapSize; i++ )
|
||||
{
|
||||
for( U32 j=0; j < mLightMapSize; j++ )
|
||||
{
|
||||
|
||||
ColorF val;
|
||||
val = _getValue( i-1, j-1 ) * kernel[0][0];
|
||||
val += _getValue( i-1, j ) * kernel[0][1];
|
||||
val += _getValue( i-1, j+1 ) * kernel[0][2];
|
||||
val += _getValue( i, j-1 ) * kernel[1][0];
|
||||
val += _getValue( i, j ) * kernel[1][1];
|
||||
val += _getValue( i, j+1 ) * kernel[1][2];
|
||||
val += _getValue( i+1, j-1 ) * kernel[2][0];
|
||||
val += _getValue( i+1, j ) * kernel[2][1];
|
||||
val += _getValue( i+1, j+1 ) * kernel[2][2];
|
||||
|
||||
U32 edge = 0;
|
||||
|
||||
if( j == 0 || j == mLightMapSize - 1 )
|
||||
edge++;
|
||||
|
||||
if( i == 0 || i == mLightMapSize - 1 )
|
||||
edge++;
|
||||
|
||||
if( !edge )
|
||||
val = val / divisor;
|
||||
else
|
||||
val = mLightmap[ i * mLightMapSize + j ];
|
||||
|
||||
// clamp values
|
||||
mLightmap[ i * mLightMapSize + j ]= val;
|
||||
}
|
||||
}
|
||||
|
||||
// And stuff it into the texture...
|
||||
GBitmap *terrLightMap = terrain->getLightMap();
|
||||
for(U32 y = 0; y < mLightMapSize; y++)
|
||||
{
|
||||
for(U32 x = 0; x < mLightMapSize; x++)
|
||||
{
|
||||
ColorI color(255, 255, 255, 255);
|
||||
|
||||
color.red = mLightmap[x + y * mLightMapSize].red * 255;
|
||||
color.green = mLightmap[x + y * mLightMapSize].green * 255;
|
||||
color.blue = mLightmap[x + y * mLightMapSize].blue * 255;
|
||||
|
||||
terrLightMap->setColor(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// This handles matching up the outer edges of the terrain
|
||||
// lightmap when it has neighbors
|
||||
if (!terrain->isTiling())
|
||||
{
|
||||
for (S32 y = 0; y < terrLightMap->getHeight(); y++)
|
||||
{
|
||||
ColorI c;
|
||||
if (terrain->getFile()->mEdgeTerrainFiles[0])
|
||||
{
|
||||
terrLightMap->getColor(terrLightMap->getWidth()-1,y,c);
|
||||
terrLightMap->setColor(0,y,c);
|
||||
terrLightMap->setColor(1,y,c);
|
||||
}
|
||||
else
|
||||
{
|
||||
terrLightMap->getColor(0,y,c);
|
||||
terrLightMap->setColor(terrLightMap->getWidth()-1,y,c);
|
||||
terrLightMap->setColor(terrLightMap->getWidth()-2,y,c);
|
||||
}
|
||||
}
|
||||
|
||||
for (S32 x = 0; x < terrLightMap->getHeight(); x++)
|
||||
{
|
||||
ColorI c;
|
||||
if (terrain->getFile()->mEdgeTerrainFiles[1])
|
||||
{
|
||||
terrLightMap->getColor(x,terrLightMap->getHeight()-1,c);
|
||||
terrLightMap->setColor(x,0,c);
|
||||
terrLightMap->setColor(x,1,c);
|
||||
}
|
||||
else
|
||||
{
|
||||
terrLightMap->getColor(x,0,c);
|
||||
terrLightMap->setColor(x,terrLightMap->getHeight()-1,c);
|
||||
terrLightMap->setColor(x,terrLightMap->getHeight()-2,c);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
delete mShadowVolume;
|
||||
|
||||
Con::printf(" = terrain lit in %3.3f seconds", (Platform::getRealMilliseconds()-time)/1000.f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
S32 blTerrainProxy::testSquare(const Point3F & min, const Point3F & max, S32 mask, F32 expand, const Vector<PlaneF> & clipPlanes)
|
||||
{
|
||||
expand = 0;
|
||||
S32 retMask = 0;
|
||||
Point3F minPoint, maxPoint;
|
||||
for(S32 i = 0; i < clipPlanes.size(); i++)
|
||||
{
|
||||
if(mask & (1 << i))
|
||||
{
|
||||
if(clipPlanes[i].x > 0)
|
||||
{
|
||||
maxPoint.x = max.x;
|
||||
minPoint.x = min.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxPoint.x = min.x;
|
||||
minPoint.x = max.x;
|
||||
}
|
||||
if(clipPlanes[i].y > 0)
|
||||
{
|
||||
maxPoint.y = max.y;
|
||||
minPoint.y = min.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxPoint.y = min.y;
|
||||
minPoint.y = max.y;
|
||||
}
|
||||
if(clipPlanes[i].z > 0)
|
||||
{
|
||||
maxPoint.z = max.z;
|
||||
minPoint.z = min.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxPoint.z = min.z;
|
||||
minPoint.z = max.z;
|
||||
}
|
||||
F32 maxDot = mDot(maxPoint, clipPlanes[i]);
|
||||
F32 minDot = mDot(minPoint, clipPlanes[i]);
|
||||
F32 planeD = clipPlanes[i].d;
|
||||
if(maxDot <= -(planeD + expand))
|
||||
return(U16(-1));
|
||||
if(minDot <= -planeD)
|
||||
retMask |= (1 << i);
|
||||
}
|
||||
}
|
||||
return(retMask);
|
||||
}
|
||||
|
||||
bool blTerrainProxy::getShadowedSquares(const Vector<PlaneF> & clipPlanes, Vector<U16> & shadowList)
|
||||
{
|
||||
TerrainBlock *terrain = getObject();
|
||||
if ( !terrain )
|
||||
return false;
|
||||
|
||||
// TODO: Fix me for variable terrain sizes!
|
||||
return true;
|
||||
|
||||
/*
|
||||
SquareStackNode stack[TerrainBlock::BlockShift * 4];
|
||||
|
||||
stack[0].mLevel = TerrainBlock::BlockShift;
|
||||
stack[0].mClipFlags = 0xff;
|
||||
stack[0].mPos.set(0,0);
|
||||
|
||||
U32 stackSize = 1;
|
||||
|
||||
Point3F blockPos;
|
||||
terrain->getTransform().getColumn(3, &blockPos);
|
||||
S32 squareSize = terrain->getSquareSize();
|
||||
F32 floatSquareSize = (F32)squareSize;
|
||||
|
||||
bool marked = false;
|
||||
|
||||
// push through all the levels of the quadtree
|
||||
while(stackSize)
|
||||
{
|
||||
SquareStackNode * node = &stack[stackSize - 1];
|
||||
|
||||
S32 clipFlags = node->mClipFlags;
|
||||
Point2I pos = node->mPos;
|
||||
GridSquare * sq = terrain->findSquare(node->mLevel, pos);
|
||||
|
||||
Point3F minPoint, maxPoint;
|
||||
minPoint.set(squareSize * pos.x + blockPos.x,
|
||||
squareSize * pos.y + blockPos.y,
|
||||
fixedToFloat(sq->minHeight));
|
||||
maxPoint.set(minPoint.x + (squareSize << node->mLevel),
|
||||
minPoint.y + (squareSize << node->mLevel),
|
||||
fixedToFloat(sq->maxHeight));
|
||||
|
||||
// test the square against the current level
|
||||
if(clipFlags)
|
||||
{
|
||||
clipFlags = testSquare(minPoint, maxPoint, clipFlags, floatSquareSize, clipPlanes);
|
||||
if(clipFlags == U16(-1))
|
||||
{
|
||||
stackSize--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// shadowed?
|
||||
if(node->mLevel == 0)
|
||||
{
|
||||
marked = true;
|
||||
shadowList.push_back(pos.x + (pos.y << TerrainBlock::BlockShift));
|
||||
stackSize--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// setup the next level of squares
|
||||
U8 nextLevel = node->mLevel - 1;
|
||||
S32 squareHalfSize = 1 << nextLevel;
|
||||
|
||||
for(U32 i = 0; i < 4; i++)
|
||||
{
|
||||
node[i].mLevel = nextLevel;
|
||||
node[i].mClipFlags = clipFlags;
|
||||
}
|
||||
|
||||
node[3].mPos = pos;
|
||||
node[2].mPos.set(pos.x + squareHalfSize, pos.y);
|
||||
node[1].mPos.set(pos.x, pos.y + squareHalfSize);
|
||||
node[0].mPos.set(pos.x + squareHalfSize, pos.y + squareHalfSize);
|
||||
|
||||
stackSize += 3;
|
||||
}
|
||||
|
||||
return marked;
|
||||
*/
|
||||
}
|
||||
|
||||
void blTerrainProxy::lightVector(LightInfo * light)
|
||||
{
|
||||
// Grab our terrain object
|
||||
TerrainBlock* terrain = getObject();
|
||||
if (!terrain)
|
||||
return;
|
||||
|
||||
// Get the direction to the light (the inverse of the direction
|
||||
// the light is pointing)
|
||||
Point3F lightDir = -light->getDirection();
|
||||
lightDir.normalize();
|
||||
|
||||
// Get the ratio between the light map pixel and world space (used below)
|
||||
F32 lmTerrRatio = (F32)mTerrainBlockSize / (F32) mLightMapSize;
|
||||
lmTerrRatio *= terrain->getSquareSize();
|
||||
|
||||
// Get the terrain position
|
||||
Point3F terrPos( terrain->getTransform().getPosition() );
|
||||
|
||||
U32 i = 0;
|
||||
for (U32 y = 0; y < mLightMapSize; y++)
|
||||
{
|
||||
for (U32 x = 0; x < mLightMapSize; x++)
|
||||
{
|
||||
// Get the relative pixel position and scale it
|
||||
// by the ratio between lightmap and world space
|
||||
Point2F pixelPos(x, y);
|
||||
pixelPos *= lmTerrRatio;
|
||||
|
||||
// Start with a default normal of straight up
|
||||
Point3F normal(0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Try to get the actual normal from the terrain.
|
||||
// Note: this won't change the default normal if
|
||||
// it can't find a normal.
|
||||
terrain->getNormal(pixelPos, &normal);
|
||||
|
||||
// The terrain lightmap only contains shadows.
|
||||
F32 shadowed = 0.0f;
|
||||
|
||||
// Get the height at the lightmap pixel's position
|
||||
F32 height = 0.0f;
|
||||
terrain->getHeight(pixelPos, &height);
|
||||
|
||||
// Calculate the 3D position of the pixel
|
||||
Point3F pixelPos3F(pixelPos.x, pixelPos.y, height);
|
||||
|
||||
// Translate that position by the terrain's transform
|
||||
terrain->getTransform().mulP(pixelPos3F);
|
||||
|
||||
// Offset slighting along the normal so that we don't
|
||||
// raycast into ourself
|
||||
pixelPos3F += (normal * 0.1f);
|
||||
|
||||
// Calculate the light's position.
|
||||
// If it is a vector light like the sun (no position
|
||||
// just direction) then translate along that direction
|
||||
// a reasonable distance to get a point sufficiently
|
||||
// far away
|
||||
Point3F lightPos = light->getPosition();
|
||||
if(light->getType() == LightInfo::Vector)
|
||||
{
|
||||
lightPos = 1000.f * lightDir;
|
||||
lightPos = pixelPos3F + lightPos;
|
||||
}
|
||||
|
||||
// Cast a ray from the world space position of the lightmap pixel to the light source.
|
||||
// If we hit something then we are in shadow. This allows us to be shadowed by anything
|
||||
// that supports a castRay operation.
|
||||
RayInfo info;
|
||||
if(terrain->getContainer()->castRay(pixelPos3F, lightPos, STATIC_COLLISION_TYPEMASK, &info))
|
||||
{
|
||||
// Shadow the pixel.
|
||||
shadowed = 1.0f;
|
||||
}
|
||||
|
||||
// Set the final lightmap color.
|
||||
mLightmap[i++] += ColorF::WHITE * mClampF( 1.0f - shadowed, 0.0f, 1.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
U32 blTerrainProxy::getResourceCRC()
|
||||
{
|
||||
TerrainBlock * terrain = getObject();
|
||||
if(!terrain)
|
||||
return(0);
|
||||
return(terrain->getCRC());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool blTerrainProxy::setPersistInfo(PersistInfo::PersistChunk * info)
|
||||
{
|
||||
if(!Parent::setPersistInfo(info))
|
||||
return(false);
|
||||
|
||||
blTerrainChunk * chunk = dynamic_cast<blTerrainChunk*>(info);
|
||||
AssertFatal(chunk, "blTerrainProxy::setPersistInfo: invalid info chunk!");
|
||||
|
||||
TerrainBlock * terrain = getObject();
|
||||
if(!terrain || !terrain->getLightMap())
|
||||
return(false);
|
||||
|
||||
terrain->setLightMap( new GBitmap( *chunk->mLightmap) );
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool blTerrainProxy::getPersistInfo(PersistInfo::PersistChunk * info)
|
||||
{
|
||||
if(!Parent::getPersistInfo(info))
|
||||
return(false);
|
||||
|
||||
blTerrainChunk * chunk = dynamic_cast<blTerrainChunk*>(info);
|
||||
AssertFatal(chunk, "blTerrainProxy::getPersistInfo: invalid info chunk!");
|
||||
|
||||
TerrainBlock * terrain = getObject();
|
||||
if(!terrain || !terrain->getLightMap())
|
||||
return(false);
|
||||
|
||||
if(chunk->mLightmap) delete chunk->mLightmap;
|
||||
|
||||
chunk->mLightmap = new GBitmap(*terrain->getLightMap());
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool blTerrainProxy::supportsShadowVolume()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void blTerrainProxy::getClipPlanes(Vector<PlaneF>& planes)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void blTerrainProxy::addToShadowVolume(ShadowVolumeBSP * shadowVolume, LightInfo * light, S32 level)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void blTerrainSystem::init()
|
||||
{
|
||||
}
|
||||
|
||||
U32 blTerrainSystem::addObjectType()
|
||||
{
|
||||
return TerrainObjectType;
|
||||
}
|
||||
|
||||
SceneLighting::ObjectProxy* blTerrainSystem::createObjectProxy(SceneObject* obj, SceneLighting::ObjectProxyList* sceneObjects)
|
||||
{
|
||||
if ((obj->getTypeMask() & TerrainObjectType) != 0)
|
||||
return new blTerrainProxy(obj);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PersistInfo::PersistChunk* blTerrainSystem::createPersistChunk(const U32 chunkType)
|
||||
{
|
||||
if (chunkType == PersistInfo::PersistChunk::TerrainChunkType)
|
||||
return new blTerrainChunk();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool blTerrainSystem::createPersistChunkFromProxy(SceneLighting::ObjectProxy* objproxy, PersistInfo::PersistChunk **ret)
|
||||
{
|
||||
if (dynamic_cast<blTerrainProxy*>(objproxy) != NULL)
|
||||
{
|
||||
*ret = new blTerrainChunk();
|
||||
return true;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Given a ray, this will return the color from the lightmap of this object, return true if handled
|
||||
bool blTerrainSystem::getColorFromRayInfo(const RayInfo & collision, ColorF& result) const
|
||||
{
|
||||
TerrainBlock *terrain = dynamic_cast<TerrainBlock *>(collision.object);
|
||||
if (!terrain)
|
||||
return false;
|
||||
|
||||
Point2F uv;
|
||||
F32 terrainlength = (F32)terrain->getBlockSize();
|
||||
Point3F pos = terrain->getPosition();
|
||||
uv.x = (collision.point.x - pos.x) / terrainlength;
|
||||
uv.y = (collision.point.y - pos.y) / terrainlength;
|
||||
|
||||
// similar to x = x & width...
|
||||
uv.x = uv.x - F32(U32(uv.x));
|
||||
uv.y = uv.y - F32(U32(uv.y));
|
||||
const GBitmap* lightmap = terrain->getLightMap();
|
||||
if (!lightmap)
|
||||
return false;
|
||||
|
||||
result = lightmap->sampleTexel(uv.x, uv.y);
|
||||
// terrain lighting is dim - look into this (same thing done in shaders)...
|
||||
result *= 2.0f;
|
||||
return true;
|
||||
}
|
||||
49
Engine/source/lighting/basic/blTerrainSystem.h
Normal file
49
Engine/source/lighting/basic/blTerrainSystem.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _BLTERRAINSYSTEM_H_
|
||||
#define _BLTERRAINSYSTEM_H_
|
||||
|
||||
#ifndef _SCENELIGHTING_H_
|
||||
#include "lighting/common/sceneLighting.h"
|
||||
#endif
|
||||
#ifndef _SG_SYSTEM_INTERFACE_H
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#endif
|
||||
|
||||
//
|
||||
// Lighting system interface
|
||||
//
|
||||
class blTerrainSystem : public SceneLightingInterface
|
||||
{
|
||||
public:
|
||||
virtual void init();
|
||||
virtual U32 addObjectType();
|
||||
virtual SceneLighting::ObjectProxy* createObjectProxy(SceneObject* obj, SceneLighting::ObjectProxyList* sceneObjects);
|
||||
virtual PersistInfo::PersistChunk* createPersistChunk(const U32 chunkType);
|
||||
virtual bool createPersistChunkFromProxy(SceneLighting::ObjectProxy* objproxy, PersistInfo::PersistChunk **ret);
|
||||
|
||||
// Given a ray, this will return the color from the lightmap of this object, return true if handled
|
||||
virtual bool getColorFromRayInfo(const RayInfo & collision, ColorF& result) const;
|
||||
};
|
||||
|
||||
#endif // !_BLTERRAINSYSTEM_H_
|
||||
352
Engine/source/lighting/common/blobShadow.cpp
Normal file
352
Engine/source/lighting/common/blobShadow.cpp
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/common/blobShadow.h"
|
||||
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxTextureManager.h"
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "lighting/lightInfo.h"
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#include "T3D/shapeBase.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "ts/tsMesh.h"
|
||||
|
||||
DepthSortList BlobShadow::smDepthSortList;
|
||||
GFXTexHandle BlobShadow::smGenericShadowTexture = NULL;
|
||||
S32 BlobShadow::smGenericShadowDim = 32;
|
||||
U32 BlobShadow::smShadowMask = TerrainObjectType | InteriorObjectType;
|
||||
F32 BlobShadow::smGenericRadiusSkew = 0.4f; // shrink radius of shape when it always uses generic shadow...
|
||||
|
||||
Box3F gBlobShadowBox;
|
||||
SphereF gBlobShadowSphere;
|
||||
Point3F gBlobShadowPoly[4];
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
BlobShadow::BlobShadow(SceneObject* parentObject, LightInfo* light, TSShapeInstance* shapeInstance)
|
||||
{
|
||||
mParentObject = parentObject;
|
||||
mShapeBase = dynamic_cast<ShapeBase*>(parentObject);
|
||||
mParentLight = light;
|
||||
mShapeInstance = shapeInstance;
|
||||
mRadius = 0.0f;
|
||||
mLastRenderTime = 0;
|
||||
mDepthBias = -0.0002f;
|
||||
|
||||
generateGenericShadowBitmap(smGenericShadowDim);
|
||||
setupStateBlocks();
|
||||
}
|
||||
|
||||
void BlobShadow::setupStateBlocks()
|
||||
{
|
||||
GFXStateBlockDesc sh;
|
||||
sh.cullDefined = true;
|
||||
sh.cullMode = GFXCullNone;
|
||||
sh.zDefined = true;
|
||||
sh.zEnable = true;
|
||||
sh.zWriteEnable = false;
|
||||
|
||||
sh.zBias = mDepthBias;
|
||||
sh.blendDefined = true;
|
||||
sh.blendEnable = true;
|
||||
sh.blendSrc = GFXBlendSrcAlpha;
|
||||
sh.blendDest = GFXBlendInvSrcAlpha;
|
||||
sh.alphaDefined = true;
|
||||
sh.alphaTestEnable = true;
|
||||
sh.alphaTestFunc = GFXCmpGreater;
|
||||
sh.alphaTestRef = 0;
|
||||
sh.samplersDefined = true;
|
||||
sh.samplers[0] = GFXSamplerStateDesc::getClampLinear();
|
||||
mShadowSB = GFX->createStateBlock(sh);
|
||||
}
|
||||
|
||||
BlobShadow::~BlobShadow()
|
||||
{
|
||||
mShadowBuffer = NULL;
|
||||
}
|
||||
|
||||
bool BlobShadow::shouldRender(F32 camDist)
|
||||
{
|
||||
Point3F lightDir;
|
||||
|
||||
if (mShapeBase && mShapeBase->getFadeVal() < TSMesh::VISIBILITY_EPSILON)
|
||||
return false;
|
||||
|
||||
F32 shadowLen = 10.0f * mShapeInstance->getShape()->radius;
|
||||
Point3F pos = mShapeInstance->getShape()->center;
|
||||
|
||||
// this is a bit of a hack...move generic shadows towards feet/base of shape
|
||||
pos *= 0.5f;
|
||||
pos.convolve(mParentObject->getScale());
|
||||
mParentObject->getRenderTransform().mulP(pos);
|
||||
if(mParentLight->getType() == LightInfo::Vector)
|
||||
{
|
||||
lightDir = mParentLight->getDirection();
|
||||
}
|
||||
else
|
||||
{
|
||||
lightDir = pos - mParentLight->getPosition();
|
||||
lightDir.normalize();
|
||||
}
|
||||
|
||||
// pos is where shadow will be centered (in world space)
|
||||
setRadius(mShapeInstance, mParentObject->getScale());
|
||||
bool render = prepare(pos, lightDir, shadowLen);
|
||||
return render;
|
||||
}
|
||||
|
||||
void BlobShadow::generateGenericShadowBitmap(S32 dim)
|
||||
{
|
||||
if(smGenericShadowTexture)
|
||||
return;
|
||||
GBitmap * bitmap = new GBitmap(dim,dim,false,GFXFormatR8G8B8A8);
|
||||
U8 * bits = bitmap->getWritableBits();
|
||||
dMemset(bits, 0, dim*dim*4);
|
||||
S32 center = dim >> 1;
|
||||
F32 invRadiusSq = 1.0f / (F32)(center*center);
|
||||
F32 tmpF;
|
||||
for (S32 i=0; i<dim; i++)
|
||||
{
|
||||
for (S32 j=0; j<dim; j++)
|
||||
{
|
||||
tmpF = (F32)((i-center)*(i-center)+(j-center)*(j-center)) * invRadiusSq;
|
||||
U8 val = tmpF>0.99f ? 0 : (U8)(180.0f*(1.0f-tmpF)); // 180 out of 255 max
|
||||
bits[(i*dim*4)+(j*4)+3] = val;
|
||||
}
|
||||
}
|
||||
|
||||
smGenericShadowTexture.set( bitmap, &GFXDefaultStaticDiffuseProfile, true, "BlobShadow" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
void BlobShadow::setLightMatrices(const Point3F & lightDir, const Point3F & pos)
|
||||
{
|
||||
AssertFatal(mDot(lightDir,lightDir)>0.0001f,"BlobShadow::setLightDir: light direction must be a non-zero vector.");
|
||||
|
||||
// construct light matrix
|
||||
Point3F x,z;
|
||||
if (mFabs(lightDir.z)>0.001f)
|
||||
{
|
||||
// mCross(Point3F(1,0,0),lightDir,&z);
|
||||
z.x = 0.0f;
|
||||
z.y = lightDir.z;
|
||||
z.z = -lightDir.y;
|
||||
z.normalize();
|
||||
mCross(lightDir,z,&x);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCross(lightDir,Point3F(0,0,1),&x);
|
||||
x.normalize();
|
||||
mCross(x,lightDir,&z);
|
||||
}
|
||||
|
||||
mLightToWorld.identity();
|
||||
mLightToWorld.setColumn(0,x);
|
||||
mLightToWorld.setColumn(1,lightDir);
|
||||
mLightToWorld.setColumn(2,z);
|
||||
mLightToWorld.setColumn(3,pos);
|
||||
|
||||
mWorldToLight = mLightToWorld;
|
||||
mWorldToLight.inverse();
|
||||
}
|
||||
|
||||
void BlobShadow::setRadius(F32 radius)
|
||||
{
|
||||
mRadius = radius;
|
||||
}
|
||||
|
||||
void BlobShadow::setRadius(TSShapeInstance * shapeInstance, const Point3F & scale)
|
||||
{
|
||||
const Box3F & bounds = shapeInstance->getShape()->bounds;
|
||||
F32 dx = 0.5f * (bounds.maxExtents.x-bounds.minExtents.x) * scale.x;
|
||||
F32 dy = 0.5f * (bounds.maxExtents.y-bounds.minExtents.y) * scale.y;
|
||||
F32 dz = 0.5f * (bounds.maxExtents.z-bounds.minExtents.z) * scale.z;
|
||||
mRadius = mSqrt(dx*dx+dy*dy+dz*dz);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
bool BlobShadow::prepare(const Point3F & pos, Point3F lightDir, F32 shadowLen)
|
||||
{
|
||||
if (mPartition.empty())
|
||||
{
|
||||
// --------------------------------------
|
||||
// 1.
|
||||
F32 dirMult = (1.0f) * (1.0f);
|
||||
if (dirMult < 0.99f)
|
||||
{
|
||||
lightDir.z *= dirMult;
|
||||
lightDir.z -= 1.0f - dirMult;
|
||||
}
|
||||
lightDir.normalize();
|
||||
shadowLen *= (1.0f) * (1.0f);
|
||||
|
||||
// --------------------------------------
|
||||
// 2. get polys
|
||||
F32 radius = mRadius;
|
||||
radius *= smGenericRadiusSkew;
|
||||
buildPartition(pos,lightDir,radius,shadowLen);
|
||||
}
|
||||
if (mPartition.empty())
|
||||
// no need to draw shadow if nothing to cast it onto
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
void BlobShadow::buildPartition(const Point3F & p, const Point3F & lightDir, F32 radius, F32 shadowLen)
|
||||
{
|
||||
setLightMatrices(lightDir,p);
|
||||
|
||||
Point3F extent(2.0f*radius,shadowLen,2.0f*radius);
|
||||
smDepthSortList.clear();
|
||||
smDepthSortList.set(mWorldToLight,extent);
|
||||
smDepthSortList.setInterestNormal(lightDir);
|
||||
|
||||
if (shadowLen<1.0f)
|
||||
// no point in even this short of a shadow...
|
||||
shadowLen = 1.0f;
|
||||
mInvShadowDistance = 1.0f / shadowLen;
|
||||
|
||||
// build world space box and sphere around shadow
|
||||
|
||||
Point3F x,y,z;
|
||||
mLightToWorld.getColumn(0,&x);
|
||||
mLightToWorld.getColumn(1,&y);
|
||||
mLightToWorld.getColumn(2,&z);
|
||||
x *= radius;
|
||||
y *= shadowLen;
|
||||
z *= radius;
|
||||
gBlobShadowBox.maxExtents.set(mFabs(x.x)+mFabs(y.x)+mFabs(z.x),
|
||||
mFabs(x.y)+mFabs(y.y)+mFabs(z.y),
|
||||
mFabs(x.z)+mFabs(y.z)+mFabs(z.z));
|
||||
y *= 0.5f;
|
||||
gBlobShadowSphere.radius = gBlobShadowBox.maxExtents.len();
|
||||
gBlobShadowSphere.center = p + y;
|
||||
gBlobShadowBox.minExtents = y + p - gBlobShadowBox.maxExtents;
|
||||
gBlobShadowBox.maxExtents += y + p;
|
||||
|
||||
// get polys
|
||||
|
||||
gClientContainer.findObjects(STATIC_COLLISION_TYPEMASK, BlobShadow::collisionCallback, this);
|
||||
|
||||
// setup partition list
|
||||
gBlobShadowPoly[0].set(-radius,0,-radius);
|
||||
gBlobShadowPoly[1].set(-radius,0, radius);
|
||||
gBlobShadowPoly[2].set( radius,0, radius);
|
||||
gBlobShadowPoly[3].set( radius,0,-radius);
|
||||
|
||||
mPartition.clear();
|
||||
mPartitionVerts.clear();
|
||||
smDepthSortList.depthPartition(gBlobShadowPoly,4,mPartition,mPartitionVerts);
|
||||
|
||||
if(mPartitionVerts.empty())
|
||||
return;
|
||||
|
||||
// Find the rough distance of the shadow verts
|
||||
// from the object position and use that to scale
|
||||
// the visibleAlpha so that the shadow fades out
|
||||
// the further away from you it gets
|
||||
F32 dist = 0.0f;
|
||||
|
||||
// Calculate the center of the partition verts
|
||||
Point3F shadowCenter(0.0f, 0.0f, 0.0f);
|
||||
for (U32 i = 0; i < mPartitionVerts.size(); i++)
|
||||
shadowCenter += mPartitionVerts[i];
|
||||
|
||||
shadowCenter /= mPartitionVerts.size();
|
||||
|
||||
mLightToWorld.mulP(shadowCenter);
|
||||
|
||||
dist = (p - shadowCenter).len();
|
||||
|
||||
// now set up tverts & colors
|
||||
mShadowBuffer.set(GFX, mPartitionVerts.size(), GFXBufferTypeVolatile);
|
||||
mShadowBuffer.lock();
|
||||
|
||||
F32 visibleAlpha = 255.0f;
|
||||
if (mShapeBase && mShapeBase->getFadeVal())
|
||||
visibleAlpha = mClampF(255.0f * mShapeBase->getFadeVal(), 0, 255);
|
||||
visibleAlpha *= 1.0f - (dist / gBlobShadowSphere.radius);
|
||||
F32 invRadius = 1.0f / radius;
|
||||
for (S32 i=0; i<mPartitionVerts.size(); i++)
|
||||
{
|
||||
Point3F vert = mPartitionVerts[i];
|
||||
mShadowBuffer[i].point.set(vert);
|
||||
mShadowBuffer[i].color.set(255, 255, 255, visibleAlpha);
|
||||
mShadowBuffer[i].texCoord.set(0.5f + 0.5f * mPartitionVerts[i].x * invRadius, 0.5f + 0.5f * mPartitionVerts[i].z * invRadius);
|
||||
};
|
||||
|
||||
mShadowBuffer.unlock();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
void BlobShadow::collisionCallback(SceneObject * obj, void* thisPtr)
|
||||
{
|
||||
if (obj->getWorldBox().isOverlapped(gBlobShadowBox))
|
||||
{
|
||||
// only interiors clip...
|
||||
ClippedPolyList::allowClipping = (obj->getTypeMask() & LIGHTMGR->getSceneLightingInterface()->mClippingMask) != 0;
|
||||
obj->buildPolyList(PLC_Collision,&smDepthSortList,gBlobShadowBox,gBlobShadowSphere);
|
||||
ClippedPolyList::allowClipping = true;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
void BlobShadow::render( F32 camDist, const TSRenderState &rdata )
|
||||
{
|
||||
mLastRenderTime = Platform::getRealMilliseconds();
|
||||
GFX->pushWorldMatrix();
|
||||
MatrixF world = GFX->getWorldMatrix();
|
||||
world.mul(mLightToWorld);
|
||||
GFX->setWorldMatrix(world);
|
||||
|
||||
GFX->disableShaders();
|
||||
|
||||
GFX->setStateBlock(mShadowSB);
|
||||
GFX->setTexture(0, smGenericShadowTexture);
|
||||
GFX->setVertexBuffer(mShadowBuffer);
|
||||
|
||||
for(U32 p=0; p<mPartition.size(); p++)
|
||||
GFX->drawPrimitive(GFXTriangleFan, mPartition[p].vertexStart, (mPartition[p].vertexCount - 2));
|
||||
|
||||
// This is a bad nasty hack which forces the shadow to reconstruct itself every frame.
|
||||
mPartition.clear();
|
||||
|
||||
GFX->popWorldMatrix();
|
||||
}
|
||||
|
||||
void BlobShadow::deleteGenericShadowBitmap()
|
||||
{
|
||||
smGenericShadowTexture = NULL;
|
||||
}
|
||||
87
Engine/source/lighting/common/blobShadow.h
Normal file
87
Engine/source/lighting/common/blobShadow.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _BLOBSHADOW_H_
|
||||
#define _BLOBSHADOW_H_
|
||||
|
||||
#include "collision/depthSortList.h"
|
||||
#include "scene/sceneObject.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "lighting/common/shadowBase.h"
|
||||
|
||||
class ShapeBase;
|
||||
class LightInfo;
|
||||
|
||||
class BlobShadow : public ShadowBase
|
||||
{
|
||||
F32 mRadius;
|
||||
F32 mInvShadowDistance;
|
||||
MatrixF mLightToWorld;
|
||||
MatrixF mWorldToLight;
|
||||
|
||||
Vector<DepthSortList::Poly> mPartition;
|
||||
Vector<Point3F> mPartitionVerts;
|
||||
GFXVertexBufferHandle<GFXVertexPCT> mShadowBuffer;
|
||||
|
||||
static U32 smShadowMask;
|
||||
|
||||
static DepthSortList smDepthSortList;
|
||||
static GFXTexHandle smGenericShadowTexture;
|
||||
static F32 smGenericRadiusSkew;
|
||||
static S32 smGenericShadowDim;
|
||||
|
||||
U32 mLastRenderTime;
|
||||
|
||||
static void collisionCallback(SceneObject*,void *);
|
||||
|
||||
private:
|
||||
SceneObject* mParentObject;
|
||||
ShapeBase* mShapeBase;
|
||||
LightInfo* mParentLight;
|
||||
TSShapeInstance* mShapeInstance;
|
||||
GFXStateBlockRef mShadowSB;
|
||||
F32 mDepthBias;
|
||||
|
||||
void setupStateBlocks();
|
||||
void setLightMatrices(const Point3F & lightDir, const Point3F & pos);
|
||||
void buildPartition(const Point3F & p, const Point3F & lightDir, F32 radius, F32 shadowLen);
|
||||
public:
|
||||
|
||||
BlobShadow(SceneObject* parentobject, LightInfo* light, TSShapeInstance* shapeinstance);
|
||||
~BlobShadow();
|
||||
|
||||
void setRadius(F32 radius);
|
||||
void setRadius(TSShapeInstance *, const Point3F & scale);
|
||||
|
||||
bool prepare(const Point3F & pos, Point3F lightDir, F32 shadowLen);
|
||||
|
||||
bool shouldRender(F32 camDist);
|
||||
|
||||
void update( const SceneRenderState *state ) {}
|
||||
void render( F32 camDist, const TSRenderState &rdata );
|
||||
U32 getLastRenderTime() const { return mLastRenderTime; }
|
||||
|
||||
static void generateGenericShadowBitmap(S32 dim);
|
||||
static void deleteGenericShadowBitmap();
|
||||
};
|
||||
|
||||
#endif
|
||||
61
Engine/source/lighting/common/lightMapParams.cpp
Normal file
61
Engine/source/lighting/common/lightMapParams.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "lighting/common/lightMapParams.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
|
||||
const LightInfoExType LightMapParams::Type( "LightMapParams" );
|
||||
|
||||
LightMapParams::LightMapParams( LightInfo *light ) :
|
||||
representedInLightmap(false),
|
||||
includeLightmappedGeometryInShadow(false),
|
||||
shadowDarkenColor(0.0f, 0.0f, 0.0f, -1.0f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LightMapParams::~LightMapParams()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LightMapParams::set( const LightInfoEx *ex )
|
||||
{
|
||||
// TODO: Do we even need this?
|
||||
}
|
||||
|
||||
void LightMapParams::packUpdate( BitStream *stream ) const
|
||||
{
|
||||
stream->writeFlag(representedInLightmap);
|
||||
stream->writeFlag(includeLightmappedGeometryInShadow);
|
||||
stream->write(shadowDarkenColor);
|
||||
}
|
||||
|
||||
void LightMapParams::unpackUpdate( BitStream *stream )
|
||||
{
|
||||
representedInLightmap = stream->readFlag();
|
||||
includeLightmappedGeometryInShadow = stream->readFlag();
|
||||
stream->read(&shadowDarkenColor);
|
||||
|
||||
// Always make sure that the alpha value of the shadowDarkenColor is -1.0
|
||||
shadowDarkenColor.alpha = -1.0f;
|
||||
}
|
||||
54
Engine/source/lighting/common/lightMapParams.h
Normal file
54
Engine/source/lighting/common/lightMapParams.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _LIGHTMAPPARAMS_H_
|
||||
#define _LIGHTMAPPARAMS_H_
|
||||
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
|
||||
class LightMapParams : public LightInfoEx
|
||||
{
|
||||
public:
|
||||
LightMapParams( LightInfo *light );
|
||||
virtual ~LightMapParams();
|
||||
|
||||
/// 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 );
|
||||
|
||||
public:
|
||||
// We're leaving these public for easy access
|
||||
// for console protected fields.
|
||||
|
||||
bool representedInLightmap; ///< This light is represented in lightmaps (static light, default: false)
|
||||
ColorF shadowDarkenColor; ///< The color that should be used to multiply-blend dynamic shadows onto lightmapped geometry (ignored if 'representedInLightmap' is false)
|
||||
bool includeLightmappedGeometryInShadow; ///< This light should render lightmapped geometry during its shadow-map update (ignored if 'representedInLightmap' is false)
|
||||
};
|
||||
|
||||
#endif
|
||||
582
Engine/source/lighting/common/projectedShadow.cpp
Normal file
582
Engine/source/lighting/common/projectedShadow.cpp
Normal file
|
|
@ -0,0 +1,582 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/common/projectedShadow.h"
|
||||
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxTextureManager.h"
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "lighting/lightInfo.h"
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#include "T3D/shapeBase.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "ts/tsMesh.h"
|
||||
#include "T3D/decal/decalManager.h"
|
||||
#include "T3D/decal/decalInstance.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "renderInstance/renderMeshMgr.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "materials/customMaterialDefinition.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "postFx/postEffect.h"
|
||||
#include "lighting/basic/basicLightManager.h"
|
||||
#include "lighting/shadowMap/shadowMatHook.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "lighting/shadowMap/lightShadowMap.h"
|
||||
|
||||
|
||||
SimObjectPtr<RenderPassManager> ProjectedShadow::smRenderPass = NULL;
|
||||
SimObjectPtr<PostEffect> ProjectedShadow::smShadowFilter = NULL;
|
||||
F32 ProjectedShadow::smDepthAdjust = 10.0f;
|
||||
|
||||
float ProjectedShadow::smFadeStartPixelSize = 200.0f;
|
||||
float ProjectedShadow::smFadeEndPixelSize = 35.0f;
|
||||
|
||||
|
||||
GFX_ImplementTextureProfile( BLProjectedShadowProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize |
|
||||
GFXTextureProfile::RenderTarget |
|
||||
GFXTextureProfile::Pooled,
|
||||
GFXTextureProfile::None );
|
||||
|
||||
GFX_ImplementTextureProfile( BLProjectedShadowZProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize |
|
||||
GFXTextureProfile::ZTarget |
|
||||
GFXTextureProfile::Pooled,
|
||||
GFXTextureProfile::None );
|
||||
|
||||
|
||||
ProjectedShadow::ProjectedShadow( SceneObject *object )
|
||||
{
|
||||
mParentObject = object;
|
||||
mShapeBase = dynamic_cast<ShapeBase*>( object );
|
||||
|
||||
mRadius = 0;
|
||||
mLastRenderTime = 0;
|
||||
mUpdateTexture = false;
|
||||
|
||||
mShadowLength = 10.0f;
|
||||
|
||||
mDecalData = new DecalData;
|
||||
mDecalData->skipVertexNormals = true;
|
||||
|
||||
mDecalInstance = NULL;
|
||||
|
||||
mLastLightDir.set( 0, 0, 0 );
|
||||
mLastObjectPosition.set( object->getRenderPosition() );
|
||||
mLastObjectScale.set( object->getScale() );
|
||||
|
||||
CustomMaterial *customMat = NULL;
|
||||
Sim::findObject( "BL_ProjectedShadowMaterial", customMat );
|
||||
if ( customMat )
|
||||
{
|
||||
mDecalData->material = customMat;
|
||||
mDecalData->matInst = customMat->createMatInstance();
|
||||
}
|
||||
else
|
||||
mDecalData->matInst = MATMGR->createMatInstance( "WarningMaterial" );
|
||||
|
||||
mDecalData->matInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>() );
|
||||
|
||||
mCasterPositionSC = NULL;
|
||||
mShadowLengthSC = NULL;
|
||||
}
|
||||
|
||||
ProjectedShadow::~ProjectedShadow()
|
||||
{
|
||||
if ( mDecalInstance )
|
||||
gDecalManager->removeDecal( mDecalInstance );
|
||||
|
||||
delete mDecalData;
|
||||
|
||||
mShadowTexture = NULL;
|
||||
mRenderTarget = NULL;
|
||||
}
|
||||
|
||||
bool ProjectedShadow::shouldRender( const SceneRenderState *state )
|
||||
{
|
||||
// Don't render if our object has been removed from the
|
||||
// scene graph.
|
||||
|
||||
if( !mParentObject->getSceneManager() )
|
||||
return false;
|
||||
|
||||
// Don't render if the ShapeBase
|
||||
// object's fade value is greater
|
||||
// than the visibility epsilon.
|
||||
bool shapeFade = mShapeBase && mShapeBase->getFadeVal() < TSMesh::VISIBILITY_EPSILON;
|
||||
|
||||
// Get the shapebase datablock if we have one.
|
||||
ShapeBaseData *data = NULL;
|
||||
if ( mShapeBase )
|
||||
data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() );
|
||||
|
||||
// Also don't render if
|
||||
// the camera distance is greater
|
||||
// than the shadow length.
|
||||
if ( shapeFade || !mDecalData ||
|
||||
( mDecalInstance &&
|
||||
mDecalInstance->calcPixelSize( state->getViewport().extent.y, state->getCameraPosition(), state->getWorldToScreenScale().y ) < mDecalInstance->mDataBlock->fadeEndPixelSize ) )
|
||||
{
|
||||
// Release our shadow texture
|
||||
// so that others can grab it out
|
||||
// of the pool.
|
||||
mShadowTexture = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectedShadow::_updateDecal( const SceneRenderState *state )
|
||||
{
|
||||
PROFILE_SCOPE( ProjectedShadow_UpdateDecal );
|
||||
|
||||
if ( !LIGHTMGR )
|
||||
return false;
|
||||
|
||||
// Get the position of the decal first.
|
||||
const Box3F &objBox = mParentObject->getObjBox();
|
||||
const Point3F boxCenter = objBox.getCenter();
|
||||
Point3F decalPos = boxCenter;
|
||||
const MatrixF &renderTransform = mParentObject->getRenderTransform();
|
||||
{
|
||||
// Set up the decal position.
|
||||
// We use the object space box center
|
||||
// multiplied by the render transform
|
||||
// of the object to ensure we benefit
|
||||
// from interpolation.
|
||||
MatrixF t( renderTransform );
|
||||
t.setColumn(2,Point3F::UnitZ);
|
||||
t.mulP( decalPos );
|
||||
}
|
||||
|
||||
if ( mDecalInstance )
|
||||
{
|
||||
mDecalInstance->mPosition = decalPos;
|
||||
if ( !shouldRender( state ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the sunlight for the shadow projection.
|
||||
// We want the LightManager to return NULL if it can't
|
||||
// get the "real" sun, so we specify false for the useDefault parameter.
|
||||
LightInfo *lights[4] = {0};
|
||||
LightQuery query;
|
||||
query.init( mParentObject->getWorldSphere() );
|
||||
query.getLights( lights, 4 );
|
||||
|
||||
Point3F pos = renderTransform.getPosition();
|
||||
|
||||
Point3F lightDir( 0, 0, 0 );
|
||||
Point3F tmp( 0, 0, 0 );
|
||||
F32 weight = 0;
|
||||
F32 range = 0;
|
||||
U32 lightCount = 0;
|
||||
F32 dist = 0;
|
||||
F32 fade = 0;
|
||||
for ( U32 i = 0; i < 4; i++ )
|
||||
{
|
||||
// If we got a NULL light,
|
||||
// we're at the end of the list.
|
||||
if ( !lights[i] )
|
||||
break;
|
||||
|
||||
if ( !lights[i]->getCastShadows() )
|
||||
continue;
|
||||
|
||||
if ( lights[i]->getType() != LightInfo::Point )
|
||||
tmp = lights[i]->getDirection();
|
||||
else
|
||||
tmp = pos - lights[i]->getPosition();
|
||||
|
||||
range = lights[i]->getRange().x;
|
||||
dist = ( (tmp.lenSquared()) / ((range * range) * 0.5f));
|
||||
weight = mClampF( 1.0f - ( tmp.lenSquared() / (range * range)), 0.00001f, 1.0f );
|
||||
|
||||
if ( lights[i]->getType() == LightInfo::Vector )
|
||||
fade = getMax( fade, 1.0f );
|
||||
else
|
||||
fade = getMax( fade, mClampF( 1.0f - dist, 0.00001f, 1.0f ) );
|
||||
|
||||
lightDir += tmp * weight;
|
||||
lightCount++;
|
||||
}
|
||||
|
||||
lightDir.normalize();
|
||||
|
||||
// No light... no shadow.
|
||||
if ( !lights[0] )
|
||||
return false;
|
||||
|
||||
// Has the light direction
|
||||
// changed since last update?
|
||||
bool lightDirChanged = !mLastLightDir.equal( lightDir );
|
||||
|
||||
// Has the parent object moved
|
||||
// or scaled since the last update?
|
||||
bool hasMoved = !mLastObjectPosition.equal( mParentObject->getRenderPosition() );
|
||||
bool hasScaled = !mLastObjectScale.equal( mParentObject->getScale() );
|
||||
|
||||
// Set the last light direction
|
||||
// to the current light direction.
|
||||
mLastLightDir = lightDir;
|
||||
mLastObjectPosition = mParentObject->getRenderPosition();
|
||||
mLastObjectScale = mParentObject->getScale();
|
||||
|
||||
|
||||
// Temps used to generate
|
||||
// tangent vector for DecalInstance below.
|
||||
VectorF right( 0, 0, 0 );
|
||||
VectorF fwd( 0, 0, 0 );
|
||||
VectorF tmpFwd( 0, 0, 0 );
|
||||
|
||||
U32 idx = lightDir.getLeastComponentIndex();
|
||||
|
||||
tmpFwd[idx] = 1.0f;
|
||||
|
||||
right = mCross( tmpFwd, lightDir );
|
||||
fwd = mCross( lightDir, right );
|
||||
right = mCross( fwd, lightDir );
|
||||
|
||||
right.normalize();
|
||||
|
||||
// Set up the world to light space
|
||||
// matrix, along with proper position
|
||||
// and rotation to be used as the world
|
||||
// matrix for the render to texture later on.
|
||||
static MatrixF sRotMat(EulerF( 0.0f, -(M_PI_F/2.0f), 0.0f));
|
||||
mWorldToLight.identity();
|
||||
MathUtils::getMatrixFromForwardVector( lightDir, &mWorldToLight );
|
||||
mWorldToLight.setPosition( ( pos + boxCenter ) - ( ( (mRadius * smDepthAdjust) + 0.001f ) * lightDir ) );
|
||||
mWorldToLight.mul( sRotMat );
|
||||
mWorldToLight.inverse();
|
||||
|
||||
// Get the shapebase datablock if we have one.
|
||||
ShapeBaseData *data = NULL;
|
||||
if ( mShapeBase )
|
||||
data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() );
|
||||
|
||||
// We use the object box's extents multiplied
|
||||
// by the object's scale divided by 2 for the radius
|
||||
// because the object's worldsphere radius is not
|
||||
// rotationally invariant.
|
||||
mRadius = (objBox.getExtents() * mParentObject->getScale()).len() * 0.5f;
|
||||
|
||||
if ( data )
|
||||
mRadius *= data->shadowSphereAdjust;
|
||||
|
||||
// Create the decal if we don't have one yet.
|
||||
if ( !mDecalInstance )
|
||||
mDecalInstance = gDecalManager->addDecal( decalPos,
|
||||
lightDir,
|
||||
right,
|
||||
mDecalData,
|
||||
1.0f,
|
||||
0,
|
||||
PermanentDecal | ClipDecal | CustomDecal );
|
||||
|
||||
if ( !mDecalInstance )
|
||||
return false;
|
||||
|
||||
mDecalInstance->mVisibility = fade;
|
||||
|
||||
// Setup decal parameters.
|
||||
mDecalInstance->mSize = mRadius * 2.0f;
|
||||
mDecalInstance->mNormal = -lightDir;
|
||||
mDecalInstance->mTangent = -right;
|
||||
mDecalInstance->mRotAroundNormal = 0;
|
||||
mDecalInstance->mPosition = decalPos;
|
||||
mDecalInstance->mDataBlock = mDecalData;
|
||||
|
||||
// If the position of the world
|
||||
// space box center is the same
|
||||
// as the decal's position, and
|
||||
// the light direction has not
|
||||
// changed, we don't need to clip.
|
||||
bool shouldClip = lightDirChanged || hasMoved || hasScaled;
|
||||
|
||||
// Now, check and see if the object is visible.
|
||||
const Frustum &frust = state->getFrustum();
|
||||
if ( frust.isCulled( SphereF( mDecalInstance->mPosition, mDecalInstance->mSize * mDecalInstance->mSize ) ) && !shouldClip )
|
||||
return false;
|
||||
|
||||
F32 shadowLen = 10.0f;
|
||||
if ( data )
|
||||
shadowLen = data->shadowProjectionDistance;
|
||||
|
||||
const Point3F &boxExtents = objBox.getExtents();
|
||||
|
||||
|
||||
mShadowLength = shadowLen * mParentObject->getScale().z;
|
||||
|
||||
// Set up clip depth, and box half
|
||||
// offset for decal clipping.
|
||||
Point2F clipParams( mShadowLength, (boxExtents.x + boxExtents.y) * 0.25f );
|
||||
|
||||
bool render = false;
|
||||
bool clipSucceeded = true;
|
||||
|
||||
// Clip!
|
||||
if ( shouldClip )
|
||||
{
|
||||
clipSucceeded = gDecalManager->clipDecal( mDecalInstance,
|
||||
NULL,
|
||||
&clipParams );
|
||||
}
|
||||
|
||||
// If the clip failed,
|
||||
// we'll return false in
|
||||
// order to keep from
|
||||
// unnecessarily rendering
|
||||
// into the texture. If
|
||||
// there was no reason to clip
|
||||
// on this update, we'll assume we
|
||||
// should update the texture.
|
||||
render = clipSucceeded;
|
||||
|
||||
// Tell the DecalManager we've changed this decal.
|
||||
gDecalManager->notifyDecalModified( mDecalInstance );
|
||||
|
||||
return render;
|
||||
}
|
||||
|
||||
void ProjectedShadow::_calcScore( const SceneRenderState *state )
|
||||
{
|
||||
if ( !mDecalInstance )
|
||||
return;
|
||||
|
||||
F32 pixRadius = mDecalInstance->calcPixelSize( state->getViewport().extent.y, state->getCameraPosition(), state->getWorldToScreenScale().y );
|
||||
|
||||
F32 pct = pixRadius / mDecalInstance->mDataBlock->fadeStartPixelSize;
|
||||
|
||||
U32 msSinceLastRender = Platform::getVirtualMilliseconds() - getLastRenderTime();
|
||||
|
||||
ShapeBaseData *data = NULL;
|
||||
if ( mShapeBase )
|
||||
data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() );
|
||||
|
||||
// For every 1s this shadow hasn't been
|
||||
// updated we'll add 10 to the score.
|
||||
F32 secs = mFloor( (F32)msSinceLastRender / 1000.0f );
|
||||
|
||||
mScore = pct + secs;
|
||||
mClampF( mScore, 0.0f, 2000.0f );
|
||||
}
|
||||
|
||||
void ProjectedShadow::update( const SceneRenderState *state )
|
||||
{
|
||||
mUpdateTexture = true;
|
||||
|
||||
// Set the decal lod settings.
|
||||
mDecalData->fadeStartPixelSize = smFadeStartPixelSize;
|
||||
mDecalData->fadeEndPixelSize = smFadeEndPixelSize;
|
||||
|
||||
// Update our decal before
|
||||
// we render to texture.
|
||||
// If it fails, something bad happened
|
||||
// (no light to grab/failed clip) and we should return.
|
||||
if ( !_updateDecal( state ) )
|
||||
{
|
||||
// Release our shadow texture
|
||||
// so that others can grab it out
|
||||
// of the pool.
|
||||
mShadowTexture = NULL;
|
||||
mUpdateTexture = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_calcScore( state );
|
||||
|
||||
if ( !mCasterPositionSC || !mCasterPositionSC->isValid() )
|
||||
mCasterPositionSC = mDecalData->matInst->getMaterialParameterHandle( "$shadowCasterPosition" );
|
||||
|
||||
if ( !mShadowLengthSC || !mShadowLengthSC->isValid() )
|
||||
mShadowLengthSC = mDecalData->matInst->getMaterialParameterHandle( "$shadowLength" );
|
||||
|
||||
MaterialParameters *matParams = mDecalData->matInst->getMaterialParameters();
|
||||
|
||||
matParams->setSafe( mCasterPositionSC, mParentObject->getRenderPosition() );
|
||||
matParams->setSafe( mShadowLengthSC, mShadowLength / 4.0f );
|
||||
}
|
||||
|
||||
void ProjectedShadow::render( F32 camDist, const TSRenderState &rdata )
|
||||
{
|
||||
if ( !mUpdateTexture )
|
||||
return;
|
||||
|
||||
// Do the render to texture,
|
||||
// DecalManager handles rendering
|
||||
// the shadow onto the world.
|
||||
_renderToTexture( camDist, rdata );
|
||||
}
|
||||
|
||||
BaseMatInstance* ProjectedShadow::_getShadowMaterial( BaseMatInstance *inMat )
|
||||
{
|
||||
// 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( ShadowType_Spot );
|
||||
}
|
||||
|
||||
void ProjectedShadow::_renderToTexture( F32 camDist, const TSRenderState &rdata )
|
||||
{
|
||||
PROFILE_SCOPE( ProjectedShadow_RenderToTexture );
|
||||
|
||||
GFXDEBUGEVENT_SCOPE( ProjectedShadow_RenderToTexture, ColorI( 255, 0, 0 ) );
|
||||
|
||||
RenderPassManager *renderPass = _getRenderPass();
|
||||
if ( !renderPass )
|
||||
return;
|
||||
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// NOTE: GFXTransformSaver does not save/restore the frustum
|
||||
// so we must save it here before we modify it.
|
||||
F32 l, r, b, t, n, f;
|
||||
bool ortho;
|
||||
GFX->getFrustum( &l, &r, &b, &t, &n, &f, &ortho );
|
||||
|
||||
// Set the orthographic projection
|
||||
// matrix up, to be based on the radius
|
||||
// generated based on our shape.
|
||||
GFX->setOrtho( -mRadius, mRadius, -mRadius, mRadius, 0.001f, (mRadius * 2) * smDepthAdjust, true );
|
||||
|
||||
// Set the world to light space
|
||||
// matrix set up in shouldRender().
|
||||
GFX->setWorldMatrix( mWorldToLight );
|
||||
|
||||
// Get the shapebase datablock if we have one.
|
||||
ShapeBaseData *data = NULL;
|
||||
if ( mShapeBase )
|
||||
data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() );
|
||||
|
||||
// Init or update the shadow texture size.
|
||||
if ( mShadowTexture.isNull() || ( data && data->shadowSize != mShadowTexture.getWidth() ) )
|
||||
{
|
||||
U32 texSize = getNextPow2( data ? data->shadowSize : 256 * LightShadowMap::smShadowTexScalar );
|
||||
mShadowTexture.set( texSize, texSize, GFXFormatR8G8B8A8, &PostFxTargetProfile, "BLShadow" );
|
||||
}
|
||||
|
||||
GFX->pushActiveRenderTarget();
|
||||
|
||||
if ( !mRenderTarget )
|
||||
mRenderTarget = GFX->allocRenderToTextureTarget();
|
||||
|
||||
mRenderTarget->attachTexture( GFXTextureTarget::DepthStencil, _getDepthTarget( mShadowTexture->getWidth(), mShadowTexture->getHeight() ) );
|
||||
mRenderTarget->attachTexture( GFXTextureTarget::Color0, mShadowTexture );
|
||||
GFX->setActiveRenderTarget( mRenderTarget );
|
||||
|
||||
GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, ColorI( 0, 0, 0, 0 ), 1.0f, 0 );
|
||||
|
||||
const SceneRenderState *diffuseState = rdata.getSceneState();
|
||||
SceneManager *sceneManager = diffuseState->getSceneManager();
|
||||
|
||||
SceneRenderState baseState
|
||||
(
|
||||
sceneManager,
|
||||
SPT_Shadow,
|
||||
SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ),
|
||||
renderPass
|
||||
);
|
||||
|
||||
baseState.getMaterialDelegate().bind( &ProjectedShadow::_getShadowMaterial );
|
||||
baseState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
baseState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
baseState.getCullingState().disableZoneCulling( true );
|
||||
|
||||
mParentObject->prepRenderImage( &baseState );
|
||||
renderPass->renderPass( &baseState );
|
||||
|
||||
// Delete the SceneRenderState we allocated.
|
||||
mRenderTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
|
||||
// If we're close enough then filter the shadow.
|
||||
if ( camDist < BasicLightManager::getShadowFilterDistance() )
|
||||
{
|
||||
if ( !smShadowFilter )
|
||||
{
|
||||
PostEffect *filter = NULL;
|
||||
|
||||
if ( !Sim::findObject( "BL_ShadowFilterPostFx", filter ) )
|
||||
Con::errorf( "ProjectedShadow::_renderToTexture() - 'BL_ShadowFilterPostFx' not found!" );
|
||||
|
||||
smShadowFilter = filter;
|
||||
}
|
||||
|
||||
if ( smShadowFilter )
|
||||
smShadowFilter->process( NULL, mShadowTexture );
|
||||
}
|
||||
|
||||
// Restore frustum
|
||||
if (!ortho)
|
||||
GFX->setFrustum(l, r, b, t, n, f);
|
||||
else
|
||||
GFX->setOrtho(l, r, b, t, n, f);
|
||||
|
||||
// Set the last render time.
|
||||
mLastRenderTime = Platform::getVirtualMilliseconds();
|
||||
|
||||
// HACK: Will remove in future release!
|
||||
mDecalInstance->mCustomTex = &mShadowTexture;
|
||||
}
|
||||
|
||||
RenderPassManager* ProjectedShadow::_getRenderPass()
|
||||
{
|
||||
if ( smRenderPass.isNull() )
|
||||
{
|
||||
SimObject* renderPass = NULL;
|
||||
|
||||
if ( !Sim::findObject( "BL_ProjectedShadowRPM", renderPass ) )
|
||||
Con::errorf( "ProjectedShadow::init() - 'BL_ProjectedShadowRPM' not initialized" );
|
||||
else
|
||||
smRenderPass = dynamic_cast<RenderPassManager*>(renderPass);
|
||||
}
|
||||
|
||||
return smRenderPass;
|
||||
}
|
||||
|
||||
GFXTextureObject* ProjectedShadow::_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, &BLProjectedShadowZProfile,
|
||||
"ProjectedShadow::_getDepthTarget()" );
|
||||
|
||||
return depthTex;
|
||||
}
|
||||
127
Engine/source/lighting/common/projectedShadow.h
Normal file
127
Engine/source/lighting/common/projectedShadow.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PROJECTEDSHADOW_H_
|
||||
#define _PROJECTEDSHADOW_H_
|
||||
|
||||
#ifndef _DEPTHSORTLIST_H_
|
||||
#include "collision/depthSortList.h"
|
||||
#endif
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _TSSHAPEINSTANCE_H_
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINGSYSTEM_SHADOWBASE_H_
|
||||
#include "lighting/common/shadowBase.h"
|
||||
#endif
|
||||
|
||||
class ShapeBase;
|
||||
class LightInfo;
|
||||
class DecalData;
|
||||
class DecalInstance;
|
||||
class RenderPassManager;
|
||||
class PostEffect;
|
||||
class RenderMeshMgr;
|
||||
class CustomMaterial;
|
||||
class BaseMatInstance;
|
||||
class MaterialParameterHandle;
|
||||
|
||||
|
||||
GFX_DeclareTextureProfile( BLProjectedShadowProfile );
|
||||
GFX_DeclareTextureProfile( BLProjectedShadowZProfile );
|
||||
|
||||
class ProjectedShadow : public ShadowBase
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/// This parameter is used to
|
||||
/// adjust the far plane out for our
|
||||
/// orthographic render in order to
|
||||
/// force our object towards one end of the
|
||||
/// the eye space depth range.
|
||||
static F32 smDepthAdjust;
|
||||
|
||||
F32 mRadius;
|
||||
MatrixF mWorldToLight;
|
||||
U32 mLastRenderTime;
|
||||
|
||||
F32 mShadowLength;
|
||||
|
||||
F32 mScore;
|
||||
bool mUpdateTexture;
|
||||
|
||||
Point3F mLastObjectScale;
|
||||
Point3F mLastObjectPosition;
|
||||
VectorF mLastLightDir;
|
||||
|
||||
DecalData *mDecalData;
|
||||
DecalInstance *mDecalInstance;
|
||||
|
||||
SceneObject *mParentObject;
|
||||
ShapeBase *mShapeBase;
|
||||
|
||||
MaterialParameterHandle *mCasterPositionSC;
|
||||
MaterialParameterHandle *mShadowLengthSC;
|
||||
|
||||
static SimObjectPtr<RenderPassManager> smRenderPass;
|
||||
|
||||
static SimObjectPtr<PostEffect> smShadowFilter;
|
||||
|
||||
static RenderPassManager* _getRenderPass();
|
||||
|
||||
GFXTexHandle mShadowTexture;
|
||||
GFXTextureTargetRef mRenderTarget;
|
||||
|
||||
GFXTextureObject* _getDepthTarget( U32 width, U32 height );
|
||||
void _renderToTexture( F32 camDist, const TSRenderState &rdata );
|
||||
|
||||
bool _updateDecal( const SceneRenderState *sceneState );
|
||||
|
||||
void _calcScore( const SceneRenderState *state );
|
||||
|
||||
/// Returns a spotlight shadow material for use when
|
||||
/// rendering meshes into the projected shadow.
|
||||
static BaseMatInstance* _getShadowMaterial( BaseMatInstance *inMat );
|
||||
|
||||
public:
|
||||
|
||||
/// @see DecalData
|
||||
static float smFadeStartPixelSize;
|
||||
static float smFadeEndPixelSize;
|
||||
|
||||
ProjectedShadow( SceneObject *object );
|
||||
virtual ~ProjectedShadow();
|
||||
|
||||
bool shouldRender( const SceneRenderState *state );
|
||||
|
||||
void update( const SceneRenderState *state );
|
||||
void render( F32 camDist, const TSRenderState &rdata );
|
||||
U32 getLastRenderTime() const { return mLastRenderTime; }
|
||||
const F32 getScore() const { return mScore; }
|
||||
|
||||
};
|
||||
|
||||
#endif // _PROJECTEDSHADOW_H_
|
||||
1110
Engine/source/lighting/common/sceneLighting.cpp
Normal file
1110
Engine/source/lighting/common/sceneLighting.cpp
Normal file
File diff suppressed because it is too large
Load diff
254
Engine/source/lighting/common/sceneLighting.h
Normal file
254
Engine/source/lighting/common/sceneLighting.h
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _SCENELIGHTING_H_
|
||||
#define _SCENELIGHTING_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _SGSCENEPERSIST_H_
|
||||
#include "lighting/common/scenePersist.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
|
||||
class ShadowVolumeBSP;
|
||||
class LightInfo;
|
||||
class AvailableSLInterfaces;
|
||||
|
||||
class SceneLighting : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
protected:
|
||||
AvailableSLInterfaces* mLightingInterfaces;
|
||||
virtual void getMLName(const char* misName, const U32 missionCRC, const U32 buffSize, char* filenameBuffer);
|
||||
public:
|
||||
S32 sgTimeTemp;
|
||||
S32 sgTimeTemp2;
|
||||
|
||||
virtual void sgNewEvent(U32 light, S32 object, U32 event);
|
||||
|
||||
virtual void sgLightingStartEvent();
|
||||
virtual void sgLightingCompleteEvent();
|
||||
|
||||
virtual void sgTGEPassSetupEvent();
|
||||
virtual void sgTGELightStartEvent(U32 light);
|
||||
virtual void sgTGELightProcessEvent(U32 light, S32 object);
|
||||
virtual void sgTGELightCompleteEvent(U32 light);
|
||||
virtual void sgTGESetProgress(U32 light, S32 object);
|
||||
|
||||
virtual void sgSGPassSetupEvent();
|
||||
virtual void sgSGObjectStartEvent(S32 object);
|
||||
virtual void sgSGObjectProcessEvent(U32 light, S32 object);
|
||||
virtual void sgSGObjectCompleteEvent(S32 object);
|
||||
virtual void sgSGSetProgress(U32 light, S32 object);
|
||||
|
||||
// 'sg' prefix omitted to conform with existing 'addInterior' method...
|
||||
void addStatic(ShadowVolumeBSP *shadowVolume, SceneObject *sceneobject, LightInfo *light, S32 level);
|
||||
|
||||
// persist objects moved to 'sgScenePersist.h' for clarity...
|
||||
// everything below this line should be original code...
|
||||
|
||||
U32 calcMissionCRC();
|
||||
|
||||
bool verifyMissionInfo(PersistInfo::PersistChunk *);
|
||||
bool getMissionInfo(PersistInfo::PersistChunk *);
|
||||
|
||||
bool loadPersistInfo(const char *);
|
||||
bool savePersistInfo(const char *);
|
||||
|
||||
class ObjectProxy;
|
||||
|
||||
enum {
|
||||
SHADOW_DETAIL = -1
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Create a proxy for each object to store data.
|
||||
class ObjectProxy
|
||||
{
|
||||
public:
|
||||
SimObjectPtr<SceneObject> mObj;
|
||||
U32 mChunkCRC;
|
||||
|
||||
ObjectProxy(SceneObject * obj) : mObj(obj){mChunkCRC = 0;}
|
||||
virtual ~ObjectProxy(){}
|
||||
SceneObject * operator->() {return(mObj);}
|
||||
SceneObject * getObject() {return(mObj);}
|
||||
|
||||
/// @name Lighting Interface
|
||||
/// @{
|
||||
virtual bool loadResources() {return(true);}
|
||||
virtual void init() {}
|
||||
virtual bool tgePreLight(LightInfo* light) { return preLight(light); }
|
||||
virtual bool preLight(LightInfo *) {return(false);}
|
||||
virtual void light(LightInfo *) {}
|
||||
virtual void postLight(bool lastLight) {}
|
||||
/// @}
|
||||
|
||||
/// @name Lighting events
|
||||
/// @{
|
||||
// Called when the lighting process begins
|
||||
virtual void processLightingStart() {}
|
||||
// Called when a TGELight event is started, return true if status has been reported to console
|
||||
virtual void processTGELightProcessEvent(U32 curr, U32 max, LightInfo*) { Con::printf(" Lighting object %d of %d...", (curr+1), max); }
|
||||
// Called for lighting kit lights
|
||||
virtual bool processStartObjectLightingEvent(U32 current, U32 max) { Con::printf(" Lighting object %d of %d... %s: %s", (current+1), max, mObj->getClassName(), mObj->getName()); return true; }
|
||||
// Called once per object and SG light - used for calling light on an object
|
||||
virtual void processSGObjectProcessEvent(LightInfo* currLight) { light(currLight); };
|
||||
/// @}
|
||||
|
||||
/// @name Persistence
|
||||
///
|
||||
/// We cache lighting information to cut down on load times.
|
||||
///
|
||||
/// There are flags such as ForceAlways and LoadOnly which allow you
|
||||
/// to control this behaviour.
|
||||
/// @{
|
||||
bool calcValidation();
|
||||
bool isValidChunk(PersistInfo::PersistChunk *);
|
||||
|
||||
virtual U32 getResourceCRC() = 0;
|
||||
virtual bool setPersistInfo(PersistInfo::PersistChunk *);
|
||||
virtual bool getPersistInfo(PersistInfo::PersistChunk *);
|
||||
/// @}
|
||||
|
||||
// Called to figure out if this object should be added to the shadow volume
|
||||
virtual bool supportsShadowVolume() { return false; }
|
||||
// Called to retrieve the clip planes of the object. Currently used for terrain lighting, but could be used to speed up other
|
||||
// lighting calculations.
|
||||
virtual void getClipPlanes(Vector<PlaneF>& planes) { }
|
||||
// Called to add the object to the shadow volume
|
||||
virtual void addToShadowVolume(ShadowVolumeBSP * shadowVolume, LightInfo * light, S32 level) { } ;
|
||||
};
|
||||
|
||||
typedef Vector<ObjectProxy*> ObjectProxyList;
|
||||
|
||||
ObjectProxyList mSceneObjects;
|
||||
ObjectProxyList mLitObjects;
|
||||
|
||||
LightInfoList mLights;
|
||||
|
||||
SceneLighting(AvailableSLInterfaces* lightingInterfaces);
|
||||
~SceneLighting();
|
||||
|
||||
enum Flags {
|
||||
ForceAlways = BIT(0), ///< Regenerate the scene lighting no matter what.
|
||||
ForceWritable = BIT(1), ///< Regenerate the scene lighting only if we can write to the lighting cache files.
|
||||
LoadOnly = BIT(2), ///< Just load cached lighting data.
|
||||
};
|
||||
bool lightScene(const char *, BitSet32 flags = 0);
|
||||
bool isLighting();
|
||||
|
||||
S32 mStartTime;
|
||||
char mFileName[1024];
|
||||
SceneManager * mSceneManager;
|
||||
|
||||
bool light(BitSet32);
|
||||
void completed(bool success);
|
||||
void processEvent(U32 light, S32 object);
|
||||
void processCache();
|
||||
};
|
||||
|
||||
class sgSceneLightingProcessEvent : public SimEvent
|
||||
{
|
||||
private:
|
||||
U32 sgLightIndex;
|
||||
S32 sgObjectIndex;
|
||||
U32 sgEvent;
|
||||
|
||||
public:
|
||||
enum sgEventTypes
|
||||
{
|
||||
sgLightingStartEventType,
|
||||
sgLightingCompleteEventType,
|
||||
|
||||
sgSGPassSetupEventType,
|
||||
sgSGObjectStartEventType,
|
||||
sgSGObjectCompleteEventType,
|
||||
sgSGObjectProcessEventType,
|
||||
|
||||
sgTGEPassSetupEventType,
|
||||
sgTGELightStartEventType,
|
||||
sgTGELightCompleteEventType,
|
||||
sgTGELightProcessEventType
|
||||
};
|
||||
|
||||
sgSceneLightingProcessEvent(U32 lightIndex, S32 objectIndex, U32 event)
|
||||
{
|
||||
sgLightIndex = lightIndex;
|
||||
sgObjectIndex = objectIndex;
|
||||
sgEvent = event;
|
||||
}
|
||||
void process(SimObject * object)
|
||||
{
|
||||
AssertFatal(object, "SceneLightingProcessEvent:: null event object!");
|
||||
if(!object)
|
||||
return;
|
||||
|
||||
SceneLighting *sl = static_cast<SceneLighting*>(object);
|
||||
switch(sgEvent)
|
||||
{
|
||||
case sgLightingStartEventType:
|
||||
sl->sgLightingStartEvent();
|
||||
break;
|
||||
case sgLightingCompleteEventType:
|
||||
sl->sgLightingCompleteEvent();
|
||||
break;
|
||||
|
||||
case sgTGEPassSetupEventType:
|
||||
sl->sgTGEPassSetupEvent();
|
||||
break;
|
||||
case sgTGELightStartEventType:
|
||||
sl->sgTGELightStartEvent(sgLightIndex);
|
||||
break;
|
||||
case sgTGELightProcessEventType:
|
||||
sl->sgTGELightProcessEvent(sgLightIndex, sgObjectIndex);
|
||||
break;
|
||||
case sgTGELightCompleteEventType:
|
||||
sl->sgTGELightCompleteEvent(sgLightIndex);
|
||||
break;
|
||||
|
||||
case sgSGPassSetupEventType:
|
||||
sl->sgSGPassSetupEvent();
|
||||
break;
|
||||
case sgSGObjectStartEventType:
|
||||
sl->sgSGObjectStartEvent(sgObjectIndex);
|
||||
break;
|
||||
case sgSGObjectProcessEventType:
|
||||
sl->sgSGObjectProcessEvent(sgLightIndex, sgObjectIndex);
|
||||
break;
|
||||
case sgSGObjectCompleteEventType:
|
||||
sl->sgSGObjectCompleteEvent(sgObjectIndex);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
extern SceneLighting *gLighting;
|
||||
|
||||
#endif//_SGSCENELIGHTING_H_
|
||||
66
Engine/source/lighting/common/sceneLightingGlobals.h
Normal file
66
Engine/source/lighting/common/sceneLightingGlobals.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const Point3F BoxNormals[] =
|
||||
{
|
||||
Point3F( 1, 0, 0),
|
||||
Point3F(-1, 0, 0),
|
||||
Point3F( 0, 1, 0),
|
||||
Point3F( 0,-1, 0),
|
||||
Point3F( 0, 0, 1),
|
||||
Point3F( 0, 0,-1)
|
||||
};
|
||||
|
||||
static U32 BoxVerts[][4] = {
|
||||
{7,6,4,5}, // +x
|
||||
{0,2,3,1}, // -x
|
||||
{7,3,2,6}, // +y
|
||||
{0,1,5,4}, // -y
|
||||
{7,5,1,3}, // +z
|
||||
{0,4,6,2} // -z
|
||||
};
|
||||
|
||||
static U32 BoxSharedEdgeMask[][6] = {
|
||||
{0, 0, 1, 4, 8, 2},
|
||||
{0, 0, 2, 8, 4, 1},
|
||||
{8, 2, 0, 0, 1, 4},
|
||||
{4, 1, 0, 0, 2, 8},
|
||||
{1, 4, 8, 2, 0, 0},
|
||||
{2, 8, 4, 1, 0, 0}
|
||||
};
|
||||
|
||||
static Point3F BoxPnts[] = {
|
||||
Point3F(0,0,0),
|
||||
Point3F(0,0,1),
|
||||
Point3F(0,1,0),
|
||||
Point3F(0,1,1),
|
||||
Point3F(1,0,0),
|
||||
Point3F(1,0,1),
|
||||
Point3F(1,1,0),
|
||||
Point3F(1,1,1)
|
||||
};
|
||||
|
||||
extern SceneLighting *gLighting;
|
||||
extern F32 gParellelVectorThresh;
|
||||
extern F32 gPlaneNormThresh;
|
||||
extern F32 gPlaneDistThresh;
|
||||
|
||||
144
Engine/source/lighting/common/scenePersist.cpp
Normal file
144
Engine/source/lighting/common/scenePersist.cpp
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/common/scenePersist.h"
|
||||
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "lighting/lightManager.h"
|
||||
|
||||
|
||||
U32 PersistInfo::smFileVersion = 0x11;
|
||||
|
||||
PersistInfo::~PersistInfo()
|
||||
{
|
||||
for(U32 i = 0; i < mChunks.size(); i++)
|
||||
delete mChunks[i];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool PersistInfo::read(Stream & stream)
|
||||
{
|
||||
U32 version;
|
||||
if(!stream.read(&version) || version != smFileVersion)
|
||||
return(false);
|
||||
|
||||
U32 numChunks;
|
||||
if(!stream.read(&numChunks))
|
||||
return(false);
|
||||
|
||||
if(numChunks == 0)
|
||||
return(false);
|
||||
|
||||
// read in all the chunks
|
||||
for(U32 i = 0; i < numChunks; i++)
|
||||
{
|
||||
U32 chunkType;
|
||||
if(!stream.read(&chunkType))
|
||||
return(false);
|
||||
|
||||
// MissionChunk must be first chunk
|
||||
if(i == 0 && chunkType != PersistChunk::MissionChunkType)
|
||||
return(false);
|
||||
if(i != 0 && chunkType == PersistChunk::MissionChunkType)
|
||||
return(false);
|
||||
|
||||
// Create the right chunk for the system
|
||||
bool bChunkFound = false;
|
||||
SceneLightingInterfaces sli = LIGHTMGR->getSceneLightingInterface()->mAvailableSystemInterfaces;
|
||||
for(SceneLightingInterface** itr = sli.begin(); itr != sli.end() && !bChunkFound; itr++)
|
||||
{
|
||||
PersistInfo::PersistChunk* pc = (*itr)->createPersistChunk(chunkType);
|
||||
if (pc != NULL)
|
||||
{
|
||||
mChunks.push_back(pc);
|
||||
bChunkFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bChunkFound)
|
||||
{
|
||||
// create the chunk
|
||||
switch(chunkType)
|
||||
{
|
||||
case PersistChunk::MissionChunkType:
|
||||
mChunks.push_back(new PersistInfo::MissionChunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
return(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// load the chunk info
|
||||
if(!mChunks[i]->read(stream))
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool PersistInfo::write(Stream & stream)
|
||||
{
|
||||
if(!stream.write(smFileVersion))
|
||||
return(false);
|
||||
|
||||
if(!stream.write((U32)mChunks.size()))
|
||||
return(false);
|
||||
|
||||
for(U32 i = 0; i < mChunks.size(); i++)
|
||||
{
|
||||
if(!stream.write(mChunks[i]->mChunkType))
|
||||
return(false);
|
||||
if(!mChunks[i]->write(stream))
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class SceneLighting::PersistInfo::PersistChunk
|
||||
//------------------------------------------------------------------------------
|
||||
bool PersistInfo::PersistChunk::read(Stream & stream)
|
||||
{
|
||||
if(!stream.read(&mChunkCRC))
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool PersistInfo::PersistChunk::write(Stream & stream)
|
||||
{
|
||||
if(!stream.write(mChunkCRC))
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class SceneLighting::PersistInfo::MissionChunk
|
||||
//------------------------------------------------------------------------------
|
||||
PersistInfo::MissionChunk::MissionChunk()
|
||||
{
|
||||
mChunkType = PersistChunk::MissionChunkType;
|
||||
}
|
||||
68
Engine/source/lighting/common/scenePersist.h
Normal file
68
Engine/source/lighting/common/scenePersist.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _SGSCENEPERSIST_H_
|
||||
#define _SGSCENEPERSIST_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class Stream;
|
||||
|
||||
struct PersistInfo
|
||||
{
|
||||
struct PersistChunk
|
||||
{
|
||||
enum {
|
||||
MissionChunkType = 0,
|
||||
InteriorChunkType,
|
||||
TerrainChunkType,
|
||||
AtlasLightMapChunkType
|
||||
};
|
||||
|
||||
U32 mChunkType;
|
||||
U32 mChunkCRC;
|
||||
|
||||
virtual ~PersistChunk() {}
|
||||
|
||||
virtual bool read(Stream &);
|
||||
virtual bool write(Stream &);
|
||||
};
|
||||
|
||||
struct MissionChunk : public PersistChunk
|
||||
{
|
||||
typedef PersistChunk Parent;
|
||||
MissionChunk();
|
||||
};
|
||||
|
||||
~PersistInfo();
|
||||
|
||||
Vector<PersistChunk*> mChunks;
|
||||
static U32 smFileVersion;
|
||||
|
||||
bool read(Stream &);
|
||||
bool write(Stream &);
|
||||
};
|
||||
|
||||
|
||||
#endif//_SGSCENEPERSIST_H_
|
||||
40
Engine/source/lighting/common/shadowBase.h
Normal file
40
Engine/source/lighting/common/shadowBase.h
Normal file
|
|
@ -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 _LIGHTINGSYSTEM_SHADOWBASE_H_
|
||||
#define _LIGHTINGSYSTEM_SHADOWBASE_H_
|
||||
|
||||
class TSRenderState;
|
||||
|
||||
class ShadowBase
|
||||
{
|
||||
public:
|
||||
virtual ~ShadowBase() {}
|
||||
virtual bool shouldRender( const SceneRenderState *state ) = 0;
|
||||
|
||||
virtual void update( const SceneRenderState *state ) = 0;
|
||||
virtual void render(F32 camDist, const TSRenderState &rdata ) = 0;
|
||||
virtual U32 getLastRenderTime() const = 0;
|
||||
virtual const F32 getScore() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
731
Engine/source/lighting/common/shadowVolumeBSP.cpp
Normal file
731
Engine/source/lighting/common/shadowVolumeBSP.cpp
Normal file
|
|
@ -0,0 +1,731 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/common/shadowVolumeBSP.h"
|
||||
|
||||
#include "lighting/lightInfo.h"
|
||||
#include "math/mPlane.h"
|
||||
|
||||
|
||||
ShadowVolumeBSP::ShadowVolumeBSP() :
|
||||
mSVRoot(0),
|
||||
mNodeStore(0),
|
||||
mPolyStore(0),
|
||||
mFirstInteriorNode(0)
|
||||
{
|
||||
}
|
||||
|
||||
ShadowVolumeBSP::~ShadowVolumeBSP()
|
||||
{
|
||||
for(U32 i = 0; i < mSurfaces.size(); i++)
|
||||
delete mSurfaces[i];
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::insertShadowVolume(SVNode ** root, U32 volume)
|
||||
{
|
||||
SVNode * traverse = mShadowVolumes[volume];
|
||||
|
||||
// insert 'em
|
||||
while(traverse)
|
||||
{
|
||||
// copy it
|
||||
*root = createNode();
|
||||
(*root)->mPlaneIndex = traverse->mPlaneIndex;
|
||||
(*root)->mSurfaceInfo = traverse->mSurfaceInfo;
|
||||
(*root)->mShadowVolume = traverse->mShadowVolume;
|
||||
|
||||
// do the next
|
||||
root = &(*root)->mFront;
|
||||
traverse = traverse->mFront;
|
||||
}
|
||||
}
|
||||
|
||||
ShadowVolumeBSP::SVNode::Side ShadowVolumeBSP::whichSide(SVPoly * poly, const PlaneF & plane) const
|
||||
{
|
||||
bool front = false;
|
||||
bool back = false;
|
||||
|
||||
for(U32 i = 0; i < poly->mWindingCount; i++)
|
||||
{
|
||||
switch(plane.whichSide(poly->mWinding[i]))
|
||||
{
|
||||
case PlaneF::Front:
|
||||
if(back)
|
||||
return(SVNode::Split);
|
||||
front = true;
|
||||
break;
|
||||
|
||||
case PlaneF::Back:
|
||||
if(front)
|
||||
return(SVNode::Split);
|
||||
back = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal(!(front && back), "ShadowVolumeBSP::whichSide - failed to classify poly");
|
||||
|
||||
if(!front && !back)
|
||||
return(SVNode::On);
|
||||
|
||||
return(front ? SVNode::Front : SVNode::Back);
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::splitPoly(SVPoly * poly, const PlaneF & plane, SVPoly ** front, SVPoly ** back)
|
||||
{
|
||||
PlaneF::Side sides[SVPoly::MaxWinding];
|
||||
|
||||
U32 i;
|
||||
for(i = 0; i < poly->mWindingCount; i++)
|
||||
sides[i] = plane.whichSide(poly->mWinding[i]);
|
||||
|
||||
// create the polys
|
||||
(*front) = createPoly();
|
||||
(*back) = createPoly();
|
||||
|
||||
// copy the info
|
||||
(*front)->mWindingCount = (*back)->mWindingCount = 0;
|
||||
(*front)->mPlane = (*back)->mPlane = poly->mPlane;
|
||||
(*front)->mTarget = (*back)->mTarget = poly->mTarget;
|
||||
(*front)->mSurfaceInfo = (*back)->mSurfaceInfo = poly->mSurfaceInfo;
|
||||
(*front)->mShadowVolume = (*back)->mShadowVolume = poly->mShadowVolume;
|
||||
|
||||
//
|
||||
for(i = 0; i < poly->mWindingCount; i++)
|
||||
{
|
||||
U32 j = (i+1) % poly->mWindingCount;
|
||||
|
||||
if(sides[i] == PlaneF::On)
|
||||
{
|
||||
(*front)->mWinding[(*front)->mWindingCount++] = poly->mWinding[i];
|
||||
(*back)->mWinding[(*back)->mWindingCount++] = poly->mWinding[i];
|
||||
}
|
||||
else if(sides[i] == PlaneF::Front)
|
||||
{
|
||||
(*front)->mWinding[(*front)->mWindingCount++] = poly->mWinding[i];
|
||||
|
||||
if(sides[j] == PlaneF::Back)
|
||||
{
|
||||
const Point3F & a = poly->mWinding[i];
|
||||
const Point3F & b = poly->mWinding[j];
|
||||
|
||||
F32 t = plane.intersect(a, b);
|
||||
AssertFatal(t >=0 && t <= 1, "ShadowVolumeBSP::splitPoly - bad plane intersection");
|
||||
|
||||
Point3F pos;
|
||||
pos.interpolate(a, b, t);
|
||||
|
||||
//
|
||||
(*front)->mWinding[(*front)->mWindingCount++] =
|
||||
(*back)->mWinding[(*back)->mWindingCount++] = pos;
|
||||
}
|
||||
}
|
||||
else if(sides[i] == PlaneF::Back)
|
||||
{
|
||||
(*back)->mWinding[(*back)->mWindingCount++] = poly->mWinding[i];
|
||||
|
||||
if(sides[j] == PlaneF::Front)
|
||||
{
|
||||
const Point3F & a = poly->mWinding[i];
|
||||
const Point3F & b = poly->mWinding[j];
|
||||
|
||||
F32 t = plane.intersect(a, b);
|
||||
AssertFatal(t >=0 && t <= 1, "ShadowVolumeBSP::splitPoly - bad plane intersection");
|
||||
|
||||
Point3F pos;
|
||||
pos.interpolate(a, b, t);
|
||||
|
||||
(*front)->mWinding[(*front)->mWindingCount++] =
|
||||
(*back)->mWinding[(*back)->mWindingCount++] = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal((*front)->mWindingCount && (*back)->mWindingCount, "ShadowVolume::split - invalid split");
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::addUniqueVolume(SurfaceInfo * surfaceInfo, U32 volume)
|
||||
{
|
||||
if(!surfaceInfo)
|
||||
return;
|
||||
|
||||
for(U32 i = 0; i < surfaceInfo->mShadowed.size(); i++)
|
||||
if(surfaceInfo->mShadowed[i] == volume)
|
||||
return;
|
||||
|
||||
// add it
|
||||
surfaceInfo->mShadowed.push_back(volume);
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::insertPoly(SVNode ** root, SVPoly * poly)
|
||||
{
|
||||
if(!(*root))
|
||||
{
|
||||
insertShadowVolume(root, poly->mShadowVolume);
|
||||
|
||||
if(poly->mSurfaceInfo && !mFirstInteriorNode)
|
||||
mFirstInteriorNode = mShadowVolumes[poly->mShadowVolume];
|
||||
|
||||
if(poly->mTarget)
|
||||
addUniqueVolume(poly->mTarget->mSurfaceInfo, poly->mShadowVolume);
|
||||
|
||||
recyclePoly(poly);
|
||||
return;
|
||||
}
|
||||
|
||||
const PlaneF & plane = getPlane((*root)->mPlaneIndex);
|
||||
|
||||
//
|
||||
switch(whichSide(poly, plane))
|
||||
{
|
||||
case SVNode::On:
|
||||
case SVNode::Front:
|
||||
insertPolyFront(root, poly);
|
||||
break;
|
||||
|
||||
case SVNode::Back:
|
||||
insertPolyBack(root, poly);
|
||||
break;
|
||||
|
||||
case SVNode::Split:
|
||||
{
|
||||
SVPoly * front;
|
||||
SVPoly * back;
|
||||
|
||||
splitPoly(poly, plane, &front, &back);
|
||||
recyclePoly(poly);
|
||||
|
||||
insertPolyFront(root, front);
|
||||
insertPolyBack(root, back);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::insertPolyFront(SVNode ** root, SVPoly * poly)
|
||||
{
|
||||
// POLY type node?
|
||||
if(!(*root)->mFront)
|
||||
{
|
||||
if(poly->mSurfaceInfo && !mFirstInteriorNode)
|
||||
mFirstInteriorNode = mShadowVolumes[poly->mShadowVolume];
|
||||
addUniqueVolume(poly->mSurfaceInfo, (*root)->mShadowVolume);
|
||||
recyclePoly(poly);
|
||||
}
|
||||
else
|
||||
insertPoly(&(*root)->mFront, poly);
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::insertPolyBack(SVNode ** root, SVPoly * poly)
|
||||
{
|
||||
// list of nodes where an interior has been added
|
||||
if(poly->mSurfaceInfo && !(*root)->mSurfaceInfo && !(*root)->mBack)
|
||||
{
|
||||
if(!mFirstInteriorNode)
|
||||
mFirstInteriorNode = mShadowVolumes[poly->mShadowVolume];
|
||||
mParentNodes.push_back(*root);
|
||||
}
|
||||
|
||||
// POLY type node?
|
||||
if(!(*root)->mFront)
|
||||
{
|
||||
poly->mTarget = (*root);
|
||||
insertPoly(&(*root)->mBack, poly);
|
||||
}
|
||||
else
|
||||
insertPoly(&(*root)->mBack, poly);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ShadowVolumeBSP::SVNode * ShadowVolumeBSP::createNode()
|
||||
{
|
||||
SVNode * node;
|
||||
if(mNodeStore)
|
||||
{
|
||||
node = mNodeStore;
|
||||
mNodeStore = mNodeStore->mFront;
|
||||
}
|
||||
else
|
||||
node = mNodeChunker.alloc();
|
||||
|
||||
//
|
||||
node->mFront = node->mBack = 0;
|
||||
node->mShadowVolume = 0;
|
||||
node->mSurfaceInfo = 0;
|
||||
|
||||
return(node);
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::recycleNode(SVNode * node)
|
||||
{
|
||||
if(!node)
|
||||
return;
|
||||
|
||||
recycleNode(node->mFront);
|
||||
recycleNode(node->mBack);
|
||||
|
||||
//
|
||||
node->mFront = mNodeStore;
|
||||
node->mBack = 0;
|
||||
mNodeStore = node;
|
||||
}
|
||||
|
||||
ShadowVolumeBSP::SVPoly * ShadowVolumeBSP::createPoly()
|
||||
{
|
||||
SVPoly * poly;
|
||||
|
||||
if(mPolyStore)
|
||||
{
|
||||
poly = mPolyStore;
|
||||
mPolyStore = mPolyStore->mNext;
|
||||
}
|
||||
else
|
||||
poly = mPolyChunker.alloc();
|
||||
|
||||
//
|
||||
poly->mNext = 0;
|
||||
poly->mTarget = 0;
|
||||
poly->mSurfaceInfo = 0;
|
||||
poly->mShadowVolume = 0;
|
||||
poly->mWindingCount = 0;
|
||||
|
||||
for (U32 i = 0; i < SVPoly::MaxWinding; i++)
|
||||
poly->mWinding[i] = Point3F(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return(poly);
|
||||
}
|
||||
|
||||
void ShadowVolumeBSP::recyclePoly(SVPoly * poly)
|
||||
{
|
||||
if(!poly)
|
||||
return;
|
||||
|
||||
recyclePoly(poly->mNext);
|
||||
|
||||
//
|
||||
poly->mNext = mPolyStore;
|
||||
mPolyStore = poly;
|
||||
}
|
||||
|
||||
U32 ShadowVolumeBSP::insertPlane(const PlaneF & plane)
|
||||
{
|
||||
mPlanes.push_back(plane);
|
||||
return(mPlanes.size() - 1);
|
||||
}
|
||||
|
||||
const PlaneF & ShadowVolumeBSP::getPlane(U32 index) const
|
||||
{
|
||||
AssertFatal(index < mPlanes.size(), "ShadowVolumeBSP::getPlane - index out of range");
|
||||
return(mPlanes[index]);
|
||||
}
|
||||
|
||||
ShadowVolumeBSP::SVNode * ShadowVolumeBSP::getShadowVolume(U32 index)
|
||||
{
|
||||
AssertFatal(index < mShadowVolumes.size(), "ShadowVolumeBSP::getShadowVolume - index out of range");
|
||||
return(mShadowVolumes[index]);
|
||||
}
|
||||
|
||||
bool ShadowVolumeBSP::testPoint(SVNode * root, const Point3F & pnt)
|
||||
{
|
||||
const PlaneF & plane = getPlane(root->mPlaneIndex);
|
||||
switch(plane.whichSide(pnt))
|
||||
{
|
||||
case PlaneF::On:
|
||||
|
||||
if(!root->mFront)
|
||||
return(true);
|
||||
else
|
||||
{
|
||||
if(testPoint(root->mFront, pnt))
|
||||
return(true);
|
||||
else
|
||||
{
|
||||
if(!root->mBack)
|
||||
return(false);
|
||||
else
|
||||
return(testPoint(root->mBack, pnt));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//
|
||||
case PlaneF::Front:
|
||||
if(root->mFront)
|
||||
return(testPoint(root->mFront, pnt));
|
||||
else
|
||||
return(true);
|
||||
break;
|
||||
|
||||
//
|
||||
case PlaneF::Back:
|
||||
if(root->mBack)
|
||||
return(testPoint(root->mBack, pnt));
|
||||
else
|
||||
return(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool ShadowVolumeBSP::testPoly(SVNode * root, SVPoly * poly)
|
||||
{
|
||||
const PlaneF & plane = getPlane(root->mPlaneIndex);
|
||||
switch(whichSide(poly, plane))
|
||||
{
|
||||
case SVNode::On:
|
||||
case SVNode::Front:
|
||||
if(root->mFront)
|
||||
return(testPoly(root->mFront, poly));
|
||||
|
||||
recyclePoly(poly);
|
||||
return(true);
|
||||
|
||||
case SVNode::Back:
|
||||
if(root->mBack)
|
||||
return(testPoly(root->mBack, poly));
|
||||
recyclePoly(poly);
|
||||
break;
|
||||
|
||||
case SVNode::Split:
|
||||
{
|
||||
if(!root->mFront)
|
||||
{
|
||||
recyclePoly(poly);
|
||||
return(true);
|
||||
}
|
||||
|
||||
SVPoly * front;
|
||||
SVPoly * back;
|
||||
|
||||
splitPoly(poly, plane, &front, &back);
|
||||
recyclePoly(poly);
|
||||
|
||||
if(testPoly(root->mFront, front))
|
||||
{
|
||||
recyclePoly(back);
|
||||
return(true);
|
||||
}
|
||||
|
||||
if(root->mBack)
|
||||
return(testPoly(root->mBack, back));
|
||||
|
||||
recyclePoly(back);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ShadowVolumeBSP::buildPolyVolume(SVPoly * poly, LightInfo * light)
|
||||
{
|
||||
if(light->getType() != LightInfo::Vector)
|
||||
return;
|
||||
|
||||
// build the poly
|
||||
Point3F pointOffset = light->getDirection() * 10.f;
|
||||
|
||||
// create the shadow volume
|
||||
mShadowVolumes.increment();
|
||||
SVNode ** traverse = &mShadowVolumes.last();
|
||||
U32 shadowVolumeIndex = mShadowVolumes.size() - 1;
|
||||
|
||||
for(U32 i = 0; i < poly->mWindingCount; i++)
|
||||
{
|
||||
U32 j = (i + 1) % poly->mWindingCount;
|
||||
if(poly->mWinding[i] == poly->mWinding[j])
|
||||
continue;
|
||||
|
||||
(*traverse) = createNode();
|
||||
Point3F & a = poly->mWinding[i];
|
||||
Point3F & b = poly->mWinding[j];
|
||||
Point3F c = b + pointOffset;
|
||||
|
||||
(*traverse)->mPlaneIndex = insertPlane(PlaneF(a,b,c));
|
||||
(*traverse)->mShadowVolume = shadowVolumeIndex;
|
||||
|
||||
traverse = &(*traverse)->mFront;
|
||||
}
|
||||
|
||||
// do the poly node
|
||||
(*traverse) = createNode();
|
||||
(*traverse)->mPlaneIndex = insertPlane(poly->mPlane);
|
||||
(*traverse)->mShadowVolume = poly->mShadowVolume = shadowVolumeIndex;
|
||||
}
|
||||
|
||||
ShadowVolumeBSP::SVPoly * ShadowVolumeBSP::copyPoly(SVPoly * src)
|
||||
{
|
||||
SVPoly * poly = createPoly();
|
||||
dMemcpy(poly, src, sizeof(SVPoly));
|
||||
|
||||
poly->mTarget = 0;
|
||||
poly->mNext = 0;
|
||||
|
||||
return(poly);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ShadowVolumeBSP::addToPolyList(SVPoly ** store, SVPoly * poly) const
|
||||
{
|
||||
poly->mNext = *store;
|
||||
*store = poly;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ShadowVolumeBSP::clipPoly(SVNode * root, SVPoly ** store, SVPoly * poly)
|
||||
{
|
||||
if(!root)
|
||||
{
|
||||
recyclePoly(poly);
|
||||
return;
|
||||
}
|
||||
|
||||
const PlaneF & plane = getPlane(root->mPlaneIndex);
|
||||
|
||||
switch(whichSide(poly, plane))
|
||||
{
|
||||
case SVNode::On:
|
||||
case SVNode::Back:
|
||||
if(root->mBack)
|
||||
clipPoly(root->mBack, store, poly);
|
||||
else
|
||||
addToPolyList(store, poly);
|
||||
break;
|
||||
|
||||
case SVNode::Front:
|
||||
// encountered POLY node?
|
||||
if(!root->mFront)
|
||||
{
|
||||
recyclePoly(poly);
|
||||
return;
|
||||
}
|
||||
else
|
||||
clipPoly(root->mFront, store, poly);
|
||||
break;
|
||||
|
||||
case SVNode::Split:
|
||||
{
|
||||
SVPoly * front;
|
||||
SVPoly * back;
|
||||
|
||||
splitPoly(poly, plane, &front, &back);
|
||||
AssertFatal(front && back, "ShadowVolumeBSP::clipPoly: invalid split");
|
||||
recyclePoly(poly);
|
||||
|
||||
// front
|
||||
if(!root->mFront)
|
||||
{
|
||||
recyclePoly(front);
|
||||
return;
|
||||
}
|
||||
else
|
||||
clipPoly(root->mFront, store, front);
|
||||
|
||||
// back
|
||||
if(root->mBack)
|
||||
clipPoly(root->mBack, store, back);
|
||||
else
|
||||
addToPolyList(store, back);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clip a poly to it's own shadow volume
|
||||
void ShadowVolumeBSP::clipToSelf(SVNode * root, SVPoly ** store, SVPoly * poly)
|
||||
{
|
||||
if(!root)
|
||||
{
|
||||
addToPolyList(store, poly);
|
||||
return;
|
||||
}
|
||||
|
||||
const PlaneF & plane = getPlane(root->mPlaneIndex);
|
||||
|
||||
switch(whichSide(poly, plane))
|
||||
{
|
||||
case SVNode::Front:
|
||||
clipToSelf(root->mFront, store, poly);
|
||||
break;
|
||||
|
||||
case SVNode::On:
|
||||
addToPolyList(store, poly);
|
||||
break;
|
||||
|
||||
case SVNode::Back:
|
||||
recyclePoly(poly);
|
||||
break;
|
||||
|
||||
case SVNode::Split:
|
||||
{
|
||||
SVPoly * front = 0;
|
||||
SVPoly * back = 0;
|
||||
splitPoly(poly, plane, &front, &back);
|
||||
AssertFatal(front && back, "ShadowVolumeBSP::clipToSelf: invalid split");
|
||||
|
||||
recyclePoly(poly);
|
||||
recyclePoly(back);
|
||||
|
||||
clipToSelf(root->mFront, store, front);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
F32 ShadowVolumeBSP::getPolySurfaceArea(SVPoly * poly) const
|
||||
{
|
||||
if(!poly)
|
||||
return(0.f);
|
||||
|
||||
Point3F areaNorm(0,0,0);
|
||||
for(U32 i = 0; i < poly->mWindingCount; i++)
|
||||
{
|
||||
U32 j = (i + 1) % poly->mWindingCount;
|
||||
|
||||
Point3F tmp;
|
||||
mCross(poly->mWinding[i], poly->mWinding[j], &tmp);
|
||||
|
||||
areaNorm += tmp;
|
||||
}
|
||||
|
||||
F32 area = mDot(poly->mPlane, areaNorm);
|
||||
|
||||
if(area < 0.f)
|
||||
area *= -0.5f;
|
||||
else
|
||||
area *= 0.5f;
|
||||
|
||||
if(poly->mNext)
|
||||
area += getPolySurfaceArea(poly->mNext);
|
||||
|
||||
return(area);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
F32 ShadowVolumeBSP::getClippedSurfaceArea(SVNode * root, SVPoly * poly)
|
||||
{
|
||||
SVPoly * store = 0;
|
||||
clipPoly(root, &store, poly);
|
||||
|
||||
F32 area = getPolySurfaceArea(store);
|
||||
recyclePoly(store);
|
||||
return(area);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Class SceneLighting::ShadowVolumeBSP
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
void ShadowVolumeBSP::movePolyList(SVPoly ** dest, SVPoly * list) const
|
||||
{
|
||||
while(list)
|
||||
{
|
||||
SVPoly * next = list->mNext;
|
||||
addToPolyList(dest, list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F32 ShadowVolumeBSP::getLitSurfaceArea(SVPoly * poly, SurfaceInfo * surfaceInfo)
|
||||
{
|
||||
// clip the poly to the shadow volumes
|
||||
SVPoly * polyStore = poly;
|
||||
|
||||
for(U32 i = 0; polyStore && (i < surfaceInfo->mShadowed.size()); i++)
|
||||
{
|
||||
SVPoly * polyList = 0;
|
||||
SVPoly * traverse = polyStore;
|
||||
|
||||
while(traverse)
|
||||
{
|
||||
SVPoly * next = traverse->mNext;
|
||||
traverse->mNext = 0;
|
||||
|
||||
SVPoly * currentStore = 0;
|
||||
|
||||
clipPoly(mShadowVolumes[surfaceInfo->mShadowed[i]], ¤tStore, traverse);
|
||||
|
||||
if(currentStore)
|
||||
movePolyList(&polyList, currentStore);
|
||||
|
||||
traverse = next;
|
||||
}
|
||||
polyStore = polyList;
|
||||
}
|
||||
|
||||
// get the lit area
|
||||
F32 area = getPolySurfaceArea(polyStore);
|
||||
recyclePoly(polyStore);
|
||||
return(area);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ShadowVolumeBSP::removeLastInterior()
|
||||
{
|
||||
if(!mSVRoot || !mFirstInteriorNode)
|
||||
return;
|
||||
|
||||
AssertFatal(mFirstInteriorNode->mSurfaceInfo, "No surface info for first interior node!");
|
||||
|
||||
// reset the planes
|
||||
mPlanes.setSize(mFirstInteriorNode->mPlaneIndex);
|
||||
|
||||
U32 i;
|
||||
|
||||
// flush the shadow volumes
|
||||
for(i = mFirstInteriorNode->mShadowVolume; i < mShadowVolumes.size(); i++)
|
||||
recycleNode(mShadowVolumes[i]);
|
||||
mShadowVolumes.setSize(mFirstInteriorNode->mShadowVolume);
|
||||
|
||||
// flush the interior nodes
|
||||
if(!mParentNodes.size() && (mFirstInteriorNode->mShadowVolume == mSVRoot->mShadowVolume))
|
||||
{
|
||||
recycleNode(mSVRoot);
|
||||
mSVRoot = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i = 0; i < mParentNodes.size(); i++)
|
||||
{
|
||||
recycleNode(mParentNodes[i]->mBack);
|
||||
mParentNodes[i]->mBack = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// flush the surfaces
|
||||
for(i = 0; i < mSurfaces.size(); i++)
|
||||
delete mSurfaces[i];
|
||||
mSurfaces.clear();
|
||||
|
||||
mFirstInteriorNode = 0;
|
||||
}
|
||||
154
Engine/source/lighting/common/shadowVolumeBSP.h
Normal file
154
Engine/source/lighting/common/shadowVolumeBSP.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _SHADOWVOLUMEBSP_H_
|
||||
#define _SHADOWVOLUMEBSP_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
#ifndef _MMATH_H_
|
||||
#include "math/mMath.h"
|
||||
#endif
|
||||
#ifndef _DATACHUNKER_H_
|
||||
#include "core/dataChunker.h"
|
||||
#endif
|
||||
#ifndef _LIGHTMANAGER_H_
|
||||
#include "lighting/lightManager.h"
|
||||
#endif
|
||||
|
||||
/// Used to calculate shadows.
|
||||
class ShadowVolumeBSP
|
||||
{
|
||||
public:
|
||||
ShadowVolumeBSP();
|
||||
~ShadowVolumeBSP();
|
||||
|
||||
struct SVNode;
|
||||
struct SurfaceInfo
|
||||
{
|
||||
U32 mSurfaceIndex;
|
||||
U32 mPlaneIndex;
|
||||
Vector<U32> mShadowed;
|
||||
SVNode * mShadowVolume;
|
||||
};
|
||||
|
||||
struct SVNode
|
||||
{
|
||||
enum Side
|
||||
{
|
||||
Front = 0,
|
||||
Back = 1,
|
||||
On = 2,
|
||||
Split = 3
|
||||
};
|
||||
|
||||
SVNode * mFront;
|
||||
SVNode * mBack;
|
||||
U32 mPlaneIndex;
|
||||
U32 mShadowVolume;
|
||||
|
||||
/// Used with shadowed interiors.
|
||||
SurfaceInfo * mSurfaceInfo;
|
||||
};
|
||||
|
||||
struct SVPoly
|
||||
{
|
||||
enum {
|
||||
MaxWinding = 32
|
||||
};
|
||||
|
||||
U32 mWindingCount;
|
||||
Point3F mWinding[MaxWinding];
|
||||
|
||||
PlaneF mPlane;
|
||||
SVNode * mTarget;
|
||||
U32 mShadowVolume;
|
||||
SVPoly * mNext;
|
||||
SurfaceInfo * mSurfaceInfo;
|
||||
};
|
||||
|
||||
void insertPoly(SVNode **, SVPoly *);
|
||||
void insertPolyFront(SVNode **, SVPoly *);
|
||||
void insertPolyBack(SVNode **, SVPoly *);
|
||||
|
||||
void splitPoly(SVPoly *, const PlaneF &, SVPoly **, SVPoly **);
|
||||
void insertShadowVolume(SVNode **, U32);
|
||||
void addUniqueVolume(SurfaceInfo *, U32);
|
||||
|
||||
SVNode::Side whichSide(SVPoly *, const PlaneF &) const;
|
||||
|
||||
//
|
||||
bool testPoint(SVNode *, const Point3F &);
|
||||
bool testPoly(SVNode *, SVPoly *);
|
||||
void addToPolyList(SVPoly **, SVPoly *) const;
|
||||
void clipPoly(SVNode *, SVPoly **, SVPoly *);
|
||||
void clipToSelf(SVNode *, SVPoly **, SVPoly *);
|
||||
F32 getPolySurfaceArea(SVPoly *) const;
|
||||
F32 getClippedSurfaceArea(SVNode *, SVPoly *);
|
||||
void movePolyList(SVPoly **, SVPoly *) const;
|
||||
F32 getLitSurfaceArea(SVPoly *, SurfaceInfo *);
|
||||
|
||||
Vector<SurfaceInfo *> mSurfaces;
|
||||
|
||||
Chunker<SVNode> mNodeChunker;
|
||||
Chunker<SVPoly> mPolyChunker;
|
||||
|
||||
SVNode * createNode();
|
||||
void recycleNode(SVNode *);
|
||||
|
||||
SVPoly * createPoly();
|
||||
void recyclePoly(SVPoly *);
|
||||
|
||||
U32 insertPlane(const PlaneF &);
|
||||
const PlaneF & getPlane(U32) const;
|
||||
|
||||
//
|
||||
SVNode * mSVRoot;
|
||||
Vector<SVNode*> mShadowVolumes;
|
||||
SVNode * getShadowVolume(U32);
|
||||
|
||||
Vector<PlaneF> mPlanes;
|
||||
SVNode * mNodeStore;
|
||||
SVPoly * mPolyStore;
|
||||
|
||||
// used to remove the last inserted interior from the tree
|
||||
Vector<SVNode*> mParentNodes;
|
||||
SVNode * mFirstInteriorNode;
|
||||
void removeLastInterior();
|
||||
|
||||
/// @name Access functions
|
||||
/// @{
|
||||
void insertPoly(SVPoly * poly) {insertPoly(&mSVRoot, poly);}
|
||||
bool testPoint(Point3F & pnt) {return(testPoint(mSVRoot, pnt));}
|
||||
bool testPoly(SVPoly * poly) {return(testPoly(mSVRoot, poly));}
|
||||
F32 getClippedSurfaceArea(SVPoly * poly) {return(getClippedSurfaceArea(mSVRoot, poly));}
|
||||
/// @}
|
||||
|
||||
/// @name Helpers
|
||||
/// @{
|
||||
void buildPolyVolume(SVPoly *, LightInfo *);
|
||||
SVPoly * copyPoly(SVPoly *);
|
||||
/// @}
|
||||
};
|
||||
|
||||
#endif
|
||||
221
Engine/source/lighting/lightInfo.cpp
Normal file
221
Engine/source/lighting/lightInfo.cpp
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/lightInfo.h"
|
||||
|
||||
#include "math/mMath.h"
|
||||
#include "core/color.h"
|
||||
#include "gfx/gfxCubemap.h"
|
||||
#include "console/simObject.h"
|
||||
#include "math/mathUtils.h"
|
||||
|
||||
|
||||
LightInfoExType::LightInfoExType( const char *type )
|
||||
{
|
||||
TypeMap::Iterator iter = getTypeMap().find( type );
|
||||
if ( iter == getTypeMap().end() )
|
||||
iter = getTypeMap().insertUnique( type, getTypeMap().size() );
|
||||
|
||||
mTypeIndex = iter->value;
|
||||
}
|
||||
|
||||
|
||||
LightInfo::LightInfo()
|
||||
: mTransform( true ),
|
||||
mColor( 0.0f, 0.0f, 0.0f, 1.0f ),
|
||||
mBrightness( 1.0f ),
|
||||
mAmbient( 0.0f, 0.0f, 0.0f, 1.0f ),
|
||||
mRange( 1.0f, 1.0f, 1.0f ),
|
||||
mInnerConeAngle( 90.0f ),
|
||||
mOuterConeAngle( 90.0f ),
|
||||
mType( Vector ),
|
||||
mCastShadows( false ),
|
||||
mPriority( 1.0f ),
|
||||
mScore( 0.0f ),
|
||||
mDebugRender( false )
|
||||
{
|
||||
}
|
||||
|
||||
LightInfo::~LightInfo()
|
||||
{
|
||||
deleteAllLightInfoEx();
|
||||
}
|
||||
|
||||
void LightInfo::set( const LightInfo *light )
|
||||
{
|
||||
mTransform = light->mTransform;
|
||||
mColor = light->mColor;
|
||||
mBrightness = light->mBrightness;
|
||||
mAmbient = light->mAmbient;
|
||||
mRange = light->mRange;
|
||||
mInnerConeAngle = light->mInnerConeAngle;
|
||||
mOuterConeAngle = light->mOuterConeAngle;
|
||||
mType = light->mType;
|
||||
mCastShadows = light->mCastShadows;
|
||||
|
||||
for ( U32 i=0; i < mExtended.size(); i++ )
|
||||
{
|
||||
LightInfoEx *ex = light->mExtended[ i ];
|
||||
if ( ex )
|
||||
mExtended[i]->set( ex );
|
||||
else
|
||||
{
|
||||
delete mExtended[i];
|
||||
mExtended[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightInfo::setGFXLight( GFXLightInfo *outLight )
|
||||
{
|
||||
switch( getType() )
|
||||
{
|
||||
case LightInfo::Point :
|
||||
outLight->mType = GFXLightInfo::Point;
|
||||
break;
|
||||
case LightInfo::Spot :
|
||||
outLight->mType = GFXLightInfo::Spot;
|
||||
break;
|
||||
case LightInfo::Vector:
|
||||
outLight->mType = GFXLightInfo::Vector;
|
||||
break;
|
||||
case LightInfo::Ambient:
|
||||
outLight->mType = GFXLightInfo::Ambient;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
outLight->mPos = getPosition();
|
||||
outLight->mDirection = getDirection();
|
||||
outLight->mColor = mColor * mBrightness;
|
||||
outLight->mAmbient = mAmbient;
|
||||
outLight->mRadius = mRange.x;
|
||||
outLight->mInnerConeAngle = mInnerConeAngle;
|
||||
outLight->mOuterConeAngle = mOuterConeAngle;
|
||||
}
|
||||
|
||||
void LightInfo::setDirection( const VectorF &dir )
|
||||
{
|
||||
MathUtils::getMatrixFromForwardVector( mNormalize( dir ), &mTransform );
|
||||
}
|
||||
|
||||
void LightInfo::deleteExtended( const LightInfoExType& type )
|
||||
{
|
||||
if ( type >= mExtended.size() )
|
||||
return;
|
||||
|
||||
SAFE_DELETE( mExtended[ type ] );
|
||||
}
|
||||
|
||||
void LightInfo::deleteAllLightInfoEx()
|
||||
{
|
||||
for ( U32 i = 0; i < mExtended.size(); i++ )
|
||||
delete mExtended[ i ];
|
||||
|
||||
mExtended.clear();
|
||||
}
|
||||
|
||||
LightInfoEx* LightInfo::getExtended( const LightInfoExType &type ) const
|
||||
{
|
||||
if ( type >= mExtended.size() )
|
||||
return NULL;
|
||||
|
||||
return mExtended[ type ];
|
||||
}
|
||||
|
||||
void LightInfo::addExtended( LightInfoEx *lightInfoEx )
|
||||
{
|
||||
AssertFatal( lightInfoEx, "LightInfo::addExtended() - Got null extended light info!" );
|
||||
|
||||
const LightInfoExType &type = lightInfoEx->getType();
|
||||
|
||||
while ( mExtended.size() <= type )
|
||||
mExtended.push_back( NULL );
|
||||
|
||||
delete mExtended[type];
|
||||
mExtended[type] = lightInfoEx;
|
||||
}
|
||||
|
||||
void LightInfo::packExtended( BitStream *stream ) const
|
||||
{
|
||||
for ( U32 i = 0; i < mExtended.size(); i++ )
|
||||
if ( mExtended[ i ] )
|
||||
mExtended[ i ]->packUpdate( stream );
|
||||
}
|
||||
|
||||
void LightInfo::unpackExtended( BitStream *stream )
|
||||
{
|
||||
for ( U32 i = 0; i < mExtended.size(); i++ )
|
||||
if ( mExtended[ i ] )
|
||||
mExtended[ i ]->unpackUpdate( stream );
|
||||
}
|
||||
|
||||
void LightInfo::getWorldToLightProj( MatrixF *outMatrix ) const
|
||||
{
|
||||
if ( mType == Spot )
|
||||
{
|
||||
// For spots we need to include the cone projection.
|
||||
F32 fov = mDegToRad( getOuterConeAngle() );
|
||||
F32 range = getRange().x;
|
||||
MatrixF proj;
|
||||
MathUtils::makeProjection( &proj, fov, 1.0f, range * 0.01f, range, true );
|
||||
|
||||
MatrixF light = getTransform();
|
||||
light.inverse();
|
||||
|
||||
*outMatrix = proj * light;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The other lights just use the light transform.
|
||||
*outMatrix = getTransform();
|
||||
outMatrix->inverse();
|
||||
}
|
||||
}
|
||||
|
||||
void LightInfoList::registerLight( LightInfo *light )
|
||||
{
|
||||
if(!light)
|
||||
return;
|
||||
// just add the light, we'll try to scan for dupes later...
|
||||
push_back(light);
|
||||
}
|
||||
|
||||
void LightInfoList::unregisterLight( LightInfo *light )
|
||||
{
|
||||
// remove all of them...
|
||||
LightInfoList &list = *this;
|
||||
for(U32 i=0; i<list.size(); i++)
|
||||
{
|
||||
if(list[i] != light)
|
||||
continue;
|
||||
|
||||
// this moves last to i, which allows
|
||||
// the search to continue forward...
|
||||
list.erase_fast(i);
|
||||
// want to check this location again...
|
||||
i--;
|
||||
}
|
||||
}
|
||||
258
Engine/source/lighting/lightInfo.h
Normal file
258
Engine/source/lighting/lightInfo.h
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _LIGHTINFO_H_
|
||||
#define _LIGHTINFO_H_
|
||||
|
||||
#ifndef _GFXSTRUCTS_H_
|
||||
#include "gfx/gfxStructs.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
#ifndef _TDICTIONARY_H_
|
||||
#include "core/util/tDictionary.h"
|
||||
#endif
|
||||
|
||||
struct SceneData;
|
||||
class LightManager;
|
||||
class SimObject;
|
||||
class BitStream;
|
||||
|
||||
|
||||
/// The extended light info type wrapper object.
|
||||
class LightInfoExType
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef HashTable<String,U32> TypeMap;
|
||||
|
||||
/// Returns the map of all the info types. We create
|
||||
/// it as a method static so that its available to other
|
||||
/// statics regardless of initialization order.
|
||||
static inline TypeMap& getTypeMap()
|
||||
{
|
||||
static TypeMap smTypeMap;
|
||||
return smTypeMap;
|
||||
}
|
||||
|
||||
/// The info type index for this type.
|
||||
U32 mTypeIndex;
|
||||
|
||||
public:
|
||||
|
||||
LightInfoExType( const char *type );
|
||||
|
||||
inline LightInfoExType( const LightInfoExType &type )
|
||||
: mTypeIndex( type.mTypeIndex )
|
||||
{
|
||||
}
|
||||
|
||||
inline operator U32 () const { return mTypeIndex; }
|
||||
};
|
||||
|
||||
/// This is the base class for extended lighting info
|
||||
/// that lies outside of the normal info stored in LightInfo.
|
||||
class LightInfoEx
|
||||
{
|
||||
public:
|
||||
|
||||
/// Basic destructor so we can delete the extended info
|
||||
/// without knowing the concrete type.
|
||||
virtual ~LightInfoEx() { }
|
||||
|
||||
///
|
||||
virtual const LightInfoExType& getType() const = 0;
|
||||
|
||||
/// Copy the values from the other LightInfoEx.
|
||||
virtual void set( const LightInfoEx *ex ) {}
|
||||
|
||||
///
|
||||
virtual void packUpdate( BitStream *stream ) const {}
|
||||
|
||||
///
|
||||
virtual void unpackUpdate( BitStream *stream ) {}
|
||||
};
|
||||
|
||||
|
||||
/// This is the base light information class that will be tracked by the
|
||||
/// engine. Should basically contain a bounding volume and methods to interact
|
||||
/// with the rest of the system (for example, setting GFX fixed function lights).
|
||||
class LightInfo
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type
|
||||
{
|
||||
Point = 0,
|
||||
Spot = 1,
|
||||
Vector = 2,
|
||||
Ambient = 3,
|
||||
Count = 4,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
Type mType;
|
||||
|
||||
/// The primary light color.
|
||||
ColorF mColor;
|
||||
|
||||
F32 mBrightness;
|
||||
|
||||
ColorF mAmbient;
|
||||
|
||||
MatrixF mTransform;
|
||||
|
||||
Point3F mRange;
|
||||
|
||||
F32 mInnerConeAngle;
|
||||
|
||||
F32 mOuterConeAngle;
|
||||
|
||||
bool mCastShadows;
|
||||
|
||||
::Vector<LightInfoEx*> mExtended;
|
||||
|
||||
/// The priority of this light used for
|
||||
/// light and shadow scoring.
|
||||
F32 mPriority;
|
||||
|
||||
/// A temporary which holds the score used
|
||||
/// when prioritizing lights for rendering.
|
||||
F32 mScore;
|
||||
|
||||
/// Whether to render debugging visualizations
|
||||
/// for this light.
|
||||
bool mDebugRender;
|
||||
|
||||
public:
|
||||
|
||||
LightInfo();
|
||||
~LightInfo();
|
||||
|
||||
// Copies data passed in from light
|
||||
void set( const LightInfo *light );
|
||||
|
||||
// Sets a fixed function GFXLight with our properties
|
||||
void setGFXLight( GFXLightInfo *light );
|
||||
|
||||
// Accessors
|
||||
Type getType() const { return mType; }
|
||||
void setType( Type val ) { mType = val; }
|
||||
|
||||
const MatrixF& getTransform() const { return mTransform; }
|
||||
void setTransform( const MatrixF &xfm ) { mTransform = xfm; }
|
||||
|
||||
Point3F getPosition() const { return mTransform.getPosition(); }
|
||||
void setPosition( const Point3F &pos ) { mTransform.setPosition( pos ); }
|
||||
|
||||
VectorF getDirection() const { return mTransform.getForwardVector(); }
|
||||
void setDirection( const VectorF &val );
|
||||
|
||||
const ColorF& getColor() const { return mColor; }
|
||||
void setColor( const ColorF &val ) { mColor = val; }
|
||||
|
||||
F32 getBrightness() const { return mBrightness; }
|
||||
void setBrightness( F32 val ) { mBrightness = val; }
|
||||
|
||||
const ColorF& getAmbient() const { return mAmbient; }
|
||||
void setAmbient( const ColorF &val ) { mAmbient = val; }
|
||||
|
||||
const Point3F& getRange() const { return mRange; }
|
||||
void setRange( const Point3F &range ) { mRange = range; }
|
||||
void setRange( F32 range ) { mRange.set( range, range, range ); }
|
||||
|
||||
F32 getInnerConeAngle() const { return mInnerConeAngle; }
|
||||
void setInnerConeAngle( F32 val ) { mInnerConeAngle = val; }
|
||||
|
||||
F32 getOuterConeAngle() const { return mOuterConeAngle; }
|
||||
void setOuterConeAngle( F32 val ) { mOuterConeAngle = val; }
|
||||
|
||||
bool getCastShadows() const { return mCastShadows; }
|
||||
void setCastShadows( bool castShadows ) { mCastShadows = castShadows; }
|
||||
|
||||
void setPriority( F32 priority ) { mPriority = priority; }
|
||||
F32 getPriority() const { return mPriority; }
|
||||
|
||||
void setScore( F32 score ) { mScore = score; }
|
||||
F32 getScore() const { return mScore; }
|
||||
|
||||
bool isDebugRenderingEnabled() const { return mDebugRender; }
|
||||
void enableDebugRendering( bool value ) { mDebugRender = value; }
|
||||
|
||||
/// Helper function for getting the extended light info.
|
||||
/// @see getExtended
|
||||
template <class ExClass>
|
||||
inline ExClass* getExtended() const { return (ExClass*)getExtended( ExClass::Type ); }
|
||||
|
||||
/// Returns the extended light info for the selected type.
|
||||
LightInfoEx* getExtended( const LightInfoExType &type ) const;
|
||||
|
||||
/// Adds the extended info to the light deleting the
|
||||
/// existing extended info if it has one.
|
||||
void addExtended( LightInfoEx *lightInfoEx );
|
||||
|
||||
/// Delete all registered LightInfoEx instances of the given
|
||||
/// type.
|
||||
void deleteExtended( const LightInfoExType& type );
|
||||
|
||||
///
|
||||
void deleteAllLightInfoEx();
|
||||
|
||||
// Builds the world to light view projection used for
|
||||
// shadow texture and cookie lookups.
|
||||
void getWorldToLightProj( MatrixF *outMatrix ) const;
|
||||
|
||||
///
|
||||
void packExtended( BitStream *stream ) const;
|
||||
|
||||
///
|
||||
void unpackExtended( BitStream *stream );
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
class LightInfoList : public Vector<LightInfo*>
|
||||
{
|
||||
public:
|
||||
void registerLight( LightInfo *light );
|
||||
void unregisterLight( LightInfo *light );
|
||||
};
|
||||
|
||||
|
||||
/// When the scene is queried for lights, the light manager will get
|
||||
/// this interface to trigger a register light call.
|
||||
class ISceneLight
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~ISceneLight() {}
|
||||
|
||||
/// Submit lights to the light manager passed in.
|
||||
virtual void submitLights( LightManager *lm, bool staticLighting ) = 0;
|
||||
|
||||
///
|
||||
virtual LightInfo* getLight() = 0;
|
||||
};
|
||||
|
||||
#endif // _LIGHTINFO_H_
|
||||
499
Engine/source/lighting/lightManager.cpp
Normal file
499
Engine/source/lighting/lightManager.cpp
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/lightManager.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "console/sim.h"
|
||||
#include "console/simSet.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/sceneData.h"
|
||||
#include "lighting/lightInfo.h"
|
||||
#include "lighting/lightingInterfaces.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "gfx/gfxStringEnumTranslate.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
|
||||
|
||||
Signal<void(const char*,bool)> LightManager::smActivateSignal;
|
||||
LightManager *LightManager::smActiveLM = NULL;
|
||||
|
||||
|
||||
LightManager::LightManager( const char *name, const char *id )
|
||||
: mName( name ),
|
||||
mId( id ),
|
||||
mIsActive( false ),
|
||||
mSceneManager( NULL ),
|
||||
mDefaultLight( NULL ),
|
||||
mAvailableSLInterfaces( NULL ),
|
||||
mCullPos( Point3F::Zero )
|
||||
{
|
||||
_getLightManagers().insert( mName, this );
|
||||
|
||||
dMemset( &mSpecialLights, 0, sizeof( mSpecialLights ) );
|
||||
}
|
||||
|
||||
LightManager::~LightManager()
|
||||
{
|
||||
_getLightManagers().erase( mName );
|
||||
SAFE_DELETE( mAvailableSLInterfaces );
|
||||
SAFE_DELETE( mDefaultLight );
|
||||
}
|
||||
|
||||
LightManagerMap& LightManager::_getLightManagers()
|
||||
{
|
||||
static LightManagerMap lightManagerMap;
|
||||
return lightManagerMap;
|
||||
}
|
||||
|
||||
LightManager* LightManager::findByName( const char *name )
|
||||
{
|
||||
LightManagerMap &lightManagers = _getLightManagers();
|
||||
|
||||
LightManagerMap::Iterator iter = lightManagers.find( name );
|
||||
if ( iter != lightManagers.end() )
|
||||
return iter->value;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LightManager::getLightManagerNames( String *outString )
|
||||
{
|
||||
LightManagerMap &lightManagers = _getLightManagers();
|
||||
LightManagerMap::Iterator iter = lightManagers.begin();
|
||||
for ( ; iter != lightManagers.end(); iter++ )
|
||||
*outString += iter->key + "\t";
|
||||
|
||||
// TODO!
|
||||
//outString->rtrim();
|
||||
}
|
||||
|
||||
LightInfo* LightManager::createLightInfo(LightInfo* light /* = NULL */)
|
||||
{
|
||||
LightInfo *outLight = (light != NULL) ? light : new LightInfo;
|
||||
|
||||
LightManagerMap &lightManagers = _getLightManagers();
|
||||
LightManagerMap::Iterator iter = lightManagers.begin();
|
||||
for ( ; iter != lightManagers.end(); iter++ )
|
||||
{
|
||||
LightManager *lm = iter->value;
|
||||
lm->_addLightInfoEx( outLight );
|
||||
}
|
||||
|
||||
return outLight;
|
||||
}
|
||||
|
||||
void LightManager::initLightFields()
|
||||
{
|
||||
LightManagerMap &lightManagers = _getLightManagers();
|
||||
|
||||
LightManagerMap::Iterator iter = lightManagers.begin();
|
||||
for ( ; iter != lightManagers.end(); iter++ )
|
||||
{
|
||||
LightManager *lm = iter->value;
|
||||
lm->_initLightFields();
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_GLOBAL_CALLBACK( onLightManagerActivate, void, ( const char *name ), ( name ),
|
||||
"A callback called by the engine when a light manager is activated.\n"
|
||||
"@param name The name of the light manager being activated.\n"
|
||||
"@ingroup Lighting\n" );
|
||||
|
||||
void LightManager::activate( SceneManager *sceneManager )
|
||||
{
|
||||
AssertFatal( sceneManager, "LightManager::activate() - Got null scene manager!" );
|
||||
AssertFatal( mIsActive == false, "LightManager::activate() - Already activated!" );
|
||||
AssertFatal( smActiveLM == NULL, "LightManager::activate() - A previous LM is still active!" );
|
||||
|
||||
mIsActive = true;
|
||||
mSceneManager = sceneManager;
|
||||
smActiveLM = this;
|
||||
|
||||
onLightManagerActivate_callback( getName() );
|
||||
}
|
||||
|
||||
IMPLEMENT_GLOBAL_CALLBACK( onLightManagerDeactivate, void, ( const char *name ), ( name ),
|
||||
"A callback called by the engine when a light manager is deactivated.\n"
|
||||
"@param name The name of the light manager being deactivated.\n"
|
||||
"@ingroup Lighting\n" );
|
||||
|
||||
void LightManager::deactivate()
|
||||
{
|
||||
AssertFatal( mIsActive == true, "LightManager::deactivate() - Already deactivated!" );
|
||||
AssertFatal( smActiveLM == this, "LightManager::activate() - This isn't the active light manager!" );
|
||||
|
||||
if( Sim::getRootGroup() ) // To protect against shutdown.
|
||||
onLightManagerDeactivate_callback( getName() );
|
||||
|
||||
mIsActive = false;
|
||||
mSceneManager = NULL;
|
||||
smActiveLM = NULL;
|
||||
|
||||
// Just in case... make sure we're all clear.
|
||||
unregisterAllLights();
|
||||
}
|
||||
|
||||
LightInfo* LightManager::getDefaultLight()
|
||||
{
|
||||
// The sun is always our default light when
|
||||
// when its registered.
|
||||
if ( mSpecialLights[ LightManager::slSunLightType ] )
|
||||
return mSpecialLights[ LightManager::slSunLightType ];
|
||||
|
||||
// Else return a dummy special light.
|
||||
if ( !mDefaultLight )
|
||||
mDefaultLight = createLightInfo();
|
||||
return mDefaultLight;
|
||||
}
|
||||
|
||||
LightInfo* LightManager::getSpecialLight( LightManager::SpecialLightTypesEnum type, bool useDefault )
|
||||
{
|
||||
if ( mSpecialLights[type] )
|
||||
return mSpecialLights[type];
|
||||
|
||||
if ( useDefault )
|
||||
return getDefaultLight();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LightManager::setSpecialLight( LightManager::SpecialLightTypesEnum type, LightInfo *light )
|
||||
{
|
||||
if ( light && type == slSunLightType )
|
||||
{
|
||||
// The sun must be specially positioned and ranged
|
||||
// so that it can be processed like a point light
|
||||
// in the stock light shader used by Basic Lighting.
|
||||
|
||||
light->setPosition( mCullPos - ( light->getDirection() * 10000.0f ) );
|
||||
light->setRange( 2000000.0f );
|
||||
}
|
||||
|
||||
mSpecialLights[type] = light;
|
||||
registerGlobalLight( light, NULL );
|
||||
}
|
||||
|
||||
void LightManager::registerGlobalLights( const Frustum *frustum, bool staticLighting )
|
||||
{
|
||||
PROFILE_SCOPE( LightManager_RegisterGlobalLights );
|
||||
|
||||
// TODO: We need to work this out...
|
||||
//
|
||||
// 1. Why do we register and unregister lights on every
|
||||
// render when they don't often change... shouldn't we
|
||||
// just register once and keep them?
|
||||
//
|
||||
// 2. If we do culling of lights should this happen as part
|
||||
// of registration or somewhere else?
|
||||
//
|
||||
|
||||
// Grab the lights to process.
|
||||
Vector<SceneObject*> activeLights;
|
||||
const U32 lightMask = LightObjectType;
|
||||
|
||||
if ( staticLighting || !frustum )
|
||||
{
|
||||
// We're processing static lighting or want all the lights
|
||||
// in the container registerd... so no culling.
|
||||
getSceneManager()->getContainer()->findObjectList( lightMask, &activeLights );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cull the lights using the frustum.
|
||||
getSceneManager()->getContainer()->findObjectList( *frustum, lightMask, &activeLights );
|
||||
|
||||
// Store the culling position for sun placement
|
||||
// later... see setSpecialLight.
|
||||
mCullPos = frustum->getPosition();
|
||||
|
||||
// HACK: Make sure the control object always gets
|
||||
// processed as lights mounted to it don't change
|
||||
// the shape bounds and can often get culled.
|
||||
|
||||
GameConnection *conn = GameConnection::getConnectionToServer();
|
||||
if ( conn->getControlObject() )
|
||||
{
|
||||
GameBase *conObject = conn->getControlObject();
|
||||
activeLights.push_back_unique( conObject );
|
||||
}
|
||||
}
|
||||
|
||||
// Let the lights register themselves.
|
||||
for ( U32 i = 0; i < activeLights.size(); i++ )
|
||||
{
|
||||
ISceneLight *lightInterface = dynamic_cast<ISceneLight*>( activeLights[i] );
|
||||
if ( lightInterface )
|
||||
lightInterface->submitLights( this, staticLighting );
|
||||
}
|
||||
}
|
||||
|
||||
void LightManager::registerGlobalLight( LightInfo *light, SimObject *obj )
|
||||
{
|
||||
AssertFatal( !mRegisteredLights.contains( light ),
|
||||
"LightManager::registerGlobalLight - This light is already registered!" );
|
||||
|
||||
mRegisteredLights.push_back( light );
|
||||
}
|
||||
|
||||
void LightManager::unregisterGlobalLight( LightInfo *light )
|
||||
{
|
||||
mRegisteredLights.unregisterLight( light );
|
||||
|
||||
// If this is the sun... clear the special light too.
|
||||
if ( light == mSpecialLights[slSunLightType] )
|
||||
dMemset( mSpecialLights, 0, sizeof( mSpecialLights ) );
|
||||
}
|
||||
|
||||
void LightManager::registerLocalLight( LightInfo *light )
|
||||
{
|
||||
// TODO: What should we do here?
|
||||
}
|
||||
|
||||
void LightManager::unregisterLocalLight( LightInfo *light )
|
||||
{
|
||||
// TODO: What should we do here?
|
||||
}
|
||||
|
||||
void LightManager::unregisterAllLights()
|
||||
{
|
||||
dMemset( mSpecialLights, 0, sizeof( mSpecialLights ) );
|
||||
mRegisteredLights.clear();
|
||||
}
|
||||
|
||||
void LightManager::getAllUnsortedLights( Vector<LightInfo*> *list ) const
|
||||
{
|
||||
list->merge( mRegisteredLights );
|
||||
}
|
||||
|
||||
void LightManager::_update4LightConsts( const SceneData &sgData,
|
||||
GFXShaderConstHandle *lightPositionSC,
|
||||
GFXShaderConstHandle *lightDiffuseSC,
|
||||
GFXShaderConstHandle *lightAmbientSC,
|
||||
GFXShaderConstHandle *lightInvRadiusSqSC,
|
||||
GFXShaderConstHandle *lightSpotDirSC,
|
||||
GFXShaderConstHandle *lightSpotAngleSC,
|
||||
GFXShaderConstHandle *lightSpotFalloffSC,
|
||||
GFXShaderConstBuffer *shaderConsts )
|
||||
{
|
||||
PROFILE_SCOPE( LightManager_Update4LightConsts );
|
||||
|
||||
// Skip over gathering lights if we don't have to!
|
||||
if ( lightPositionSC->isValid() ||
|
||||
lightDiffuseSC->isValid() ||
|
||||
lightInvRadiusSqSC->isValid() ||
|
||||
lightSpotDirSC->isValid() ||
|
||||
lightSpotAngleSC->isValid() ||
|
||||
lightSpotFalloffSC->isValid() )
|
||||
{
|
||||
PROFILE_SCOPE( LightManager_Update4LightConsts_setLights );
|
||||
|
||||
// NOTE: We haven't ported the lighting shaders on OSX
|
||||
// to the optimized HLSL versions.
|
||||
#ifdef TORQUE_OS_MAC
|
||||
static AlignedArray<Point3F> lightPositions( 4, sizeof( Point4F ) );
|
||||
#else
|
||||
static AlignedArray<Point4F> lightPositions( 3, sizeof( Point4F ) );
|
||||
static AlignedArray<Point4F> lightSpotDirs( 3, sizeof( Point4F ) );
|
||||
#endif
|
||||
static AlignedArray<Point4F> lightColors( 4, sizeof( Point4F ) );
|
||||
static Point4F lightInvRadiusSq;
|
||||
static Point4F lightSpotAngle;
|
||||
static Point4F lightSpotFalloff;
|
||||
F32 range;
|
||||
|
||||
// Need to clear the buffers so that we don't leak
|
||||
// lights from previous passes or have NaNs.
|
||||
dMemset( lightPositions.getBuffer(), 0, lightPositions.getBufferSize() );
|
||||
dMemset( lightColors.getBuffer(), 0, lightColors.getBufferSize() );
|
||||
lightInvRadiusSq = Point4F::Zero;
|
||||
lightSpotAngle.set( -1.0f, -1.0f, -1.0f, -1.0f );
|
||||
lightSpotFalloff.set( F32_MAX, F32_MAX, F32_MAX, F32_MAX );
|
||||
|
||||
// Gather the data for the first 4 lights.
|
||||
const LightInfo *light;
|
||||
for ( U32 i=0; i < 4; i++ )
|
||||
{
|
||||
light = sgData.lights[i];
|
||||
if ( !light )
|
||||
break;
|
||||
|
||||
#ifdef TORQUE_OS_MAC
|
||||
|
||||
lightPositions[i] = light->getPosition();
|
||||
|
||||
#else
|
||||
|
||||
// The light positions and spot directions are
|
||||
// in SoA order to make optimal use of the GPU.
|
||||
const Point3F &lightPos = light->getPosition();
|
||||
lightPositions[0][i] = lightPos.x;
|
||||
lightPositions[1][i] = lightPos.y;
|
||||
lightPositions[2][i] = lightPos.z;
|
||||
|
||||
const VectorF &lightDir = light->getDirection();
|
||||
lightSpotDirs[0][i] = lightDir.x;
|
||||
lightSpotDirs[1][i] = lightDir.y;
|
||||
lightSpotDirs[2][i] = lightDir.z;
|
||||
|
||||
if ( light->getType() == LightInfo::Spot )
|
||||
{
|
||||
lightSpotAngle[i] = mCos( mDegToRad( light->getOuterConeAngle() / 2.0f ) );
|
||||
lightSpotFalloff[i] = 1.0f / getMax( F32_MIN, mCos( mDegToRad( light->getInnerConeAngle() / 2.0f ) ) - lightSpotAngle[i] );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Prescale the light color by the brightness to
|
||||
// avoid doing this in the shader.
|
||||
lightColors[i] = Point4F(light->getColor()) * light->getBrightness();
|
||||
|
||||
// We need 1 over range^2 here.
|
||||
range = light->getRange().x;
|
||||
lightInvRadiusSq[i] = 1.0f / ( range * range );
|
||||
}
|
||||
|
||||
shaderConsts->setSafe( lightPositionSC, lightPositions );
|
||||
shaderConsts->setSafe( lightDiffuseSC, lightColors );
|
||||
shaderConsts->setSafe( lightInvRadiusSqSC, lightInvRadiusSq );
|
||||
|
||||
#ifndef TORQUE_OS_MAC
|
||||
|
||||
shaderConsts->setSafe( lightSpotDirSC, lightSpotDirs );
|
||||
shaderConsts->setSafe( lightSpotAngleSC, lightSpotAngle );
|
||||
shaderConsts->setSafe( lightSpotFalloffSC, lightSpotFalloff );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// Setup the ambient lighting from the first
|
||||
// light which is the directional light if
|
||||
// one exists at all in the scene.
|
||||
if ( lightAmbientSC->isValid() )
|
||||
shaderConsts->set( lightAmbientSC, sgData.ambientLightColor );
|
||||
}
|
||||
|
||||
AvailableSLInterfaces* LightManager::getSceneLightingInterface()
|
||||
{
|
||||
if ( !mAvailableSLInterfaces )
|
||||
mAvailableSLInterfaces = new AvailableSLInterfaces();
|
||||
|
||||
return mAvailableSLInterfaces;
|
||||
}
|
||||
|
||||
bool LightManager::lightScene( const char* callback, const char* param )
|
||||
{
|
||||
BitSet32 flags = 0;
|
||||
|
||||
if ( param )
|
||||
{
|
||||
if ( !dStricmp( param, "forceAlways" ) )
|
||||
flags.set( SceneLighting::ForceAlways );
|
||||
else if ( !dStricmp(param, "forceWritable" ) )
|
||||
flags.set( SceneLighting::ForceWritable );
|
||||
else if ( !dStricmp(param, "loadOnly" ) )
|
||||
flags.set( SceneLighting::LoadOnly );
|
||||
}
|
||||
|
||||
// The SceneLighting object will delete itself
|
||||
// once the lighting process is complete.
|
||||
SceneLighting* sl = new SceneLighting( getSceneLightingInterface() );
|
||||
return sl->lightScene( callback, flags );
|
||||
}
|
||||
|
||||
RenderPrePassMgr* LightManager::_findPrePassRenderBin()
|
||||
{
|
||||
RenderPassManager* rpm = getSceneManager()->getDefaultRenderPass();
|
||||
for( U32 i = 0; i < rpm->getManagerCount(); i++ )
|
||||
{
|
||||
RenderBinManager *bin = rpm->getManager( i );
|
||||
if( bin->getRenderInstType() == RenderPrePassMgr::RIT_PrePass )
|
||||
{
|
||||
return ( RenderPrePassMgr* ) bin;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DefineEngineFunction( setLightManager, bool, ( const char *name ),,
|
||||
"Finds and activates the named light manager.\n"
|
||||
"@return Returns true if the light manager is found and activated.\n"
|
||||
"@ingroup Lighting\n" )
|
||||
{
|
||||
return gClientSceneGraph->setLightManager( name );
|
||||
}
|
||||
|
||||
DefineEngineFunction( lightScene, bool, ( const char *completeCallbackFn, const char *mode ), ( NULL, NULL ),
|
||||
"Will generate static lighting for the scene if supported by the active light manager.\n\n"
|
||||
"If mode is \"forceAlways\", the lightmaps will be regenerated regardless of whether "
|
||||
"lighting cache files can be written to. If mode is \"forceWritable\", then the lightmaps "
|
||||
"will be regenerated only if the lighting cache files can be written.\n"
|
||||
"@param completeCallbackFn The name of the function to execute when the lighting is complete.\n"
|
||||
"@param mode One of \"forceAlways\", \"forceWritable\" or \"loadOnly\".\n"
|
||||
"@return Returns true if the scene lighting process was started.\n"
|
||||
"@ingroup Lighting\n" )
|
||||
{
|
||||
if ( !LIGHTMGR )
|
||||
return false;
|
||||
|
||||
return LIGHTMGR->lightScene( completeCallbackFn, mode );
|
||||
}
|
||||
|
||||
DefineEngineFunction( getLightManagerNames, String, (),,
|
||||
"Returns a tab seperated list of light manager names.\n"
|
||||
"@ingroup Lighting\n" )
|
||||
{
|
||||
String names;
|
||||
LightManager::getLightManagerNames( &names );
|
||||
return names;
|
||||
}
|
||||
|
||||
DefineEngineFunction( getActiveLightManager, const char*, (),,
|
||||
"Returns the active light manager name.\n"
|
||||
"@ingroup Lighting\n" )
|
||||
{
|
||||
if ( !LIGHTMGR )
|
||||
return NULL;
|
||||
|
||||
return LIGHTMGR->getName();
|
||||
}
|
||||
|
||||
DefineEngineFunction( resetLightManager, void, (),,
|
||||
"@brief Deactivates and then activates the currently active light manager."
|
||||
"This causes most shaders to be regenerated and is often used when global "
|
||||
"rendering changes have occured.\n"
|
||||
"@ingroup Lighting\n" )
|
||||
{
|
||||
LightManager *lm = LIGHTMGR;
|
||||
if ( !lm )
|
||||
return;
|
||||
|
||||
SceneManager *sm = lm->getSceneManager();
|
||||
lm->deactivate();
|
||||
lm->activate( sm );
|
||||
}
|
||||
232
Engine/source/lighting/lightManager.h
Normal file
232
Engine/source/lighting/lightManager.h
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _LIGHTMANAGER_H_
|
||||
#define _LIGHTMANAGER_H_
|
||||
|
||||
#ifndef _TORQUE_STRING_H_
|
||||
#include "core/util/str.h"
|
||||
#endif
|
||||
#ifndef _TSIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
#ifndef _LIGHTQUERY_H_
|
||||
#include "lighting/lightQuery.h"
|
||||
#endif
|
||||
|
||||
class SimObject;
|
||||
class LightManager;
|
||||
class Material;
|
||||
class ProcessedMaterial;
|
||||
class SceneManager;
|
||||
struct SceneData;
|
||||
class Point3F;
|
||||
class AvailableSLInterfaces;
|
||||
class SceneObject;
|
||||
class GFXShaderConstBuffer;
|
||||
class GFXShaderConstHandle;
|
||||
class ShaderConstHandles;
|
||||
class SceneRenderState;
|
||||
class RenderPrePassMgr;
|
||||
class Frustum;
|
||||
|
||||
///
|
||||
typedef Map<String,LightManager*> LightManagerMap;
|
||||
|
||||
|
||||
class LightManager
|
||||
{
|
||||
public:
|
||||
|
||||
enum SpecialLightTypesEnum
|
||||
{
|
||||
slSunLightType,
|
||||
slSpecialLightTypesCount
|
||||
};
|
||||
|
||||
LightManager( const char *name, const char *id );
|
||||
|
||||
virtual ~LightManager();
|
||||
|
||||
///
|
||||
static void initLightFields();
|
||||
|
||||
///
|
||||
static LightInfo* createLightInfo(LightInfo* light = NULL);
|
||||
|
||||
///
|
||||
static LightManager* findByName( const char *name );
|
||||
|
||||
/// Returns a tab seperated list of available light managers.
|
||||
static void getLightManagerNames( String *outString );
|
||||
|
||||
/// The light manager activation signal.
|
||||
static Signal<void(const char*,bool)> smActivateSignal;
|
||||
|
||||
/// Returns the active LM.
|
||||
static inline LightManager* getActiveLM() { return smActiveLM; }
|
||||
|
||||
/// Return an id string used to load different versions of light manager
|
||||
/// specific assets. It shoud be short, contain no spaces, and be safe
|
||||
/// for filename use.
|
||||
const char* getName() const { return mName.c_str(); }
|
||||
|
||||
/// Return an id string used to load different versions of light manager
|
||||
/// specific assets. It shoud be short, contain no spaces, and be safe
|
||||
/// for filename use.
|
||||
const char* getId() const { return mId.c_str(); }
|
||||
|
||||
// Returns the scene manager passed at activation.
|
||||
SceneManager* getSceneManager() { return mSceneManager; }
|
||||
|
||||
// Should return true if this light manager is compatible
|
||||
// on the current platform and GFX device.
|
||||
virtual bool isCompatible() const = 0;
|
||||
|
||||
// Called when the lighting manager should become active
|
||||
virtual void activate( SceneManager *sceneManager );
|
||||
|
||||
// Called when we don't want the light manager active (should clean up)
|
||||
virtual void deactivate();
|
||||
|
||||
// Returns the active scene lighting interface for this light manager.
|
||||
virtual AvailableSLInterfaces* getSceneLightingInterface();
|
||||
|
||||
// Returns a "default" light info that callers should not free. Used for instances where we don't actually care about
|
||||
// the light (for example, setting default data for SceneData)
|
||||
virtual LightInfo* getDefaultLight();
|
||||
|
||||
/// Returns the special light or the default light if useDefault is true.
|
||||
/// @see getDefaultLight
|
||||
virtual LightInfo* getSpecialLight( SpecialLightTypesEnum type,
|
||||
bool useDefault = true );
|
||||
|
||||
/// Set a special light type.
|
||||
virtual void setSpecialLight( SpecialLightTypesEnum type, LightInfo *light );
|
||||
|
||||
// registered before scene traversal...
|
||||
virtual void registerGlobalLight( LightInfo *light, SimObject *obj );
|
||||
virtual void unregisterGlobalLight( LightInfo *light );
|
||||
|
||||
// registered per object...
|
||||
virtual void registerLocalLight( LightInfo *light );
|
||||
virtual void unregisterLocalLight( LightInfo *light );
|
||||
|
||||
virtual void registerGlobalLights( const Frustum *frustum, bool staticlighting );
|
||||
virtual void unregisterAllLights();
|
||||
|
||||
/// Returns all unsorted and un-scored lights (both global and local).
|
||||
void getAllUnsortedLights( Vector<LightInfo*> *list ) const;
|
||||
|
||||
/// Sets shader constants / textures for light infos
|
||||
virtual void setLightInfo( ProcessedMaterial *pmat,
|
||||
const Material *mat,
|
||||
const SceneData &sgData,
|
||||
const SceneRenderState *state,
|
||||
U32 pass,
|
||||
GFXShaderConstBuffer *shaderConsts ) = 0;
|
||||
|
||||
/// Allows us to set textures during the Material::setTextureStage call, return true if we've done work.
|
||||
virtual bool setTextureStage( const SceneData &sgData,
|
||||
const U32 currTexFlag,
|
||||
const U32 textureSlot,
|
||||
GFXShaderConstBuffer *shaderConsts,
|
||||
ShaderConstHandles *handles ) = 0;
|
||||
|
||||
/// Called when the static scene lighting (aka lightmaps) should be computed.
|
||||
virtual bool lightScene( const char* callback, const char* param );
|
||||
|
||||
/// Returns true if this light manager is active
|
||||
virtual bool isActive() const { return mIsActive; }
|
||||
|
||||
protected:
|
||||
|
||||
/// The current active light manager.
|
||||
static LightManager *smActiveLM;
|
||||
|
||||
/// Find the pre-pass render bin on the scene's default render pass.
|
||||
RenderPrePassMgr* _findPrePassRenderBin();
|
||||
|
||||
/// This helper function sets the shader constansts
|
||||
/// for the stock 4 light forward lighting code.
|
||||
static void _update4LightConsts( const SceneData &sgData,
|
||||
GFXShaderConstHandle *lightPositionSC,
|
||||
GFXShaderConstHandle *lightDiffuseSC,
|
||||
GFXShaderConstHandle *lightAmbientSC,
|
||||
GFXShaderConstHandle *lightInvRadiusSqSC,
|
||||
GFXShaderConstHandle *lightSpotDirSC,
|
||||
GFXShaderConstHandle *lightSpotAngleSC,
|
||||
GFXShaderConstHandle *lightSpotFalloffSC,
|
||||
GFXShaderConstBuffer *shaderConsts );
|
||||
|
||||
/// A dummy default light used when no lights
|
||||
/// happen to be registered with the manager.
|
||||
LightInfo *mDefaultLight;
|
||||
|
||||
/// The list of global registered lights which is
|
||||
/// initialized before the scene is rendered.
|
||||
LightInfoList mRegisteredLights;
|
||||
|
||||
/// The registered special light list.
|
||||
LightInfo *mSpecialLights[slSpecialLightTypesCount];
|
||||
|
||||
/// The root culling position used for
|
||||
/// special sun light placement.
|
||||
/// @see setSpecialLight
|
||||
Point3F mCullPos;
|
||||
|
||||
/// The scene lighting interfaces for
|
||||
/// lightmap generation.
|
||||
AvailableSLInterfaces *mAvailableSLInterfaces;
|
||||
|
||||
/// Attaches any LightInfoEx data for this manager
|
||||
/// to the light info object.
|
||||
virtual void _addLightInfoEx( LightInfo *lightInfo ) = 0;
|
||||
|
||||
///
|
||||
virtual void _initLightFields() = 0;
|
||||
|
||||
/// Returns the static light manager map.
|
||||
static LightManagerMap& _getLightManagers();
|
||||
|
||||
/// The constant light manager name initialized
|
||||
/// in the constructor.
|
||||
const String mName;
|
||||
|
||||
/// The constant light manager identifier initialized
|
||||
/// in the constructor.
|
||||
const String mId;
|
||||
|
||||
/// Is true if this light manager has been activated.
|
||||
bool mIsActive;
|
||||
|
||||
/// The scene graph the light manager is associated with.
|
||||
SceneManager *mSceneManager;
|
||||
};
|
||||
|
||||
/// Returns the current active light manager.
|
||||
#define LIGHTMGR LightManager::getActiveLM()
|
||||
|
||||
#endif // _LIGHTMANAGER_H_
|
||||
171
Engine/source/lighting/lightQuery.cpp
Normal file
171
Engine/source/lighting/lightQuery.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/lightQuery.h"
|
||||
|
||||
#include "lighting/lightManager.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
|
||||
LightQuery::LightQuery( U32 maxLights )
|
||||
: mMaxLights( maxLights )
|
||||
{
|
||||
}
|
||||
|
||||
LightQuery::~LightQuery()
|
||||
{
|
||||
}
|
||||
|
||||
void LightQuery::init( const Point3F &cameraPos,
|
||||
const Point3F &cameraDir,
|
||||
F32 viewDist )
|
||||
{
|
||||
mVolume.center = cameraPos;
|
||||
mVolume.radius = viewDist;
|
||||
mLights.clear();
|
||||
}
|
||||
|
||||
void LightQuery::init( const SphereF &bounds )
|
||||
{
|
||||
mVolume = bounds;
|
||||
mLights.clear();
|
||||
}
|
||||
|
||||
void LightQuery::init( const Box3F &bounds )
|
||||
{
|
||||
bounds.getCenter( &mVolume.center );
|
||||
mVolume.radius = ( bounds.maxExtents - mVolume.center ).len();
|
||||
mLights.clear();
|
||||
}
|
||||
|
||||
void LightQuery::getLights( LightInfo** outLights, U32 maxLights )
|
||||
{
|
||||
PROFILE_SCOPE( LightQuery_getLights );
|
||||
|
||||
// Gather lights if we haven't already.
|
||||
if ( mLights.empty() )
|
||||
_scoreLights();
|
||||
|
||||
U32 lightCount = getMin( (U32)mLights.size(), getMin( mMaxLights, maxLights ) );
|
||||
|
||||
// Copy them over.
|
||||
for ( U32 i = 0; i < lightCount; i++ )
|
||||
{
|
||||
LightInfo *light = mLights[i];
|
||||
|
||||
// If the score reaches zero then we got to
|
||||
// the end of the valid lights for this object.
|
||||
if ( light->getScore() <= 0.0f )
|
||||
break;
|
||||
|
||||
outLights[i] = light;
|
||||
}
|
||||
}
|
||||
|
||||
void LightQuery::_scoreLights()
|
||||
{
|
||||
PROFILE_SCOPE( LightQuery_scoreLights );
|
||||
|
||||
if ( !LIGHTMGR )
|
||||
return;
|
||||
|
||||
// Get all the lights.
|
||||
LIGHTMGR->getAllUnsortedLights( &mLights );
|
||||
LightInfo *sun = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
|
||||
|
||||
const Point3F lumDot( 0.2125f, 0.7154f, 0.0721f );
|
||||
|
||||
Vector<LightInfo*>::iterator iter = mLights.begin();
|
||||
for ( ; iter != mLights.end(); iter++ )
|
||||
{
|
||||
// Get the light.
|
||||
LightInfo *light = (*iter);
|
||||
|
||||
F32 luminace = 0.0f;
|
||||
F32 dist = 0.0f;
|
||||
F32 weight = 0.0f;
|
||||
|
||||
const bool isSpot = light->getType() == LightInfo::Spot;
|
||||
const bool isPoint = light->getType() == LightInfo::Point;
|
||||
|
||||
if ( isPoint || isSpot )
|
||||
{
|
||||
// Get the luminocity.
|
||||
luminace = mDot( light->getColor(), lumDot ) * light->getBrightness();
|
||||
|
||||
// Get the distance to the light... score it 1 to 0 near to far.
|
||||
F32 lenSq = ( mVolume.center - light->getPosition() ).lenSquared();
|
||||
|
||||
F32 radiusSq = mSquared( light->getRange().x + mVolume.radius );
|
||||
F32 distSq = radiusSq - lenSq;
|
||||
|
||||
if ( distSq > 0.0f )
|
||||
dist = mClampF( distSq / ( 1000.0f * 1000.0f ), 0.0f, 1.0f );
|
||||
|
||||
// TODO: This culling is broken... it culls spotlights
|
||||
// that are actually visible.
|
||||
if ( false && isSpot && dist > 0.0f )
|
||||
{
|
||||
// TODO: I cannot test to see if we're within
|
||||
// the cone without a more detailed test... so
|
||||
// just reject if we're behind the spot direction.
|
||||
|
||||
Point3F toCenter = mVolume.center - light->getPosition();
|
||||
F32 angDot = mDot( toCenter, light->getDirection() );
|
||||
if ( angDot < 0.0f )
|
||||
dist = 0.0f;
|
||||
}
|
||||
|
||||
weight = light->getPriority();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The sun always goes first
|
||||
// regardless of the settings.
|
||||
if ( light == sun )
|
||||
{
|
||||
weight = F32_MAX;
|
||||
dist = 1.0f;
|
||||
luminace = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: When we have multiple directional
|
||||
// lights we should score them here.
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Manager ambient lights here too!
|
||||
|
||||
light->setScore( luminace * weight * dist );
|
||||
}
|
||||
|
||||
// Sort them!
|
||||
mLights.sort( _lightScoreCmp );
|
||||
}
|
||||
|
||||
S32 LightQuery::_lightScoreCmp( LightInfo* const *a, LightInfo* const *b )
|
||||
{
|
||||
F32 diff = (*a)->getScore() - (*b)->getScore();
|
||||
return diff < 0 ? 1 : diff > 0 ? -1 : 0;
|
||||
}
|
||||
82
Engine/source/lighting/lightQuery.h
Normal file
82
Engine/source/lighting/lightQuery.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _LIGHTQUERY_H_
|
||||
#define _LIGHTQUERY_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MSPHERE_H_
|
||||
#include "math/mSphere.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MBOX_H_
|
||||
#include "math/mBox.h"
|
||||
#endif
|
||||
|
||||
|
||||
class LightManager;
|
||||
class LightInfo;
|
||||
|
||||
|
||||
/// Used to gather an score lights for rendering.
|
||||
class LightQuery
|
||||
{
|
||||
public:
|
||||
|
||||
LightQuery( U32 maxLights = 4 );
|
||||
~LightQuery();
|
||||
|
||||
/// Set the query volume from a camera position and direction.
|
||||
void init( const Point3F &cameraPos,
|
||||
const Point3F &cameraDir,
|
||||
F32 viewDist );
|
||||
|
||||
/// Set the query volume from a sphere.
|
||||
void init( const SphereF &bounds );
|
||||
|
||||
/// Set the query volume from a box.
|
||||
void init( const Box3F &bounds );
|
||||
|
||||
/// This returns the best lights based on the query volume.
|
||||
void getLights( LightInfo** outLights, U32 maxLights );
|
||||
|
||||
protected:
|
||||
|
||||
void _scoreLights();
|
||||
|
||||
static S32 _lightScoreCmp( LightInfo* const *a, LightInfo* const *b );
|
||||
|
||||
/// The maximum lights to return from the query.
|
||||
const U32 mMaxLights;
|
||||
|
||||
/// The sorted list of best lights.
|
||||
Vector<LightInfo*> mLights;
|
||||
|
||||
/// The sphere used to query for lights.
|
||||
SphereF mVolume;
|
||||
};
|
||||
|
||||
|
||||
#endif // _LIGHTQUERY_H_
|
||||
51
Engine/source/lighting/lightingInterfaces.cpp
Normal file
51
Engine/source/lighting/lightingInterfaces.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/lightingInterfaces.h"
|
||||
|
||||
|
||||
void AvailableSLInterfaces::registerSystem(SceneLightingInterface* si)
|
||||
{
|
||||
mAvailableSystemInterfaces.push_back(si);
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
void AvailableSLInterfaces::initInterfaces()
|
||||
{
|
||||
if ( !mDirty )
|
||||
return;
|
||||
|
||||
mAvailableObjectTypes = mClippingMask = mZoneLightSkipMask = 0;
|
||||
|
||||
SceneLightingInterface** sitr = mAvailableSystemInterfaces.begin();
|
||||
for ( ; sitr != mAvailableSystemInterfaces.end(); sitr++ )
|
||||
{
|
||||
SceneLightingInterface* si = (*sitr);
|
||||
si->init();
|
||||
mAvailableObjectTypes |= si->addObjectType();
|
||||
mClippingMask |= si->addToClippingMask();
|
||||
mZoneLightSkipMask |= si->addToZoneLightSkipMask();
|
||||
}
|
||||
|
||||
mDirty = false;
|
||||
}
|
||||
123
Engine/source/lighting/lightingInterfaces.h
Normal file
123
Engine/source/lighting/lightingInterfaces.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _SG_SYSTEM_INTERFACE_H
|
||||
#define _SG_SYSTEM_INTERFACE_H
|
||||
|
||||
#ifndef _SGSCENEPERSIST_H_
|
||||
#include "lighting/common/scenePersist.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SCENELIGHTING_H_
|
||||
#include "lighting/common/sceneLighting.h"
|
||||
#endif
|
||||
|
||||
class ObjectProxy;
|
||||
class ObjectProxyList;
|
||||
class SceneLightingInterface;
|
||||
|
||||
template <class T> class Vector;
|
||||
typedef Vector<SceneLightingInterface*> SceneLightingInterfaces;
|
||||
|
||||
// List of available "systems" that the lighting kit can use
|
||||
class AvailableSLInterfaces
|
||||
{
|
||||
protected:
|
||||
|
||||
bool mDirty;
|
||||
|
||||
public:
|
||||
AvailableSLInterfaces()
|
||||
: mAvailableObjectTypes( 0 ),
|
||||
mClippingMask( 0 ),
|
||||
mZoneLightSkipMask( 0 ),
|
||||
mDirty( true )
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( mAvailableSystemInterfaces );
|
||||
}
|
||||
|
||||
// Register a system
|
||||
void registerSystem(SceneLightingInterface* si);
|
||||
|
||||
// Init the interfaces
|
||||
void initInterfaces();
|
||||
|
||||
// The actual list of SceneLightingInterfaces
|
||||
SceneLightingInterfaces mAvailableSystemInterfaces;
|
||||
|
||||
// Object types that are registered with the system
|
||||
U32 mAvailableObjectTypes;
|
||||
|
||||
// Clipping typemask
|
||||
U32 mClippingMask;
|
||||
|
||||
// Object types that we should skip zone lighting for
|
||||
U32 mZoneLightSkipMask;
|
||||
};
|
||||
|
||||
// This object is responsible for returning PersistChunk and ObjectProxy classes for the lighting system to use
|
||||
// We may want to eventually split this into scene lighting vs. dynamic lighting. getColorFromRayInfo is a dynamic
|
||||
// lighting thing.
|
||||
class SceneLightingInterface
|
||||
{
|
||||
public:
|
||||
SceneLightingInterface()
|
||||
{
|
||||
}
|
||||
virtual ~SceneLightingInterface() { }
|
||||
|
||||
virtual void init() { }
|
||||
|
||||
//
|
||||
// Scene lighting methods
|
||||
//
|
||||
// Creates an object proxy for obj
|
||||
virtual SceneLighting::ObjectProxy* createObjectProxy(SceneObject* obj, SceneLighting::ObjectProxyList* sceneObjects) = 0;
|
||||
|
||||
// Creates a PersistChunk based on the chunkType flag
|
||||
virtual PersistInfo::PersistChunk* createPersistChunk(const U32 chunkType) = 0;
|
||||
|
||||
// Creates a PersistChunk if needed for a proxy, returns true if it's "handled" by the system and ret contains the PersistChunk if needed.
|
||||
virtual bool createPersistChunkFromProxy(SceneLighting::ObjectProxy* proxy, PersistInfo::PersistChunk** ret) = 0;
|
||||
|
||||
// Returns which object type flag this system supports (used to query scene graph for objects to light)
|
||||
virtual U32 addObjectType() = 0;
|
||||
|
||||
// Add an object type flag to the "allow clipping mask" (used for blob shadows)
|
||||
virtual U32 addToClippingMask() { return 0; }
|
||||
|
||||
// Add an object type flag to skip zone lighting
|
||||
virtual U32 addToZoneLightSkipMask() { return 0; }
|
||||
|
||||
// Allows for processing/validating of the scene list after loading cached persistant info, return false if a relight is required or true if the data looks good.
|
||||
virtual bool postProcessLoad(PersistInfo* pi, SceneLighting::ObjectProxyList* sceneObjects) { return true; }
|
||||
|
||||
virtual void processLightingBegin() { }
|
||||
virtual void processLightingCompleted(bool success) { }
|
||||
|
||||
//
|
||||
// Runtime / dynamic methods
|
||||
//
|
||||
// Given a ray, this will return the color from the lightmap of this object, return true if handled
|
||||
virtual bool getColorFromRayInfo(const RayInfo & collision, ColorF& result) const { return false; }
|
||||
};
|
||||
|
||||
#endif
|
||||
79
Engine/source/lighting/shadowManager.cpp
Normal file
79
Engine/source/lighting/shadowManager.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/shadowManager.h"
|
||||
|
||||
#include "scene/sceneManager.h"
|
||||
#include "materials/materialManager.h"
|
||||
|
||||
const String ShadowManager::ManagerTypeName("ShadowManager");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ShadowManager::canActivate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ShadowManager::activate()
|
||||
{
|
||||
mSceneManager = gClientSceneGraph; //;getWorld()->findWorldManager<SceneManager>();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
SceneManager* ShadowManager::getSceneManager()
|
||||
{
|
||||
return mSceneManager;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Runtime switching of shadow systems. Requires correct world to be pushed at console.
|
||||
ConsoleFunction( setShadowManager, bool, 1, 3, "string sShadowSystemName" )
|
||||
{
|
||||
/*
|
||||
// Make sure this new one exists
|
||||
ShadowManager * newSM = dynamic_cast<ShadowManager*>(ConsoleObject::create(argv[1]));
|
||||
if (!newSM)
|
||||
return false;
|
||||
|
||||
// Cleanup current
|
||||
ShadowManager * currentSM = world->findWorldManager<ShadowManager>();
|
||||
if (currentSM)
|
||||
{
|
||||
currentSM->deactivate();
|
||||
world->removeWorldManager(currentSM);
|
||||
delete currentSM;
|
||||
}
|
||||
|
||||
// Add to world and init.
|
||||
world->addWorldManager(newSM);
|
||||
newSM->activate();
|
||||
MaterialManager::get()->reInitInstances();
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
66
Engine/source/lighting/shadowManager.h
Normal file
66
Engine/source/lighting/shadowManager.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _SHADOWMANAGER_H_
|
||||
#define _SHADOWMANAGER_H_
|
||||
|
||||
#ifndef _TSIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
#ifndef _TORQUE_STRING_H_
|
||||
#include "core/util/str.h"
|
||||
#endif
|
||||
|
||||
class SceneManager;
|
||||
|
||||
class ShadowManager
|
||||
{
|
||||
public:
|
||||
ShadowManager() : mSceneManager(NULL) {}
|
||||
virtual ~ShadowManager() { }
|
||||
|
||||
// Called when the shadow manager should become active
|
||||
virtual void activate();
|
||||
|
||||
// Called when we don't want the shadow manager active (should clean up)
|
||||
virtual void deactivate() { }
|
||||
|
||||
// Return an "id" that other systems can use to load different versions of assets (custom shaders, etc.)
|
||||
// Should be short and contain no spaces and safe for filename use.
|
||||
//virtual const char* getId() const = 0;
|
||||
|
||||
// SceneManager manager
|
||||
virtual SceneManager* getSceneManager();
|
||||
|
||||
// Called to find out if it is valid to activate this shadow system. If not, we should print out
|
||||
// a console warning explaining why.
|
||||
virtual bool canActivate();
|
||||
|
||||
// SimWorldManager
|
||||
static const String ManagerTypeName;
|
||||
const String & getManagerTypeName() const { return ManagerTypeName; }
|
||||
|
||||
private:
|
||||
SceneManager* mSceneManager;
|
||||
};
|
||||
|
||||
#endif // _SHADOWMANAGER_H_
|
||||
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