/* This file is based on OpenSceneGraph's src/osgShadow/ViewDependentShadowMap.cpp.
* Where applicable , any changes made are covered by OpenMW ' s GPL 3 license , not the OSGPL .
* The original copyright notice is listed below .
*/
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield
*
* This library is open source and may be redistributed and / or modified under
* the terms of the OpenSceneGraph Public License ( OSGPL ) version 0.0 or
* ( at your option ) any later version . The full license is in LICENSE file
* included with this distribution , and on the openscenegraph . org website .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* OpenSceneGraph Public License for more details .
*/
# include "mwshadowtechnique.hpp"
# include <osgShadow/ShadowedScene>
# include <osg/CullFace>
# include <osg/Geometry>
# include <osg/io_utils>
# include <osg/Depth>
# include <osg/ClipControl>
# include <sstream>
# include "shadowsbin.hpp"
namespace {
using namespace osgShadow ;
using namespace SceneUtil ;
# define dbl_max std::numeric_limits<double>::max()
//////////////////////////////////////////////////////////////////
// fragment shader
//
#if 0
static const char fragmentShaderSource_withBaseTexture [ ] =
" uniform sampler2D baseTexture; \n "
" uniform sampler2DShadow shadowTexture; \n "
" \n "
" void main(void) \n "
" { \n "
" vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n "
" vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy ); \n "
" color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture, gl_TexCoord[1] ).r ); \n "
" gl_FragColor = color; \n "
" } \n " ;
# else
static const char fragmentShaderSource_withBaseTexture [ ] =
" uniform sampler2D baseTexture; \n "
" uniform int baseTextureUnit; \n "
" uniform sampler2DShadow shadowTexture0; \n "
" uniform int shadowTextureUnit0; \n "
" \n "
" void main(void) \n "
" { \n "
" vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n "
" vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n "
" color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r ); \n "
" gl_FragColor = color; \n "
" } \n " ;
static const char fragmentShaderSource_withBaseTexture_twoShadowMaps [ ] =
" uniform sampler2D baseTexture; \n "
" uniform int baseTextureUnit; \n "
" uniform sampler2DShadow shadowTexture0; \n "
" uniform int shadowTextureUnit0; \n "
" uniform sampler2DShadow shadowTexture1; \n "
" uniform int shadowTextureUnit1; \n "
" \n "
" void main(void) \n "
" { \n "
" vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n "
" vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n "
" float shadow0 = shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r; \n "
" float shadow1 = shadow2DProj( shadowTexture1, gl_TexCoord[shadowTextureUnit1] ).r; \n "
" color *= mix( colorAmbientEmissive, gl_Color, shadow0*shadow1 ); \n "
" gl_FragColor = color; \n "
" } \n " ;
# endif
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 "
# if 1
" float f = texture2D(texture, gl_TexCoord[0].xy).r; \n "
" \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
" gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n "
# endif
" } \n " ;
std : : string debugFrustumVertexShaderSource = " varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z / gl_Position.w;} " ;
std : : string debugFrustumFragmentShaderSource =
" varying float depth; \n "
" \n "
" void main(void) \n "
" { \n "
# if 1
" float f = depth; \n "
" \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
" gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0); \n "
# endif
" } \n " ;
template < class T >
class RenderLeafTraverser : public T
{
public :
RenderLeafTraverser ( )
{
}
void traverse ( const osgUtil : : RenderStage * rs )
{
traverse ( static_cast < const osgUtil : : RenderBin * > ( rs ) ) ;
}
void traverse ( const osgUtil : : RenderBin * renderBin )
{
const osgUtil : : RenderBin : : RenderBinList & rbl = renderBin - > getRenderBinList ( ) ;
for ( osgUtil : : RenderBin : : RenderBinList : : const_iterator itr = rbl . begin ( ) ;
itr ! = rbl . end ( ) ;
+ + itr )
{
traverse ( itr - > second . get ( ) ) ;
}
const osgUtil : : RenderBin : : RenderLeafList & rll = renderBin - > getRenderLeafList ( ) ;
for ( osgUtil : : RenderBin : : RenderLeafList : : const_iterator itr = rll . begin ( ) ;
itr ! = rll . end ( ) ;
+ + itr )
{
handle ( * itr ) ;
}
const osgUtil : : RenderBin : : StateGraphList & rgl = renderBin - > getStateGraphList ( ) ;
for ( osgUtil : : RenderBin : : StateGraphList : : const_iterator itr = rgl . begin ( ) ;
itr ! = rgl . end ( ) ;
+ + itr )
{
traverse ( * itr ) ;
}
}
void traverse ( const osgUtil : : StateGraph * stateGraph )
{
const osgUtil : : StateGraph : : ChildList & cl = stateGraph - > _children ;
for ( osgUtil : : StateGraph : : ChildList : : const_iterator itr = cl . begin ( ) ;
itr ! = cl . end ( ) ;
+ + itr )
{
traverse ( itr - > second . get ( ) ) ;
}
const osgUtil : : StateGraph : : LeafList & ll = stateGraph - > _leaves ;
for ( osgUtil : : StateGraph : : LeafList : : const_iterator itr = ll . begin ( ) ;
itr ! = ll . end ( ) ;
+ + itr )
{
handle ( itr - > get ( ) ) ;
}
}
inline void handle ( const osgUtil : : RenderLeaf * renderLeaf )
{
this - > operator ( ) ( renderLeaf ) ;
}
} ;
///////////////////////////////////////////////////////////////////////////////////////////////
//
// VDSMCameraCullCallback
//
class VDSMCameraCullCallback : public osg : : NodeCallback
{
public :
VDSMCameraCullCallback ( MWShadowTechnique * vdsm , osg : : Polytope & polytope ) ;
void operator ( ) ( osg : : Node * , osg : : NodeVisitor * nv ) override ;
osg : : RefMatrix * getProjectionMatrix ( ) { return _projectionMatrix . get ( ) ; }
osgUtil : : RenderStage * getRenderStage ( ) { return _renderStage . get ( ) ; }
protected :
MWShadowTechnique * _vdsm ;
osg : : ref_ptr < osg : : RefMatrix > _projectionMatrix ;
osg : : ref_ptr < osgUtil : : RenderStage > _renderStage ;
osg : : Polytope _polytope ;
} ;
VDSMCameraCullCallback : : VDSMCameraCullCallback ( MWShadowTechnique * vdsm , osg : : Polytope & polytope ) :
_vdsm ( vdsm ) ,
_polytope ( polytope )
{
}
void VDSMCameraCullCallback : : operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv )
{
osgUtil : : CullVisitor * cv = static_cast < osgUtil : : CullVisitor * > ( nv ) ;
osg : : Camera * camera = node - > asCamera ( ) ;
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
// bin has to go inside camera cull or the rendertexture stage will override it
static osg : : ref_ptr < osg : : StateSet > ss ;
if ( ! ss )
{
ShadowsBinAdder adder ( " ShadowsBin " , _vdsm - > getCastingPrograms ( ) ) ;
ss = new osg : : StateSet ;
ss - > setRenderBinDetails ( osg : : StateSet : : OPAQUE_BIN , " ShadowsBin " , osg : : StateSet : : OVERRIDE_PROTECTED_RENDERBIN_DETAILS ) ;
}
cv - > pushStateSet ( ss ) ;
if ( _vdsm - > getShadowedScene ( ) )
{
_vdsm - > getShadowedScene ( ) - > osg : : Group : : traverse ( * nv ) ;
}
cv - > popStateSet ( ) ;
# 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 ( ) ;
}
} // namespace
MWShadowTechnique : : ComputeLightSpaceBounds : : ComputeLightSpaceBounds ( osg : : Viewport * viewport , const osg : : Matrixd & projectionMatrix , osg : : Matrixd & viewMatrix ) :
osg : : NodeVisitor ( osg : : NodeVisitor : : TRAVERSE_ACTIVE_CHILDREN )
{
setCullingMode ( osg : : CullSettings : : VIEW_FRUSTUM_CULLING ) ;
pushViewport ( viewport ) ;
pushProjectionMatrix ( new osg : : RefMatrix ( projectionMatrix ) ) ;
pushModelViewMatrix ( new osg : : RefMatrix ( viewMatrix ) , osg : : Transform : : ABSOLUTE_RF ) ;
setName ( " SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds,AcceptedByComponentsTerrainQuadTreeWorld " ) ;
}
void MWShadowTechnique : : ComputeLightSpaceBounds : : apply ( osg : : Node & node )
{
if ( isCulled ( node ) ) return ;
// push the culling mode.
pushCurrentMask ( ) ;
traverse ( node ) ;
// pop the culling mode.
popCurrentMask ( ) ;
}
void MWShadowTechnique : : ComputeLightSpaceBounds : : apply ( osg : : Drawable & drawable )
{
if ( isCulled ( drawable ) ) return ;
// push the culling mode.
pushCurrentMask ( ) ;
updateBound ( drawable . getBoundingBox ( ) ) ;
// pop the culling mode.
popCurrentMask ( ) ;
}
void MWShadowTechnique : : 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 ) ) ;
}
void MWShadowTechnique : : ComputeLightSpaceBounds : : apply ( osg : : Billboard & )
{
OSG_INFO < < " Warning Billboards not yet supported " < < std : : endl ;
return ;
}
void MWShadowTechnique : : ComputeLightSpaceBounds : : apply ( osg : : Projection & )
{
// projection nodes won't affect a shadow map so their subgraphs should be ignored
return ;
}
void MWShadowTechnique : : ComputeLightSpaceBounds : : apply ( osg : : Transform & transform )
{
if ( isCulled ( transform ) ) return ;
// push the culling mode.
pushCurrentMask ( ) ;
// 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 ( ) ) ;
traverse ( transform ) ;
popModelViewMatrix ( ) ;
}
// pop the culling mode.
popCurrentMask ( ) ;
}
void MWShadowTechnique : : ComputeLightSpaceBounds : : apply ( osg : : Camera & )
{
// camera nodes won't affect a shadow map so their subgraphs should be ignored
return ;
}
void MWShadowTechnique : : 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 MWShadowTechnique : : ComputeLightSpaceBounds : : update ( const osg : : Vec3 & v )
{
if ( v . z ( ) < - 1.0f )
{
//OSG_NOTICE<<"discarding("<<v<<")"<<std::endl;
return ;
}
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 ( ) ) ) ;
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// LightData
//
MWShadowTechnique : : LightData : : LightData ( MWShadowTechnique : : ViewDependentData * vdd ) :
_viewDependentData ( vdd ) ,
directionalLight ( false )
{
}
void MWShadowTechnique : : LightData : : setLightData ( osg : : RefMatrix * lm , const osg : : Light * l , const osg : : Matrixd & modelViewMatrix )
{
lightMatrix = lm ;
light = l ;
lightPos = light - > getPosition ( ) ;
directionalLight = ( light - > getPosition ( ) . w ( ) = = 0.0 ) ;
if ( directionalLight )
{
lightPos3 . set ( 0.0 , 0.0 , 0.0 ) ; // directional light has no destinct position
lightDir . set ( - lightPos . x ( ) , - lightPos . y ( ) , - lightPos . z ( ) ) ;
lightDir . normalize ( ) ;
OSG_INFO < < " Directional light, lightPos= " < < lightPos < < " , lightDir= " < < lightDir < < std : : endl ;
if ( lightMatrix . valid ( ) & & * lightMatrix ! = osg : : Matrixf ( modelViewMatrix ) )
{
OSG_INFO < < " Light matrix " < < * lightMatrix < < std : : endl ;
osg : : Matrix lightToLocalMatrix ( * lightMatrix * osg : : Matrix : : inverse ( modelViewMatrix ) ) ;
lightDir = osg : : Matrix : : transform3x3 ( lightDir , lightToLocalMatrix ) ;
lightDir . normalize ( ) ;
OSG_INFO < < " new LightDir = " < < lightDir < < std : : endl ;
}
}
else
{
OSG_INFO < < " Positional light, lightPos= " < < lightPos < < std : : endl ;
lightDir = light - > getDirection ( ) ;
lightDir . normalize ( ) ;
if ( lightMatrix . valid ( ) )
{
OSG_INFO < < " Light matrix " < < * lightMatrix < < std : : endl ;
osg : : Matrix lightToLocalMatrix ( * lightMatrix * osg : : Matrix : : inverse ( modelViewMatrix ) ) ;
lightPos = lightPos * lightToLocalMatrix ;
lightDir = osg : : Matrix : : transform3x3 ( lightDir , lightToLocalMatrix ) ;
lightDir . normalize ( ) ;
OSG_INFO < < " new LightPos = " < < lightPos < < std : : endl ;
OSG_INFO < < " new LightDir = " < < lightDir < < std : : endl ;
}
lightPos3 . set ( lightPos . x ( ) / lightPos . w ( ) , lightPos . y ( ) / lightPos . w ( ) , lightPos . z ( ) / lightPos . w ( ) ) ;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// ShadowData
//
MWShadowTechnique : : ShadowData : : ShadowData ( MWShadowTechnique : : ViewDependentData * vdd ) :
_viewDependentData ( vdd ) ,
_textureUnit ( 0 )
{
const ShadowSettings * settings = vdd - > getViewDependentShadowMap ( ) - > getShadowedScene ( ) - > getShadowSettings ( ) ;
bool debug = settings - > getDebugDraw ( ) ;
// set up texgen
_texgen = new osg : : TexGen ;
// set up the texture
_texture = new osg : : Texture2D ;
osg : : Vec2s textureSize = debug ? osg : : Vec2s ( 512 , 512 ) : settings - > getTextureSize ( ) ;
_texture - > setTextureSize ( textureSize . x ( ) , textureSize . y ( ) ) ;
if ( debug )
{
_texture - > setInternalFormat ( GL_RGB ) ;
}
else
{
_texture - > setInternalFormat ( GL_DEPTH_COMPONENT ) ;
_texture - > setShadowComparison ( true ) ;
_texture - > setShadowTextureMode ( osg : : Texture2D : : LUMINANCE ) ;
}
_texture - > setFilter ( osg : : Texture2D : : MIN_FILTER , osg : : Texture2D : : LINEAR ) ;
_texture - > setFilter ( osg : : Texture2D : : MAG_FILTER , osg : : Texture2D : : LINEAR ) ;
// the shadow comparison should fail if object is outside the texture
_texture - > setWrap ( osg : : Texture2D : : WRAP_S , osg : : Texture2D : : CLAMP_TO_BORDER ) ;
_texture - > setWrap ( osg : : Texture2D : : WRAP_T , osg : : Texture2D : : CLAMP_TO_BORDER ) ;
_texture - > setBorderColor ( osg : : Vec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ;
//_texture->setBorderColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
// set up the camera
_camera = new osg : : Camera ;
_camera - > setName ( " ShadowCamera " ) ;
_camera - > setReferenceFrame ( osg : : Camera : : ABSOLUTE_RF_INHERIT_VIEWPOINT ) ;
# ifndef __APPLE__ // workaround shadow issue on macOS, https://gitlab.com/OpenMW/openmw/-/issues/6057
_camera - > setImplicitBufferAttachmentMask ( 0 , 0 ) ;
# endif
//_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
_camera - > setClearColor ( osg : : Vec4 ( 0.0f , 0.0f , 0.0f , 0.0f ) ) ;
//_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
//_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
// Now we are using Depth Clamping, we want to not cull things on the wrong side of the near plane.
// When the near and far planes are computed, OSG always culls anything on the wrong side of the near plane, even if it's told not to.
// Even if that weren't an issue, the near plane can't go past any shadow receivers or the depth-clamped fragments which ended up on the near plane can't cast shadows on those receivers.
// Unfortunately, this change will make shadows have less depth precision when there are no casters outside the view frustum.
// TODO: Find a better solution. E.g. detect when there are no casters outside the view frustum, write a new cull visitor that does all the wacky things we'd need it to.
_camera - > setComputeNearFarMode ( osg : : Camera : : DO_NOT_COMPUTE_NEAR_FAR ) ;
// switch off small feature culling as this can cull out geometry that will still be large enough once perspective correction takes effect.
_camera - > setCullingMode ( _camera - > getCullingMode ( ) & ~ osg : : CullSettings : : SMALL_FEATURE_CULLING ) ;
// set viewport
_camera - > setViewport ( 0 , 0 , textureSize . x ( ) , textureSize . y ( ) ) ;
if ( debug )
{
// clear just the depth buffer
_camera - > setClearMask ( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ) ;
// render after the main camera
_camera - > setRenderOrder ( osg : : Camera : : POST_RENDER ) ;
// attach the texture and use it as the color buffer.
//_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
_camera - > attach ( osg : : Camera : : COLOR_BUFFER , _texture . get ( ) ) ;
}
else
{
// clear the depth and colour bufferson each clear.
_camera - > setClearMask ( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ) ;
// set the camera to render before the main camera.
_camera - > setRenderOrder ( osg : : Camera : : PRE_RENDER ) ;
// tell the camera to use OpenGL frame buffer object where supported.
_camera - > setRenderTargetImplementation ( osg : : Camera : : FRAME_BUFFER_OBJECT ) ;
// attach the texture and use it as the color buffer.
_camera - > attach ( osg : : Camera : : DEPTH_BUFFER , _texture . get ( ) ) ;
//_camera->attach(osg::Camera::COLOR_BUFFER, _texture.get());
}
}
void MWShadowTechnique : : ShadowData : : releaseGLObjects ( osg : : State * state ) const
{
OSG_INFO < < " MWShadowTechnique::ShadowData::releaseGLObjects " < < std : : endl ;
_texture - > releaseGLObjects ( state ) ;
_camera - > releaseGLObjects ( state ) ;
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// Frustum
//
MWShadowTechnique : : Frustum : : Frustum ( osgUtil : : CullVisitor * cv , double minZNear , double maxZFar ) :
corners ( 8 ) ,
faces ( 6 ) ,
edges ( 12 )
{
projectionMatrix = * ( cv - > getProjectionMatrix ( ) ) ;
modelViewMatrix = * ( cv - > getModelViewMatrix ( ) ) ;
OSG_INFO < < " Projection matrix " < < projectionMatrix < < std : : endl ;
if ( cv - > getComputeNearFarMode ( ) ! = osg : : CullSettings : : DO_NOT_COMPUTE_NEAR_FAR )
{
osg : : Matrix : : value_type zNear = osg : : maximum < osg : : Matrix : : value_type > ( cv - > getCalculatedNearPlane ( ) , minZNear ) ;
osg : : Matrix : : value_type zFar = osg : : minimum < osg : : Matrix : : value_type > ( cv - > getCalculatedFarPlane ( ) , maxZFar ) ;
cv - > clampProjectionMatrix ( projectionMatrix , zNear , zFar ) ;
OSG_INFO < < " zNear = " < < zNear < < " , zFar = " < < zFar < < std : : endl ;
OSG_INFO < < " Projection matrix after clamping " < < projectionMatrix < < std : : endl ;
}
corners [ 0 ] . set ( - 1.0 , - 1.0 , - 1.0 ) ;
corners [ 1 ] . set ( 1.0 , - 1.0 , - 1.0 ) ;
corners [ 2 ] . set ( 1.0 , - 1.0 , 1.0 ) ;
corners [ 3 ] . set ( - 1.0 , - 1.0 , 1.0 ) ;
corners [ 4 ] . set ( - 1.0 , 1.0 , - 1.0 ) ;
corners [ 5 ] . set ( 1.0 , 1.0 , - 1.0 ) ;
corners [ 6 ] . set ( 1.0 , 1.0 , 1.0 ) ;
corners [ 7 ] . set ( - 1.0 , 1.0 , 1.0 ) ;
osg : : Matrixd clipToWorld ;
clipToWorld . invert ( modelViewMatrix * projectionMatrix ) ;
// transform frustum corners from clipspace to world coords, and compute center
for ( Vertices : : iterator itr = corners . begin ( ) ;
itr ! = corners . end ( ) ;
+ + itr )
{
* itr = ( * itr ) * clipToWorld ;
OSG_INFO < < " corner " < < * itr < < std : : endl ;
}
// compute eye point
eye = osg : : Vec3d ( 0.0 , 0.0 , 0.0 ) * osg : : Matrix : : inverse ( modelViewMatrix ) ;
// compute center and the frustumCenterLine
centerNearPlane = ( corners [ 0 ] + corners [ 1 ] + corners [ 5 ] + corners [ 4 ] ) * 0.25 ;
centerFarPlane = ( corners [ 3 ] + corners [ 2 ] + corners [ 6 ] + corners [ 7 ] ) * 0.25 ;
center = ( centerNearPlane + centerFarPlane ) * 0.5 ;
frustumCenterLine = centerFarPlane - centerNearPlane ;
frustumCenterLine . normalize ( ) ;
OSG_INFO < < " center " < < center < < std : : endl ;
faces [ 0 ] . push_back ( 0 ) ;
faces [ 0 ] . push_back ( 3 ) ;
faces [ 0 ] . push_back ( 7 ) ;
faces [ 0 ] . push_back ( 4 ) ;
faces [ 1 ] . push_back ( 1 ) ;
faces [ 1 ] . push_back ( 5 ) ;
faces [ 1 ] . push_back ( 6 ) ;
faces [ 1 ] . push_back ( 2 ) ;
faces [ 2 ] . push_back ( 0 ) ;
faces [ 2 ] . push_back ( 1 ) ;
faces [ 2 ] . push_back ( 2 ) ;
faces [ 2 ] . push_back ( 3 ) ;
faces [ 3 ] . push_back ( 4 ) ;
faces [ 3 ] . push_back ( 7 ) ;
faces [ 3 ] . push_back ( 6 ) ;
faces [ 3 ] . push_back ( 5 ) ;
faces [ 4 ] . push_back ( 0 ) ;
faces [ 4 ] . push_back ( 4 ) ;
faces [ 4 ] . push_back ( 5 ) ;
faces [ 4 ] . push_back ( 1 ) ;
faces [ 5 ] . push_back ( 2 ) ;
faces [ 5 ] . push_back ( 6 ) ;
faces [ 5 ] . push_back ( 7 ) ;
faces [ 5 ] . push_back ( 3 ) ;
edges [ 0 ] . push_back ( 0 ) ; edges [ 0 ] . push_back ( 1 ) ; // corner points on edge
edges [ 0 ] . push_back ( 2 ) ; edges [ 0 ] . push_back ( 4 ) ; // faces on edge
edges [ 1 ] . push_back ( 1 ) ; edges [ 1 ] . push_back ( 2 ) ; // corner points on edge
edges [ 1 ] . push_back ( 2 ) ; edges [ 1 ] . push_back ( 1 ) ; // faces on edge
edges [ 2 ] . push_back ( 2 ) ; edges [ 2 ] . push_back ( 3 ) ; // corner points on edge
edges [ 2 ] . push_back ( 2 ) ; edges [ 2 ] . push_back ( 5 ) ; // faces on edge
edges [ 3 ] . push_back ( 3 ) ; edges [ 3 ] . push_back ( 0 ) ; // corner points on edge
edges [ 3 ] . push_back ( 2 ) ; edges [ 3 ] . push_back ( 0 ) ; // faces on edge
edges [ 4 ] . push_back ( 0 ) ; edges [ 4 ] . push_back ( 4 ) ; // corner points on edge
edges [ 4 ] . push_back ( 0 ) ; edges [ 4 ] . push_back ( 4 ) ; // faces on edge
edges [ 5 ] . push_back ( 1 ) ; edges [ 5 ] . push_back ( 5 ) ; // corner points on edge
edges [ 5 ] . push_back ( 4 ) ; edges [ 5 ] . push_back ( 1 ) ; // faces on edge
edges [ 6 ] . push_back ( 2 ) ; edges [ 6 ] . push_back ( 6 ) ; // corner points on edge
edges [ 6 ] . push_back ( 1 ) ; edges [ 6 ] . push_back ( 5 ) ; // faces on edge
edges [ 7 ] . push_back ( 3 ) ; edges [ 7 ] . push_back ( 7 ) ; // corner points on edge
edges [ 7 ] . push_back ( 5 ) ; edges [ 7 ] . push_back ( 0 ) ; // faces on edge
edges [ 8 ] . push_back ( 4 ) ; edges [ 8 ] . push_back ( 5 ) ; // corner points on edge
edges [ 8 ] . push_back ( 3 ) ; edges [ 8 ] . push_back ( 4 ) ; // faces on edge
edges [ 9 ] . push_back ( 5 ) ; edges [ 9 ] . push_back ( 6 ) ; // corner points on edge
edges [ 9 ] . push_back ( 3 ) ; edges [ 9 ] . push_back ( 1 ) ; // faces on edge
edges [ 10 ] . push_back ( 6 ) ; edges [ 10 ] . push_back ( 7 ) ; // corner points on edge
edges [ 10 ] . push_back ( 3 ) ; edges [ 10 ] . push_back ( 5 ) ; // faces on edge
edges [ 11 ] . push_back ( 7 ) ; edges [ 11 ] . push_back ( 4 ) ; // corner points on edge
edges [ 11 ] . push_back ( 3 ) ; edges [ 11 ] . push_back ( 0 ) ; // faces on edge
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// ViewDependentData
//
MWShadowTechnique : : ViewDependentData : : ViewDependentData ( MWShadowTechnique * vdsm ) :
_viewDependentShadowMap ( vdsm )
{
OSG_INFO < < " ViewDependentData::ViewDependentData() " < < this < < std : : endl ;
for ( auto & perFrameStateset : _stateset )
perFrameStateset = new osg : : StateSet ;
}
void MWShadowTechnique : : ViewDependentData : : releaseGLObjects ( osg : : State * state ) const
{
for ( ShadowDataList : : const_iterator itr = _shadowDataList . begin ( ) ;
itr ! = _shadowDataList . end ( ) ;
+ + itr )
{
( * itr ) - > releaseGLObjects ( state ) ;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// MWShadowTechnique
//
MWShadowTechnique : : MWShadowTechnique ( ) :
ShadowTechnique ( ) ,
_enableShadows ( false ) ,
_debugHud ( nullptr ) ,
_castingPrograms { nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr }
{
_shadowRecievingPlaceholderStateSet = new osg : : StateSet ;
mSetDummyStateWhenDisabled = false ;
}
MWShadowTechnique : : MWShadowTechnique ( const MWShadowTechnique & vdsm , const osg : : CopyOp & copyop ) :
ShadowTechnique ( vdsm , copyop )
, _castingPrograms ( vdsm . _castingPrograms )
{
_shadowRecievingPlaceholderStateSet = new osg : : StateSet ;
_enableShadows = vdsm . _enableShadows ;
mSetDummyStateWhenDisabled = vdsm . mSetDummyStateWhenDisabled ;
}
MWShadowTechnique : : ~ MWShadowTechnique ( )
{
}
void MWShadowTechnique : : init ( )
{
if ( ! _shadowedScene ) return ;
OSG_INFO < < " MWShadowTechnique::init() " < < std : : endl ;
createShaders ( ) ;
_dirty = false ;
}
void MWShadowTechnique : : cleanSceneGraph ( )
{
OSG_INFO < < " MWShadowTechnique::cleanSceneGraph() " < < std : : endl ;
}
void MWShadowTechnique : : enableShadows ( )
{
_enableShadows = true ;
}
void MWShadowTechnique : : disableShadows ( bool setDummyState )
{
_enableShadows = false ;
mSetDummyStateWhenDisabled = setDummyState ;
}
void SceneUtil : : MWShadowTechnique : : enableDebugHUD ( )
{
_debugHud = new DebugHUD ( getShadowedScene ( ) - > getShadowSettings ( ) - > getNumShadowMapsPerLight ( ) ) ;
}
void SceneUtil : : MWShadowTechnique : : disableDebugHUD ( )
{
_debugHud = nullptr ;
}
void SceneUtil : : MWShadowTechnique : : setSplitPointUniformLogarithmicRatio ( double ratio )
{
_splitPointUniformLogRatio = ratio ;
}
void SceneUtil : : MWShadowTechnique : : setSplitPointDeltaBias ( double bias )
{
_splitPointDeltaBias = bias ;
}
void SceneUtil : : MWShadowTechnique : : setPolygonOffset ( float factor , float units )
{
_polygonOffsetFactor = factor ;
_polygonOffsetUnits = units ;
if ( _polygonOffset )
{
_polygonOffset - > setFactor ( factor ) ;
_polygonOffset - > setUnits ( units ) ;
}
}
void SceneUtil : : MWShadowTechnique : : setShadowFadeStart ( float shadowFadeStart )
{
_shadowFadeStart = shadowFadeStart ;
}
void SceneUtil : : MWShadowTechnique : : enableFrontFaceCulling ( )
{
_useFrontFaceCulling = true ;
if ( _shadowCastingStateSet )
{
_shadowCastingStateSet - > setAttribute ( new osg : : CullFace ( osg : : CullFace : : FRONT ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
_shadowCastingStateSet - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
}
}
void SceneUtil : : MWShadowTechnique : : disableFrontFaceCulling ( )
{
_useFrontFaceCulling = false ;
if ( _shadowCastingStateSet )
{
_shadowCastingStateSet - > removeAttribute ( osg : : StateAttribute : : CULLFACE ) ;
_shadowCastingStateSet - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF | osg : : StateAttribute : : OVERRIDE ) ;
}
}
void SceneUtil : : MWShadowTechnique : : enableReverseZ ( )
{
_reverseZ = true ;
}
void SceneUtil : : MWShadowTechnique : : disableReverseZ ( )
{
_reverseZ = false ;
}
void SceneUtil : : MWShadowTechnique : : setupCastingShader ( Shader : : ShaderManager & shaderManager )
{
// This can't be part of the constructor as OSG mandates that there be a trivial constructor available
osg : : ref_ptr < osg : : Shader > castingVertexShader = shaderManager . getShader ( " shadowcasting_vertex.glsl " , { } , osg : : Shader : : VERTEX ) ;
osg : : ref_ptr < osg : : GLExtensions > exts = osg : : GLExtensions : : Get ( 0 , false ) ;
std : : string useGPUShader4 = exts & & exts - > isGpuShader4Supported ? " 1 " : " 0 " ;
for ( int alphaFunc = GL_NEVER ; alphaFunc < = GL_ALWAYS ; + + alphaFunc )
{
auto & program = _castingPrograms [ alphaFunc - GL_NEVER ] ;
program = new osg : : Program ( ) ;
program - > addShader ( castingVertexShader ) ;
program - > addShader ( shaderManager . getShader ( " shadowcasting_fragment.glsl " , { { " alphaFunc " , std : : to_string ( alphaFunc ) } ,
{ " alphaToCoverage " , " 0 " } ,
{ " adjustCoverage " , " 1 " } ,
{ " useGPUShader4 " , useGPUShader4 }
} , osg : : Shader : : FRAGMENT ) ) ;
}
}
MWShadowTechnique : : ViewDependentData * MWShadowTechnique : : createViewDependentData ( osgUtil : : CullVisitor * /*cv*/ )
{
return new ViewDependentData ( this ) ;
}
MWShadowTechnique : : ViewDependentData * MWShadowTechnique : : getViewDependentData ( osgUtil : : CullVisitor * cv )
{
std : : lock_guard < std : : mutex > lock ( _viewDependentDataMapMutex ) ;
ViewDependentDataMap : : iterator itr = _viewDependentDataMap . find ( cv ) ;
if ( itr ! = _viewDependentDataMap . end ( ) ) return itr - > second . get ( ) ;
osg : : ref_ptr < ViewDependentData > vdd = createViewDependentData ( cv ) ;
_viewDependentDataMap [ cv ] = vdd ;
return vdd . release ( ) ;
}
void MWShadowTechnique : : update ( osg : : NodeVisitor & nv )
{
OSG_INFO < < " MWShadowTechnique::update(osg::NodeVisitor& " < < & nv < < " ) " < < std : : endl ;
_shadowedScene - > osg : : Group : : traverse ( nv ) ;
}
void MWShadowTechnique : : cull ( osgUtil : : CullVisitor & cv )
{
if ( ! _enableShadows )
{
if ( mSetDummyStateWhenDisabled )
{
osg : : ref_ptr < osg : : StateSet > dummyState = new osg : : StateSet ( ) ;
ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
int baseUnit = settings - > getBaseShadowTextureUnit ( ) ;
int endUnit = baseUnit + settings - > getNumShadowMapsPerLight ( ) ;
for ( int i = baseUnit ; i < endUnit ; + + i )
{
dummyState - > setTextureAttributeAndModes ( i , _fallbackShadowMapTexture , osg : : StateAttribute : : ON ) ;
dummyState - > addUniform ( new osg : : Uniform ( ( " shadowTexture " + std : : to_string ( i - baseUnit ) ) . c_str ( ) , i ) ) ;
dummyState - > addUniform ( new osg : : Uniform ( ( " shadowTextureUnit " + std : : to_string ( i - baseUnit ) ) . c_str ( ) , i ) ) ;
}
cv . pushStateSet ( dummyState ) ;
}
_shadowedScene - > osg : : Group : : traverse ( cv ) ;
if ( mSetDummyStateWhenDisabled )
cv . popStateSet ( ) ;
return ;
}
OSG_INFO < < std : : endl < < std : : endl < < " MWShadowTechnique::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
auto * shadowReceiverStateSet = vdd - > getStateSet ( cv . getTraversalNumber ( ) ) ;
shadowReceiverStateSet - > clear ( ) ;
cv . pushStateSet ( shadowReceiverStateSet ) ;
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;
// Workaround for absurdly huge viewing distances where OSG would otherwise push the near plane out.
cv . setNearFarRatio ( minZNear / maxZFar ) ;
Frustum frustum ( & cv , minZNear , maxZFar ) ;
if ( _debugHud )
{
osg : : ref_ptr < osg : : Vec3Array > vertexArray = new osg : : Vec3Array ( ) ;
for ( osg : : Vec3d & vertex : frustum . corners )
vertexArray - > push_back ( ( osg : : Vec3 ) vertex ) ;
_debugHud - > setFrustumVertices ( vertexArray , cv . getTraversalNumber ( ) ) ;
}
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 ;
}
// 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 ( ) ;
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 ( ) ) ;
osg : : Matrixd cornerConverter = osg : : Matrixd : : inverse ( projectionMatrix ) * osg : : Matrixd : : inverse ( viewMatrix ) * * cv . getModelViewMatrix ( ) ;
double minZ = dbl_max ;
double maxZ = - dbl_max ;
clsb . _bb . _max [ 2 ] = 1.0 ;
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 ) ;
// 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 ) ) ;
}
}
#if 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 ;
}
}
# endif
// 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 ( ) ) ;
}
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 ) ;
double cascaseNear = reducedNear ;
double cascadeFar = reducedFar ;
if ( numShadowMapsPerLight > 1 )
{
// compute the start and end range in non-dimensional coords
#if 0
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 ) ;
# elif 0
// hardwired for 2 splits
double r_start = ( sm_i = = 0 ) ? - 1.0 : splitPoint ;
double r_end = ( sm_i + 1 = = numShadowMapsPerLight ) ? 1.0 : splitPoint ;
# else
double r_start , r_end ;
// split system based on the original Parallel Split Shadow Maps paper.
double n = reducedNear ;
double f = reducedFar ;
double i = double ( sm_i ) ;
double m = double ( numShadowMapsPerLight ) ;
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 ;
double ci = _splitPointUniformLogRatio * ciLog + ( 1.0 - _splitPointUniformLogRatio ) * ciUniform + _splitPointDeltaBias ;
cascaseNear = ci ;
// 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 ;
double ci = _splitPointUniformLogRatio * ciLog + ( 1.0 - _splitPointUniformLogRatio ) * ciUniform + _splitPointDeltaBias ;
cascadeFar = ci ;
// 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 ( ) ;
}
# endif
// 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 ;
// We can't add these clipping planes with cascaded shadow maps as they wouldn't be parallel to the light direction.
if ( settings - > getMultipleShadowMapHint ( ) = = ShadowSettings : : PARALLEL_SPLIT & & 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 ( settings - > getMultipleShadowMapHint ( ) = = ShadowSettings : : PARALLEL_SPLIT & & 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 ( ) ;
if ( settings - > getMultipleShadowMapHint ( ) = = ShadowSettings : : PARALLEL_SPLIT )
{
// 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 ) ) ) ;
}
}
std : : vector < osg : : Plane > extraPlanes ;
if ( settings - > getMultipleShadowMapHint ( ) = = ShadowSettings : : CASCADED )
{
cropShadowCameraToMainFrustum ( frustum , camera , cascaseNear , cascadeFar , extraPlanes ) ;
for ( const auto & plane : extraPlanes )
local_polytope . getPlaneList ( ) . push_back ( plane ) ;
local_polytope . setupMask ( ) ;
}
else
cropShadowCameraToMainFrustum ( frustum , camera , reducedNear , reducedFar , extraPlanes ) ;
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 ( ) = = ShadowSettings : : PERSPECTIVE_SHADOW_MAP )
{
{
osg : : Matrix validRegionMatrix = cv . getCurrentCamera ( ) - > getInverseViewMatrix ( ) * camera - > getViewMatrix ( ) * camera - > getProjectionMatrix ( ) ;
std : : string validRegionUniformName = " validRegionMatrix " + std : : to_string ( sm_i ) ;
osg : : ref_ptr < osg : : Uniform > validRegionUniform ;
for ( auto uniform : _uniforms [ cv . getTraversalNumber ( ) % 2 ] )
{
if ( uniform - > getName ( ) = = validRegionUniformName )
validRegionUniform = uniform ;
}
if ( ! validRegionUniform )
{
validRegionUniform = new osg : : Uniform ( osg : : Uniform : : FLOAT_MAT4 , validRegionUniformName ) ;
_uniforms [ cv . getTraversalNumber ( ) % 2 ] . push_back ( validRegionUniform ) ;
}
validRegionUniform - > set ( validRegionMatrix ) ;
}
if ( settings - > getMultipleShadowMapHint ( ) = = ShadowSettings : : CASCADED )
adjustPerspectiveShadowMapCameraSettings ( vdsmCallback - > getRenderStage ( ) , frustum , pl , camera . get ( ) , cascaseNear , cascadeFar ) ;
else
adjustPerspectiveShadowMapCameraSettings ( vdsmCallback - > getRenderStage ( ) , frustum , pl , camera . get ( ) , reducedNear , reducedFar ) ;
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 ( _debugHud )
_debugHud - > draw ( sd - > _texture , sm_i , camera - > getViewMatrix ( ) * camera - > getProjectionMatrix ( ) , cv ) ;
}
}
if ( numValidShadows > 0 )
{
prepareStateSetForRenderingShadow ( * vdd , cv . getTraversalNumber ( ) ) ;
}
// OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl;
}
bool MWShadowTechnique : : selectActiveLights ( osgUtil : : CullVisitor * cv , ViewDependentData * vdd ) const
{
OSG_INFO < < " selectActiveLights " < < std : : endl ;
LightDataList & pll = vdd - > getLightDataList ( ) ;
LightDataList previous_ldl ;
previous_ldl . swap ( pll ) ;
//MR testing giving a specific light
osgUtil : : RenderStage * rs = cv - > getCurrentRenderBin ( ) - > getStage ( ) ;
OSG_INFO < < " selectActiveLights osgUtil::RenderStage= " < < rs < < std : : endl ;
osg : : Matrixd modelViewMatrix = * ( cv - > getModelViewMatrix ( ) ) ;
osgUtil : : PositionalStateContainer : : AttrMatrixList & aml =
rs - > getPositionalStateContainer ( ) - > getAttrMatrixList ( ) ;
const ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
for ( osgUtil : : PositionalStateContainer : : AttrMatrixList : : reverse_iterator itr = aml . rbegin ( ) ;
itr ! = aml . rend ( ) ;
+ + itr )
{
const osg : : Light * light = dynamic_cast < const osg : : Light * > ( itr - > first . get ( ) ) ;
if ( light & & light - > getLightNum ( ) > = 0 )
{
// is LightNum matched to that defined in settings
if ( settings & & settings - > getLightNum ( ) > = 0 & & light - > getLightNum ( ) ! = settings - > getLightNum ( ) ) continue ;
LightDataList : : iterator pll_itr = pll . begin ( ) ;
for ( ; pll_itr ! = pll . end ( ) ; + + pll_itr )
{
if ( ( * pll_itr ) - > light - > getLightNum ( ) = = light - > getLightNum ( ) ) break ;
}
if ( pll_itr = = pll . end ( ) )
{
OSG_INFO < < " Light num " < < light - > getLightNum ( ) < < std : : endl ;
LightData * ld = new LightData ( vdd ) ;
ld - > setLightData ( itr - > second . get ( ) , light , modelViewMatrix ) ;
pll . push_back ( ld ) ;
}
else
{
OSG_INFO < < " Light num " < < light - > getLightNum ( ) < < " already used, ignore light " < < std : : endl ;
}
}
}
return ! pll . empty ( ) ;
}
void MWShadowTechnique : : createShaders ( )
{
OSG_INFO < < " MWShadowTechnique::createShaders() " < < std : : endl ;
unsigned int _baseTextureUnit = 0 ;
_shadowCastingStateSet = new osg : : StateSet ;
ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
if ( ! settings - > getDebugDraw ( ) )
{
// note soft (attribute only no mode override) setting. When this works ?
// 1. for objects prepared for backface culling
// because they usually also set CullFace and CullMode on in their state
// For them we override CullFace but CullMode remains set by them
// 2. For one faced, trees, and similar objects which cannot use
// backface nor front face so they usually use CullMode off set here.
// In this case we will draw them in their entirety.
if ( _useFrontFaceCulling )
{
_shadowCastingStateSet - > setAttribute ( new osg : : CullFace ( osg : : CullFace : : FRONT ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
// make sure GL_CULL_FACE is off by default
// we assume that if object has cull face attribute set to back
// it will also set cull face mode ON so no need for override
_shadowCastingStateSet - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
}
else
_shadowCastingStateSet - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF | osg : : StateAttribute : : OVERRIDE ) ;
}
_polygonOffset = new osg : : PolygonOffset ( _polygonOffsetFactor , _polygonOffsetUnits ) ;
_shadowCastingStateSet - > setAttribute ( _polygonOffset . get ( ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
_shadowCastingStateSet - > setMode ( GL_POLYGON_OFFSET_FILL , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
osg : : ref_ptr < osg : : Uniform > baseTextureSampler = new osg : : Uniform ( " baseTexture " , ( int ) _baseTextureUnit ) ;
osg : : ref_ptr < osg : : Uniform > baseTextureUnit = new osg : : Uniform ( " baseTextureUnit " , ( int ) _baseTextureUnit ) ;
osg : : ref_ptr < osg : : Uniform > maxDistance = new osg : : Uniform ( " maximumShadowMapDistance " , ( float ) settings - > getMaximumShadowMapDistance ( ) ) ;
osg : : ref_ptr < osg : : Uniform > fadeStart = new osg : : Uniform ( " shadowFadeStart " , ( float ) _shadowFadeStart ) ;
for ( auto & perFrameUniformList : _uniforms )
{
perFrameUniformList . clear ( ) ;
perFrameUniformList . push_back ( baseTextureSampler ) ;
perFrameUniformList . emplace_back ( baseTextureUnit . get ( ) ) ;
perFrameUniformList . push_back ( maxDistance ) ;
perFrameUniformList . push_back ( fadeStart ) ;
}
for ( unsigned int sm_i = 0 ; sm_i < settings - > getNumShadowMapsPerLight ( ) ; + + sm_i )
{
{
std : : stringstream sstr ;
sstr < < " shadowTexture " < < sm_i ;
osg : : ref_ptr < osg : : Uniform > shadowTextureSampler = new osg : : Uniform ( sstr . str ( ) . c_str ( ) , ( int ) ( settings - > getBaseShadowTextureUnit ( ) + sm_i ) ) ;
for ( auto & perFrameUniformList : _uniforms )
perFrameUniformList . emplace_back ( shadowTextureSampler . get ( ) ) ;
}
{
std : : stringstream sstr ;
sstr < < " shadowTextureUnit " < < sm_i ;
osg : : ref_ptr < osg : : Uniform > shadowTextureUnit = new osg : : Uniform ( sstr . str ( ) . c_str ( ) , ( int ) ( settings - > getBaseShadowTextureUnit ( ) + sm_i ) ) ;
for ( auto & perFrameUniformList : _uniforms )
perFrameUniformList . emplace_back ( shadowTextureUnit . get ( ) ) ;
}
}
switch ( settings - > getShaderHint ( ) )
{
case ( ShadowSettings : : NO_SHADERS ) :
{
OSG_INFO < < " No shaders provided by, user must supply own shaders " < < std : : endl ;
break ;
}
case ( ShadowSettings : : PROVIDE_VERTEX_AND_FRAGMENT_SHADER ) :
case ( ShadowSettings : : PROVIDE_FRAGMENT_SHADER ) :
{
_program = new osg : : Program ;
//osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
if ( settings - > getNumShadowMapsPerLight ( ) = = 2 )
{
_program - > addShader ( new osg : : Shader ( osg : : Shader : : FRAGMENT , fragmentShaderSource_withBaseTexture_twoShadowMaps ) ) ;
}
else
{
_program - > addShader ( new osg : : Shader ( osg : : Shader : : FRAGMENT , fragmentShaderSource_withBaseTexture ) ) ;
}
break ;
}
}
{
osg : : ref_ptr < osg : : Image > image = new osg : : Image ;
image - > allocateImage ( 1 , 1 , 1 , GL_RGBA , GL_UNSIGNED_BYTE ) ;
* ( osg : : Vec4ub * ) image - > data ( ) = osg : : Vec4ub ( 0xFF , 0xFF , 0xFF , 0xFF ) ;
_fallbackBaseTexture = new osg : : Texture2D ( image . get ( ) ) ;
_fallbackBaseTexture - > setWrap ( osg : : Texture2D : : WRAP_S , osg : : Texture2D : : REPEAT ) ;
_fallbackBaseTexture - > setWrap ( osg : : Texture2D : : WRAP_T , osg : : Texture2D : : REPEAT ) ;
_fallbackBaseTexture - > setFilter ( osg : : Texture2D : : MIN_FILTER , osg : : Texture2D : : NEAREST ) ;
_fallbackBaseTexture - > setFilter ( osg : : Texture2D : : MAG_FILTER , osg : : Texture2D : : NEAREST ) ;
_fallbackShadowMapTexture = new osg : : Texture2D ( image . get ( ) ) ;
_fallbackShadowMapTexture - > setWrap ( osg : : Texture2D : : WRAP_S , osg : : Texture2D : : REPEAT ) ;
_fallbackShadowMapTexture - > setWrap ( osg : : Texture2D : : WRAP_T , osg : : Texture2D : : REPEAT ) ;
_fallbackShadowMapTexture - > setFilter ( osg : : Texture2D : : MIN_FILTER , osg : : Texture2D : : NEAREST ) ;
_fallbackShadowMapTexture - > setFilter ( osg : : Texture2D : : MAG_FILTER , osg : : Texture2D : : NEAREST ) ;
_fallbackShadowMapTexture - > setShadowComparison ( true ) ;
_fallbackShadowMapTexture - > setShadowCompareFunc ( osg : : Texture : : ShadowCompareFunc : : ALWAYS ) ;
}
if ( ! _castingPrograms [ GL_ALWAYS - GL_NEVER ] )
OSG_NOTICE < < " Shadow casting shader has not been set up. Remember to call setupCastingShader(Shader::ShaderManager &) " < < std : : endl ;
// Always use the GL_ALWAYS shader as the shadows bin will change it if necessary
_shadowCastingStateSet - > setAttributeAndModes ( _castingPrograms [ GL_ALWAYS - GL_NEVER ] , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
// The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied
_shadowCastingStateSet - > setTextureAttributeAndModes ( 0 , _fallbackBaseTexture . get ( ) , osg : : StateAttribute : : ON ) ;
_shadowCastingStateSet - > addUniform ( new osg : : Uniform ( " useDiffuseMapForShadowAlpha " , true ) ) ;
_shadowCastingStateSet - > addUniform ( new osg : : Uniform ( " alphaTestShadows " , false ) ) ;
osg : : ref_ptr < osg : : Depth > depth = new osg : : Depth ;
depth - > setWriteMask ( true ) ;
if ( _reverseZ )
{
osg : : ref_ptr < osg : : ClipControl > clipcontrol = new osg : : ClipControl ( osg : : ClipControl : : LOWER_LEFT , osg : : ClipControl : : NEGATIVE_ONE_TO_ONE ) ;
_shadowCastingStateSet - > setAttribute ( clipcontrol , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
}
_shadowCastingStateSet - > setAttribute ( depth , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
_shadowCastingStateSet - > setMode ( GL_DEPTH_CLAMP , osg : : StateAttribute : : ON ) ;
// TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader
}
osg : : Polytope MWShadowTechnique : : computeLightViewFrustumPolytope ( Frustum & frustum , LightData & positionedLight )
{
OSG_INFO < < " computeLightViewFrustumPolytope() " < < std : : endl ;
osg : : Polytope polytope ;
polytope . setToUnitFrustum ( ) ;
polytope . transformProvidingInverse ( frustum . projectionMatrix ) ;
polytope . transformProvidingInverse ( frustum . modelViewMatrix ) ;
osg : : Polytope lightVolumePolytope ;
if ( positionedLight . directionalLight )
{
osg : : Polytope : : PlaneList & planes = polytope . getPlaneList ( ) ;
osg : : Polytope : : ClippingMask selector_mask = 0x1 ;
osg : : Polytope : : ClippingMask result_mask = 0x0 ;
for ( unsigned int i = 0 ; i < planes . size ( ) ; + + i , selector_mask < < = 1 )
{
OSG_INFO < < " plane " < < planes [ i ] < < " planes[ " < < i < < " ].dotProductNormal(lightDir)= " < < planes [ i ] . dotProductNormal ( positionedLight . lightDir ) ;
if ( planes [ i ] . dotProductNormal ( positionedLight . lightDir ) > = 0.0 )
{
OSG_INFO < < " Need remove side " < < i < < std : : endl ;
}
else
{
OSG_INFO < < std : : endl ;
lightVolumePolytope . add ( planes [ i ] ) ;
result_mask = result_mask | selector_mask ;
}
}
OSG_INFO < < " planes.size() = " < < planes . size ( ) < < std : : endl ;
OSG_INFO < < " planes.getResultMask() = " < < polytope . getResultMask ( ) < < std : : endl ;
OSG_INFO < < " resultMask = " < < result_mask < < std : : endl ;
polytope . setResultMask ( result_mask ) ;
}
else
{
const osg : : Polytope : : PlaneList & planes = polytope . getPlaneList ( ) ;
osg : : Polytope : : ClippingMask selector_mask = 0x1 ;
osg : : Polytope : : ClippingMask result_mask = 0x0 ;
for ( unsigned int i = 0 ; i < planes . size ( ) ; + + i , selector_mask < < = 1 )
{
double d = planes [ i ] . distance ( positionedLight . lightPos3 ) ;
OSG_INFO < < " plane " < < planes [ i ] < < " planes[ " < < i < < " ].distance(lightPos3)= " < < d ;
if ( d < 0.0 )
{
OSG_INFO < < " Need remove side " < < i < < std : : endl ;
}
else
{
OSG_INFO < < std : : endl ;
lightVolumePolytope . add ( planes [ i ] ) ;
result_mask = result_mask | selector_mask ;
}
}
OSG_INFO < < " planes.size() = " < < planes . size ( ) < < std : : endl ;
OSG_INFO < < " planes.getResultMask() = " < < polytope . getResultMask ( ) < < std : : endl ;
OSG_INFO < < " resultMask = " < < result_mask < < std : : endl ;
polytope . setResultMask ( result_mask ) ;
}
OSG_INFO < < " Which frustum edges are active? " < < std : : endl ;
for ( unsigned int i = 0 ; i < 12 ; + + i )
{
Frustum : : Indices & indices = frustum . edges [ i ] ;
unsigned int corner_a = indices [ 0 ] ;
unsigned int corner_b = indices [ 1 ] ;
unsigned int face_a = indices [ 2 ] ;
unsigned int face_b = indices [ 3 ] ;
bool face_a_active = ( polytope . getResultMask ( ) & ( 0x1 < < face_a ) ) ! = 0 ;
bool face_b_active = ( polytope . getResultMask ( ) & ( 0x1 < < face_b ) ) ! = 0 ;
unsigned int numActive = 0 ;
if ( face_a_active ) + + numActive ;
if ( face_b_active ) + + numActive ;
if ( numActive = = 1 )
{
osg : : Plane boundaryPlane ;
if ( positionedLight . directionalLight )
{
osg : : Vec3d normal = ( frustum . corners [ corner_b ] - frustum . corners [ corner_a ] ) ^ positionedLight . lightDir ;
normal . normalize ( ) ;
boundaryPlane . set ( normal , frustum . corners [ corner_a ] ) ;
}
else
{
boundaryPlane . set ( positionedLight . lightPos3 , frustum . corners [ corner_a ] , frustum . corners [ corner_b ] ) ;
}
OSG_INFO < < " Boundary Edge " < < i < < " , corner_a= " < < corner_a < < " , corner_b= " < < corner_b < < " , face_a_active= " < < face_a_active < < " , face_b_active= " < < face_b_active ;
if ( boundaryPlane . distance ( frustum . center ) < 0.0 )
{
boundaryPlane . flip ( ) ;
OSG_INFO < < " , flipped boundary edge " < < boundaryPlane < < std : : endl ;
}
else
{
OSG_INFO < < " , no need to flip boundary edge " < < boundaryPlane < < std : : endl ;
}
lightVolumePolytope . add ( boundaryPlane ) ;
}
else OSG_INFO < < " Internal Edge " < < i < < " , corner_a= " < < corner_a < < " , corner_b= " < < corner_b < < " , face_a_active= " < < face_a_active < < " , face_b_active= " < < face_b_active < < std : : endl ;
}
const osg : : Polytope : : PlaneList & planes = lightVolumePolytope . getPlaneList ( ) ;
for ( unsigned int i = 0 ; i < planes . size ( ) ; + + i )
{
OSG_INFO < < " plane " < < planes [ i ] < < " " < < ( ( lightVolumePolytope . getResultMask ( ) & ( 0x1 < < i ) ) ? " on " : " off " ) < < std : : endl ;
}
return lightVolumePolytope ;
}
bool MWShadowTechnique : : computeShadowCameraSettings ( Frustum & frustum , LightData & positionedLight , osg : : Matrixd & projectionMatrix , osg : : Matrixd & viewMatrix )
{
OSG_INFO < < " standardShadowMapCameraSettings() " < < std : : endl ;
osg : : Vec3d lightSide ;
const ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
double dotProduct_v = positionedLight . lightDir * frustum . frustumCenterLine ;
double gamma_v = acos ( dotProduct_v ) ;
if ( gamma_v < osg : : DegreesToRadians ( settings - > getPerspectiveShadowMapCutOffAngle ( ) ) | | gamma_v > osg : : DegreesToRadians ( 180.0 - settings - > getPerspectiveShadowMapCutOffAngle ( ) ) )
{
OSG_INFO < < " View direction and Light direction below tolerance " < < std : : endl ;
osg : : Vec3d viewSide = osg : : Matrixd : : transform3x3 ( frustum . modelViewMatrix , osg : : Vec3d ( 1.0 , 0.0 , 0.0 ) ) ;
lightSide = positionedLight . lightDir ^ ( viewSide ^ positionedLight . lightDir ) ;
lightSide . normalize ( ) ;
}
else
{
lightSide = positionedLight . lightDir ^ frustum . frustumCenterLine ;
lightSide . normalize ( ) ;
}
osg : : Vec3d lightUp = lightSide ^ positionedLight . lightDir ;
#if 0
OSG_NOTICE < < " positionedLight.lightDir= " < < positionedLight . lightDir < < std : : endl ;
OSG_NOTICE < < " lightSide= " < < lightSide < < std : : endl ;
OSG_NOTICE < < " lightUp= " < < lightUp < < std : : endl ;
# endif
if ( positionedLight . directionalLight )
{
double xMin = 0.0 , xMax = 0.0 ;
double yMin = 0.0 , yMax = 0.0 ;
double zMin = 0.0 , zMax = 0.0 ;
for ( Frustum : : Vertices : : iterator itr = frustum . corners . begin ( ) ;
itr ! = frustum . corners . end ( ) ;
+ + itr )
{
osg : : Vec3d cornerDelta ( * itr - frustum . center ) ;
osg : : Vec3d cornerInLightCoords ( cornerDelta * lightSide ,
cornerDelta * lightUp ,
cornerDelta * positionedLight . lightDir ) ;
OSG_INFO < < " corner = " < < * itr < < " in lightcoords " < < cornerInLightCoords < < std : : endl ;
xMin = osg : : minimum ( xMin , cornerInLightCoords . x ( ) ) ;
xMax = osg : : maximum ( xMax , cornerInLightCoords . x ( ) ) ;
yMin = osg : : minimum ( yMin , cornerInLightCoords . y ( ) ) ;
yMax = osg : : maximum ( yMax , cornerInLightCoords . y ( ) ) ;
zMin = osg : : minimum ( zMin , cornerInLightCoords . z ( ) ) ;
zMax = osg : : maximum ( zMax , cornerInLightCoords . z ( ) ) ;
}
OSG_INFO < < " before bs xMin= " < < xMin < < " , xMax= " < < xMax < < " , yMin= " < < yMin < < " , yMax= " < < yMax < < " , zMin= " < < zMin < < " , zMax= " < < zMax < < std : : endl ;
osg : : BoundingSphere bs = _shadowedScene - > getBound ( ) ;
osg : : Vec3d modelCenterRelativeFrustumCenter ( bs . center ( ) - frustum . center ) ;
osg : : Vec3d modelCenterInLightCoords ( modelCenterRelativeFrustumCenter * lightSide ,
modelCenterRelativeFrustumCenter * lightUp ,
modelCenterRelativeFrustumCenter * positionedLight . lightDir ) ;
OSG_INFO < < " modelCenterInLight= " < < modelCenterInLightCoords < < " radius= " < < bs . radius ( ) < < std : : endl ;
double radius ( bs . radius ( ) ) ;
xMin = osg : : maximum ( xMin , modelCenterInLightCoords . x ( ) - radius ) ;
xMax = osg : : minimum ( xMax , modelCenterInLightCoords . x ( ) + radius ) ;
yMin = osg : : maximum ( yMin , modelCenterInLightCoords . y ( ) - radius ) ;
yMax = osg : : minimum ( yMax , modelCenterInLightCoords . y ( ) + radius ) ;
zMin = modelCenterInLightCoords . z ( ) - radius ;
zMax = osg : : minimum ( zMax , modelCenterInLightCoords . z ( ) + radius ) ;
OSG_INFO < < " after bs xMin= " < < xMin < < " , xMax= " < < xMax < < " , yMin= " < < yMin < < " , yMax= " < < yMax < < " , zMin= " < < zMin < < " , zMax= " < < zMax < < std : : endl ;
if ( xMin > = xMax | | yMin > = yMax | | zMin > = zMax )
{
OSG_INFO < < " Warning nothing available to create shadows " < < zMax < < std : : endl ;
return false ;
}
else
{
projectionMatrix . makeOrtho ( xMin , xMax , yMin , yMax , 0.0 , zMax - zMin ) ;
viewMatrix . makeLookAt ( frustum . center + positionedLight . lightDir * zMin , frustum . center + positionedLight . lightDir * zMax , lightUp ) ;
}
}
else
{
double zMax = - dbl_max ;
OSG_INFO < < " lightDir = " < < positionedLight . lightDir < < std : : endl ;
OSG_INFO < < " lightPos3 = " < < positionedLight . lightPos3 < < std : : endl ;
for ( Frustum : : Vertices : : iterator itr = frustum . corners . begin ( ) ;
itr ! = frustum . corners . end ( ) ;
+ + itr )
{
osg : : Vec3d cornerDelta ( * itr - positionedLight . lightPos3 ) ;
osg : : Vec3d cornerInLightCoords ( cornerDelta * lightSide ,
cornerDelta * lightUp ,
cornerDelta * positionedLight . lightDir ) ;
OSG_INFO < < " cornerInLightCoords= " < < cornerInLightCoords < < std : : endl ;
zMax = osg : : maximum ( zMax , cornerInLightCoords . z ( ) ) ;
}
OSG_INFO < < " zMax = " < < zMax < < std : : endl ;
if ( zMax < 0.0 )
{
// view frustum entirely behind light
return false ;
}
double minRatio = 0.0001 ;
double zMin = zMax * minRatio ;
double fov = positionedLight . light - > getSpotCutoff ( ) * 2.0 ;
if ( fov < 180.0 ) // spotlight
{
projectionMatrix . makePerspective ( fov , 1.0 , zMin , zMax ) ;
viewMatrix . makeLookAt ( positionedLight . lightPos3 ,
positionedLight . lightPos3 + positionedLight . lightDir , lightUp ) ;
}
else
{
double fovMAX = 160.0f ;
fov = 0.0 ;
// calculate the max FOV from the corners of the frustum relative to the light position
for ( Frustum : : Vertices : : iterator itr = frustum . corners . begin ( ) ;
itr ! = frustum . corners . end ( ) ;
+ + itr )
{
osg : : Vec3d cornerDelta ( * itr - positionedLight . lightPos3 ) ;
double length = cornerDelta . length ( ) ;
if ( length = = 0.0 ) fov = osg : : minimum ( fov , 180.0 ) ;
else
{
double dotProduct = cornerDelta * positionedLight . lightDir ;
double angle = 2.0 * osg : : RadiansToDegrees ( acos ( dotProduct / length ) ) ;
fov = osg : : maximum ( fov , angle ) ;
}
}
OSG_INFO < < " Computed fov = " < < fov < < std : : endl ;
if ( fov > fovMAX )
{
OSG_INFO < < " Clampping fov = " < < fov < < std : : endl ;
fov = fovMAX ;
}
projectionMatrix . makePerspective ( fov , 1.0 , zMin , zMax ) ;
viewMatrix . makeLookAt ( positionedLight . lightPos3 ,
positionedLight . lightPos3 + positionedLight . lightDir , lightUp ) ;
}
}
return true ;
}
struct ConvexHull
{
typedef std : : vector < osg : : Vec3d > Vertices ;
typedef std : : pair < osg : : Vec3d , osg : : Vec3d > Edge ;
typedef std : : list < Edge > Edges ;
Edges _edges ;
bool valid ( ) const { return ! _edges . empty ( ) ; }
void setToFrustum ( MWShadowTechnique : : Frustum & frustum )
{
_edges . push_back ( Edge ( frustum . corners [ 0 ] , frustum . corners [ 1 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 1 ] , frustum . corners [ 2 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 2 ] , frustum . corners [ 3 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 3 ] , frustum . corners [ 0 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 4 ] , frustum . corners [ 5 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 5 ] , frustum . corners [ 6 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 6 ] , frustum . corners [ 7 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 7 ] , frustum . corners [ 4 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 0 ] , frustum . corners [ 4 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 1 ] , frustum . corners [ 5 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 2 ] , frustum . corners [ 6 ] ) ) ;
_edges . push_back ( Edge ( frustum . corners [ 3 ] , frustum . corners [ 7 ] ) ) ;
}
struct ConvexHull2D
{
// Implementation based on https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#C++
typedef osg : : Vec3d Point ;
static double cross ( const Point & O , const Point & A , const Point & B )
{
return ( A . x ( ) - O . x ( ) ) * ( B . y ( ) - O . y ( ) ) - ( A . y ( ) - O . y ( ) ) * ( B . x ( ) - O . x ( ) ) ;
}
// Calculates the 2D convex hull and returns it as a vector containing the points in CCW order with the first and last point being the same.
static std : : vector < Point > convexHull ( std : : set < Point > & P )
{
size_t n = P . size ( ) , k = 0 ;
if ( n < = 3 )
return std : : vector < Point > ( P . cbegin ( ) , P . cend ( ) ) ;
std : : vector < Point > H ( 2 * n ) ;
// Points are already sorted in a std::set
// Build lower hull
for ( auto pItr = P . cbegin ( ) ; pItr ! = P . cend ( ) ; + + pItr )
{
while ( k > = 2 & & cross ( H [ k - 2 ] , H [ k - 1 ] , * pItr ) < = 0 )
k - - ;
H [ k + + ] = * pItr ;
}
// Build upper hull
size_t t = k + 1 ;
for ( auto pItr = std : : next ( P . crbegin ( ) ) ; pItr ! = P . crend ( ) ; + + pItr )
{
while ( k > = t & & cross ( H [ k - 2 ] , H [ k - 1 ] , * pItr ) < = 0 )
k - - ;
H [ k + + ] = * pItr ;
}
H . resize ( k - 1 ) ;
return H ;
}
} ;
Vertices findInternalEdges ( const osg : : Vec3d & mainVertex , const Vertices & connectedVertices )
{
Vertices internalEdgeVertices ;
for ( const auto & vertex : connectedVertices )
{
osg : : Matrixd matrix ;
osg : : Vec3d dir = vertex - mainVertex ;
matrix . makeLookAt ( mainVertex , vertex , dir . z ( ) = = 0 ? osg : : Vec3d ( 0 , 0 , 1 ) : osg : : Vec3d ( 1 , 0 , 0 ) ) ;
Vertices testVertices ;
for ( const auto & testVertex : connectedVertices )
{
if ( vertex ! = testVertex )
testVertices . push_back ( testVertex ) ;
}
std : : vector < double > bearings ;
for ( const auto & testVertex : testVertices )
{
osg : : Vec3d transformedVertex = testVertex * matrix ;
bearings . push_back ( atan2 ( transformedVertex . y ( ) , transformedVertex . x ( ) ) ) ;
}
std : : sort ( bearings . begin ( ) , bearings . end ( ) ) ;
bool keep = false ;
for ( auto itr = bearings . begin ( ) ; itr + 1 ! = bearings . end ( ) ; + + itr )
{
if ( * itr + osg : : PI < * ( itr + 1 ) )
{
keep = true ;
break ;
}
}
if ( ! keep & & bearings [ 0 ] + osg : : PI > bearings . back ( ) )
keep = true ;
if ( ! keep )
internalEdgeVertices . push_back ( vertex ) ;
}
return internalEdgeVertices ;
}
void extendTowardsNegativeZ ( )
{
typedef std : : set < osg : : Vec3d > VertexSet ;
// Collect the set of vertices
VertexSet vertices ;
for ( const Edge & edge : _edges )
{
vertices . insert ( edge . first ) ;
vertices . insert ( edge . second ) ;
}
if ( vertices . size ( ) = = 0 )
return ;
// Get the vertices contributing to the 2D convex hull
Vertices extremeVertices = ConvexHull2D : : convexHull ( vertices ) ;
VertexSet extremeVerticesSet ( extremeVertices . cbegin ( ) , extremeVertices . cend ( ) ) ;
// Add their extrusions to the final edge collection
// We extrude as far as -1.5 as the coordinate space shouldn't ever put any shadow casters further than -1.0
Edges finalEdges ;
// Add edges towards -Z
for ( auto vertex : extremeVertices )
finalEdges . push_back ( Edge ( vertex , osg : : Vec3d ( vertex . x ( ) , vertex . y ( ) , - 1.5 ) ) ) ;
// Add edge loop to 'seal' the hull
for ( auto itr = extremeVertices . cbegin ( ) ; itr ! = extremeVertices . cend ( ) - 1 ; + + itr )
finalEdges . push_back ( Edge ( osg : : Vec3d ( itr - > x ( ) , itr - > y ( ) , - 1.5 ) , osg : : Vec3d ( ( itr + 1 ) - > x ( ) , ( itr + 1 ) - > y ( ) , - 1.5 ) ) ) ;
// The convex hull algorithm we are using sometimes places a point at both ends of the vector, so we don't always need to add the last edge separately.
if ( extremeVertices . front ( ) ! = extremeVertices . back ( ) )
finalEdges . push_back ( Edge ( osg : : Vec3d ( extremeVertices . front ( ) . x ( ) , extremeVertices . front ( ) . y ( ) , - 1.5 ) , osg : : Vec3d ( extremeVertices . back ( ) . x ( ) , extremeVertices . back ( ) . y ( ) , - 1.5 ) ) ) ;
// Remove internal edges connected to extreme vertices
for ( auto vertex : extremeVertices )
{
Vertices connectedVertices ;
for ( const Edge & edge : _edges )
{
if ( edge . first = = vertex )
connectedVertices . push_back ( edge . second ) ;
else if ( edge . second = = vertex )
connectedVertices . push_back ( edge . first ) ;
}
connectedVertices . push_back ( osg : : Vec3d ( vertex . x ( ) , vertex . y ( ) , - 1.5 ) ) ;
Vertices unwantedEdgeEnds = findInternalEdges ( vertex , connectedVertices ) ;
for ( auto edgeEnd : unwantedEdgeEnds )
{
for ( auto itr = _edges . begin ( ) ; itr ! = _edges . end ( ) ; )
{
if ( * itr = = Edge ( vertex , edgeEnd ) )
{
itr = _edges . erase ( itr ) ;
break ;
}
else if ( * itr = = Edge ( edgeEnd , vertex ) )
{
itr = _edges . erase ( itr ) ;
break ;
}
else
+ + itr ;
}
}
}
// Gather connected vertices
VertexSet unprocessedConnectedVertices ( extremeVertices . begin ( ) , extremeVertices . end ( ) ) ;
VertexSet connectedVertices ;
while ( unprocessedConnectedVertices . size ( ) > 0 )
{
osg : : Vec3d vertex = * unprocessedConnectedVertices . begin ( ) ;
unprocessedConnectedVertices . erase ( unprocessedConnectedVertices . begin ( ) ) ;
connectedVertices . insert ( vertex ) ;
for ( const Edge & edge : _edges )
{
osg : : Vec3d otherEnd ;
if ( edge . first = = vertex )
otherEnd = edge . second ;
else if ( edge . second = = vertex )
otherEnd = edge . first ;
else
continue ;
if ( connectedVertices . count ( otherEnd ) )
continue ;
unprocessedConnectedVertices . insert ( otherEnd ) ;
}
}
for ( const Edge & edge : _edges )
{
if ( connectedVertices . count ( edge . first ) | | connectedVertices . count ( edge . second ) )
finalEdges . push_back ( edge ) ;
}
_edges = finalEdges ;
}
void transform ( const osg : : Matrixd & m )
{
for ( Edges : : iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
+ + itr )
{
itr - > first = itr - > first * m ;
itr - > second = itr - > second * m ;
}
}
void clip ( const osg : : Plane & plane )
{
Vertices intersections ;
// OSG_NOTICE<<"clip("<<plane<<") edges.size()="<<_edges.size()<<std::endl;
for ( Edges : : iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
)
{
double d0 = plane . distance ( itr - > first ) ;
double d1 = plane . distance ( itr - > second ) ;
if ( d0 < 0.0 & & d1 < 0.0 )
{
// OSG_NOTICE<<" Edge completely outside, removing"<<std::endl;
Edges : : iterator to_delete_itr = itr ;
+ + itr ;
_edges . erase ( to_delete_itr ) ;
}
else if ( d0 > = 0.0 & & d1 > = 0.0 )
{
// OSG_NOTICE<<" Edge completely inside"<<std::endl;
+ + itr ;
}
else
{
osg : : Vec3d & v0 = itr - > first ;
osg : : Vec3d & v1 = itr - > second ;
osg : : Vec3d intersection = v0 - ( v1 - v0 ) * ( d0 / ( d1 - d0 ) ) ;
intersections . push_back ( intersection ) ;
// OSG_NOTICE<<" Edge across clip plane, v0="<<v0<<", v1="<<v1<<", intersection= "<<intersection<<std::endl;
if ( d0 < 0.0 )
{
// move first vertex on edge
v0 = intersection ;
}
else
{
// move second vertex on edge
v1 = intersection ;
}
+ + itr ;
}
}
// OSG_NOTICE<<"After clipping, have "<<intersections.size()<<" to insert"<<std::endl;
if ( intersections . size ( ) < 2 )
{
return ;
}
if ( intersections . size ( ) = = 2 )
{
_edges . push_back ( Edge ( intersections [ 0 ] , intersections [ 1 ] ) ) ;
return ;
}
if ( intersections . size ( ) = = 3 )
{
_edges . push_back ( Edge ( intersections [ 0 ] , intersections [ 1 ] ) ) ;
_edges . push_back ( Edge ( intersections [ 1 ] , intersections [ 2 ] ) ) ;
_edges . push_back ( Edge ( intersections [ 2 ] , intersections [ 0 ] ) ) ;
return ;
}
// more than 3 intersections so have to sort them in clockwise order so that
// we can generate the edges correctly.
osg : : Vec3d normal ( plane . getNormal ( ) ) ;
osg : : Vec3d side_x = osg : : Vec3d ( 1.0 , 0.0 , 0.0 ) ^ normal ;
osg : : Vec3d side_y = osg : : Vec3d ( 0.0 , 1.0 , 0.0 ) ^ normal ;
osg : : Vec3d side = ( side_x . length2 ( ) > = side_y . length2 ( ) ) ? side_x : side_y ;
side . normalize ( ) ;
osg : : Vec3d up = side ^ normal ;
up . normalize ( ) ;
osg : : Vec3d center ;
for ( Vertices : : iterator itr = intersections . begin ( ) ;
itr ! = intersections . end ( ) ;
+ + itr )
{
center + = * itr ;
center . x ( ) = osg : : maximum ( center . x ( ) , - dbl_max ) ;
center . y ( ) = osg : : maximum ( center . y ( ) , - dbl_max ) ;
center . z ( ) = osg : : maximum ( center . z ( ) , - dbl_max ) ;
center . x ( ) = osg : : minimum ( center . x ( ) , dbl_max ) ;
center . y ( ) = osg : : minimum ( center . y ( ) , dbl_max ) ;
center . z ( ) = osg : : minimum ( center . z ( ) , dbl_max ) ;
}
center / = double ( intersections . size ( ) ) ;
typedef std : : map < double , std : : list < std : : pair < osg : : Vec3d , double > > > VertexMap ;
VertexMap vertexMap ;
for ( Vertices : : iterator itr = intersections . begin ( ) ;
itr ! = intersections . end ( ) ;
+ + itr )
{
osg : : Vec3d dv = ( * itr - center ) ;
double h = dv * side ;
double v = dv * up ;
double angle = atan2 ( h , v ) ;
// OSG_NOTICE<<"angle = "<<osg::RadiansToDegrees(angle)<<", h="<<h<<" v= "<<v<<std::endl;
// We need to make sure all intersections are added to the list in the right order, even if they're so far away that their angles work out the same.
double sortValue ;
if ( angle < osg : : DegreesToRadians ( - 135.0 ) | | angle > osg : : DegreesToRadians ( 135.0 ) )
sortValue = - h ;
else if ( angle < osg : : DegreesToRadians ( - 45.0 ) )
sortValue = v ;
else if ( angle < osg : : DegreesToRadians ( 45.0 ) )
sortValue = h ;
else
sortValue = - v ;
if ( vertexMap . count ( angle ) )
{
auto listItr = vertexMap [ angle ] . begin ( ) ;
while ( listItr ! = vertexMap [ angle ] . end ( ) & & listItr - > second < sortValue )
+ + listItr ;
vertexMap [ angle ] . insert ( listItr , std : : make_pair ( * itr , sortValue ) ) ;
}
else
vertexMap [ angle ] . push_back ( std : : make_pair ( * itr , sortValue ) ) ;
}
osg : : Vec3d previous_v = vertexMap . rbegin ( ) - > second . back ( ) . first ;
for ( VertexMap : : iterator itr = vertexMap . begin ( ) ;
itr ! = vertexMap . end ( ) ;
+ + itr )
{
for ( auto vertex : itr - > second )
{
_edges . push_back ( Edge ( previous_v , vertex . first ) ) ;
previous_v = vertex . first ;
}
}
// OSG_NOTICE<<" after clip("<<plane<<") edges.size()="<<_edges.size()<<std::endl;
}
void clip ( const osg : : Polytope & polytope )
{
const osg : : Polytope : : PlaneList & planes = polytope . getPlaneList ( ) ;
for ( osg : : Polytope : : PlaneList : : const_iterator itr = planes . begin ( ) ;
itr ! = planes . end ( ) ;
+ + itr )
{
clip ( * itr ) ;
}
}
double min ( unsigned int index ) const
{
double m = dbl_max ;
for ( Edges : : const_iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
+ + itr )
{
const Edge & edge = * itr ;
if ( edge . first [ index ] < m ) m = edge . first [ index ] ;
if ( edge . second [ index ] < m ) m = edge . second [ index ] ;
}
return m ;
}
double max ( unsigned int index ) const
{
double m = - dbl_max ;
for ( Edges : : const_iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
+ + itr )
{
const Edge & edge = * itr ;
if ( edge . first [ index ] > m ) m = edge . first [ index ] ;
if ( edge . second [ index ] > m ) m = edge . second [ index ] ;
}
return m ;
}
double minRatio ( const osg : : Vec3d & eye , unsigned int index ) const
{
double m = dbl_max ;
osg : : Vec3d delta ;
double ratio ;
for ( Edges : : const_iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
+ + itr )
{
const Edge & edge = * itr ;
delta = edge . first - eye ;
ratio = delta [ index ] / delta [ 1 ] ;
if ( ratio < m ) m = ratio ;
delta = edge . second - eye ;
ratio = delta [ index ] / delta [ 1 ] ;
if ( ratio < m ) m = ratio ;
}
return m ;
}
double maxRatio ( const osg : : Vec3d & eye , unsigned int index ) const
{
double m = - dbl_max ;
osg : : Vec3d delta ;
double ratio ;
for ( Edges : : const_iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
+ + itr )
{
const Edge & edge = * itr ;
delta = edge . first - eye ;
ratio = delta [ index ] / delta [ 1 ] ;
if ( ratio > m ) m = ratio ;
delta = edge . second - eye ;
ratio = delta [ index ] / delta [ 1 ] ;
if ( ratio > m ) m = ratio ;
}
return m ;
}
void output ( std : : ostream & out )
{
out < < " ConvexHull " < < std : : endl ;
for ( Edges : : const_iterator itr = _edges . begin ( ) ;
itr ! = _edges . end ( ) ;
+ + itr )
{
const Edge & edge = * itr ;
out < < " edge ( " < < edge . first < < " ) ( " < < edge . second < < " ) " < < std : : endl ;
}
}
} ;
struct RenderLeafBounds
{
RenderLeafBounds ( ) :
computeRatios ( false ) ,
numRenderLeaf ( 0 ) ,
n ( 0.0 ) ,
previous_modelview ( 0 ) ,
clip_min_x ( - 1.0 ) , clip_max_x ( 1.0 ) ,
clip_min_y ( - 1.0 ) , clip_max_y ( 1.0 ) ,
clip_min_z ( - 1.0 ) , clip_max_z ( 1.0 ) ,
clip_min_x_ratio ( - dbl_max ) , clip_max_x_ratio ( dbl_max ) ,
clip_min_z_ratio ( - dbl_max ) , clip_max_z_ratio ( dbl_max ) ,
min_x_ratio ( dbl_max ) , max_x_ratio ( - dbl_max ) ,
min_z_ratio ( dbl_max ) , max_z_ratio ( - dbl_max ) ,
min_x ( 1.0 ) , max_x ( - 1.0 ) ,
min_y ( 1.0 ) , max_y ( - 1.0 ) ,
min_z ( 1.0 ) , max_z ( - 1.0 )
{
//OSG_NOTICE<<std::endl<<"RenderLeafBounds"<<std::endl;
}
void set ( const osg : : Matrixd & p )
{
computeRatios = false ;
light_p = p ;
clip_min_x = - dbl_max ; clip_max_x = dbl_max ;
clip_min_y = - dbl_max ; clip_max_y = dbl_max ;
clip_min_z = - dbl_max ; clip_max_z = dbl_max ;
min_x = dbl_max ; max_x = - dbl_max ;
min_y = dbl_max ; max_y = - dbl_max ;
min_z = dbl_max ; max_z = - dbl_max ;
}
void set ( const osg : : Matrixd & p , osg : : Vec3d & e_ls , double nr )
{
computeRatios = true ;
light_p = p ;
eye_ls = e_ls ;
n = nr ;
}
void operator ( ) ( const osgUtil : : RenderLeaf * renderLeaf )
{
+ + numRenderLeaf ;
if ( renderLeaf - > _modelview . get ( ) ! = previous_modelview )
{
previous_modelview = renderLeaf - > _modelview . get ( ) ;
if ( previous_modelview )
{
light_mvp . mult ( * renderLeaf - > _modelview , light_p ) ;
}
else
{
// no modelview matrix (such as when LightPointNode is in the scene graph) so assume
// that modelview matrix is indentity.
light_mvp = light_p ;
}
// OSG_INFO<<"Computing new light_mvp "<<light_mvp<<std::endl;
}
else
{
// OSG_INFO<<"Reusing light_mvp "<<light_mvp<<std::endl;
}
const osg : : BoundingBox & bb = renderLeaf - > _drawable - > getBoundingBox ( ) ;
if ( bb . valid ( ) )
{
// OSG_NOTICE<<"checked extents of "<<renderLeaf->_drawable->getName()<<std::endl;
handle ( osg : : Vec3d ( bb . xMin ( ) , bb . yMin ( ) , bb . zMin ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMax ( ) , bb . yMin ( ) , bb . zMin ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMin ( ) , bb . yMax ( ) , bb . zMin ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMax ( ) , bb . yMax ( ) , bb . zMin ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMin ( ) , bb . yMin ( ) , bb . zMax ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMax ( ) , bb . yMin ( ) , bb . zMax ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMin ( ) , bb . yMax ( ) , bb . zMax ( ) ) ) ;
handle ( osg : : Vec3d ( bb . xMax ( ) , bb . yMax ( ) , bb . zMax ( ) ) ) ;
}
else
{
OSG_INFO < < " bb invalid " < < std : : endl ;
}
}
void handle ( const osg : : Vec3d & v )
{
osg : : Vec3d ls = v * light_mvp ;
// OSG_NOTICE<<" corner v="<<v<<", ls="<<ls<<std::endl;
if ( computeRatios )
{
osg : : Vec3d delta = ls - eye_ls ;
double x_ratio , z_ratio ;
if ( delta . y ( ) > n )
{
x_ratio = delta . x ( ) / delta . y ( ) ;
z_ratio = delta . z ( ) / delta . y ( ) ;
}
else
{
x_ratio = delta . x ( ) / n ;
z_ratio = delta . z ( ) / n ;
}
if ( x_ratio < min_x_ratio ) min_x_ratio = x_ratio ;
if ( x_ratio > max_x_ratio ) max_x_ratio = x_ratio ;
if ( z_ratio < min_z_ratio ) min_z_ratio = z_ratio ;
if ( z_ratio > max_z_ratio ) max_z_ratio = z_ratio ;
}
// clip to the light space
if ( ls . x ( ) < clip_min_x ) ls . x ( ) = clip_min_x ;
if ( ls . x ( ) > clip_max_x ) ls . x ( ) = clip_max_x ;
if ( ls . y ( ) < clip_min_y ) ls . y ( ) = clip_min_y ;
if ( ls . y ( ) > clip_max_y ) ls . y ( ) = clip_max_y ;
if ( ls . z ( ) < clip_min_z ) ls . z ( ) = clip_min_z ;
if ( ls . z ( ) > clip_max_z ) ls . z ( ) = clip_max_z ;
// compute the xyz range.
if ( ls . x ( ) < min_x ) min_x = ls . x ( ) ;
if ( ls . x ( ) > max_x ) max_x = ls . x ( ) ;
if ( ls . y ( ) < min_y ) min_y = ls . y ( ) ;
if ( ls . y ( ) > max_y ) max_y = ls . y ( ) ;
if ( ls . z ( ) < min_z ) { min_z = ls . z ( ) ; /* OSG_NOTICE<<" - ";*/ }
if ( ls . z ( ) > max_z ) { max_z = ls . z ( ) ; /* OSG_NOTICE<<" + ";*/ }
// OSG_NOTICE<<" bb.z() in ls = "<<ls.z()<<std::endl;
}
bool computeRatios ;
unsigned int numRenderLeaf ;
osg : : Matrixd light_p ;
osg : : Vec3d eye_ls ;
double n ;
osg : : Matrixd light_mvp ;
osg : : RefMatrix * previous_modelview ;
double clip_min_x , clip_max_x ;
double clip_min_y , clip_max_y ;
double clip_min_z , clip_max_z ;
double clip_min_x_ratio , clip_max_x_ratio ;
double clip_min_z_ratio , clip_max_z_ratio ;
double min_x_ratio , max_x_ratio ;
double min_z_ratio , max_z_ratio ;
double min_x , max_x ;
double min_y , max_y ;
double min_z , max_z ;
} ;
bool MWShadowTechnique : : cropShadowCameraToMainFrustum ( Frustum & frustum , osg : : Camera * camera , double viewNear , double viewFar , std : : vector < osg : : Plane > & planeList )
{
osg : : Matrixd light_p = camera - > getProjectionMatrix ( ) ;
osg : : Matrixd light_v = camera - > getViewMatrix ( ) ;
osg : : Matrixd light_vp = light_v * light_p ;
osg : : Matrixd oldLightP = light_p ;
ConvexHull convexHull ;
convexHull . setToFrustum ( frustum ) ;
osg : : Vec3d nearPoint = frustum . eye + frustum . frustumCenterLine * viewNear ;
osg : : Vec3d farPoint = frustum . eye + frustum . frustumCenterLine * viewFar ;
double nearDist = - frustum . frustumCenterLine * nearPoint ;
double farDist = frustum . frustumCenterLine * farPoint ;
convexHull . clip ( osg : : Plane ( frustum . frustumCenterLine , nearDist ) ) ;
convexHull . clip ( osg : : Plane ( - frustum . frustumCenterLine , farDist ) ) ;
convexHull . transform ( light_vp ) ;
double xMin = - 1.0 , xMax = 1.0 ;
double yMin = - 1.0 , yMax = 1.0 ;
double zMin = - 1.0 , zMax = 1.0 ;
if ( convexHull . valid ( ) )
{
xMin = osg : : maximum ( - 1.0 , convexHull . min ( 0 ) ) ;
xMax = osg : : minimum ( 1.0 , convexHull . max ( 0 ) ) ;
yMin = osg : : maximum ( - 1.0 , convexHull . min ( 1 ) ) ;
yMax = osg : : minimum ( 1.0 , convexHull . max ( 1 ) ) ;
zMin = osg : : maximum ( - 1.0 , convexHull . min ( 2 ) ) ;
zMax = osg : : minimum ( 1.0 , convexHull . max ( 2 ) ) ;
}
else
return false ;
if ( xMin ! = - 1.0 | | yMin ! = - 1.0 | | zMin ! = - 1.0 | |
xMax ! = 1.0 | | yMax ! = 1.0 | | zMax ! = 1.0 )
{
osg : : Matrix m ;
m . makeTranslate ( osg : : Vec3d ( - 0.5 * ( xMax + xMin ) ,
- 0.5 * ( yMax + yMin ) ,
- 0.5 * ( zMax + zMin ) ) ) ;
m . postMultScale ( osg : : Vec3d ( 2.0 / ( xMax - xMin ) ,
2.0 / ( yMax - yMin ) ,
2.0 / ( zMax - zMin ) ) ) ;
light_p . postMult ( m ) ;
camera - > setProjectionMatrix ( light_p ) ;
convexHull . transform ( osg : : Matrixd : : inverse ( oldLightP ) ) ;
xMin = convexHull . min ( 0 ) ;
xMax = convexHull . max ( 0 ) ;
yMin = convexHull . min ( 1 ) ;
yMax = convexHull . max ( 1 ) ;
zMin = convexHull . min ( 2 ) ;
planeList . emplace_back ( 0.0 , - 1.0 , 0.0 , yMax ) ;
planeList . emplace_back ( 0.0 , 1.0 , 0.0 , - yMin ) ;
planeList . emplace_back ( - 1.0 , 0.0 , 0.0 , xMax ) ;
planeList . emplace_back ( 1.0 , 0.0 , 0.0 , - xMin ) ;
// In view space, the light is at the most positive value, and we want to cull stuff beyond the minimum value.
planeList . emplace_back ( 0.0 , 0.0 , 1.0 , - zMin ) ;
// Don't add a zMax culling plane - we still want those objects, but don't care about their depth buffer value.
}
return true ;
}
bool MWShadowTechnique : : adjustPerspectiveShadowMapCameraSettings ( osgUtil : : RenderStage * renderStage , Frustum & frustum , LightData & /*positionedLight*/ , osg : : Camera * camera , double viewNear , double viewFar )
{
const ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
//frustum.projectionMatrix;
//frustum.modelViewMatrix;
osg : : Matrixd light_p = camera - > getProjectionMatrix ( ) ;
osg : : Matrixd light_v = camera - > getViewMatrix ( ) ;
osg : : Matrixd light_vp = light_v * light_p ;
osg : : Vec3d lightdir ( 0.0 , 0.0 , - 1.0 ) ;
// check whether this light space projection is perspective or orthographic.
bool orthographicLightSpaceProjection = light_p ( 0 , 3 ) = = 0.0 & & light_p ( 1 , 3 ) = = 0.0 & & light_p ( 2 , 3 ) = = 0.0 ;
if ( ! orthographicLightSpaceProjection )
{
OSG_INFO < < " perspective light space projection not yet supported. " < < std : : endl ;
return false ;
}
//OSG_NOTICE<<"light_v="<<light_v<<std::endl;
//OSG_NOTICE<<"light_p="<<light_p<<std::endl;
ConvexHull convexHull ;
convexHull . setToFrustum ( frustum ) ;
osg : : Vec3d nearPoint = frustum . eye + frustum . frustumCenterLine * viewNear ;
osg : : Vec3d farPoint = frustum . eye + frustum . frustumCenterLine * viewFar ;
double nearDist = - frustum . frustumCenterLine * nearPoint ;
double farDist = frustum . frustumCenterLine * farPoint ;
convexHull . clip ( osg : : Plane ( frustum . frustumCenterLine , nearDist ) ) ;
convexHull . clip ( osg : : Plane ( - frustum . frustumCenterLine , farDist ) ) ;
#if 0
OSG_NOTICE < < " ws ConvexHull xMin= " < < convexHull . min ( 0 ) < < " , xMax= " < < convexHull . max ( 0 ) < < std : : endl ;
OSG_NOTICE < < " ws ConvexHull yMin= " < < convexHull . min ( 1 ) < < " , yMax= " < < convexHull . max ( 1 ) < < std : : endl ;
OSG_NOTICE < < " ws ConvexHull zMin= " < < convexHull . min ( 2 ) < < " , zMax= " < < convexHull . max ( 2 ) < < std : : endl ;
convexHull . output ( osg : : notify ( osg : : NOTICE ) ) ;
# endif
convexHull . transform ( light_vp ) ;
ConvexHull convexHullUnextended = convexHull ;
convexHull . extendTowardsNegativeZ ( ) ;
#if 0
convexHull . output ( osg : : notify ( osg : : NOTICE ) ) ;
OSG_NOTICE < < " ls ConvexHull xMin= " < < convexHull . min ( 0 ) < < " , xMax= " < < convexHull . max ( 0 ) < < std : : endl ;
OSG_NOTICE < < " ls ConvexHull yMin= " < < convexHull . min ( 1 ) < < " , yMax= " < < convexHull . max ( 1 ) < < std : : endl ;
OSG_NOTICE < < " ls ConvexHull zMin= " < < convexHull . min ( 2 ) < < " , zMax= " < < convexHull . max ( 2 ) < < std : : endl ;
# endif
#if 0
// only applicable when the light space contains the whole model contained in the view frustum.
{
convexHull . clip ( osg : : Plane ( 0.0 , 0.0 , 1 , 1.0 ) ) ; // clip by near plane of light space.
convexHull . clip ( osg : : Plane ( 0.0 , 0.0 , - 1 , 1.0 ) ) ; // clip by far plane of light space.
}
# endif
# if 1
if ( renderStage )
{
# if 1
osg : : ElapsedTime timer ;
# endif
RenderLeafTraverser < RenderLeafBounds > rli ;
rli . set ( light_p ) ;
rli . traverse ( renderStage ) ;
if ( rli . numRenderLeaf = = 0 )
{
return false ;
}
#if 0
OSG_NOTICE < < " New Time for RenderLeafTraverser " < < timer . elapsedTime_m ( ) < < " ms, number of render leaves " < < rli . numRenderLeaf < < std : : endl ;
OSG_NOTICE < < " scene bounds min_x= " < < rli . min_x < < " , max_x= " < < rli . max_x < < std : : endl ;
OSG_NOTICE < < " scene bounds min_y= " < < rli . min_y < < " , max_y= " < < rli . max_y < < std : : endl ;
OSG_NOTICE < < " scene bounds min_z= " < < rli . min_z < < " , max_z= " < < rli . max_z < < std : : endl ;
# endif
#if 0
double widest_x = osg : : maximum ( fabs ( rli . min_x ) , fabs ( rli . max_x ) ) ;
double widest_y = osg : : maximum ( fabs ( rli . min_y ) , fabs ( rli . max_y ) ) ;
double widest_z = osg : : maximum ( fabs ( rli . min_z ) , fabs ( rli . max_z ) ) ;
# endif
# if 1
# if 1
convexHull . clip ( osg : : Plane ( 1.0 , 0.0 , 0.0 , - rli . min_x ) ) ;
convexHull . clip ( osg : : Plane ( - 1.0 , 0.0 , 0.0 , rli . max_x ) ) ;
convexHullUnextended . clip ( osg : : Plane ( 1.0 , 0.0 , 0.0 , - rli . min_x ) ) ;
convexHullUnextended . clip ( osg : : Plane ( - 1.0 , 0.0 , 0.0 , rli . max_x ) ) ;
# else
convexHull . clip ( osg : : Plane ( 1.0 , 0.0 , 0.0 , widest_x ) ) ;
convexHull . clip ( osg : : Plane ( - 1.0 , 0.0 , 0.0 , widest_x ) ) ;
# endif
# if 1
convexHull . clip ( osg : : Plane ( 0.0 , 1.0 , 0.0 , - rli . min_y ) ) ;
convexHull . clip ( osg : : Plane ( 0.0 , - 1.0 , 0.0 , rli . max_y ) ) ;
convexHullUnextended . clip ( osg : : Plane ( 0.0 , 1.0 , 0.0 , - rli . min_y ) ) ;
convexHullUnextended . clip ( osg : : Plane ( 0.0 , - 1.0 , 0.0 , rli . max_y ) ) ;
# endif
# endif
# if 1
convexHull . clip ( osg : : Plane ( 0.0 , 0.0 , 1.0 , - rli . min_z ) ) ;
convexHull . clip ( osg : : Plane ( 0.0 , 0.0 , - 1.0 , rli . max_z ) ) ;
convexHullUnextended . clip ( osg : : Plane ( 0.0 , 0.0 , 1.0 , - rli . min_z ) ) ;
convexHullUnextended . clip ( osg : : Plane ( 0.0 , 0.0 , - 1.0 , rli . max_z ) ) ;
# elif 0
convexHull . clip ( osg : : Plane ( 0.0 , 0.0 , 1.0 , 1.0 ) ) ;
convexHull . clip ( osg : : Plane ( 0.0 , 0.0 , - 1.0 , 1.0 ) ) ;
# endif
#if 0
OSG_NOTICE < < " widest_x = " < < widest_x < < std : : endl ;
OSG_NOTICE < < " widest_y = " < < widest_y < < std : : endl ;
OSG_NOTICE < < " widest_z = " < < widest_z < < std : : endl ;
# endif
}
# endif
#if 0
convexHull . output ( osg : : notify ( osg : : NOTICE ) ) ;
OSG_NOTICE < < " after clipped ls ConvexHull xMin= " < < convexHull . min ( 0 ) < < " , xMax= " < < convexHull . max ( 0 ) < < std : : endl ;
OSG_NOTICE < < " after clipped ls ConvexHull yMin= " < < convexHull . min ( 1 ) < < " , yMax= " < < convexHull . max ( 1 ) < < std : : endl ;
OSG_NOTICE < < " after clipped ls ConvexHull zMin= " < < convexHull . min ( 2 ) < < " , zMax= " < < convexHull . max ( 2 ) < < std : : endl ;
# endif
double xMin = - 1.0 , xMax = 1.0 ;
double yMin = - 1.0 , yMax = 1.0 ;
double zMin = - 1.0 , zMax = 1.0 ;
if ( convexHull . valid ( ) )
{
double widest_x = osg : : maximum ( fabs ( convexHull . min ( 0 ) ) , fabs ( convexHull . max ( 0 ) ) ) ;
xMin = osg : : maximum ( - 1.0 , - widest_x ) ;
xMax = osg : : minimum ( 1.0 , widest_x ) ;
yMin = osg : : maximum ( - 1.0 , convexHull . min ( 1 ) ) ;
yMax = osg : : minimum ( 1.0 , convexHull . max ( 1 ) ) ;
}
else
{
// clipping of convex hull has invalidated it, so reset it so later checks on it provide valid results.
convexHull . setToFrustum ( frustum ) ;
convexHull . transform ( light_vp ) ;
}
#if 0
OSG_NOTICE < < " xMin = " < < xMin < < " , \t xMax = " < < xMax < < std : : endl ;
OSG_NOTICE < < " yMin = " < < yMin < < " , \t yMax = " < < yMax < < std : : endl ;
OSG_NOTICE < < " zMin = " < < zMin < < " , \t zMax = " < < zMax < < std : : endl ;
# endif
# if 1
// we always want the lightspace to include the computed near plane.
zMin = - 1.0 ;
if ( xMin ! = - 1.0 | | yMin ! = - 1.0 | | zMin ! = - 1.0 | |
xMax ! = 1.0 | | yMax ! = 1.0 | | zMax ! = 1.0 )
{
osg : : Matrix m ;
m . makeTranslate ( osg : : Vec3d ( - 0.5 * ( xMax + xMin ) ,
- 0.5 * ( yMax + yMin ) ,
- 0.5 * ( zMax + zMin ) ) ) ;
m . postMultScale ( osg : : Vec3d ( 2.0 / ( xMax - xMin ) ,
2.0 / ( yMax - yMin ) ,
2.0 / ( zMax - zMin ) ) ) ;
convexHull . transform ( m ) ;
convexHullUnextended . transform ( m ) ;
light_p . postMult ( m ) ;
light_vp = light_v * light_p ;
#if 0
OSG_NOTICE < < " Adjusting projection matrix " < < m < < std : : endl ;
convexHull . output ( osg : : notify ( osg : : NOTICE ) ) ;
# endif
camera - > setProjectionMatrix ( light_p ) ;
}
# endif
osg : : Vec3d eye_v = frustum . eye * light_v ;
//osg::Vec3d centerNearPlane_v = frustum.centerNearPlane * light_v;
osg : : Vec3d center_v = frustum . center * light_v ;
osg : : Vec3d viewdir_v = center_v - eye_v ; viewdir_v . normalize ( ) ;
double dotProduct_v = lightdir * viewdir_v ;
double gamma_v = acos ( dotProduct_v ) ;
if ( gamma_v < osg : : DegreesToRadians ( settings - > getPerspectiveShadowMapCutOffAngle ( ) ) | | gamma_v > osg : : DegreesToRadians ( 180 - settings - > getPerspectiveShadowMapCutOffAngle ( ) ) )
{
// OSG_NOTICE<<"Light and view vectors near parallel - use standard shadow map."<<std::endl;
return true ;
}
//OSG_NOTICE<<"gamma="<<osg::RadiansToDegrees(gamma_v)<<std::endl;
//OSG_NOTICE<<"eye_v="<<eye_v<<std::endl;
//OSG_NOTICE<<"viewdir_v="<<viewdir_v<<std::endl;
osg : : Vec3d eye_ls = frustum . eye * light_vp ;
#if 0
if ( eye_ls . y ( ) > - 1.0 )
{
OSG_NOTICE < < " Eye point within light space - use standard shadow map. " < < std : : endl ;
return true ;
}
# endif
//osg::Vec3d centerNearPlane_ls = frustum.centerNearPlane * light_vp;
//osg::Vec3d centerFarPlane_ls = frustum.centerFarPlane * light_vp;
osg : : Vec3d center_ls = frustum . center * light_vp ;
osg : : Vec3d viewdir_ls = center_ls - eye_ls ; viewdir_ls . normalize ( ) ;
osg : : Vec3d side = lightdir ^ viewdir_ls ; side . normalize ( ) ;
osg : : Vec3d up = side ^ lightdir ;
double d = 2.0 ;
double alpha = osg : : DegreesToRadians ( 30.0 ) ;
double n = tan ( alpha ) * tan ( osg : : PI_2 - gamma_v ) * tan ( osg : : PI_2 - gamma_v ) ;
//double n = tan(alpha)*tan(osg::PI_2-gamma_v);
//OSG_NOTICE<<"n = "<<n<<", eye_ls.y()="<<eye_ls.y()<<", eye_v="<<eye_v<<", eye="<<frustum.eye<<std::endl;
double min_n = osg : : maximum ( - 1.0 - eye_ls . y ( ) , settings - > getMinimumShadowMapNearFarRatio ( ) ) ;
if ( n < min_n )
{
//OSG_NOTICE<<"Clamping n to eye point"<<std::endl;
n = min_n ;
}
//n = min_n;
//n = 0.01;
//n = z_n;
double f = n + d ;
double a = ( f + n ) / ( f - n ) ;
double b = - 2.0 * f * n / ( f - n ) ;
osg : : Vec3d virtual_eye ( 0.0 , - 1.0 - n , eye_ls . z ( ) ) ;
osg : : Matrixd lightView ;
lightView . makeLookAt ( virtual_eye , virtual_eye + lightdir , up ) ;
#if 0
OSG_NOTICE < < " n = " < < n < < " , f= " < < f < < std : : endl ;
OSG_NOTICE < < " eye_ls = " < < eye_ls < < " , virtual_eye= " < < virtual_eye < < std : : endl ;
OSG_NOTICE < < " frustum.eyes= " < < frustum . eye < < std : : endl ;
# endif
double min_x_ratio = 0.0 ;
double max_x_ratio = 0.0 ;
double min_z_ratio = dbl_max ;
double max_z_ratio = - dbl_max ;
min_x_ratio = convexHull . valid ( ) ? convexHull . minRatio ( virtual_eye , 0 ) : - dbl_max ;
max_x_ratio = convexHull . valid ( ) ? convexHull . maxRatio ( virtual_eye , 0 ) : dbl_max ;
//min_z_ratio = convexHull.minRatio(virtual_eye,2);
//max_z_ratio = convexHull.maxRatio(virtual_eye,2);
if ( convexHullUnextended . valid ( ) )
{
min_z_ratio = convexHullUnextended . minRatio ( virtual_eye , 2 ) ;
max_z_ratio = convexHullUnextended . maxRatio ( virtual_eye , 2 ) ;
}
#if 0
OSG_NOTICE < < " convexHull min_x_ratio = " < < min_x_ratio < < std : : endl ;
OSG_NOTICE < < " convexHull max_x_ratio = " < < max_x_ratio < < std : : endl ;
OSG_NOTICE < < " convexHull min_z_ratio = " < < min_z_ratio < < std : : endl ;
OSG_NOTICE < < " convexHull max_z_ratio = " < < max_z_ratio < < std : : endl ;
# endif
# if 1
if ( renderStage )
{
# if 1
osg : : ElapsedTime timer ;
# endif
RenderLeafTraverser < RenderLeafBounds > rli ;
rli . set ( light_p , virtual_eye , n ) ;
rli . traverse ( renderStage ) ;
if ( rli . numRenderLeaf = = 0 )
{
return false ;
}
#if 0
OSG_NOTICE < < " Time for RenderLeafTraverser " < < timer . elapsedTime_m ( ) < < " ms, number of render leaves " < < rli . numRenderLeaf < < std : : endl ;
OSG_NOTICE < < " scene bounds min_x= " < < rli . min_x < < " , max_x= " < < rli . max_x < < std : : endl ;
OSG_NOTICE < < " scene bounds min_y= " < < rli . min_y < < " , max_y= " < < rli . max_y < < std : : endl ;
OSG_NOTICE < < " scene bounds min_z= " < < rli . min_z < < " , max_z= " < < rli . max_z < < std : : endl ;
OSG_NOTICE < < " min_x_ratio= " < < rli . min_x_ratio < < " , max_x_ratio= " < < rli . max_x_ratio < < std : : endl ;
OSG_NOTICE < < " min_z_ratio= " < < rli . min_z_ratio < < " , max_z_ratio= " < < rli . max_z_ratio < < std : : endl ;
# endif
if ( rli . min_x_ratio > min_x_ratio ) min_x_ratio = rli . min_x_ratio ;
if ( rli . max_x_ratio < max_x_ratio ) max_x_ratio = rli . max_x_ratio ;
if ( min_z_ratio = = dbl_max | | rli . min_z_ratio > min_z_ratio )
min_z_ratio = rli . min_z_ratio ;
if ( max_z_ratio = = - dbl_max | | rli . max_z_ratio < max_z_ratio )
max_z_ratio = rli . max_z_ratio ;
}
# endif
double best_x_ratio = osg : : maximum ( fabs ( min_x_ratio ) , fabs ( max_x_ratio ) ) ;
double best_z_ratio = osg : : maximum ( fabs ( min_z_ratio ) , fabs ( max_z_ratio ) ) ;
//best_z_ratio = osg::maximum(1.0, best_z_ratio);
#if 0
OSG_NOTICE < < " min_x_ratio = " < < min_x_ratio < < std : : endl ;
OSG_NOTICE < < " max_x_ratio = " < < max_x_ratio < < std : : endl ;
OSG_NOTICE < < " best_x_ratio = " < < best_x_ratio < < std : : endl ;
OSG_NOTICE < < " min_z_ratio = " < < min_z_ratio < < std : : endl ;
OSG_NOTICE < < " max_z_ratio = " < < max_z_ratio < < std : : endl ;
OSG_NOTICE < < " best_z_ratio = " < < best_z_ratio < < std : : endl ;
# endif
//best_z_ratio *= 10.0;
osg : : Matrixd lightPerspective ( 1.0 / best_x_ratio , 0.0 , 0.0 , 0.0 ,
0.0 , a , 0.0 , 1.0 ,
0.0 , 0.0 , 1.0 / best_z_ratio , 0.0 ,
0.0 , b , 0.0 , 0.0 ) ;
osg : : Matrixd light_persp = light_p * lightView * lightPerspective ;
#if 0
OSG_NOTICE < < " light_p = " < < light_p < < std : : endl ;
OSG_NOTICE < < " lightView = " < < lightView < < std : : endl ;
OSG_NOTICE < < " lightPerspective = " < < lightPerspective < < std : : endl ;
OSG_NOTICE < < " light_persp result = " < < light_persp < < std : : endl ;
# endif
camera - > setProjectionMatrix ( light_persp ) ;
return true ;
}
bool MWShadowTechnique : : assignTexGenSettings ( osgUtil : : CullVisitor * cv , osg : : Camera * camera , unsigned int textureUnit , osg : : TexGen * texgen )
{
OSG_INFO < < " assignTexGenSettings() textureUnit= " < < textureUnit < < " texgen= " < < texgen < < std : : endl ;
texgen - > setMode ( osg : : TexGen : : EYE_LINEAR ) ;
// compute the matrix which takes a vertex from local coords into tex coords
// We actually use two matrices one used to define texgen
// and second that will be used as modelview when appling to OpenGL
texgen - > setPlanesFromMatrix ( camera - > getProjectionMatrix ( ) *
osg : : Matrix : : translate ( 1.0 , 1.0 , 1.0 ) *
osg : : Matrix : : scale ( 0.5 , 0.5 , 0.5 ) ) ;
// Place texgen with modelview which removes big offsets (making it float friendly)
osg : : ref_ptr < osg : : RefMatrix > refMatrix =
new osg : : RefMatrix ( camera - > getInverseViewMatrix ( ) * ( * ( cv - > getModelViewMatrix ( ) ) ) ) ;
osgUtil : : RenderStage * currentStage = cv - > getCurrentRenderBin ( ) - > getStage ( ) ;
currentStage - > getPositionalStateContainer ( ) - > addPositionedTextureAttribute ( textureUnit , refMatrix . get ( ) , texgen ) ;
return true ;
}
void MWShadowTechnique : : cullShadowReceivingScene ( osgUtil : : CullVisitor * cv ) const
{
OSG_INFO < < " cullShadowReceivingScene() " < < std : : endl ;
// record the traversal mask on entry so we can reapply it later.
unsigned int traversalMask = cv - > getTraversalMask ( ) ;
cv - > setTraversalMask ( traversalMask & _shadowedScene - > getShadowSettings ( ) - > getReceivesShadowTraversalMask ( ) ) ;
_shadowedScene - > osg : : Group : : traverse ( * cv ) ;
cv - > setTraversalMask ( traversalMask ) ;
return ;
}
void MWShadowTechnique : : cullShadowCastingScene ( osgUtil : : CullVisitor * cv , osg : : Camera * camera ) const
{
OSG_INFO < < " cullShadowCastingScene() " < < std : : endl ;
// record the traversal mask on entry so we can reapply it later.
unsigned int traversalMask = cv - > getTraversalMask ( ) ;
cv - > setTraversalMask ( traversalMask & _shadowedScene - > getShadowSettings ( ) - > getCastsShadowTraversalMask ( ) ) ;
if ( camera ) camera - > accept ( * cv ) ;
cv - > setTraversalMask ( traversalMask ) ;
return ;
}
osg : : StateSet * MWShadowTechnique : : prepareStateSetForRenderingShadow ( ViewDependentData & vdd , unsigned int traversalNumber ) const
{
OSG_INFO < < " prepareStateSetForRenderingShadow() " < < vdd . getStateSet ( traversalNumber ) < < std : : endl ;
osg : : ref_ptr < osg : : StateSet > stateset = vdd . getStateSet ( traversalNumber ) ;
stateset - > clear ( ) ;
stateset - > setTextureAttributeAndModes ( 0 , _fallbackBaseTexture . get ( ) , osg : : StateAttribute : : ON ) ;
for ( const auto & uniform : _uniforms [ traversalNumber % 2 ] )
{
OSG_INFO < < " addUniform( " < < uniform - > getName ( ) < < " ) " < < std : : endl ;
stateset - > addUniform ( uniform ) ;
}
if ( _program . valid ( ) )
{
stateset - > setAttribute ( _program . get ( ) ) ;
}
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 ) ;
// if no texture units have been activated for this light then no shadow state required.
if ( pl . textureUnits . empty ( ) ) continue ;
for ( LightData : : ActiveTextureUnits : : iterator atu_itr = pl . textureUnits . begin ( ) ;
atu_itr ! = pl . textureUnits . end ( ) ;
+ + atu_itr )
{
OSG_INFO < < " Need to assign state for " < < * atu_itr < < std : : endl ;
}
}
const ShadowSettings * settings = getShadowedScene ( ) - > getShadowSettings ( ) ;
unsigned int shadowMapModeValue = settings - > getUseOverrideForShadowMapTexture ( ) ?
osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE :
osg : : StateAttribute : : ON ;
ShadowDataList & sdl = vdd . getShadowDataList ( ) ;
for ( ShadowDataList : : iterator itr = sdl . begin ( ) ;
itr ! = sdl . end ( ) ;
+ + itr )
{
// 3. create per light/per shadow map division of lightspace/frustum
// create a list of light/shadow map data structures
ShadowData & sd = ( * * itr ) ;
OSG_INFO < < " ShadowData for " < < sd . _textureUnit < < std : : endl ;
stateset - > setTextureAttributeAndModes ( sd . _textureUnit , sd . _texture . get ( ) , shadowMapModeValue ) ;
stateset - > setTextureMode ( sd . _textureUnit , GL_TEXTURE_GEN_S , osg : : StateAttribute : : ON ) ;
stateset - > setTextureMode ( sd . _textureUnit , GL_TEXTURE_GEN_T , osg : : StateAttribute : : ON ) ;
stateset - > setTextureMode ( sd . _textureUnit , GL_TEXTURE_GEN_R , osg : : StateAttribute : : ON ) ;
stateset - > setTextureMode ( sd . _textureUnit , GL_TEXTURE_GEN_Q , osg : : StateAttribute : : ON ) ;
}
return stateset ;
}
void MWShadowTechnique : : resizeGLObjectBuffers ( unsigned int /*maxSize*/ )
{
// the way that ViewDependentData is mapped shouldn't
}
void MWShadowTechnique : : releaseGLObjects ( osg : : State * state ) const
{
std : : lock_guard < std : : mutex > lock ( _viewDependentDataMapMutex ) ;
for ( ViewDependentDataMap : : const_iterator itr = _viewDependentDataMap . begin ( ) ;
itr ! = _viewDependentDataMap . end ( ) ;
+ + itr )
{
ViewDependentData * vdd = itr - > second . get ( ) ;
if ( vdd )
{
vdd - > releaseGLObjects ( state ) ;
}
}
if ( _debugHud )
_debugHud - > releaseGLObjects ( state ) ;
}
class DoubleBufferCallback : public osg : : Callback
{
public :
DoubleBufferCallback ( osg : : NodeList & children ) : mChildren ( children ) { }
bool run ( osg : : Object * node , osg : : Object * visitor ) override
{
// We can't use a static cast as NodeVisitor virtually inherits from Object
osg : : ref_ptr < osg : : NodeVisitor > nodeVisitor = visitor - > asNodeVisitor ( ) ;
unsigned int traversalNumber = nodeVisitor - > getTraversalNumber ( ) ;
mChildren [ traversalNumber % 2 ] - > accept ( * nodeVisitor ) ;
return true ;
}
protected :
osg : : NodeList mChildren ;
} ;
SceneUtil : : MWShadowTechnique : : DebugHUD : : DebugHUD ( int numberOfShadowMapsPerLight ) : mDebugProgram ( new osg : : Program )
{
osg : : ref_ptr < osg : : Shader > vertexShader = new osg : : Shader ( osg : : Shader : : VERTEX , debugVertexShaderSource ) ;
mDebugProgram - > addShader ( vertexShader ) ;
osg : : ref_ptr < osg : : Shader > fragmentShader = new osg : : Shader ( osg : : Shader : : FRAGMENT , debugFragmentShaderSource ) ;
mDebugProgram - > addShader ( fragmentShader ) ;
osg : : ref_ptr < osg : : Program > frustumProgram = new osg : : Program ;
vertexShader = new osg : : Shader ( osg : : Shader : : VERTEX , debugFrustumVertexShaderSource ) ;
frustumProgram - > addShader ( vertexShader ) ;
fragmentShader = new osg : : Shader ( osg : : Shader : : FRAGMENT , debugFrustumFragmentShaderSource ) ;
frustumProgram - > addShader ( fragmentShader ) ;
for ( auto & frustumGeometry : mFrustumGeometries )
{
frustumGeometry = new osg : : Geometry ( ) ;
frustumGeometry - > setCullingActive ( false ) ;
frustumGeometry - > getOrCreateStateSet ( ) - > setAttributeAndModes ( frustumProgram , osg : : StateAttribute : : ON ) ;
}
osg : : ref_ptr < osg : : DrawElementsUShort > frustumDrawElements = new osg : : DrawElementsUShort ( osg : : PrimitiveSet : : LINE_STRIP ) ;
for ( auto & geom : mFrustumGeometries )
geom - > addPrimitiveSet ( frustumDrawElements ) ;
frustumDrawElements - > push_back ( 0 ) ;
frustumDrawElements - > push_back ( 1 ) ;
frustumDrawElements - > push_back ( 2 ) ;
frustumDrawElements - > push_back ( 3 ) ;
frustumDrawElements - > push_back ( 0 ) ;
frustumDrawElements - > push_back ( 4 ) ;
frustumDrawElements - > push_back ( 5 ) ;
frustumDrawElements - > push_back ( 6 ) ;
frustumDrawElements - > push_back ( 7 ) ;
frustumDrawElements - > push_back ( 4 ) ;
frustumDrawElements = new osg : : DrawElementsUShort ( osg : : PrimitiveSet : : LINES ) ;
for ( auto & geom : mFrustumGeometries )
geom - > addPrimitiveSet ( frustumDrawElements ) ;
frustumDrawElements - > push_back ( 1 ) ;
frustumDrawElements - > push_back ( 5 ) ;
frustumDrawElements - > push_back ( 2 ) ;
frustumDrawElements - > push_back ( 6 ) ;
frustumDrawElements - > push_back ( 3 ) ;
frustumDrawElements - > push_back ( 7 ) ;
for ( int i = 0 ; i < numberOfShadowMapsPerLight ; + + i )
addAnotherShadowMap ( ) ;
}
void SceneUtil : : MWShadowTechnique : : DebugHUD : : draw ( osg : : ref_ptr < osg : : Texture2D > texture , unsigned int shadowMapNumber , const osg : : Matrixd & matrix , osgUtil : : CullVisitor & cv )
{
// It might be possible to change shadow settings at runtime
if ( shadowMapNumber > mDebugCameras . size ( ) )
addAnotherShadowMap ( ) ;
osg : : ref_ptr < osg : : StateSet > stateSet = new osg : : StateSet ( ) ;
stateSet - > setTextureAttributeAndModes ( sDebugTextureUnit , texture , osg : : StateAttribute : : ON ) ;
auto frustumUniform = mFrustumUniforms [ cv . getTraversalNumber ( ) % 2 ] [ shadowMapNumber ] ;
frustumUniform - > set ( matrix ) ;
stateSet - > addUniform ( frustumUniform ) ;
// Some of these calls may be superfluous.
unsigned int traversalMask = cv . getTraversalMask ( ) ;
cv . setTraversalMask ( mDebugGeometry [ shadowMapNumber ] - > getNodeMask ( ) ) ;
cv . pushStateSet ( stateSet ) ;
mDebugCameras [ shadowMapNumber ] - > accept ( cv ) ;
cv . popStateSet ( ) ;
cv . setTraversalMask ( traversalMask ) ;
// cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
}
void SceneUtil : : MWShadowTechnique : : DebugHUD : : releaseGLObjects ( osg : : State * state ) const
{
for ( auto const & camera : mDebugCameras )
camera - > releaseGLObjects ( state ) ;
mDebugProgram - > releaseGLObjects ( state ) ;
for ( auto const & node : mDebugGeometry )
node - > releaseGLObjects ( state ) ;
for ( auto const & node : mFrustumTransforms )
node - > releaseGLObjects ( state ) ;
for ( auto const & node : mFrustumGeometries )
node - > releaseGLObjects ( state ) ;
}
void SceneUtil : : MWShadowTechnique : : DebugHUD : : setFrustumVertices ( osg : : ref_ptr < osg : : Vec3Array > vertices , unsigned int traversalNumber )
{
mFrustumGeometries [ traversalNumber % 2 ] - > setVertexArray ( vertices ) ;
}
void SceneUtil : : MWShadowTechnique : : DebugHUD : : addAnotherShadowMap ( )
{
unsigned int shadowMapNumber = mDebugCameras . size ( ) ;
mDebugCameras . push_back ( new osg : : Camera ) ;
mDebugCameras [ shadowMapNumber ] - > setViewport ( 200 * shadowMapNumber , 0 , 200 , 200 ) ;
mDebugCameras [ shadowMapNumber ] - > setRenderOrder ( osg : : Camera : : POST_RENDER ) ;
mDebugCameras [ shadowMapNumber ] - > setClearColor ( osg : : Vec4 ( 1.0 , 1.0 , 0.0 , 1.0 ) ) ;
mDebugCameras [ shadowMapNumber ] - > getOrCreateStateSet ( ) - > setMode ( GL_DEPTH_TEST , osg : : StateAttribute : : OFF ) ;
mDebugGeometry . emplace_back ( osg : : createTexturedQuadGeometry ( osg : : Vec3 ( - 1 , - 1 , 0 ) , osg : : Vec3 ( 2 , 0 , 0 ) , osg : : Vec3 ( 0 , 2 , 0 ) ) ) ;
mDebugGeometry [ shadowMapNumber ] - > setCullingActive ( false ) ;
mDebugCameras [ shadowMapNumber ] - > addChild ( mDebugGeometry [ shadowMapNumber ] ) ;
osg : : ref_ptr < osg : : StateSet > stateSet = mDebugGeometry [ shadowMapNumber ] - > getOrCreateStateSet ( ) ;
stateSet - > setAttributeAndModes ( mDebugProgram , osg : : StateAttribute : : ON ) ;
osg : : ref_ptr < osg : : Uniform > textureUniform = new osg : : Uniform ( " texture " , sDebugTextureUnit ) ;
//textureUniform->setType(osg::Uniform::SAMPLER_2D);
stateSet - > addUniform ( textureUniform . get ( ) ) ;
mFrustumTransforms . push_back ( new osg : : Group ) ;
osg : : NodeList frustumGeometryNodeList ( mFrustumGeometries . cbegin ( ) , mFrustumGeometries . cend ( ) ) ;
mFrustumTransforms [ shadowMapNumber ] - > setCullCallback ( new DoubleBufferCallback ( frustumGeometryNodeList ) ) ;
mFrustumTransforms [ shadowMapNumber ] - > setCullingActive ( false ) ;
mDebugCameras [ shadowMapNumber ] - > addChild ( mFrustumTransforms [ shadowMapNumber ] ) ;
for ( auto & uniformVector : mFrustumUniforms )
uniformVector . push_back ( new osg : : Uniform ( osg : : Uniform : : FLOAT_MAT4 , " transform " ) ) ;
}