Files
OpenSceneGraph/src/osgShadow/MinimalDrawBoundsShadowMap.cpp
Robert Osfield a5c32da4ff Warning fixes
2008-12-17 11:00:16 +00:00

407 lines
14 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/MinimalDrawBoundsShadowMap>
#include <osgShadow/ConvexPolyhedron>
#include <osg/PolygonOffset>
#include <osgUtil/RenderLeaf>
#include <osgShadow/ShadowedScene>
#include <osg/FrameBufferObject>
#include <osg/BlendEquation>
#include <osg/Depth>
#include <osg/AlphaFunc>
#include <osg/Image>
#include <iostream>
#include <string.h>
#define ANALYSIS_DEPTH 1
#define USE_FLOAT_IMAGE 1
using namespace osgShadow;
MinimalDrawBoundsShadowMap::MinimalDrawBoundsShadowMap(): BaseClass()
{
}
MinimalDrawBoundsShadowMap::MinimalDrawBoundsShadowMap
(const MinimalDrawBoundsShadowMap& copy, const osg::CopyOp& copyop) :
BaseClass(copy,copyop)
{
}
MinimalDrawBoundsShadowMap::~MinimalDrawBoundsShadowMap()
{
}
void MinimalDrawBoundsShadowMap::ViewData::cullShadowReceivingScene( )
{
BaseClass::ViewData::cullShadowReceivingScene( );
ThisClass::ViewData::cullBoundAnalysisScene( );
}
void MinimalDrawBoundsShadowMap::ViewData::cullBoundAnalysisScene( )
{
_boundAnalysisCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF );
_boundAnalysisCamera->setViewMatrix( *_cv->getModelViewMatrix() );
_boundAnalysisCamera->setProjectionMatrix( _clampedProjection );
osg::Matrixd::value_type l,r,b,t,n,f;
_boundAnalysisCamera->getProjectionMatrixAsFrustum( l,r,b,t,n,f );
_mainCamera = _cv->getRenderStage()->getCamera();
extendProjection( _boundAnalysisCamera->getProjectionMatrix(),
_boundAnalysisCamera->getViewport(), osg::Vec2( 2,2 ) );
// record the traversal mask on entry so we can reapply it later.
unsigned int traversalMask = _cv->getTraversalMask();
_cv->setTraversalMask( traversalMask &
_st->getShadowedScene()->getReceivesShadowTraversalMask() );
// do RTT camera traversal
_boundAnalysisCamera->accept(*_cv);
// reapply the original traversal mask
_cv->setTraversalMask( traversalMask );
}
void MinimalDrawBoundsShadowMap::ViewData::createDebugHUD( )
{
// _hudSize[0] *= 2;
_viewportSize[0] *= 2;
_orthoSize[0] *= 2;
MinimalShadowMap::ViewData::createDebugHUD( );
osg::Camera * camera = _cameraDebugHUD.get();
osg::Geode* geode = new osg::Geode;
camera->addChild( geode );
osg::Geometry* geometry = osg::createTexturedQuadGeometry
( osg::Vec3(_hudOrigin[0]+_hudSize[0],_hudOrigin[1],0),
osg::Vec3(_hudSize[0],0,0),
osg::Vec3(0,_hudSize[1],0) );
geode->addDrawable(geometry);
osg::StateSet* stateset = geometry->getOrCreateStateSet();
stateset->setTextureAttributeAndModes
(0, _boundAnalysisTexture.get(),osg::StateAttribute::ON );
#if ANALYSIS_DEPTH
osg::Program* program = new osg::Program;
program->addShader( _depthColorFragmentShader.get() );
stateset->setAttribute( program );
stateset->addUniform( new osg::Uniform( "texture" , 0 ) );
#else
#endif
}
osg::BoundingBox MinimalDrawBoundsShadowMap::ViewData::scanImage
( const osg::Image * image, osg::Matrix m )
{
osg::BoundingBox bb, bbProj;
int components = osg::Image::computeNumComponents( image->getPixelFormat() );
if( image->getDataType() == GL_FLOAT ) {
float scale = 255.f / 254.f;
float * pf = (float *)image->data();
for( int y = 0; y < image->t(); y++ ) {
float fY = ( 0.5f + y ) / image->t();
for( int x = 0; x < image->s(); x++ ) {
float fX = ( 0.5f + x ) / image->s();
if( pf[0] < 1.0 ) {
float fMinZ = pf[0] * scale;
bbProj.expandBy( osg::Vec3( fX, fY, fMinZ ) );
bb.expandBy( osg::Vec3( fX, fY, fMinZ ) * m );
if( components > 1 ) {
float fMaxZ = scale * ( 1.f - pf[1] );
bbProj.expandBy( osg::Vec3( fX, fY, fMaxZ ) );
bb.expandBy( osg::Vec3( fX, fY, fMaxZ ) * m );
}
}
pf += components;
}
}
} else if( image->getDataType() == GL_UNSIGNED_BYTE ) {
unsigned char * pb = (unsigned char *)image->data();
float scale = 1.f / 254;
for( int y = 0; y < image->t(); y++ ) {
float fY = ( 0.5f + y ) / image->t();
for( int x = 0; x < image->s(); x++ ) {
float fX = ( 0.5f + x ) / image->s();
if( pb[0] < 255 ) {
float fMinZ = scale * (pb[0] - 0.5f);
fMinZ = osg::clampTo( fMinZ, 0.f, 1.f );
bbProj.expandBy( osg::Vec3( fX, fY, fMinZ ) );
bb.expandBy( osg::Vec3( fX, fY, fMinZ ) * m );
if( components > 1 ) {
float fMaxZ = scale * (255 - pb[1] + 0.5f);
fMaxZ = osg::clampTo( fMaxZ, 0.f, 1.f );
bbProj.expandBy( osg::Vec3( fX, fY, fMaxZ ) );
bb.expandBy( osg::Vec3( fX, fY, fMaxZ ) * m );
}
}
pb += components;
}
}
}
return bb;
}
void MinimalDrawBoundsShadowMap::ViewData::performBoundAnalysis( const osg::Camera& camera )
{
if( !_projection.valid() )
return;
osg::Camera::BufferAttachmentMap & bam
= const_cast<osg::Camera&>( camera ).getBufferAttachmentMap();
#if ANALYSIS_DEPTH
osg::Camera::Attachment & attachment = bam[ osg::Camera::DEPTH_BUFFER ];
#else
osg::Camera::Attachment & attachment = bam[ osg::Camera::COLOR_BUFFER ];
#endif
const osg::ref_ptr< osg::Image > image = attachment._image.get();
if( !image.valid() )
return;
osg::Matrix m;
m.invert( *_modellingSpaceToWorldPtr *
camera.getViewMatrix() *
camera.getProjectionMatrix() );
m.preMult( osg::Matrix::scale( osg::Vec3( 2.f, 2.f, 2.f ) ) *
osg::Matrix::translate( osg::Vec3( -1.f, -1.f, -1.f ) ) );
osg::BoundingBox bb = scanImage( image.get(), m );
if( getDebugDraw() ) {
ConvexPolyhedron p;
p.setToBoundingBox( bb );
p.transform( *_modellingSpaceToWorldPtr,
osg::Matrix::inverse( *_modellingSpaceToWorldPtr ) );
setDebugPolytope( "scan", p,
osg::Vec4( 0,0,0,1 ), osg::Vec4( 0,0,0,0.1 ) );
}
cutScenePolytope( *_modellingSpaceToWorldPtr,
osg::Matrix::inverse( *_modellingSpaceToWorldPtr ), bb );
frameShadowCastingCamera( _mainCamera.get(), _camera.get() );
_projection->set( _camera->getProjectionMatrix( ) );
BaseClass::ViewData::_texgen->setPlanesFromMatrix(
_camera->getProjectionMatrix() *
osg::Matrix::translate(1.0,1.0,1.0) *
osg::Matrix::scale(0.5,0.5,0.5) );
updateDebugGeometry( _mainCamera.get(), _camera.get() );
}
void MinimalDrawBoundsShadowMap::ViewData::recordShadowMapParams( )
{
const osgUtil::RenderStage * rs = _cv->getCurrentRenderBin()->getStage();
setShadowCameraProjectionMatrixPtr( _cv->getProjectionMatrix() );
if( !rs->getRenderBinList().empty() || rs->getBinNum() != 0 )
{
}
#if 0
MinimalShadowMap::RenderLeafList rll;
static unsigned pass = 0, c = 0;
pass++;
std::set< osg::ref_ptr< osg::RefMatrix > > projections;
MinimalShadowMap::GetRenderLeaves( , rll );
for( unsigned i =0; i < rll.size(); i++ ) {
if( rll[i]->_projection.get() != _projection.get() ) {
osg::RefMatrix * projection = rll[i]->_projection.get();
projections.insert( rll[i]->_projection );
c++;
}
}
if( projections.size() > 0 )
_projection = (*projections.begin()).get();
c = 0;
#endif
}
void MinimalDrawBoundsShadowMap::ViewData::init
( ThisClass *st, osgUtil::CullVisitor *cv )
{
BaseClass::ViewData::init( st, cv );
_camera->setCullCallback
( new CameraCullCallback( this, _camera->getCullCallback() ) );
_boundAnalysisTexture = new osg::Texture2D;
_boundAnalysisTexture->setTextureSize
( _boundAnalysisSize[0], _boundAnalysisSize[1] );
_boundAnalysisImage = new osg::Image;
#if ANALYSIS_DEPTH
_boundAnalysisImage->allocateImage( _boundAnalysisSize[0],
_boundAnalysisSize[1], 1,
GL_DEPTH_COMPONENT, GL_FLOAT );
_boundAnalysisTexture->setInternalFormat(GL_DEPTH_COMPONENT);
// _boundAnalysisTexture->setShadowComparison(true);
_boundAnalysisTexture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
_boundAnalysisImage->setInternalTextureFormat( GL_DEPTH_COMPONENT );
_boundAnalysisTexture->setInternalFormat( GL_DEPTH_COMPONENT );
#else
#if USE_FLOAT_IMAGE
_boundAnalysisImage->allocateImage( _boundAnalysisSize[0],
_boundAnalysisSize[1], 1,
GL_RGBA, GL_FLOAT );
_boundAnalysisImage->setInternalTextureFormat( GL_RGBA16F_ARB );
_boundAnalysisTexture->setInternalFormat(GL_RGBA16F_ARB);
#else
_boundAnalysisImage->allocateImage( _boundAnalysisSize[0],
_boundAnalysisSize[1], 1,
GL_RGBA, GL_UNSIGNED_BYTE );
_boundAnalysisImage->setInternalTextureFormat( GL_RGBA );
_boundAnalysisTexture->setInternalFormat( GL_RGBA );
#endif
#endif
memset( _boundAnalysisImage->data(), 0, _boundAnalysisImage->getImageSizeInBytes() );
if( getDebugDraw() )
_boundAnalysisTexture->setImage(0, _boundAnalysisImage.get() );
_boundAnalysisTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
_boundAnalysisTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
// the shadow comparison should fail if object is outside the texture
_boundAnalysisTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT);
_boundAnalysisTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT);
// set up the render to texture camera.
// create the camera
_boundAnalysisCamera = new osg::Camera;
_boundAnalysisCamera->setName( "AnalysisCamera" );
_boundAnalysisCamera->setCullCallback( new BaseClass::CameraCullCallback(st) );
// _boundAnalysisCamera->setPreDrawCallback( _camera->getPreDrawCallback() );
_boundAnalysisCamera->setPostDrawCallback( new CameraPostDrawCallback(this) );
_boundAnalysisCamera->setClearColor( osg::Vec4(1,1,1,1) );
_boundAnalysisCamera->setClearMask(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
_boundAnalysisCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
// set viewport
_boundAnalysisCamera->setViewport
( 0, 0, _boundAnalysisSize[0], _boundAnalysisSize[1] );
// set the camera to render before the main camera.
_boundAnalysisCamera->setRenderOrder(osg::Camera::PRE_RENDER);
// tell the camera to use OpenGL frame buffer object where supported.
_boundAnalysisCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
//_boundAnalysisCamera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
const int OVERRIDE_ON = osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON;
const int OVERRIDE_OFF = osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF;
osg::StateSet* stateset = _boundAnalysisCamera->getOrCreateStateSet();
stateset->setAttributeAndModes
( new osg::Depth( osg::Depth::LESS, 0.0, 254.f/255.f ), OVERRIDE_ON );
// stateset->setAttributeAndModes
// ( new osg::AlphaFunc( osg::AlphaFunc::EQUAL, 1.f ), OVERRIDE_ON );
stateset->setRenderBinDetails( 0, "RenderBin",
osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
osg::Program* program = new osg::Program;
program->addShader( new osg::Shader( osg::Shader::FRAGMENT,
"uniform sampler2D texture; \n"
"void main(void) \n"
"{ \n"
#if ANALYSIS_DEPTH
" gl_FragColor = texture2D( texture, gl_TexCoord[0].xy ); \n"
#else
" gl_FragColor = vec4( gl_FragCoord.z, \n"
" 1.-gl_FragCoord.z, \n"
" 1., \n"
" texture2D( texture, gl_TexCoord[0].xy ).a ); \n"
#endif
"} \n"
) ); // program->addShader Fragment
program->addShader( new osg::Shader( osg::Shader::VERTEX,
"void main(void) \n"
"{ \n"
" gl_Position = ftransform(); \n"
" gl_TexCoord[0] = gl_MultiTexCoord0; \n"
"} \n"
) ); // program->addShader Vertex
stateset->setAttribute( program, OVERRIDE_ON );
// attach the texture and use it as the color buffer.
#if ANALYSIS_DEPTH
// _boundAnalysisCamera->attach(osg::Camera::DEPTH_BUFFER, _boundAnalysisTexture.get());
_boundAnalysisCamera->attach(osg::Camera::DEPTH_BUFFER, _boundAnalysisImage.get());
stateset->setMode( GL_BLEND, OVERRIDE_OFF );
#else
// _boundAnalysisCamera->attach(osg::Camera::COLOR_BUFFER, _boundAnalysisTexture.get());
_boundAnalysisCamera->attach(osg::Camera::COLOR_BUFFER, _boundAnalysisImage.get());
stateset->setAttributeAndModes
( new osg::BlendEquation( osg::BlendEquation::RGBA_MIN ), OVERRIDE_ON );
stateset->setMode( GL_DEPTH_TEST, OVERRIDE_OFF );
#endif
}