Clean up of the shadow texture code...

This commit is contained in:
Robert Osfield
2002-11-21 14:54:14 +00:00
parent 2e1b827373
commit 3f97d6a44d

View File

@@ -27,67 +27,79 @@
#include "../osghangglide/terrain_coords.h"
class MyTexGen : public osg::TexGen
{
public:
void setMatrix(const osg::Matrix& matrix)
{
_matrix = matrix;
}
virtual void apply(osg::State& state) const
{
glPushMatrix();
glLoadMatrixf(_matrix.ptr());
TexGen::apply(state);
glPopMatrix();
}
osg::Matrix _matrix;
};
class MyCullCallback : public osg::NodeCallback
class CreateShadowTextureCullCallback : public osg::NodeCallback
{
public:
MyCullCallback(osg::Node* subgraph,osg::Texture2D* texture,const osg::Vec3& position):
_subgraph(subgraph),
_texture(texture),
_position(position) {}
CreateShadowTextureCullCallback(osg::Node* shadower,const osg::Vec3& position, const osg::Vec4& ambientLightColor, unsigned int textureUnit):
_shadower(shadower),
_position(position),
_ambientLightColor(ambientLightColor),
_unit(textureUnit)
{
_texture = new osg::Texture2D;
_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
_texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osgUtil::CullVisitor* cullVisitor = dynamic_cast<osgUtil::CullVisitor*>(nv);
if (cullVisitor && (_texture.valid() && _subgraph.valid()))
if (cullVisitor && (_texture.valid() && _shadower.valid()))
{
doPreRender(*node,*cullVisitor);
}
else
{
// must traverse the subgraph
// must traverse the shadower
traverse(node,nv);
}
}
protected:
void doPreRender(osg::Node& node, osgUtil::CullVisitor& cv);
osg::ref_ptr<osg::Node> _subgraph;
osg::ref_ptr<osg::Node> _shadower;
osg::ref_ptr<osg::Texture2D> _texture;
osg::Vec3 _position;
osg::Vec4 _ambientLightColor;
unsigned int _unit;
// we need this to get round the order dependance
// of eye linear tex gen...
class MyTexGen : public osg::TexGen
{
public:
void setMatrix(const osg::Matrix& matrix)
{
_matrix = matrix;
}
virtual void apply(osg::State& state) const
{
glPushMatrix();
glLoadMatrixf(_matrix.ptr());
TexGen::apply(state);
glPopMatrix();
}
osg::Matrix _matrix;
};
};
void MyCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
void CreateShadowTextureCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
{
const osg::BoundingSphere& bs = _subgraph->getBound();
const osg::BoundingSphere& bs = _shadower->getBound();
if (!bs.valid())
{
osg::notify(osg::WARN) << "bb invalid"<<_subgraph.get()<<std::endl;
osg::notify(osg::WARN) << "bb invalid"<<_shadower.get()<<std::endl;
return;
}
@@ -154,7 +166,7 @@ void MyCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
// make the material black for a shadow.
osg::Material* material = new osg::Material;
material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,1.0f));
material->setAmbient(osg::Material::FRONT_AND_BACK,_ambientLightColor);
material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,1.0f));
material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,1.0f));
material->setShininess(osg::Material::FRONT_AND_BACK,0.0f);
@@ -164,8 +176,8 @@ void MyCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
{
// traverse the subgraph
_subgraph->accept(cv);
// traverse the shadower
_shadower->accept(cv);
}
@@ -183,7 +195,7 @@ void MyCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
if (rtts->_renderGraphList.size()==0 && rtts->_bins.size()==0)
{
// getting to this point means that all the subgraph has been
// getting to this point means that all the shadower has been
// culled by small feature culling or is beyond LOD ranges.
return;
}
@@ -216,42 +228,18 @@ void MyCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
if (_texture.valid()) rtts->setTexture(_texture.get());
// set up the stateset to decorate the subgraph with the shadow texture
// set up the stateset to decorate the shadower with the shadow texture
// with the appropriate tex gen coords.
osg::StateSet* stateset = new osg::StateSet;
osg::Plane plane_s(MVPT(0,0),MVPT(1,0),MVPT(2,0),MVPT(3,0));
osg::Plane plane_t(MVPT(0,1),MVPT(1,1),MVPT(2,1),MVPT(3,1));
osg::Plane plane_r(MVPT(0,2),MVPT(1,2),MVPT(2,2),MVPT(3,2));
osg::Plane plane_q(MVPT(0,3),MVPT(1,3),MVPT(2,3),MVPT(3,3));
// plane_s.makeUnitLength();
// plane_t.makeUnitLength();
// plane_r.makeUnitLength();
// plane_q.makeUnitLength();
// plane_s.set(inverseMV*plane_s.asVec4());
// plane_t.set(inverseMV*plane_t.asVec4());
// plane_r.set(inverseMV*plane_r.asVec4());
// plane_q.set(inverseMV*plane_q.asVec4());
// plane_s.transformProvidingInverse(inverseMV);
// plane_t.transformProvidingInverse(inverseMV);
// plane_r.transformProvidingInverse(inverseMV);
// plane_q.transformProvidingInverse(inverseMV);
MyTexGen* texgen = new MyTexGen;
texgen->setMatrix(MV);
texgen->setMode(osg::TexGen::EYE_LINEAR);
texgen->setPlane(osg::TexGen::S,plane_s);
texgen->setPlane(osg::TexGen::T,plane_t);
texgen->setPlane(osg::TexGen::R,plane_r);
texgen->setPlane(osg::TexGen::Q,plane_q);
int _unit = 1;
texgen->setPlane(osg::TexGen::S,osg::Plane(MVPT(0,0),MVPT(1,0),MVPT(2,0),MVPT(3,0)));
texgen->setPlane(osg::TexGen::T,osg::Plane(MVPT(0,1),MVPT(1,1),MVPT(2,1),MVPT(3,1)));
texgen->setPlane(osg::TexGen::R,osg::Plane(MVPT(0,2),MVPT(1,2),MVPT(2,2),MVPT(3,2)));
texgen->setPlane(osg::TexGen::Q,osg::Plane(MVPT(0,3),MVPT(1,3),MVPT(2,3),MVPT(3,3)));
stateset->setTextureAttributeAndModes(_unit,_texture.get(),osg::StateAttribute::ON);
stateset->setTextureAttribute(_unit,texgen);
@@ -262,7 +250,7 @@ void MyCullCallback::doPreRender(osg::Node& node, osgUtil::CullVisitor& cv)
cv.pushStateSet(stateset);
// must traverse the subgraph
// must traverse the shadower
traverse(&node,&cv);
cv.popStateSet();
@@ -415,44 +403,53 @@ osg::Node* createMovingModel(const osg::Vec3& center, float radius)
return model;
}
osg::Node* createModel()
// shadowed must be at least group right now as leaf nodes such as
// osg::Geode don't get traversed so their cull callbacks don't get called.
osg::Group* createShadowedScene(osg::Node* shadower,osg::Node* shadowed,const osg::Vec3& lightPosition,float radius,unsigned int textureUnit=1)
{
osg::Vec3 center(0.0f,0.0f,0.0f);
float radius = 100.0f;
osg::Group* root = osgNew osg::Group;
// the occluder subgraph
osg::Node* occluder = createMovingModel(center,radius*0.5f);
// the occludee subgraph
osg::Node* occludee = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.25),radius);
// now add a state with a texture for the shadow
osg::Texture2D* texture = new osg::Texture2D;
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
osg::Vec3 lightPosition(center+osg::Vec3(0.0f,0.0f,radius));
osg::Geode* lightgeode = new osg::Geode;
lightgeode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(lightPosition,radius/100.0f)));
osg::LightSource* lightgroup = new osg::LightSource;
osg::Light* light = new osg::Light;
light->setPosition(osg::Vec4(lightPosition,1.0f));
light->setLightNum(0);
osg::LightSource* lightsource = new osg::LightSource;
lightsource->setLight(light);
lightgroup->setLight(light);
osg::Vec4 ambientLightColor(0.1f,0.1f,0.1f,1.0f);
occludee->setCullCallback(new MyCullCallback(occluder,texture,lightPosition));
// add the shadower
lightgroup->addChild(shadower);
root->addChild(lightgeode);
root->addChild(lightsource);
root->addChild(occluder);
root->addChild(occludee);
// add the shadowed with the callback to generate the shadow texture.
shadowed->setCullCallback(new CreateShadowTextureCullCallback(shadower,lightPosition,ambientLightColor,textureUnit));
lightgroup->addChild(shadowed);
osg::Geode* lightgeode = new osg::Geode;
lightgeode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
lightgeode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(lightPosition,radius)));
lightgroup->addChild(lightgeode);
return lightgroup;
}
osg::Node* createModel()
{
osg::Vec3 center(0.0f,0.0f,0.0f);
float radius = 100.0f;
osg::Vec3 lightPosition(center+osg::Vec3(0.0f,0.0f,radius));
// the shadower model
osg::Node* shadower = createMovingModel(center,radius*0.5f);
// the shadowed model
osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.25),radius);
// combine the models together to create one which has the shadower and the shadowed with the required callback.
osg::Group* root = createShadowedScene(shadower,shadowed,lightPosition,radius/100.0f,1);
return root;
}