2017-10-03 03:40:23 +01:00
# include "shadow.hpp"
2017-10-11 20:47:19 +01:00
# include <osgShadow/ShadowedScene>
# include <osg/CullFace>
# include <osg/Geode>
# include <osg/io_utils>
# include <osgDB/FileUtils>
# include <osgDB/ReadFile>
2017-12-27 02:32:17 +00:00
# include <components/settings/settings.hpp>
2017-11-08 01:44:49 +00:00
namespace SceneUtil
2017-10-03 03:40:23 +01:00
{
2017-10-11 20:47:19 +01:00
using namespace osgShadow ;
std : : string debugVertexShaderSource = " void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;} " ;
std : : string debugFragmentShaderSource =
" uniform sampler2D texture; \n "
" \n "
" void main(void) \n "
" { \n "
2017-10-14 01:13:45 +01:00
# if 1
2017-10-31 20:22:14 +01:00
" float f = texture2D( texture, gl_TexCoord[0].xy ).r; \n "
2017-10-11 20:47:19 +01:00
" \n "
" f = 256.0 * f; \n "
" float fC = floor( f ) / 256.0; \n "
" \n "
" f = 256.0 * fract( f ); \n "
" float fS = floor( f ) / 256.0; \n "
" \n "
" f = 256.0 * fract( f ); \n "
" float fH = floor( f ) / 256.0; \n "
" \n "
" fS *= 0.5; \n "
" fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n "
" \n "
" vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n "
" abs( fC - 0.333333 ), \n "
" abs( fC - 0.666667 ) ); \n "
" \n "
" rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n "
" \n "
" float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n "
" fMax = 1.0 / fMax; \n "
" \n "
" vec3 color = fMax * rgb; \n "
" \n "
" gl_FragColor = vec4( fS + fH * color, 1 ); \n "
# else
2017-10-31 20:22:14 +01:00
" gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n "
2017-10-11 20:47:19 +01:00
# endif
" } \n " ;
2017-12-27 02:32:17 +00:00
void MWShadow : : setupShadowSettings ( osg : : ref_ptr < osgShadow : : ShadowSettings > settings , int castsShadowMask )
{
if ( ! Settings : : Manager : : getBool ( " enable shadows " , " Shadows " ) )
return ;
settings - > setLightNum ( 0 ) ;
settings - > setCastsShadowTraversalMask ( castsShadowMask ) ;
settings - > setReceivesShadowTraversalMask ( ~ 0u ) ;
int numberOfShadowMapsPerLight = Settings : : Manager : : getInt ( " number of shadow maps " , " Shadows " ) ;
settings - > setNumShadowMapsPerLight ( numberOfShadowMapsPerLight ) ;
settings - > setBaseShadowTextureUnit ( 8 - numberOfShadowMapsPerLight ) ;
2018-01-25 16:08:34 +00:00
settings - > setMinimumShadowMapNearFarRatio ( Settings : : Manager : : getFloat ( " minimum lispsm near far ratio " , " Shadows " ) ) ;
2017-12-27 02:32:17 +00:00
if ( Settings : : Manager : : getBool ( " compute tight scene bounds " , " Shadows " ) )
settings - > setComputeNearFarModeOverride ( osg : : CullSettings : : COMPUTE_NEAR_FAR_USING_PRIMITIVES ) ;
int mapres = Settings : : Manager : : getInt ( " shadow map resolution " , " Shadows " ) ;
settings - > setTextureSize ( osg : : Vec2s ( mapres , mapres ) ) ;
}
2017-10-11 20:47:19 +01:00
2017-12-27 02:32:17 +00:00
void MWShadow : : disableShadowsForStateSet ( osg : : ref_ptr < osg : : StateSet > stateset )
2017-10-11 20:47:19 +01:00
{
2017-12-27 02:32:17 +00:00
int numberOfShadowMapsPerLight = Settings : : Manager : : getInt ( " number of shadow maps " , " Shadows " ) ;
int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight ;
osg : : ref_ptr < osg : : Image > fakeShadowMapImage = new osg : : Image ( ) ;
fakeShadowMapImage - > allocateImage ( 1 , 1 , 1 , GL_DEPTH_COMPONENT , GL_FLOAT ) ;
* ( float * ) fakeShadowMapImage - > data ( ) = std : : numeric_limits < float > : : infinity ( ) ;
osg : : ref_ptr < osg : : Texture > fakeShadowMapTexture = new osg : : Texture2D ( fakeShadowMapImage ) ;
fakeShadowMapTexture - > setShadowComparison ( true ) ;
fakeShadowMapTexture - > setShadowCompareFunc ( osg : : Texture : : ShadowCompareFunc : : ALWAYS ) ;
for ( int i = baseShadowTextureUnit ; i < baseShadowTextureUnit + numberOfShadowMapsPerLight ; + + i )
stateset - > setTextureAttributeAndModes ( i , fakeShadowMapTexture , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE | osg : : StateAttribute : : PROTECTED ) ;
}
2017-10-11 20:47:19 +01:00
2017-12-27 02:32:17 +00:00
MWShadow : : MWShadow ( ) : enableShadows ( Settings : : Manager : : getBool ( " enable shadows " , " Shadows " ) ) ,
numberOfShadowMapsPerLight ( Settings : : Manager : : getInt ( " number of shadow maps " , " Shadows " ) ) ,
baseShadowTextureUnit ( 8 - numberOfShadowMapsPerLight ) ,
debugHud ( Settings : : Manager : : getBool ( " enable debug hud " , " Shadows " ) ) ,
debugProgram ( new osg : : Program ) , debugTextureUnit ( 0 )
{
if ( debugHud )
2017-11-07 00:32:04 +00:00
{
2017-12-27 02:32:17 +00:00
osg : : ref_ptr < osg : : Shader > vertexShader = new osg : : Shader ( osg : : Shader : : VERTEX , debugVertexShaderSource ) ;
debugProgram - > addShader ( vertexShader ) ;
osg : : ref_ptr < osg : : Shader > fragmentShader = new osg : : Shader ( osg : : Shader : : FRAGMENT , debugFragmentShaderSource ) ;
debugProgram - > addShader ( fragmentShader ) ;
for ( int i = 0 ; i < numberOfShadowMapsPerLight ; + + i )
{
std : : cout < < i < < std : : endl ;
debugCameras . push_back ( new osg : : Camera ) ;
debugCameras [ i ] - > setViewport ( 200 * i , 0 , 200 , 200 ) ;
debugCameras [ i ] - > setRenderOrder ( osg : : Camera : : POST_RENDER ) ;
debugCameras [ i ] - > setClearColor ( osg : : Vec4 ( 1.0 , 1.0 , 0.0 , 1.0 ) ) ;
debugGeometry . push_back ( osg : : createTexturedQuadGeometry ( osg : : Vec3 ( - 1 , - 1 , 0 ) , osg : : Vec3 ( 2 , 0 , 0 ) , osg : : Vec3 ( 0 , 2 , 0 ) ) ) ;
debugGeometry [ i ] - > setCullingActive ( false ) ;
debugCameras [ i ] - > addChild ( debugGeometry [ i ] ) ;
osg : : ref_ptr < osg : : StateSet > stateSet = debugGeometry [ i ] - > getOrCreateStateSet ( ) ;
stateSet - > setAttributeAndModes ( debugProgram , osg : : StateAttribute : : ON ) ;
osg : : ref_ptr < osg : : Uniform > textureUniform = new osg : : Uniform ( " texture " , debugTextureUnit ) ;
//textureUniform->setType(osg::Uniform::SAMPLER_2D);
stateSet - > addUniform ( textureUniform . get ( ) ) ;
}
2017-11-07 00:32:04 +00:00
}
2017-10-11 20:47:19 +01:00
}
class VDSMCameraCullCallback : public osg : : NodeCallback
{
public :
VDSMCameraCullCallback ( ViewDependentShadowMap * vdsm , osg : : Polytope & polytope ) ;
virtual void operator ( ) ( osg : : Node * , osg : : NodeVisitor * nv ) ;
osg : : RefMatrix * getProjectionMatrix ( ) { return _projectionMatrix . get ( ) ; }
osgUtil : : RenderStage * getRenderStage ( ) { return _renderStage . get ( ) ; }
protected :
ViewDependentShadowMap * _vdsm ;
osg : : ref_ptr < osg : : RefMatrix > _projectionMatrix ;
osg : : ref_ptr < osgUtil : : RenderStage > _renderStage ;
osg : : Polytope _polytope ;
} ;
VDSMCameraCullCallback : : VDSMCameraCullCallback ( ViewDependentShadowMap * vdsm , osg : : Polytope & polytope ) :
_vdsm ( vdsm ) ,
_polytope ( polytope )
{
}
void VDSMCameraCullCallback : : operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv )
{
osgUtil : : CullVisitor * cv = dynamic_cast < osgUtil : : CullVisitor * > ( nv ) ;
osg : : Camera * camera = dynamic_cast < osg : : Camera * > ( node ) ;
OSG_INFO < < " VDSMCameraCullCallback::operator()(osg::Node* " < < camera < < " , osg::NodeVisitor* " < < cv < < " ) " < < std : : endl ;
# if 1
if ( ! _polytope . empty ( ) )
{
OSG_INFO < < " Pushing custom Polytope " < < std : : endl ;
osg : : CullingSet & cs = cv - > getProjectionCullingStack ( ) . back ( ) ;
cs . setFrustum ( _polytope ) ;
cv - > pushCullingSet ( ) ;
}
# endif
if ( _vdsm - > getShadowedScene ( ) )
{
_vdsm - > getShadowedScene ( ) - > osg : : Group : : traverse ( * nv ) ;
}
# if 1
if ( ! _polytope . empty ( ) )
{
OSG_INFO < < " Popping custom Polytope " < < std : : endl ;
cv - > popCullingSet ( ) ;
}
# endif
_renderStage = cv - > getCurrentRenderBin ( ) - > getStage ( ) ;
OSG_INFO < < " VDSM second : _renderStage = " < < _renderStage < < std : : endl ;
if ( cv - > getComputeNearFarMode ( ) ! = osg : : CullSettings : : DO_NOT_COMPUTE_NEAR_FAR )
{
// make sure that the near plane is computed correctly.
cv - > computeNearPlane ( ) ;
osg : : Matrixd projection = * ( cv - > getProjectionMatrix ( ) ) ;
OSG_INFO < < " RTT Projection matrix " < < projection < < std : : endl ;
osg : : Matrix : : value_type left , right , bottom , top , zNear , zFar ;
osg : : Matrix : : value_type epsilon = 1e-6 ;
if ( fabs ( projection ( 0 , 3 ) ) < epsilon & & fabs ( projection ( 1 , 3 ) ) < epsilon & & fabs ( projection ( 2 , 3 ) ) < epsilon )
{
projection . getOrtho ( left , right ,
bottom , top ,
zNear , zFar ) ;
OSG_INFO < < " Ortho zNear= " < < zNear < < " , zFar= " < < zFar < < std : : endl ;
}
else
{
projection . getFrustum ( left , right ,
bottom , top ,
zNear , zFar ) ;
OSG_INFO < < " Frustum zNear= " < < zNear < < " , zFar= " < < zFar < < std : : endl ;
}
OSG_INFO < < " Calculated zNear = " < < cv - > getCalculatedNearPlane ( ) < < " , zFar = " < < cv - > getCalculatedFarPlane ( ) < < std : : endl ;
zNear = osg : : maximum ( zNear , cv - > getCalculatedNearPlane ( ) ) ;
zFar = osg : : minimum ( zFar , cv - > getCalculatedFarPlane ( ) ) ;
cv - > setCalculatedNearPlane ( zNear ) ;
cv - > setCalculatedFarPlane ( zFar ) ;
cv - > clampProjectionMatrix ( projection , zNear , zFar ) ;
//OSG_INFO<<"RTT zNear = "<<zNear<<", zFar = "<<zFar<<std::endl;
OSG_INFO < < " RTT Projection matrix after clamping " < < projection < < std : : endl ;
camera - > setProjectionMatrix ( projection ) ;
_projectionMatrix = cv - > getProjectionMatrix ( ) ;
}
}
2018-02-04 23:27:45 +00:00
MWShadow : : ComputeLightSpaceBounds : : ComputeLightSpaceBounds ( osg : : Viewport * viewport , const osg : : Matrixd & projectionMatrix , osg : : Matrixd & viewMatrix ) :
osg : : NodeVisitor ( osg : : NodeVisitor : : TRAVERSE_ACTIVE_CHILDREN )
2017-10-03 03:40:23 +01:00
{
2018-02-04 23:27:45 +00:00
setCullingMode ( osg : : CullSettings : : VIEW_FRUSTUM_CULLING ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
pushViewport ( viewport ) ;
pushProjectionMatrix ( new osg : : RefMatrix ( projectionMatrix ) ) ;
pushModelViewMatrix ( new osg : : RefMatrix ( viewMatrix ) , osg : : Transform : : ABSOLUTE_RF ) ;
}
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Node & node )
{
if ( isCulled ( node ) ) return ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
// push the culling mode.
pushCurrentMask ( ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
traverse ( node ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
// pop the culling mode.
popCurrentMask ( ) ;
}
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Geode & node )
{
if ( isCulled ( node ) ) return ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
// push the culling mode.
pushCurrentMask ( ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
for ( unsigned int i = 0 ; i < node . getNumDrawables ( ) ; + + i )
{
if ( node . getDrawable ( i ) )
2017-10-11 20:47:19 +01:00
{
2018-02-04 23:27:45 +00:00
updateBound ( node . getDrawable ( i ) - > getBoundingBox ( ) ) ;
2017-10-11 20:47:19 +01:00
}
}
2018-02-04 23:27:45 +00:00
// pop the culling mode.
popCurrentMask ( ) ;
}
2017-10-30 19:54:54 +00:00
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Drawable & drawable )
{
if ( isCulled ( drawable ) ) return ;
2017-10-30 19:54:54 +00:00
2018-02-04 23:27:45 +00:00
// push the culling mode.
pushCurrentMask ( ) ;
2017-10-30 19:54:54 +00:00
2018-02-04 23:27:45 +00:00
updateBound ( drawable . getBoundingBox ( ) ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
// pop the culling mode.
popCurrentMask ( ) ;
}
2017-10-11 20:47:19 +01:00
2018-02-05 23:03:18 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( Terrain : : QuadTreeWorld & quadTreeWorld )
{
// For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented.
update ( osg : : Vec3 ( - 1.0 , - 1.0 , 0.0 ) ) ;
update ( osg : : Vec3 ( 1.0 , 1.0 , 0.0 ) ) ;
}
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Billboard & )
{
OSG_INFO < < " Warning Billboards not yet supported " < < std : : endl ;
return ;
}
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Projection & )
{
// projection nodes won't affect a shadow map so their subgraphs should be ignored
return ;
}
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Transform & transform )
{
if ( isCulled ( transform ) ) return ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
// push the culling mode.
pushCurrentMask ( ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
// absolute transforms won't affect a shadow map so their subgraphs should be ignored.
if ( transform . getReferenceFrame ( ) = = osg : : Transform : : RELATIVE_RF )
{
osg : : ref_ptr < osg : : RefMatrix > matrix = new osg : : RefMatrix ( * getModelViewMatrix ( ) ) ;
transform . computeLocalToWorldMatrix ( * matrix , this ) ;
pushModelViewMatrix ( matrix . get ( ) , transform . getReferenceFrame ( ) ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
traverse ( transform ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
popModelViewMatrix ( ) ;
2017-10-11 20:47:19 +01:00
}
2018-02-04 23:27:45 +00:00
// pop the culling mode.
popCurrentMask ( ) ;
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
}
2017-10-11 20:47:19 +01:00
2018-02-04 23:27:45 +00:00
void MWShadow : : ComputeLightSpaceBounds : : apply ( osg : : Camera & )
{
// camera nodes won't affect a shadow map so their subgraphs should be ignored
return ;
}
void MWShadow : : ComputeLightSpaceBounds : : updateBound ( const osg : : BoundingBox & bb )
{
if ( ! bb . valid ( ) ) return ;
const osg : : Matrix & matrix = * getModelViewMatrix ( ) * * getProjectionMatrix ( ) ;
update ( bb . corner ( 0 ) * matrix ) ;
update ( bb . corner ( 1 ) * matrix ) ;
update ( bb . corner ( 2 ) * matrix ) ;
update ( bb . corner ( 3 ) * matrix ) ;
update ( bb . corner ( 4 ) * matrix ) ;
update ( bb . corner ( 5 ) * matrix ) ;
update ( bb . corner ( 6 ) * matrix ) ;
update ( bb . corner ( 7 ) * matrix ) ;
}
void MWShadow : : ComputeLightSpaceBounds : : update ( const osg : : Vec3 & v )
{
if ( v . z ( ) < - 1.0f )
2017-10-11 20:47:19 +01:00
{
2018-02-04 23:27:45 +00:00
//OSG_NOTICE<<"discarding("<<v<<")"<<std::endl;
return ;
2017-10-11 20:47:19 +01:00
}
2018-02-04 23:27:45 +00:00
float x = v . x ( ) ;
if ( x < - 1.0f ) x = - 1.0f ;
if ( x > 1.0f ) x = 1.0f ;
float y = v . y ( ) ;
if ( y < - 1.0f ) y = - 1.0f ;
if ( y > 1.0f ) y = 1.0f ;
_bb . expandBy ( osg : : Vec3 ( x , y , v . z ( ) ) ) ;
}
2017-10-11 20:47:19 +01:00
void MWShadow : : cull ( osgUtil : : CullVisitor & cv )
{
2017-12-26 23:51:50 +00:00
if ( ! enableShadows )
{
_shadowedScene - > osg : : Group : : traverse ( cv ) ;
return ;
}
2017-10-11 20:47:19 +01:00
OSG_INFO < < std : : endl < < std : : endl < < " ViewDependentShadowMap::cull(osg::CullVisitor& " < < & cv < < " ) " < < std : : endl ;
if ( ! _shadowCastingStateSet )
{
OSG_INFO < < " Warning, init() has not yet been called so ShadowCastingStateSet has not been setup yet, unable to create shadows. " < < std : : endl ;
_shadowedScene - > osg : : Group : : traverse ( cv ) ;
return ;
}
ViewDependentData * vdd = getViewDependentData ( & cv ) ;
if ( ! vdd )
{
OSG_INFO < < " Warning, now ViewDependentData created, unable to create shadows. " < < std : : endl ;
_shadowedScene - > osg : : Group : : traverse ( cv ) ;
return ;
}
ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
OSG_INFO < < " cv->getProjectionMatrix()= " < < * cv . getProjectionMatrix ( ) < < std : : endl ;
osg : : CullSettings : : ComputeNearFarMode cachedNearFarMode = cv . getComputeNearFarMode ( ) ;
osg : : RefMatrix & viewProjectionMatrix = * cv . getProjectionMatrix ( ) ;
// check whether this main views projection is perspective or orthographic
bool orthographicViewFrustum = viewProjectionMatrix ( 0 , 3 ) = = 0.0 & &
viewProjectionMatrix ( 1 , 3 ) = = 0.0 & &
viewProjectionMatrix ( 2 , 3 ) = = 0.0 ;
double minZNear = 0.0 ;
double maxZFar = DBL_MAX ;
if ( cachedNearFarMode = = osg : : CullSettings : : DO_NOT_COMPUTE_NEAR_FAR )
{
double left , right , top , bottom ;
if ( orthographicViewFrustum )
{
viewProjectionMatrix . getOrtho ( left , right , bottom , top , minZNear , maxZFar ) ;
}
else
{
viewProjectionMatrix . getFrustum ( left , right , bottom , top , minZNear , maxZFar ) ;
}
OSG_INFO < < " minZNear= " < < minZNear < < " , maxZFar= " < < maxZFar < < std : : endl ;
}
// set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible
if ( settings - > getComputeNearFarModeOverride ( ) ! = osg : : CullSettings : : DO_NOT_COMPUTE_NEAR_FAR )
{
cv . setComputeNearFarMode ( settings - > getComputeNearFarModeOverride ( ) ) ;
}
// 1. Traverse main scene graph
cv . pushStateSet ( _shadowRecievingPlaceholderStateSet . get ( ) ) ;
osg : : ref_ptr < osgUtil : : StateGraph > decoratorStateGraph = cv . getCurrentStateGraph ( ) ;
cullShadowReceivingScene ( & cv ) ;
cv . popStateSet ( ) ;
if ( cv . getComputeNearFarMode ( ) ! = osg : : CullSettings : : DO_NOT_COMPUTE_NEAR_FAR )
{
OSG_INFO < < " Just done main subgraph traversak " < < std : : endl ;
// make sure that the near plane is computed correctly so that any projection matrix computations
// are all done correctly.
cv . computeNearPlane ( ) ;
}
// clamp the minZNear and maxZFar to those provided by ShadowSettings
maxZFar = osg : : minimum ( settings - > getMaximumShadowMapDistance ( ) , maxZFar ) ;
if ( minZNear > maxZFar ) minZNear = maxZFar * settings - > getMinimumShadowMapNearFarRatio ( ) ;
//OSG_NOTICE<<"maxZFar "<<maxZFar<<std::endl;
Frustum frustum ( & cv , minZNear , maxZFar ) ;
2018-02-23 23:31:53 +00:00
double reducedNear , reducedFar ;
if ( cv . getComputeNearFarMode ( ) ! = osg : : CullSettings : : DO_NOT_COMPUTE_NEAR_FAR )
{
reducedNear = osg : : maximum < double > ( cv . getCalculatedNearPlane ( ) , minZNear ) ;
reducedFar = osg : : minimum < double > ( cv . getCalculatedFarPlane ( ) , maxZFar ) ;
}
else
{
reducedNear = minZNear ;
reducedFar = maxZFar ;
}
2017-10-11 20:47:19 +01:00
// return compute near far mode back to it's original settings
cv . setComputeNearFarMode ( cachedNearFarMode ) ;
OSG_INFO < < " frustum.eye= " < < frustum . eye < < " , frustum.centerNearPlane, " < < frustum . centerNearPlane < < " distance = " < < ( frustum . eye - frustum . centerNearPlane ) . length ( ) < < std : : endl ;
// 2. select active light sources
// create a list of light sources + their matrices to place them
selectActiveLights ( & cv , vdd ) ;
unsigned int pos_x = 0 ;
unsigned int textureUnit = settings - > getBaseShadowTextureUnit ( ) ;
unsigned int numValidShadows = 0 ;
ShadowDataList & sdl = vdd - > getShadowDataList ( ) ;
ShadowDataList previous_sdl ;
previous_sdl . swap ( sdl ) ;
unsigned int numShadowMapsPerLight = settings - > getNumShadowMapsPerLight ( ) ;
2017-11-07 20:34:48 +00:00
/*if (numShadowMapsPerLight>2)
2017-10-11 20:47:19 +01:00
{
OSG_NOTICE < < " numShadowMapsPerLight of " < < numShadowMapsPerLight < < " is greater than maximum supported, falling back to 2. " < < std : : endl ;
numShadowMapsPerLight = 2 ;
2017-11-07 20:34:48 +00:00
} */
2017-10-11 20:47:19 +01:00
LightDataList & pll = vdd - > getLightDataList ( ) ;
for ( LightDataList : : iterator itr = pll . begin ( ) ;
itr ! = pll . end ( ) ;
+ + itr )
{
// 3. create per light/per shadow map division of lightspace/frustum
// create a list of light/shadow map data structures
LightData & pl = * * itr ;
// 3.1 compute light space polytope
//
osg : : Polytope polytope = computeLightViewFrustumPolytope ( frustum , pl ) ;
// if polytope is empty then no rendering.
if ( polytope . empty ( ) )
{
OSG_NOTICE < < " Polytope empty no shadow to render " < < std : : endl ;
continue ;
}
// 3.2 compute RTT camera view+projection matrix settings
//
osg : : Matrixd projectionMatrix ;
osg : : Matrixd viewMatrix ;
if ( ! computeShadowCameraSettings ( frustum , pl , projectionMatrix , viewMatrix ) )
{
OSG_NOTICE < < " No valid Camera settings, no shadow to render " < < std : : endl ;
continue ;
}
// if we are using multiple shadow maps and CastShadowTraversalMask is being used
// traverse the scene to compute the extents of the objects
if ( /*numShadowMapsPerLight>1 &&*/ _shadowedScene - > getCastsShadowTraversalMask ( ) ! = 0xffffffff )
{
// osg::ElapsedTime timer;
osg : : ref_ptr < osg : : Viewport > viewport = new osg : : Viewport ( 0 , 0 , 2048 , 2048 ) ;
ComputeLightSpaceBounds clsb ( viewport . get ( ) , projectionMatrix , viewMatrix ) ;
clsb . setTraversalMask ( _shadowedScene - > getCastsShadowTraversalMask ( ) ) ;
osg : : Matrixd invertModelView ;
invertModelView . invert ( viewMatrix ) ;
osg : : Polytope local_polytope ( polytope ) ;
local_polytope . transformProvidingInverse ( invertModelView ) ;
osg : : CullingSet & cs = clsb . getProjectionCullingStack ( ) . back ( ) ;
cs . setFrustum ( local_polytope ) ;
clsb . pushCullingSet ( ) ;
_shadowedScene - > accept ( clsb ) ;
// OSG_NOTICE<<"Extents of LightSpace "<<clsb._bb.xMin()<<", "<<clsb._bb.xMax()<<", "<<clsb._bb.yMin()<<", "<<clsb._bb.yMax()<<", "<<clsb._bb.zMin()<<", "<<clsb._bb.zMax()<<std::endl;
// OSG_NOTICE<<" time "<<timer.elapsedTime_m()<<"ms, mask = "<<std::hex<<_shadowedScene->getCastsShadowTraversalMask()<<std::endl;
if ( clsb . _bb . xMin ( ) > - 1.0f | | clsb . _bb . xMax ( ) < 1.0f | | clsb . _bb . yMin ( ) > - 1.0f | | clsb . _bb . yMax ( ) < 1.0f )
{
// OSG_NOTICE<<"Need to clamp projection matrix"<<std::endl;
# if 1
double xMid = ( clsb . _bb . xMin ( ) + clsb . _bb . xMax ( ) ) * 0.5f ;
double xRange = clsb . _bb . xMax ( ) - clsb . _bb . xMin ( ) ;
# else
double xMid = 0.0 ;
double xRange = 2.0 ;
# endif
double yMid = ( clsb . _bb . yMin ( ) + clsb . _bb . yMax ( ) ) * 0.5f ;
double yRange = ( clsb . _bb . yMax ( ) - clsb . _bb . yMin ( ) ) ;
2018-02-23 23:31:53 +00:00
osg : : Matrixd cornerConverter = osg : : Matrixd : : inverse ( projectionMatrix ) * osg : : Matrixd : : inverse ( viewMatrix ) * * cv . getModelViewMatrix ( ) ;
double minZ = DBL_MAX ;
double maxZ = - DBL_MAX ;
for ( unsigned int i = 0 ; i < 8 ; i + + )
{
osg : : Vec3 corner = clsb . _bb . corner ( i ) ;
corner = corner * cornerConverter ;
maxZ = osg : : maximum < double > ( maxZ , - corner . z ( ) ) ;
minZ = osg : : minimum < double > ( minZ , - corner . z ( ) ) ;
}
reducedNear = osg : : maximum < double > ( reducedNear , minZ ) ;
reducedFar = osg : : minimum < double > ( reducedFar , maxZ ) ;
2017-10-11 20:47:19 +01:00
// OSG_NOTICE<<" xMid="<<xMid<<", yMid="<<yMid<<", xRange="<<xRange<<", yRange="<<yRange<<std::endl;
projectionMatrix =
projectionMatrix *
osg : : Matrixd : : translate ( osg : : Vec3d ( - xMid , - yMid , 0.0 ) ) *
osg : : Matrixd : : scale ( osg : : Vec3d ( 2.0 / xRange , 2.0 / yRange , 1.0 ) ) ;
}
}
double splitPoint = 0.0 ;
if ( numShadowMapsPerLight > 1 )
{
osg : : Vec3d eye_v = frustum . eye * viewMatrix ;
osg : : Vec3d center_v = frustum . center * viewMatrix ;
osg : : Vec3d viewdir_v = center_v - eye_v ; viewdir_v . normalize ( ) ;
osg : : Vec3d lightdir ( 0.0 , 0.0 , - 1.0 ) ;
double dotProduct_v = lightdir * viewdir_v ;
double angle = acosf ( dotProduct_v ) ;
osg : : Vec3d eye_ls = eye_v * projectionMatrix ;
OSG_INFO < < " Angle between view vector and eye " < < osg : : RadiansToDegrees ( angle ) < < std : : endl ;
OSG_INFO < < " eye_ls= " < < eye_ls < < std : : endl ;
if ( eye_ls . y ( ) > = - 1.0 & & eye_ls . y ( ) < = 1.0 )
{
OSG_INFO < < " Eye point inside light space clip region " < < std : : endl ;
splitPoint = 0.0 ;
}
else
{
double n = - 1.0 - eye_ls . y ( ) ;
double f = 1.0 - eye_ls . y ( ) ;
double sqrt_nf = sqrt ( n * f ) ;
double mid = eye_ls . y ( ) + sqrt_nf ;
double ratioOfMidToUseForSplit = 0.8 ;
splitPoint = mid * ratioOfMidToUseForSplit ;
OSG_INFO < < " n= " < < n < < " , f= " < < f < < " , sqrt_nf= " < < sqrt_nf < < " mid= " < < mid < < std : : endl ;
}
}
// 4. For each light/shadow map
for ( unsigned int sm_i = 0 ; sm_i < numShadowMapsPerLight ; + + sm_i )
{
osg : : ref_ptr < ShadowData > sd ;
if ( previous_sdl . empty ( ) )
{
OSG_INFO < < " Create new ShadowData " < < std : : endl ;
sd = new ShadowData ( vdd ) ;
}
else
{
OSG_INFO < < " Taking ShadowData from from of previous_sdl " < < std : : endl ;
sd = previous_sdl . front ( ) ;
previous_sdl . erase ( previous_sdl . begin ( ) ) ;
}
2017-11-07 00:32:04 +00:00
if ( debugHud )
2017-10-11 20:47:19 +01:00
{
osg : : ref_ptr < osg : : Texture2D > texture = sd - > _texture ;
2017-11-07 00:32:04 +00:00
osg : : ref_ptr < osg : : StateSet > stateSet = debugGeometry [ sm_i ] - > getOrCreateStateSet ( ) ;
2017-11-03 14:33:06 +00:00
stateSet - > setTextureAttributeAndModes ( debugTextureUnit , texture , osg : : StateAttribute : : ON ) ;
2017-10-11 20:47:19 +01:00
unsigned int traversalMask = cv . getTraversalMask ( ) ;
2017-11-07 00:32:04 +00:00
cv . setTraversalMask ( debugGeometry [ sm_i ] - > getNodeMask ( ) ) ;
2017-10-11 20:47:19 +01:00
cv . pushStateSet ( stateSet ) ;
2017-11-07 00:32:04 +00:00
debugCameras [ sm_i ] - > accept ( cv ) ;
2017-10-11 20:47:19 +01:00
cv . popStateSet ( ) ;
cv . setTraversalMask ( traversalMask ) ;
cv . getState ( ) - > setCheckForGLErrors ( osg : : State : : ONCE_PER_ATTRIBUTE ) ;
}
osg : : ref_ptr < osg : : Camera > camera = sd - > _camera ;
camera - > setProjectionMatrix ( projectionMatrix ) ;
camera - > setViewMatrix ( viewMatrix ) ;
if ( settings - > getDebugDraw ( ) )
{
camera - > getViewport ( ) - > x ( ) = pos_x ;
pos_x + = static_cast < unsigned int > ( camera - > getViewport ( ) - > width ( ) ) + 40 ;
}
// transform polytope in model coords into light spaces eye coords.
osg : : Matrixd invertModelView ;
invertModelView . invert ( camera - > getViewMatrix ( ) ) ;
osg : : Polytope local_polytope ( polytope ) ;
local_polytope . transformProvidingInverse ( invertModelView ) ;
if ( numShadowMapsPerLight > 1 )
{
// compute the start and end range in non-dimensional coords
2017-12-12 22:37:40 +00:00
#if 0
2017-10-11 20:47:19 +01:00
double r_start = ( sm_i = = 0 ) ? - 1.0 : ( double ( sm_i ) / double ( numShadowMapsPerLight ) * 2.0 - 1.0 ) ;
double r_end = ( sm_i + 1 = = numShadowMapsPerLight ) ? 1.0 : ( double ( sm_i + 1 ) / double ( numShadowMapsPerLight ) * 2.0 - 1.0 ) ;
2017-12-12 22:37:40 +00:00
# elif 0
2017-10-11 20:47:19 +01:00
// hardwired for 2 splits
double r_start = ( sm_i = = 0 ) ? - 1.0 : splitPoint ;
double r_end = ( sm_i + 1 = = numShadowMapsPerLight ) ? 1.0 : splitPoint ;
2017-12-17 00:52:10 +00:00
# elif 0
2017-12-12 22:37:40 +00:00
double r_start , r_end ;
// Split such that each shadow map covers a quarter of the area of the one after it
if ( sm_i = = 0 )
r_start = - 1.0 ;
else
{
r_start = ( 1 - pow ( 4.0 , sm_i ) ) / ( 1 - pow ( 4.0 , numShadowMapsPerLight ) ) ;
r_start * = 2.0 ;
2017-12-17 00:52:10 +00:00
//r_start += double(sm_i) / double(numShadowMapsPerLight);
2017-12-12 22:37:40 +00:00
r_start - = 1.0 ;
}
if ( sm_i + 1 = = numShadowMapsPerLight )
r_end = 1.0 ;
else
{
r_end = ( 1 - pow ( 4.0 , sm_i + 1 ) ) / ( 1 - pow ( 4.0 , numShadowMapsPerLight ) ) ;
r_end * = 2.0 ;
2017-12-17 00:52:10 +00:00
//r_end += double(sm_i + 1) / double(numShadowMapsPerLight);
2017-12-12 22:37:40 +00:00
r_end - = 1.0 ;
}
2017-12-17 00:52:10 +00:00
# else
double r_start , r_end ;
// split system based on the original Parallel Split Shadow Maps paper.
2018-02-23 23:31:53 +00:00
double n = reducedNear ;
double f = reducedFar ;
2017-12-17 00:52:10 +00:00
double i = double ( sm_i ) ;
double m = double ( numShadowMapsPerLight ) ;
2018-01-25 16:08:34 +00:00
double ratio = Settings : : Manager : : getFloat ( " split point uniform logarithmic ratio " , " Shadows " ) ;
double deltaBias = Settings : : Manager : : getFloat ( " split point bias " , " Shadows " ) ;
2017-12-17 00:52:10 +00:00
if ( sm_i = = 0 )
r_start = - 1.0 ;
else
{
// compute the split point in main camera view
double ciLog = n * pow ( f / n , i / m ) ;
double ciUniform = n + ( f - n ) * i / m ;
2018-01-25 16:08:34 +00:00
double ci = ratio * ciLog + ( 1.0 - ratio ) * ciUniform + deltaBias ;
2017-12-17 00:52:10 +00:00
// work out where this is in light space
osg : : Vec3d worldSpacePos = frustum . eye + frustum . frustumCenterLine * ci ;
osg : : Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix ;
r_start = lightSpacePos . y ( ) ;
}
if ( sm_i + 1 = = numShadowMapsPerLight )
r_end = 1.0 ;
else
{
// compute the split point in main camera view
double ciLog = n * pow ( f / n , ( i + 1 ) / m ) ;
double ciUniform = n + ( f - n ) * ( i + 1 ) / m ;
2018-01-25 16:08:34 +00:00
double ci = ratio * ciLog + ( 1.0 - ratio ) * ciUniform + deltaBias ;
2017-12-17 00:52:10 +00:00
// work out where this is in light space
osg : : Vec3d worldSpacePos = frustum . eye + frustum . frustumCenterLine * ci ;
osg : : Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix ;
r_end = lightSpacePos . y ( ) ;
}
2017-11-07 20:34:48 +00:00
# endif
2017-10-11 20:47:19 +01:00
// for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap
// to prevent a seam showing through between the shadowmaps
if ( sm_i + 1 < numShadowMapsPerLight ) r_end + = 0.01 ;
if ( sm_i > 0 )
{
// not the first shadowmap so insert a polytope to clip the scene from before r_start
// plane in clip space coords
osg : : Plane plane ( 0.0 , 1.0 , 0.0 , - r_start ) ;
// transform into eye coords
plane . transformProvidingInverse ( projectionMatrix ) ;
local_polytope . getPlaneList ( ) . push_back ( plane ) ;
//OSG_NOTICE<<"Adding r_start plane "<<plane<<std::endl;
}
if ( sm_i + 1 < numShadowMapsPerLight )
{
// not the last shadowmap so insert a polytope to clip the scene from beyond r_end
// plane in clip space coords
osg : : Plane plane ( 0.0 , - 1.0 , 0.0 , r_end ) ;
// transform into eye coords
plane . transformProvidingInverse ( projectionMatrix ) ;
local_polytope . getPlaneList ( ) . push_back ( plane ) ;
//OSG_NOTICE<<"Adding r_end plane "<<plane<<std::endl;
}
local_polytope . setupMask ( ) ;
// OSG_NOTICE<<"Need to adjust RTT camera projection and view matrix here, r_start="<<r_start<<", r_end="<<r_end<<std::endl;
// OSG_NOTICE<<" textureUnit = "<<textureUnit<<std::endl;
double mid_r = ( r_start + r_end ) * 0.5 ;
double range_r = ( r_end - r_start ) ;
// OSG_NOTICE<<" mid_r = "<<mid_r<<", range_r = "<<range_r<<std::endl;
camera - > setProjectionMatrix (
camera - > getProjectionMatrix ( ) *
osg : : Matrixd : : translate ( osg : : Vec3d ( 0.0 , - mid_r , 0.0 ) ) *
osg : : Matrixd : : scale ( osg : : Vec3d ( 1.0 , 2.0 / range_r , 1.0 ) ) ) ;
}
osg : : ref_ptr < VDSMCameraCullCallback > vdsmCallback = new VDSMCameraCullCallback ( this , local_polytope ) ;
camera - > setCullCallback ( vdsmCallback . get ( ) ) ;
// 4.3 traverse RTT camera
//
cv . pushStateSet ( _shadowCastingStateSet . get ( ) ) ;
cullShadowCastingScene ( & cv , camera . get ( ) ) ;
cv . popStateSet ( ) ;
if ( ! orthographicViewFrustum & & settings - > getShadowMapProjectionHint ( ) = = osgShadow : : ShadowSettings : : PERSPECTIVE_SHADOW_MAP )
{
adjustPerspectiveShadowMapCameraSettings ( vdsmCallback - > getRenderStage ( ) , frustum , pl , camera . get ( ) ) ;
if ( vdsmCallback - > getProjectionMatrix ( ) )
{
vdsmCallback - > getProjectionMatrix ( ) - > set ( camera - > getProjectionMatrix ( ) ) ;
}
}
// 4.4 compute main scene graph TexGen + uniform settings + setup state
//
assignTexGenSettings ( & cv , camera . get ( ) , textureUnit , sd - > _texgen . get ( ) ) ;
// mark the light as one that has active shadows and requires shaders
pl . textureUnits . push_back ( textureUnit ) ;
// pass on shadow data to ShadowDataList
sd - > _textureUnit = textureUnit ;
if ( textureUnit > = 8 )
{
OSG_NOTICE < < " Shadow texture unit is invalid for texgen, will not be used. " < < std : : endl ;
}
else
{
sdl . push_back ( sd ) ;
}
// increment counters.
+ + textureUnit ;
+ + numValidShadows ;
}
}
if ( numValidShadows > 0 )
{
decoratorStateGraph - > setStateSet ( selectStateSetForRenderingShadow ( * vdd ) ) ;
}
// OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl;
2017-10-03 03:40:23 +01:00
}
2017-11-22 20:07:07 +00:00
Shader : : ShaderManager : : DefineMap MWShadow : : getShadowDefines ( )
{
if ( ! enableShadows )
return getShadowsDisabledDefines ( ) ;
Shader : : ShaderManager : : DefineMap definesWithShadows ;
definesWithShadows . insert ( std : : make_pair ( std : : string ( " shadows_enabled " ) , std : : string ( " 1 " ) ) ) ;
for ( int i = 0 ; i < numberOfShadowMapsPerLight ; + + i )
definesWithShadows [ " shadow_texture_unit_list " ] + = std : : to_string ( i ) + " , " ;
// remove extra comma
definesWithShadows [ " shadow_texture_unit_list " ] = definesWithShadows [ " shadow_texture_unit_list " ] . substr ( 0 , definesWithShadows [ " shadow_texture_unit_list " ] . length ( ) - 1 ) ;
return definesWithShadows ;
}
Shader : : ShaderManager : : DefineMap MWShadow : : getShadowsDisabledDefines ( )
{
Shader : : ShaderManager : : DefineMap definesWithShadows ;
definesWithShadows . insert ( std : : make_pair ( std : : string ( " shadows_enabled " ) , std : : string ( " 0 " ) ) ) ;
definesWithShadows [ " shadow_texture_unit_list " ] = " " ;
return definesWithShadows ;
}
2017-10-03 03:40:23 +01:00
}