mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-13 11:43:49 +00:00
shadow caching
SPECIAL NOTE: highly suggest https://github.com/GarageGames/Torque3D/pull/1441 or a variation thereof to prevent debug spew and false-postives for occlusion results. With significant research, development and prototyping assistance from both @andr3wmac (shaders and partial hook work), and @LuisAntonRebollo (additional culling) System operates as follows: 1) materials are given an additional castDynamicShadows boolean entry. (Default at time of writing is true by request. Personal usage at time of writing defaults to false. value is default-initialized in materialDefinition.cpp. script/gui exposed) 2) lights are given a staticRefreshFreq and dynamicRefreshFreq (in milliseconds). script/gui exposed 3) materials are (effectively) sorted into dynamic and static shadowmap render lists based on flag. (see shadowMapPass.cpp) 4) initial shadowmaps are generated for each light and 'list'. 5) as each refreshFreq times out, the relevant shadowmap for a given light is refreshed. Special notes: dynamicRefreshFreq for all lights is set to a (script exposed) 8MS refresh timer. StaticRefreshFreq for the lions share of lights defaults to 250 MS (1/4 of a second) scattersky's embedded light, which is intended to operate in a mobile manner, defaults to 8 to reiterate, these are all customizable per-light via script/inspector gui in the case of alternate project needs.
This commit is contained in:
parent
2044b2691e
commit
2753f562e8
54 changed files with 1477 additions and 464 deletions
|
|
@ -37,6 +37,7 @@
|
|||
#include "materials/shaderData.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "math/mathUtils.h"
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
|
|
@ -248,6 +249,9 @@ void PSSMLightShadowMap::_render( RenderPassManager* renderPass,
|
|||
TSShapeInstance::smDetailAdjust *= smDetailAdjustScale;
|
||||
TSShapeInstance::smSmallestVisiblePixelSize = smSmallestVisiblePixelSize;
|
||||
|
||||
Vector< Vector<PlaneF> > _extraCull;
|
||||
_calcPlanesCullForShadowCasters( _extraCull, fullFrustum, mLight->getDirection() );
|
||||
|
||||
for (U32 i = 0; i < mNumSplits; i++)
|
||||
{
|
||||
GFXTransformSaver saver;
|
||||
|
|
@ -365,12 +369,17 @@ void PSSMLightShadowMap::_render( RenderPassManager* renderPass,
|
|||
shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
PlaneSetF planeSet( _extraCull[i].address(), _extraCull[i].size() );
|
||||
shadowRenderState.getCullingState().setExtraPlanesCull( planeSet );
|
||||
|
||||
U32 objectMask = SHADOW_TYPEMASK;
|
||||
if ( i == mNumSplits-1 && params->lastSplitTerrainOnly )
|
||||
objectMask = TerrainObjectType;
|
||||
|
||||
sceneManager->renderSceneNoLights( &shadowRenderState, objectMask );
|
||||
|
||||
shadowRenderState.getCullingState().clearExtraPlanesCull();
|
||||
|
||||
_debugRender( &shadowRenderState );
|
||||
}
|
||||
|
||||
|
|
@ -435,18 +444,28 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
|
|||
}
|
||||
}
|
||||
|
||||
params->setSafe(lsc->mScaleXSC, sx);
|
||||
params->setSafe(lsc->mScaleYSC, sy);
|
||||
params->setSafe(lsc->mOffsetXSC, ox);
|
||||
params->setSafe(lsc->mOffsetYSC, oy);
|
||||
// These values change based on static/dynamic.
|
||||
if ( mIsDynamic )
|
||||
{
|
||||
params->setSafe(lsc->mDynamicScaleXSC, sx);
|
||||
params->setSafe(lsc->mDynamicScaleYSC, sy);
|
||||
params->setSafe(lsc->mDynamicOffsetXSC, ox);
|
||||
params->setSafe(lsc->mDynamicOffsetYSC, oy);
|
||||
params->setSafe( lsc->mDynamicFarPlaneScalePSSM, mFarPlaneScalePSSM);
|
||||
} else {
|
||||
params->setSafe(lsc->mScaleXSC, sx);
|
||||
params->setSafe(lsc->mScaleYSC, sy);
|
||||
params->setSafe(lsc->mOffsetXSC, ox);
|
||||
params->setSafe(lsc->mOffsetYSC, oy);
|
||||
params->setSafe( lsc->mFarPlaneScalePSSM, mFarPlaneScalePSSM);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -462,3 +481,117 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
|
|||
// The softness is a factor of the texel size.
|
||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
|
||||
void PSSMLightShadowMap::_calcPlanesCullForShadowCasters(Vector< Vector<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir)
|
||||
{
|
||||
|
||||
#define ENABLE_CULL_ASSERT
|
||||
|
||||
PROFILE_SCOPE(PSSMLightShadowMap_render_getCullFrustrum);
|
||||
|
||||
Point3F ligthDir = _ligthDir;
|
||||
PlaneF lightFarPlane, lightNearPlane;
|
||||
MatrixF lightFarPlaneMat(true);
|
||||
MatrixF invLightFarPlaneMat(true);
|
||||
|
||||
// init data
|
||||
{
|
||||
ligthDir.normalize();
|
||||
Point3F viewDir = viewFrustum.getTransform().getForwardVector();
|
||||
viewDir.normalize();
|
||||
const Point3F viewPosition = viewFrustum.getPosition();
|
||||
const F32 viewDistance = viewFrustum.getBounds().len();
|
||||
lightNearPlane = PlaneF(viewPosition + (viewDistance * -ligthDir), ligthDir);
|
||||
|
||||
const Point3F lightFarPlanePos = viewPosition + (viewDistance * ligthDir);
|
||||
lightFarPlane = PlaneF(lightFarPlanePos, -ligthDir);
|
||||
|
||||
lightFarPlaneMat = MathUtils::createOrientFromDir(-ligthDir);
|
||||
lightFarPlaneMat.setPosition(lightFarPlanePos);
|
||||
lightFarPlaneMat.invertTo(&invLightFarPlaneMat);
|
||||
}
|
||||
|
||||
Vector<Point2F> projVertices;
|
||||
|
||||
//project all frustum vertices into plane
|
||||
// all vertices are 2d and local to far plane
|
||||
projVertices.setSize(8);
|
||||
for (int i = 0; i < 8; ++i) //
|
||||
{
|
||||
const Point3F &point = viewFrustum.getPoints()[i];
|
||||
#ifdef ENABLE_CULL_ASSERT
|
||||
AssertFatal( PlaneF::Front == lightNearPlane.whichSide(point), "" );
|
||||
AssertFatal( PlaneF::Front == lightFarPlane.whichSide(point), "" );
|
||||
#endif
|
||||
|
||||
Point3F localPoint(lightFarPlane.project(point));
|
||||
invLightFarPlaneMat.mulP(localPoint);
|
||||
projVertices[i] = Point2F(localPoint.x, localPoint.z);
|
||||
}
|
||||
|
||||
//create hull arround projected proints
|
||||
Vector<Point2F> hullVerts;
|
||||
MathUtils::mBuildHull2D(projVertices, hullVerts);
|
||||
|
||||
Vector<PlaneF> planes;
|
||||
planes.push_back(lightNearPlane);
|
||||
planes.push_back(lightFarPlane);
|
||||
|
||||
//build planes
|
||||
for (int i = 0; i < (hullVerts.size() - 1); ++i)
|
||||
{
|
||||
Point2F pos2D = (hullVerts[i] + hullVerts[i + 1]) / 2;
|
||||
Point3F pos3D(pos2D.x, 0, pos2D.y);
|
||||
|
||||
Point3F pos3DA(hullVerts[i].x, 0, hullVerts[i].y);
|
||||
Point3F pos3DB(hullVerts[i + 1].x, 0, hullVerts[i + 1].y);
|
||||
|
||||
// move hull points to 3d space
|
||||
lightFarPlaneMat.mulP(pos3D);
|
||||
lightFarPlaneMat.mulP(pos3DA);
|
||||
lightFarPlaneMat.mulP(pos3DB);
|
||||
|
||||
PlaneF plane(pos3D, MathUtils::mTriangleNormal(pos3DB, pos3DA, (pos3DA - ligthDir)));
|
||||
planes.push_back(plane);
|
||||
}
|
||||
|
||||
//recalculate planes for each splits
|
||||
for (int split = 0; split < mNumSplits; ++split)
|
||||
{
|
||||
Frustum subFrustum(viewFrustum);
|
||||
subFrustum.cropNearFar(mSplitDist[split], mSplitDist[split + 1]);
|
||||
subFrustum.setFarDist(getMin(subFrustum.getFarDist()*2.5f, viewFrustum.getFarDist()));
|
||||
subFrustum.update();
|
||||
|
||||
Vector<PlaneF> subPlanes = planes;
|
||||
|
||||
for (int planeIdx = 0; planeIdx < subPlanes.size(); ++planeIdx)
|
||||
{
|
||||
PlaneF &plane = subPlanes[planeIdx];
|
||||
F32 minDist = 0;
|
||||
|
||||
//calculate near vertex distance
|
||||
for (int vertexIdx = 0; vertexIdx < 8; ++vertexIdx)
|
||||
{
|
||||
Point3F point = subFrustum.getPoints()[vertexIdx];
|
||||
minDist = getMin(plane.distToPlane(point), minDist);
|
||||
}
|
||||
|
||||
// move plane to near vertex
|
||||
Point3F newPos = plane.getPosition() + (plane.getNormal() * minDist);
|
||||
plane = PlaneF(newPos, plane.getNormal());
|
||||
|
||||
#ifdef ENABLE_CULL_ASSERT
|
||||
for(int x = 0; x < 8; ++x)
|
||||
{
|
||||
AssertFatal( PlaneF::Back != plane.whichSide( subFrustum.getPoints()[x] ), "");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
out.push_back(subPlanes);
|
||||
}
|
||||
|
||||
#undef ENABLE_CULL_ASSERT
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue