2: minor tweak for a DebugHUD drawn improperly case when multiple slave views shared one window. It now uses slave view viewport to correctly position DebugHUD. 3: deactivated ConvexPolyhedron notifications (they were accidentaly activated when you replaced osg::notify calls with OSG_NOTIFY macro). These warnings are useful only for shadow map developer working on shadow volume optimizations. So there is no sense in having them active all the time."
652 lines
25 KiB
C++
652 lines
25 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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.
|
|
*
|
|
* ViewDependentShadow codes Copyright (C) 2008 Wojciech Lewandowski
|
|
* Thanks to to my company http://www.ai.com.pl for allowing me free this work.
|
|
*/
|
|
#include <osgShadow/ShadowedScene>
|
|
#include <osgShadow/DebugShadowMap>
|
|
#include <osgShadow/ConvexPolyhedron>
|
|
#include <osgUtil/RenderLeaf>
|
|
#include <osgDB/WriteFile>
|
|
#include <osg/Geometry>
|
|
#include <osg/PrimitiveSet>
|
|
#include <osg/MatrixTransform>
|
|
#include <osg/Depth>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
|
|
using namespace osgShadow;
|
|
|
|
|
|
#define VECTOR_LENGTH( v ) ( sizeof(v)/sizeof(v[0]) )
|
|
|
|
#define DEFAULT_DEBUG_HUD_SIZE_X 256
|
|
#define DEFAULT_DEBUG_HUD_SIZE_Y 256
|
|
#define DEFAULT_DEBUG_HUD_ORIGIN_X 8
|
|
#define DEFAULT_DEBUG_HUD_ORIGIN_Y 8
|
|
|
|
DebugShadowMap::DebugShadowMap():
|
|
BaseClass(),
|
|
_hudSize( 2, 2 ),
|
|
_hudOrigin( -1, -1 ),
|
|
_viewportSize( DEFAULT_DEBUG_HUD_SIZE_X, DEFAULT_DEBUG_HUD_SIZE_Y ),
|
|
_viewportOrigin( DEFAULT_DEBUG_HUD_ORIGIN_X, DEFAULT_DEBUG_HUD_ORIGIN_Y ),
|
|
_orthoSize( 2, 2 ),
|
|
_orthoOrigin( -1, -1 ),
|
|
_doDebugDraw( false )
|
|
{
|
|
|
|
// Why this fancy 24 bit depth to 24 bit rainbow colors shader ?
|
|
//
|
|
// Depth values cannot be easily cast on color component because they are:
|
|
// a) 24 or 32 bit and we loose lots of precision when cast on 8 bit
|
|
// b) depth value distribution is non linear due to projection division
|
|
// when cast on componenent color there is usually very minor shade variety
|
|
// and its often difficult to notice that there is anything in the buffer
|
|
//
|
|
// Shader looks complex but it is used only for debug head-up rectangle
|
|
// so performance impact is not significant.
|
|
|
|
_depthColorFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
|
|
#if 0
|
|
"uniform sampler2D texture; \n"
|
|
" \n"
|
|
"void main(void) \n"
|
|
"{ \n"
|
|
" float f = texture2D( texture, vec3( gl_TexCoord[0].xy, 1.0).xy ).r; \n"
|
|
" gl_FragColor = vec4( 0.0, 1.0 - f, 0.5 - f, 0.5 ); \n"
|
|
"} \n"
|
|
#else
|
|
"uniform sampler2D texture; \n"
|
|
" \n"
|
|
"void main(void) \n"
|
|
"{ \n"
|
|
" float f = texture2D( texture, vec3( gl_TexCoord[0].xy, 1.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 ) * gl_Color; \n"
|
|
"} \n"
|
|
#endif
|
|
); // end _depthColorFragmentShader
|
|
}
|
|
|
|
DebugShadowMap::DebugShadowMap
|
|
(const DebugShadowMap& copy, const osg::CopyOp& copyop) :
|
|
BaseClass(copy,copyop),
|
|
_hudSize( copy._hudSize ),
|
|
_hudOrigin( copy._hudOrigin ),
|
|
_viewportSize( copy._viewportSize ),
|
|
_viewportOrigin( copy._viewportOrigin ),
|
|
_orthoSize( copy._viewportOrigin ),
|
|
_orthoOrigin( copy._viewportOrigin ),
|
|
_doDebugDraw( copy._doDebugDraw )
|
|
{
|
|
if( copy._depthColorFragmentShader.valid() )
|
|
_depthColorFragmentShader =
|
|
dynamic_cast<osg::Shader*>
|
|
( copy._depthColorFragmentShader->clone(copyop) );
|
|
}
|
|
|
|
DebugShadowMap::~DebugShadowMap()
|
|
{
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::cull( void )
|
|
{
|
|
if( getDebugDraw() && !_cameraDebugHUD.valid() )
|
|
createDebugHUD();
|
|
|
|
BaseClass::ViewData::cull( );
|
|
|
|
cullDebugGeometry( );
|
|
}
|
|
|
|
bool DebugShadowMap::ViewData::DebugBoundingBox
|
|
( const osg::BoundingBox & bb, const char * name )
|
|
{
|
|
bool result = false;
|
|
#if defined( _DEBUG ) || defined( DEBUG )
|
|
if( !name ) name = "";
|
|
|
|
osg::BoundingBox & bb_prev = _boundingBoxMap[ std::string( name ) ];
|
|
|
|
result = bb.center() != bb_prev.center() || bb.radius() != bb_prev.radius();
|
|
if( result )
|
|
std::cout << "Box<" << name << "> ("
|
|
<< ( bb._max._v[0] + bb._min._v[0] ) * 0.5 << " "
|
|
<< ( bb._max._v[1] + bb._min._v[1] ) * 0.5 << " "
|
|
<< ( bb._max._v[2] + bb._min._v[2] ) * 0.5 << ") ["
|
|
<< ( bb._max._v[0] - bb._min._v[0] ) << " "
|
|
<< ( bb._max._v[1] - bb._min._v[1] ) << " "
|
|
<< ( bb._max._v[2] - bb._min._v[2] ) << "] "
|
|
<< std::endl;
|
|
|
|
bb_prev = bb;
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
bool DebugShadowMap::ViewData::DebugPolytope
|
|
( const osg::Polytope & p, const char * name )
|
|
{
|
|
bool result = false;
|
|
#if defined( _DEBUG ) || defined( DEBUG )
|
|
if( !name ) name = "";
|
|
|
|
osg::Polytope & p_prev = _polytopeMap[ std::string( name ) ];
|
|
|
|
result = ( p.getPlaneList() != p_prev.getPlaneList() );
|
|
|
|
if( result ) {
|
|
std::cout << "Polytope<" << name
|
|
<< "> size(" << p.getPlaneList().size() << ")"
|
|
<< std::endl;
|
|
|
|
if( p.getPlaneList().size() == p_prev.getPlaneList().size() ) {
|
|
for( unsigned i = 0; i < p.getPlaneList().size(); ++i )
|
|
{
|
|
if( p.getPlaneList()[i] != p_prev.getPlaneList()[i] )
|
|
{
|
|
std::cout << "Plane<" << i
|
|
<< "> ("
|
|
<< p.getPlaneList()[i].asVec4()[0] << ", "
|
|
<< p.getPlaneList()[i].asVec4()[1] << ", "
|
|
<< p.getPlaneList()[i].asVec4()[2] << ", "
|
|
<< p.getPlaneList()[i].asVec4()[3] << ")"
|
|
<< std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
p_prev = p;
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
bool DebugShadowMap::ViewData::DebugMatrix
|
|
( const osg::Matrix & m, const char * name )
|
|
{
|
|
bool result = false;
|
|
#if defined( _DEBUG ) || defined( DEBUG )
|
|
if( !name ) name = "";
|
|
|
|
osg::Matrix & m_prev = _matrixMap[ std::string( name ) ];
|
|
|
|
result = ( m != m_prev );
|
|
|
|
if( result )
|
|
std::cout << "Matrix<" << name << "> " << std::endl
|
|
<<"[ " << m(0,0) << " " << m(0,1) << " " << m(0,2) << " " << m(0,3) << " ] " << std::endl
|
|
<<"[ " << m(1,0) << " " << m(1,1) << " " << m(1,2) << " " << m(1,3) << " ] " << std::endl
|
|
<<"[ " << m(2,0) << " " << m(2,1) << " " << m(2,2) << " " << m(2,3) << " ] " << std::endl
|
|
<<"[ " << m(3,0) << " " << m(3,1) << " " << m(3,2) << " " << m(3,3) << " ] " << std::endl;
|
|
|
|
m_prev = m;
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::setDebugPolytope
|
|
( const char * name, const ConvexPolyhedron & polytope,
|
|
osg::Vec4 colorOutline, osg::Vec4 colorInside )
|
|
{
|
|
if( !getDebugDraw() ) return;
|
|
|
|
if( &polytope == NULL ) { // delete
|
|
PolytopeGeometry & pg = _polytopeGeometryMap[ std::string( name ) ];
|
|
for( unsigned int i = 0; i < VECTOR_LENGTH( pg._geometry ) ; i++ )
|
|
{
|
|
if( pg._geometry[i].valid() ) {
|
|
if( _geode[i].valid() &&
|
|
_geode[i]->containsDrawable( pg._geometry[i].get() ) )
|
|
_geode[i]->removeDrawable( pg._geometry[i].get() );
|
|
|
|
pg._geometry[i] = NULL;
|
|
}
|
|
}
|
|
_polytopeGeometryMap.erase( std::string( name ) );
|
|
} else { // update
|
|
PolytopeGeometry & pg = _polytopeGeometryMap[ std::string( name ) ];
|
|
|
|
pg._polytope = polytope;
|
|
if( colorOutline.a() > 0 )
|
|
pg._colorOutline = colorOutline;
|
|
if( colorInside.a() > 0 )
|
|
pg._colorInside = colorInside;
|
|
|
|
for( unsigned int i = 0; i < VECTOR_LENGTH( pg._geometry ) ; i++ )
|
|
{
|
|
if( !pg._geometry[i].valid() ) {
|
|
pg._geometry[i] = new osg::Geometry;
|
|
pg._geometry[i]->setDataVariance( osg::Object::DYNAMIC );
|
|
pg._geometry[i]->setUseDisplayList( false );
|
|
pg._geometry[i]->setSupportsDisplayList( false );
|
|
}
|
|
|
|
if( _geode[i].valid() &&
|
|
!_geode[i]->containsDrawable( pg._geometry[i].get() ) ) {
|
|
osg::Geode::DrawableList & dl =
|
|
const_cast< osg::Geode::DrawableList &>
|
|
( _geode[i]->getDrawableList() );
|
|
dl.insert( dl.begin(), pg._geometry[i].get() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::updateDebugGeometry
|
|
( const osg::Camera * viewCam, const osg::Camera * shadowCam )
|
|
{
|
|
if( !getDebugDraw() ) return;
|
|
if( _polytopeGeometryMap.empty() ) return;
|
|
|
|
const int num = 2; // = VECTOR_LENGTH( PolytopeGeometry::_geometry );
|
|
|
|
osg::Matrix
|
|
transform[ num ] =
|
|
{ viewCam->getViewMatrix() *
|
|
// use near far clamped projection ( precomputed in cullDebugGeometry )
|
|
( _viewCamera==viewCam ? _viewProjection : viewCam->getProjectionMatrix() ),
|
|
shadowCam->getViewMatrix() * shadowCam->getProjectionMatrix() },
|
|
inverse[ num ] =
|
|
{ osg::Matrix::inverse( transform[0] ),
|
|
osg::Matrix::inverse( transform[1] ) };
|
|
|
|
#if 0
|
|
ConvexPolyhedron frustum[ num ];
|
|
for( int i = 0; i < num; i++ ) {
|
|
frustum[i].setToUnitFrustum( );
|
|
#if 1
|
|
frustum[i].transform( inverse[i], transform[i] );
|
|
#else
|
|
frustum[i].transform
|
|
( osg::Matrix::inverse( camera[i]->getProjectionMatrix() ),
|
|
camera[i]->getProjectionMatrix() );
|
|
frustum[i].transform
|
|
( osg::Matrix::inverse( camera[i]->getViewMatrix() ),
|
|
camera[i]->getViewMatrix() );
|
|
#endif
|
|
};
|
|
#else
|
|
osg::Polytope frustum[ num ];
|
|
for( int i = 0; i < num; i++ ) {
|
|
frustum[i].setToUnitFrustum( );
|
|
frustum[i].transformProvidingInverse( transform[i] );
|
|
}
|
|
#endif
|
|
|
|
transform[0] = viewCam->getViewMatrix();
|
|
inverse[0] = viewCam->getInverseViewMatrix();
|
|
|
|
for( PolytopeGeometryMap::iterator itr = _polytopeGeometryMap.begin();
|
|
itr != _polytopeGeometryMap.end();
|
|
++itr )
|
|
{
|
|
PolytopeGeometry & pg = itr->second;
|
|
|
|
for( int i = 0; i < num ; i++ )
|
|
{
|
|
|
|
ConvexPolyhedron cp( pg._polytope );
|
|
cp.cut( frustum[i] );
|
|
cp.transform( transform[i], inverse[i] );
|
|
|
|
pg._geometry[i] = cp.buildGeometry
|
|
( pg._colorOutline, pg._colorInside, pg._geometry[i].get() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::cullDebugGeometry( )
|
|
{
|
|
if( !getDebugDraw() ) return;
|
|
if( !_camera.valid() ) return;
|
|
|
|
// View camera may use clamping projection matrix after traversal.
|
|
// Since we need to know exact matrix for drawing the frusta,
|
|
// we have to compute it here in exactly the same way as cull visitor
|
|
// will after cull traversal completes view camera subgraph.
|
|
{
|
|
_viewProjection = *_cv->getProjectionMatrix();
|
|
_viewCamera = _cv->getRenderStage()->getCamera();
|
|
|
|
if( _cv->getComputeNearFarMode() ) {
|
|
|
|
// Redo steps from CullVisitor::popProjectionMatrix()
|
|
// which clamps projection matrix when Camera & Projection
|
|
// completes traversal of their children
|
|
|
|
// We have to do this now manually
|
|
// because we did not complete camera traversal yet but
|
|
// we need to know how this clamped projection matrix will be
|
|
|
|
_cv->computeNearPlane();
|
|
|
|
osgUtil::CullVisitor::value_type n = _cv->getCalculatedNearPlane();
|
|
osgUtil::CullVisitor::value_type f = _cv->getCalculatedFarPlane();
|
|
|
|
if( n < f )
|
|
_cv->clampProjectionMatrix( _viewProjection, n, f );
|
|
}
|
|
}
|
|
|
|
updateDebugGeometry( _viewCamera.get(), _camera.get() );
|
|
|
|
#if 1 // Add geometries of polytopes to main cam Render Stage
|
|
_transform[0]->accept( *_cv );
|
|
#else
|
|
for( PolytopeGeometryMap::iterator itr = _polytopeGeometryMap.begin();
|
|
itr != _polytopeGeometryMap.end();
|
|
++itr )
|
|
{
|
|
PolytopeGeometry & pg = itr->second;
|
|
_cv->pushStateSet( _geode[0]->getStateSet() );
|
|
_cv->addDrawableAndDepth( pg._geometry[0].get(), NULL, FLT_MAX );
|
|
_cv->popStateSet( );
|
|
}
|
|
#endif
|
|
|
|
// Add geometries of polytopes to hud cam Render Stage
|
|
_cameraDebugHUD->accept( *_cv );
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::init( ThisClass *st, osgUtil::CullVisitor *cv )
|
|
{
|
|
BaseClass::ViewData::init( st, cv );
|
|
|
|
_doDebugDrawPtr = &st->_doDebugDraw;
|
|
|
|
_hudSize = st->_hudSize;
|
|
_hudOrigin = st->_hudOrigin;
|
|
|
|
_viewportOrigin = st->_viewportOrigin;
|
|
_viewportSize = st->_viewportSize;
|
|
|
|
osg::Viewport * vp = cv->getViewport();
|
|
if( vp )
|
|
{
|
|
// view can be a slave that covers only a fraction of the screen
|
|
// so adjust debug hud location to proper viewport location
|
|
_viewportOrigin[0] += vp->x();
|
|
_viewportOrigin[1] += vp->y();
|
|
|
|
if( _viewportSize[0] > vp->width() - _viewportOrigin[0] )
|
|
_viewportSize[0] = vp->width() - _viewportOrigin[0];
|
|
|
|
if( _viewportSize[1] > vp->height() - _viewportOrigin[1] )
|
|
_viewportSize[1] = vp->height() - _viewportOrigin[1];
|
|
}
|
|
|
|
_orthoSize = st->_orthoSize;
|
|
_orthoOrigin = st->_orthoOrigin;
|
|
|
|
_depthColorFragmentShader = st->_depthColorFragmentShader;
|
|
|
|
// create placeholder geodeds for polytope geometries
|
|
// rest of their initialization will be performed during camera hud init
|
|
_geode[0] = new osg::Geode;
|
|
_geode[1] = new osg::Geode;
|
|
|
|
_cameraDebugHUD = NULL;//Force debug HUD rebuild ( if needed )
|
|
}
|
|
|
|
|
|
// Callback used by debugging hud to display Shadow Map to color buffer
|
|
// Had to do it this way because OSG does not allow to use
|
|
// the same GL Texture Id with different glTexParams.
|
|
// Callback simply turns compare mode off via GL while rendering hud and
|
|
// restores it before rendering the scene with shadows.
|
|
class DebugShadowMap::DrawableDrawWithDepthShadowComparisonOffCallback:
|
|
public osg::Drawable::DrawCallback
|
|
{
|
|
public:
|
|
DrawableDrawWithDepthShadowComparisonOffCallback( osg::Texture *pTex )
|
|
: _pTexture( pTex )
|
|
{
|
|
}
|
|
|
|
virtual void drawImplementation
|
|
( osg::RenderInfo & ri,const osg::Drawable* drawable ) const
|
|
{
|
|
ri.getState()->applyTextureAttribute( 0, _pTexture.get() );
|
|
|
|
// Turn off depth comparison mode
|
|
glTexParameteri( _pTexture->getTextureTarget(), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
|
|
|
|
drawable->drawImplementation(ri);
|
|
|
|
// Turn it back on
|
|
glTexParameteri( _pTexture->getTextureTarget(), GL_TEXTURE_COMPARE_MODE_ARB,
|
|
GL_COMPARE_R_TO_TEXTURE_ARB );
|
|
}
|
|
|
|
osg::ref_ptr< osg::Texture > _pTexture;
|
|
};
|
|
|
|
void DebugShadowMap::ViewData::dump( const char * filename )
|
|
{
|
|
osg::ref_ptr< osg::Group > root = new osg::Group;
|
|
osgUtil::CullVisitor * cv = _cv.get();
|
|
|
|
#if 1
|
|
osg::Group * cam = cv->getRenderStage()->getCamera();
|
|
|
|
for( unsigned int i = 0; i < cam->getNumChildren(); i++ )
|
|
{
|
|
root->addChild( cam->getChild( i ) );
|
|
}
|
|
#endif
|
|
|
|
root->addChild( _st->getShadowedScene() );
|
|
|
|
osg::ref_ptr< osg::MatrixTransform > transform = new osg::MatrixTransform;
|
|
root->addChild( transform.get() );
|
|
|
|
// updateDebugGeometry( _viewCamera.get(), _camera.get() );
|
|
|
|
for( PolytopeGeometryMap::iterator itr = _polytopeGeometryMap.begin();
|
|
itr != _polytopeGeometryMap.end();
|
|
++itr )
|
|
{
|
|
PolytopeGeometry & pg = itr->second;
|
|
int i = 0;
|
|
{
|
|
|
|
ConvexPolyhedron cp( pg._polytope );
|
|
|
|
pg._geometry[i] = cp.buildGeometry
|
|
( pg._colorOutline, pg._colorInside, pg._geometry[i].get() );
|
|
}
|
|
}
|
|
|
|
for( unsigned int i = 0; i < _transform[0]->getNumChildren(); i++ )
|
|
{
|
|
root->addChild( _transform[0]->getChild( i ) );
|
|
}
|
|
|
|
osgDB::writeNodeFile( *root, std::string( filename ) );
|
|
|
|
root->removeChildren( 0, root->getNumChildren() );
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::createDebugHUD( )
|
|
{
|
|
_cameraDebugHUD = new osg::Camera;
|
|
|
|
{ // Make sure default HUD layout makes sense
|
|
if( _hudSize[0] <= 0 ) _hudSize[0] = DEFAULT_DEBUG_HUD_SIZE_X;
|
|
if( _hudSize[1] <= 0 ) _hudSize[1] = DEFAULT_DEBUG_HUD_SIZE_Y;
|
|
|
|
if( _viewportSize[0] <= 0 ) _viewportSize[0] = _hudSize[0];
|
|
if( _viewportSize[1] <= 0 ) _viewportSize[1] = _hudSize[1];
|
|
|
|
if( _orthoSize[0] <= 0 ) _orthoSize[0] = _viewportSize[0];
|
|
if( _orthoSize[1] <= 0 ) _orthoSize[1] = _viewportSize[1];
|
|
}
|
|
|
|
{ // Initialize hud camera
|
|
osg::Camera * camera = _cameraDebugHUD.get();
|
|
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
|
|
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
|
camera->setViewMatrix(osg::Matrix::identity());
|
|
camera->setViewport( _viewportOrigin[0], _viewportOrigin[1],
|
|
_viewportSize[0], _viewportSize[1] );
|
|
|
|
camera->setProjectionMatrixAsOrtho(
|
|
_orthoOrigin[0], _orthoOrigin[0] + _orthoSize[0],
|
|
_orthoOrigin[1], _orthoOrigin[1] + _orthoSize[1],
|
|
-10, 10 );
|
|
|
|
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
|
|
camera->setRenderOrder(osg::Camera::POST_RENDER);
|
|
}
|
|
|
|
{ // Add geode and drawable with BaseClass display
|
|
// create geode to contain hud drawables
|
|
osg::Geode* geode = new osg::Geode;
|
|
_cameraDebugHUD->addChild(geode);
|
|
|
|
// finally create and attach hud geometry
|
|
osg::Geometry* geometry = osg::createTexturedQuadGeometry
|
|
( osg::Vec3(_hudOrigin[0],_hudOrigin[1],0),
|
|
osg::Vec3(_hudSize[0],0,0),
|
|
osg::Vec3(0,_hudSize[1],0) );
|
|
|
|
osg::StateSet* stateset = _cameraDebugHUD->getOrCreateStateSet();
|
|
stateset->setTextureAttribute(0,_texture.get(),osg::StateAttribute::ON );
|
|
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
|
|
// stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
|
|
stateset->setAttributeAndModes
|
|
( new osg::Depth( osg::Depth::ALWAYS, 0, 1, false ) );
|
|
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
|
|
|
|
osg::Program* program = new osg::Program;
|
|
program->addShader( _depthColorFragmentShader.get() );
|
|
stateset->setAttribute( program );
|
|
stateset->addUniform( new osg::Uniform( "texture" , 0 ) );
|
|
|
|
geometry->setDrawCallback
|
|
( new DrawableDrawWithDepthShadowComparisonOffCallback( _texture.get() ) );
|
|
|
|
geode->addDrawable( geometry );
|
|
}
|
|
|
|
{ // Create transforms and geodes to manage polytope drawing
|
|
osg::StateSet * stateset = new osg::StateSet;
|
|
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
|
stateset->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
|
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
|
stateset->setAttribute( new osg::Program() );
|
|
stateset->setAttributeAndModes
|
|
( new osg::Depth( osg::Depth::LEQUAL, 0, 1, false ) );
|
|
|
|
for( int i = 0; i < 2; i++ ) {
|
|
_geode[i]->setStateSet( stateset );
|
|
_transform[i] = new osg::MatrixTransform;
|
|
_transform[i]->addChild( _geode[i].get() );
|
|
_transform[i]->setMatrix( osg::Matrix::identity() );
|
|
_transform[i]->setReferenceFrame( osg::MatrixTransform::ABSOLUTE_RF );
|
|
}
|
|
|
|
_transform[1]->setMatrix
|
|
( osg::Matrix::translate( 1, 1, 0 ) *
|
|
osg::Matrix::scale( 0.5, 0.5, 1 ) *
|
|
osg::Matrix::scale( _hudSize[0], _hudSize[1], 1 ) *
|
|
osg::Matrix::translate( _hudOrigin[0], _hudOrigin[1], 0 ) );
|
|
|
|
_cameraDebugHUD->addChild( _transform[1].get() );
|
|
}
|
|
}
|
|
|
|
osg::Vec3d DebugShadowMap::ViewData::computeShadowTexelToPixelError
|
|
( const osg::Matrix & mvpwView,
|
|
const osg::Matrix & mvpwShadow,
|
|
const osg::Vec3d & vWorld,
|
|
const osg::Vec3d & vDelta )
|
|
{
|
|
osg::Vec3d vS0 = mvpwShadow * vWorld;
|
|
osg::Vec3d vS1 = mvpwShadow * ( vWorld + vDelta );
|
|
|
|
osg::Vec3d vV0 = mvpwView * vWorld;
|
|
osg::Vec3d vV1 = mvpwView * ( vWorld + vDelta );
|
|
|
|
osg::Vec3d dV = vV1 - vV0;
|
|
osg::Vec3d dS = vS1 - vS0;
|
|
|
|
return osg::Vec3( dS[0] / dV[0], dS[1] / dV[1], dS[2] / dV[2] );
|
|
}
|
|
|
|
void DebugShadowMap::ViewData::displayShadowTexelToPixelErrors
|
|
( const osg::Camera* viewCamera,
|
|
const osg::Camera* shadowCamera,
|
|
const ConvexPolyhedron* hull )
|
|
{
|
|
osg::Matrix mvpwMain =
|
|
viewCamera->getViewMatrix() *
|
|
viewCamera->getProjectionMatrix() *
|
|
viewCamera->getViewport()->computeWindowMatrix();
|
|
|
|
osg::Matrix mvpwShadow =
|
|
shadowCamera->getViewMatrix() *
|
|
shadowCamera->getProjectionMatrix() *
|
|
shadowCamera->getViewport()->computeWindowMatrix();
|
|
|
|
osg::BoundingBox bb =
|
|
hull->computeBoundingBox( viewCamera->getViewMatrix() );
|
|
|
|
osg::Matrix m = viewCamera->getInverseViewMatrix();
|
|
|
|
osg::Vec3d vn = osg::Vec3d( 0, 0, bb._max[2] ) * m;
|
|
osg::Vec3d vf = osg::Vec3d( 0, 0, bb._min[2] ) * m;
|
|
osg::Vec3d vm = osg::Vec3d( 0, 0, ( bb._max[2] + bb._min[2] ) * 0.5 ) * m;
|
|
|
|
osg::Vec3d vne = computeShadowTexelToPixelError( mvpwMain, mvpwShadow, vn );
|
|
osg::Vec3d vfe = computeShadowTexelToPixelError( mvpwMain, mvpwShadow, vf );
|
|
osg::Vec3d vme = computeShadowTexelToPixelError( mvpwMain, mvpwShadow, vm );
|
|
|
|
std::cout << std::setprecision( 3 ) << " "
|
|
<< "ne=(" << vne[0] << "," << vne[1] << "," << vne[2] << ") "
|
|
<< "fe=(" << vfe[0] << "," << vfe[1] << "," << vfe[2] << ") "
|
|
<< "me=(" << vme[0] << "," << vme[1] << "," << vme[2] << ") "
|
|
<< "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
|
|
<< "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
|
|
<< "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
|
|
<< std::flush;
|
|
}
|
|
|