Hello Robert,
I've been trying to implement osgShadow::ShadowMap, using the old
osgdepthshadow as a starting point.
I am attaching ShadowMap[.cpp] and testShadow.cpp[ based on osgshadow
example ].
I hit a bit of a wall, and here are some of the points I'm not very
clear on:
1. there is a Camera[PRE_RENDER] to RTT the depthMap, it's viewFrustum
needs to be updated according to the light, but where is the appropriate
call-back for it in the Update or in the Cull traversals ??
2. same for TexGenNode for applying the said depthMap
3. how do I add the Camera to the rendering ? (if I add it to
ShadowedScene, there is a loop, since the sceneData of the Camera is
ShadowedScene)
4. where is appropriate to add the TexGenNode (ShadowedScene seems like
the candidate) ?
Right now I've turned off the depth comparing on the depthMap to see
what is happening, and all I get is a black rectangle.
I've looked through the code for ShadowVolume, and I see you do some
magic with the renderBins in Cull traversal, but I can't quite figure if
I need to do something similar (I guess because I don't quite get what
is happening there :)
I would really like to have this going, then I could use the nodeKit
with the application we are working on ( I'll have to back-port it to
osg 1.2, but that's not a big deal if I exclude ShadowVolume technique).
Regards
Mihai Radu
------------
cm-labs.com
#include <osg/ArgumentParser>
#include <osg/LightModel>
#include <osg/Depth>
#include <osg/BlendFunc>
#include <osg/Camera>
#include <osg/Stencil>
#include <osg/StencilTwoSided>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/Switch>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/Viewer>
#include <osgViewer/StatsHandler>
#include <osgShadow/OccluderGeometry>
#include <osgShadow/ShadowedScene>
#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowMap>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <iostream>
class ComputeBoundingBoxVisitor : public osg::NodeVisitor
{
public:
ComputeBoundingBoxVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
virtual void reset()
{
_matrixStack.clear();
_bb.init();
}
osg::BoundingBox& getBoundingBox() { return _bb; }
void getPolytope(osg::Polytope& polytope, float margin=0.1) const
{
float delta = _bb.radius()*margin;
polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
polytope.add( osg::Plane(0.0, 0.0, -1.0, (_bb.zMax()+delta)) );
polytope.add( osg::Plane(1.0, 0.0, 0.0, -(_bb.xMin()-delta)) );
polytope.add( osg::Plane(-1.0, 0.0, 0.0, (_bb.xMax()+delta)) );
polytope.add( osg::Plane(0.0, 1.0, 0.0, -(_bb.yMin()-delta)) );
polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) );
}
void getBase(osg::Polytope& polytope, float margin=0.1) const
{
float delta = _bb.radius()*margin;
polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
}
void apply(osg::Node& node)
{
traverse(node);
}
void apply(osg::Transform& transform)
{
osg::Matrix matrix;
if (!_matrixStack.empty()) matrix = _matrixStack.back();
transform.computeLocalToWorldMatrix(matrix,this);
pushMatrix(matrix);
traverse(transform);
popMatrix();
}
void apply(osg::Geode& geode)
{
for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
apply(geode.getDrawable(i));
}
}
void pushMatrix(osg::Matrix& matrix)
{
_matrixStack.push_back(matrix);
}
void popMatrix()
{
_matrixStack.pop_back();
}
void apply(osg::Drawable* drawable)
{
if (_matrixStack.empty()) _bb.expandBy(drawable->getBound());
else
{
osg::Matrix& matrix = _matrixStack.back();
const osg::BoundingBox& dbb = drawable->getBound();
if (dbb.valid())
{
_bb.expandBy(dbb.corner(0) * matrix);
_bb.expandBy(dbb.corner(1) * matrix);
_bb.expandBy(dbb.corner(2) * matrix);
_bb.expandBy(dbb.corner(3) * matrix);
_bb.expandBy(dbb.corner(4) * matrix);
_bb.expandBy(dbb.corner(5) * matrix);
_bb.expandBy(dbb.corner(6) * matrix);
_bb.expandBy(dbb.corner(7) * matrix);
}
}
}
protected:
typedef std::vector<osg::Matrix> MatrixStack;
MatrixStack _matrixStack;
osg::BoundingBox _bb;
};
osg::Camera* makeHud(osg::Texture2D* tex)
{
// set hud to render shadow texture, just for interest
#if 1
osg::Geode* geode = new osg::Geode;
osg::Geometry* geom =
osg::createTexturedQuadGeometry(osg::Vec3(0,0,0),osg::Vec3(100.0,0.0,0.0),osg::Vec3(0.0,100.0,0.0));
geom->getOrCreateStateSet()->setTextureAttributeAndModes(0,tex,osg::StateAttribute::ON);
geom->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
geode->addDrawable(geom);
osg::Camera* camera = new osg::Camera;
// set the projection matrix
camera->setProjectionMatrix(osg::Matrix::ortho2D(0,100,0,100));
// set the view matrix
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
camera->setViewMatrix(osg::Matrix::identity());
camera->setViewport(50,50,100,100);
// only clear the depth buffer
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
// draw subgraph after main camera view.
camera->setRenderOrder(osg::Camera::POST_RENDER);
camera->addChild(geode);
#else
osg::Geode* geode = new osg::Geode();
{
osg::Geometry* geom = new osg::Geometry;
osg::Vec3Array* vertices = new osg::Vec3Array;
float depth = -0.1;
vertices->push_back(osg::Vec3(0,512,depth));
vertices->push_back(osg::Vec3(0,0,depth));
vertices->push_back(osg::Vec3(512,0,depth));
vertices->push_back(osg::Vec3(512,512,depth));
geom->setVertexArray(vertices);
osg::Vec3Array* normals = new osg::Vec3Array;
normals->push_back(osg::Vec3(0.0f,0.0f,1.0f));
geom->setNormalArray(normals);
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(osg::Vec4(1.0f,1.0,0.8f,0.2f));
geom->setColorArray(colors);
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4));
osg::StateSet* stateset = geom->getOrCreateStateSet();
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
//stateset->setAttribute(new
osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
geode->addDrawable(geom);
}
osg::StateSet* set = geode->getOrCreateStateSet();
set->setTextureAttributeAndModes(0, tex ,osg::StateAttribute::ON);
osg::Camera* camera = new osg::Camera;
// set the projection matrix
camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
// set the view matrix
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
camera->setViewMatrix(osg::Matrix::identity());
// only clear the depth buffer
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
// draw subgraph after main camera view.
camera->setRenderOrder(osg::Camera::POST_RENDER);
camera->addChild(geode);
#endif
return camera;
}
int main(int argc, char** argv)
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc, argv);
// set up the usage document, in case we need to print out how to use this
program.
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() +
" is the example which demonstrates using of GL_ARB_shadow extension implemented in
osg::Texture class");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display
this information");
arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", "Use
a positional light.");
arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", "Use
a direction light.");
arguments.getApplicationUsage()->addCommandLineOption("--addOccluderToScene",
"Add the occluders geometry.");
arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", "Disable the
updating the of light source.");
arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base
geometry to test shadows.");
arguments.getApplicationUsage()->addCommandLineOption("--noShadow", "Disable the
shadows.");
arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use
two-sided stencil extension for shadow volumes.");
arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use
two-pass stencil for shadow volumes.");
// hint to tell viewer to request stencil buffer when setting up windows
osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
// construct the viewer.
osgViewer::Viewer viewer;
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
{
arguments.getApplicationUsage()->write(std::cout);
return 1;
}
// default to single threaded during dev work.
viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
while (arguments.read("--SingleThreaded"))
viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
while (arguments.read("--CullDrawThreadPerContext"))
viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
while (arguments.read("--DrawThreadPerContext"))
viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
while (arguments.read("--CullThreadPerCameraDrawThreadPerContext"))
viewer.setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
bool postionalLight = false;
while (arguments.read("--positionalLight")) postionalLight = true;
while (arguments.read("--directionalLight")) postionalLight = false;
bool updateLightPosition = true;
while (arguments.read("--noUpdate")) updateLightPosition = false;
bool createBase = false;
while (arguments.read("--base")) createBase = true;
int screenNum = -1;
while (arguments.read("--screen", screenNum))
viewer.setUpViewOnSingleScreen(screenNum);
bool ShadowMap = true;
while (arguments.read("--ShadowMap")) ShadowMap = true;
// set up the camera manipulators.
{
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator =
new osgGA::KeySwitchMatrixManipulator;
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new
osgGA::TrackballManipulator() );
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new
osgGA::FlightManipulator() );
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new
osgGA::DriveManipulator() );
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new
osgGA::TerrainManipulator() );
std::string pathfile;
char keyForAnimationPath = '5';
while (arguments.read("-p",pathfile))
{
osgGA::AnimationPathManipulator* apm = new
osgGA::AnimationPathManipulator(pathfile);
if (apm || !apm->valid())
{
unsigned int num =
keyswitchManipulator->getNumMatrixManipulators();
keyswitchManipulator->addMatrixManipulator( keyForAnimationPath,
"Path", apm );
keyswitchManipulator->selectMatrixManipulator(num);
++keyForAnimationPath;
}
}
viewer.setCameraManipulator( keyswitchManipulator.get() );
}
// add the state manipulator
viewer.addEventHandler( new
osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
// add stats
viewer.addEventHandler( new osgViewer::StatsHandler() );
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occured when parsing the program aguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
if (!model)
{
return 1;
}
// get the bounds of the model.
ComputeBoundingBoxVisitor cbbv;
model->accept(cbbv);
osg::BoundingBox bb = cbbv.getBoundingBox();
if (createBase)
{
osg::ref_ptr<osg::Group> newGroup = new osg::Group;
newGroup->addChild(model.get());
osg::Geode* geode = new osg::Geode;
osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f,
(bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
geode->addDrawable( osg::createTexturedQuadGeometry(
centerBase-widthVec*1.5f-depthVec*1.5f,
widthVec*3.0f,
depthVec*3.0f) );
newGroup->addChild(geode);
model = newGroup.get();
}
osg::Vec4 lightpos;
if (postionalLight)
{
lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()
,1.0f);
}
else
{
lightpos.set(0.5f,0.25f,0.8f,0.0f);
}
osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new
osgShadow::ShadowedScene;
osg::ref_ptr<osgShadow::ShadowMap> shadowMap = new osgShadow::ShadowMap;
shadowedScene->setShadowTechnique(shadowMap.get());
shadowedScene->addChild(model.get());
osgShadow::ShadowMap* map = dynamic_cast<osgShadow::ShadowMap*>(
shadowedScene->getShadowTechnique());
osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
ls->getLight()->setPosition(lightpos);
map->setLight(ls.get());
//osg::Camera* cam = map->getCamera();
//osg::Camera::BufferAttachmentMap bMap = cam->getBufferAttachmentMap();
//osg::Camera::Attachment attach =
(*bMap.find(osg::Camera::COLOR_BUFFER)).second;
osg::ref_ptr<osg::Camera> _hud;
osg::Texture2D* tex = map->getTexture();
tex->setShadowComparison(false);
if (! tex)
exit(1);
_hud = makeHud(tex);
//shadowedScene->addChild( map->getCamera() );
shadowedScene->addChild( map->getTexGen() );
//shadowedScene->addChild( _hud.get() );
shadowedScene->addChild(model.get());
shadowedScene->addChild(ls.get());
viewer.setSceneData(shadowedScene.get());
// create the windows and run the threads.
viewer.realize();
// osgDB::writeNodeFile(*group,"test.osg");
while (!viewer.done())
{
if (updateLightPosition)
{
float t = viewer.getFrameStamp()->getSimulationTime();
if (postionalLight)
{
lightpos.set(bb.center().x()+sinf(t)*bb.radius(),
bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius() ,1.0f);
}
else
{
lightpos.set(sinf(t),cosf(t),1.0f,0.0f);
}
ls->getLight()->setPosition(lightpos);
}
viewer.frame();
}
return 0;
}
/* -*-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.
*/
#include <osgShadow/ShadowMap>
#include <osgShadow/ShadowedScene>
#include <osg/Notify>
#include <osg/Texture2D>
#include <osg/TexGenNode>
#include <osg/PolygonOffset>
#include <osg/CullFace>
#include <osg/LightSource>
#include <osgSim/DOFTransform>
#include <osg/MatrixTransform>
#include <iomanip>
using namespace osgShadow;
ShadowMap::ShadowMap() :
_useLightPos(false)
{
osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowMap technique in
development."<<std::endl;
_textureHeight = 1024;
_textureWidth = 1024;
_textureUnit = 1;
_position = osg::Vec3(5.0, 5.0, 0.0);
}
ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop):
ShadowTechnique(copy,copyop)
{
}
void ShadowMap::init()
{
if (!_shadowedScene) return;
// create the depthMap texture
_texture = new osg::Texture2D;
_texture->setTextureSize(_textureHeight, _textureWidth);
_texture->setInternalFormat(GL_DEPTH_COMPONENT);
_texture->setShadowComparison(true);
_texture->setShadowCompareFunc (osg::Texture::LEQUAL);
_texture->setShadowTextureMode(osg::Texture::LUMINANCE);
_texture->setShadowAmbient(0.2);
_texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER );
_texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER );
_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
_texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
_texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
/////////////////// create S_CameraNode
_camera = new osg::Camera;
_camera->setName("ShadowMap");
_camera->setClearMask(GL_DEPTH_BUFFER_BIT);
_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
// this turns off automatic computation of NEAR & FAR planes for the camera
_camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
// set the CullMask to allow for non_occluder nodes
_camera->setCullMask( _shadowedScene->getCastsShadowTraversalMask() );
// set viewport
_camera->setViewport(0,0,_textureHeight, _textureWidth);
osg::StateSet* _local_stateset = _camera->getOrCreateStateSet();
_local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
// PolygonOffset property to set the bias for shadow
float factor = 1.85f;
float units = 1.80f;
osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
polygon_offset->setFactor(factor);
polygon_offset->setUnits(units);
_local_stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON
| osg::StateAttribute::OVERRIDE);
_local_stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON |
osg::StateAttribute::OVERRIDE);
osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
cull_face->setMode(osg::CullFace::FRONT_AND_BACK);
_local_stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON |
osg::StateAttribute::OVERRIDE);
_local_stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF |
osg::StateAttribute::OVERRIDE);
// set the shadowCamera to render before the main camera.
_camera->setRenderOrder(osg::Camera::PRE_RENDER);
//shadowCamera->setRenderOrder(osg::CameraNode::NESTED_RENDER);
// tell the shadowCamera to use OpenGL frame buffer object where supported.
_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
// attach the texture and use it as the depth buffer.
_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
_camera->addChild(_shadowedScene);
// create TexGen node
_texGen = new osg::TexGenNode;
_texGen->setTextureUnit(_textureUnit);
/*
// find the entity the Light is attached-to
VxEntity* ent;
osg::Node* ln = NULL;
ln = (osg::Node*)VxSceneGraphManager::find(m_Light->name);
if (!ln)
VxFatalError(0,"Ooops couldn't find Light %s\n", m_Light->name.c_str());
else
{
osg::Light* light = dynamic_cast<osg::LightSource*>(ln)->getLight();
VxInfo(1,"VxShadowMap:: shadow caster GL lightID
%d\n",light->getLightNum());
// TODO set the lightID of the shadowCasting light here ???
ent = getParentEntityfromNode(ln);
}
// found the part
if ( ent )
{
const osg::Vec3 lightPosOffset(m_Light->attachementInfo.position[0],
m_Light->attachementInfo.position[1], m_Light->attachementInfo.position[2]);
// set an update callback to keep moving the camera and tex gen in the
right direction.
_Camera->setUpdateCallback( new
UpdateCameraAndTexGenCallback(lightPosOffset, ent, _TexGen.get()) );
}
*/
// enable shadowTexture on the 3Dscene
osg::StateSet* stateset = _shadowedScene->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(_textureUnit, _texture.get()
,osg::StateAttribute::ON);
stateset->setTextureMode(_textureUnit, GL_TEXTURE_GEN_S,
osg::StateAttribute::ON);
stateset->setTextureMode(_textureUnit, GL_TEXTURE_GEN_T,
osg::StateAttribute::ON);
stateset->setTextureMode(_textureUnit, GL_TEXTURE_GEN_R,
osg::StateAttribute::ON);
stateset->setTextureMode(_textureUnit, GL_TEXTURE_GEN_Q,
osg::StateAttribute::ON);
//stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON|
StateAttribute::OVERRIDE);
}
void ShadowMap::update(osg::NodeVisitor& nv)
{
_shadowedScene->osg::Group::traverse(nv);
}
void ShadowMap::cull(osgUtil::CullVisitor& cv)
{
//osg::notify(osg::NOTICE)<<className()<<"::cull(osgUtl::CullVisitor&) in
development."<<std::endl;
// now compute the camera's view and projection matrix to point at the
shadower (the camera's children)
//TODO cull the scene based on the main camera or LightNode MR
osg::BoundingSphere bs;
// Need to unfold the scene to take in account NodeMask(s)
for(unsigned int i=0; i<_shadowedScene->getNumChildren(); ++i)
{
if ( _shadowedScene->getChild(i)->getNodeMask() &
_shadowedScene->getCastsShadowTraversalMask() )
{
#ifdef _DEBUG
osg::notify(osg::NOTICE)<<className()<< " _camera bounding box exp with child "
<< i << std::endl;
#endif
bs.expandBy(_shadowedScene->getChild(i)->getBound());
}
}
if (!bs.valid())
{
osg::notify(osg::INFO) << "bb invalid"<<_camera.get()<<std::endl;
return;
}
#ifdef _DEBUG
osg::notify(osg::NOTICE)<<className()<< std::setprecision(6) <<" _camera bounding box r-x,y,z" << std::setw(10) <<
bs.radius() << std::setw(10) << (float)bs.center().x() << std::setw(10) << (float)bs.center().y() << std::setw(10) <<
(float)bs.center().z() <<std::endl;
//VxWarning(0, "ShadowMap: CameraNode bounding box r:%.2f x:%.2f y:%.2f
z:%.2f.\n",bs.radius(), bs.center().x(), bs.center().y(),bs.center().z() );
#endif
if(_useLightPos)
{
osg::Vec4 _positionU = _light->getLight()->getPosition();
if( _positionU.w() != 0.0)
_position.set(_positionU.x()/_positionU.w(),
_positionU.y()/_positionU.w(), _positionU.z()/_positionU.w());
else
_position.set(_positionU.x(), _positionU.y(), _positionU.z());
}
float centerDistance = (_position-bs.center()).length();
float znear = centerDistance-bs.radius();
float zfar = centerDistance+bs.radius();
float zNearRatio = 0.001f;
if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
#if 0
// hack to illustrate the precision problems of excessive gap between near
far range.
znear = 0.00001*zfar;
#endif
float top = (bs.radius()/centerDistance)*znear;
float right = top;
_camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
_camera->setViewMatrixAsLookAt(_position,bs.center(),osg::Vec3(0.0f,1.0f,0.0f));
// compute the matrix which takes a vertex from local coords into tex coords
// will use this later to specify osg::TexGen..
osg::Matrix MVPT = _camera->getViewMatrix() *
_camera->getProjectionMatrix() *
osg::Matrix::translate(1.0,1.0,1.0) *
osg::Matrix::scale(0.5f,0.5f,0.5f);
_texGen->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
_texGen->getTexGen()->setPlanesFromMatrix(MVPT);
//_camera->traverse(cv);
_shadowedScene->osg::Group::traverse(cv);
}
/* -*-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.
*/
#ifndef OSGSHADOW_SHADOWEDTEXTURE
#define OSGSHADOW_SHADOWEDTEXTURE 1
#include <osg/Camera>
#include <osgShadow/ShadowTechnique>
namespace osgShadow {
class osg::Texture2D;
class osg::TexGenNode;
/** ShadowedTexture provides an implementation of shadow textures.*/
class OSGSHADOW_EXPORT ShadowMap : public ShadowTechnique
{
public :
ShadowMap();
ShadowMap(const ShadowMap& es, const osg::CopyOp&
copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osgShadow, ShadowMap);
/** initialize the ShadowedScene and local cached data structures.*/
virtual void init();
/** run the update traversal of the ShadowedScene and update any loca
chached data structures.*/
virtual void update(osg::NodeVisitor& nv);
/** run the cull traversal of the ShadowedScene and set up the
rendering for this ShadowTechnique.*/
virtual void cull(osgUtil::CullVisitor& cv);
inline osg::Camera* getCamera() {
if(_dirty)
init();
return _camera.get(); };
inline osg::Texture2D* getTexture() {
if(_dirty)
init();
return _texture.get(); };
inline osg::TexGenNode* getTexGen() {
if(_dirty)
init();
return _texGen.get(); };
inline void setLight(osg::LightSource* light) { _light = light;
_useLightPos=true;};
protected :
virtual ~ShadowMap() {}
private :
unsigned int _textureHeight;
unsigned int _textureWidth;
unsigned int _textureUnit;
osg::Vec3 _position;
bool _useLightPos;
osg::LightSource* _light;
osg::ref_ptr<osg::Camera> _camera;
osg::ref_ptr<osg::Texture2D> _texture;
osg::ref_ptr<osg::TexGenNode> _texGen;
};
}
#endif
_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/