Further work on osgShadow::GeometryOccluder
This commit is contained in:
@@ -1,418 +1,16 @@
|
||||
#include <osg/ArgumentParser>
|
||||
|
||||
#include <osgProducer/Viewer>
|
||||
|
||||
#include <osg/Projection>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Texture>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/Geode>
|
||||
#include <osg/ShapeDrawable>
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Light>
|
||||
#include <osg/LightSource>
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Material>
|
||||
#include <osg/TexEnvCombine>
|
||||
#include <osg/TexEnv>
|
||||
|
||||
#include <osg/CameraNode>
|
||||
#include <osg/TexGenNode>
|
||||
#include <osgShadow/OccluderGeometry>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
using namespace osg;
|
||||
|
||||
class LightTransformCallback: public osg::NodeCallback
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LightTransformCallback(float angular_velocity, float height, float radius):
|
||||
_angular_velocity(angular_velocity),
|
||||
_height(height),
|
||||
_radius(radius),
|
||||
_previous_traversal_number(-1),
|
||||
_previous_time(-1.0f),
|
||||
_angle(0)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(Node* node, NodeVisitor* nv);
|
||||
|
||||
protected:
|
||||
|
||||
float _angular_velocity;
|
||||
float _height;
|
||||
float _radius;
|
||||
int _previous_traversal_number;
|
||||
double _previous_time;
|
||||
float _angle;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
LightTransformCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
{
|
||||
MatrixTransform* transform = dynamic_cast<MatrixTransform*>(node);
|
||||
if (nv && transform)
|
||||
{
|
||||
const FrameStamp* fs = nv->getFrameStamp();
|
||||
if (!fs) return; // not frame stamp, no handle on the time so can't move.
|
||||
|
||||
double new_time = fs->getReferenceTime();
|
||||
if (nv->getTraversalNumber() != _previous_traversal_number)
|
||||
{
|
||||
_angle += _angular_velocity * (new_time - _previous_time);
|
||||
|
||||
Matrix matrix = Matrix::rotate(atan(_height / _radius), -X_AXIS) *
|
||||
Matrix::rotate(PI_2, Y_AXIS) *
|
||||
Matrix::translate(Vec3(_radius, 0, 0)) *
|
||||
Matrix::rotate(_angle, Y_AXIS) *
|
||||
Matrix::translate(Vec3(0, _height, 0));
|
||||
|
||||
// update the specified transform
|
||||
transform->setMatrix(matrix);
|
||||
|
||||
_previous_traversal_number = nv->getTraversalNumber();
|
||||
}
|
||||
|
||||
_previous_time = new_time;
|
||||
}
|
||||
|
||||
// must call any nested node callbacks and continue subgraph traversal.
|
||||
traverse(node,nv);
|
||||
|
||||
}
|
||||
|
||||
|
||||
ref_ptr<MatrixTransform> _create_lights()
|
||||
{
|
||||
ref_ptr<MatrixTransform> transform_0 = new MatrixTransform;
|
||||
|
||||
// create a spot light.
|
||||
ref_ptr<Light> light_0 = new Light;
|
||||
light_0->setLightNum(0);
|
||||
light_0->setPosition(Vec4(0, 0, 0, 1.0f));
|
||||
light_0->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
light_0->setDiffuse(Vec4(1.0f, 0.8f, 0.8f, 1.0f));
|
||||
light_0->setSpotCutoff(60.0f);
|
||||
light_0->setSpotExponent(2.0f);
|
||||
|
||||
ref_ptr<LightSource> light_source_0 = new LightSource;
|
||||
light_source_0->setLight(light_0.get());
|
||||
light_source_0->setLocalStateSetModes(StateAttribute::ON);
|
||||
transform_0->setUpdateCallback(new LightTransformCallback(inDegrees(90.0f), 8, 5));
|
||||
transform_0->addChild(light_source_0.get());
|
||||
|
||||
ref_ptr<Geode> geode = new Geode;
|
||||
|
||||
ref_ptr<ShapeDrawable> shape;
|
||||
ref_ptr<TessellationHints> hints = new TessellationHints;
|
||||
hints->setDetailRatio(0.3f);
|
||||
shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), 0.15f), hints.get());
|
||||
shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f));
|
||||
geode->addDrawable(shape.get());
|
||||
shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, -0.4f), 0.05f, 0.8f), hints.get());
|
||||
shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f));
|
||||
geode->addDrawable(shape.get());
|
||||
|
||||
|
||||
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, StateAttribute::OFF);
|
||||
transform_0->addChild(geode.get());
|
||||
|
||||
return transform_0;
|
||||
}
|
||||
|
||||
ref_ptr<Group> _create_scene()
|
||||
{
|
||||
ref_ptr<Group> scene = new Group;
|
||||
ref_ptr<Geode> geode_1 = new Geode;
|
||||
scene->addChild(geode_1.get());
|
||||
|
||||
ref_ptr<Geode> geode_2 = new Geode;
|
||||
ref_ptr<MatrixTransform> transform_2 = new MatrixTransform;
|
||||
transform_2->addChild(geode_2.get());
|
||||
transform_2->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(45.0f)));
|
||||
scene->addChild(transform_2.get());
|
||||
|
||||
ref_ptr<Geode> geode_3 = new Geode;
|
||||
ref_ptr<MatrixTransform> transform_3 = new MatrixTransform;
|
||||
transform_3->addChild(geode_3.get());
|
||||
transform_3->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(-22.5f)));
|
||||
scene->addChild(transform_3.get());
|
||||
|
||||
const float radius = 0.8f;
|
||||
const float height = 1.0f;
|
||||
ref_ptr<TessellationHints> hints = new TessellationHints;
|
||||
hints->setDetailRatio(2.0f);
|
||||
ref_ptr<ShapeDrawable> shape;
|
||||
|
||||
shape = new ShapeDrawable(new Box(Vec3(0.0f, -2.0f, 0.0f), 10, 0.1f, 10), hints.get());
|
||||
shape->setColor(Vec4(0.5f, 0.5f, 0.7f, 1.0f));
|
||||
geode_1->addDrawable(shape.get());
|
||||
|
||||
shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get());
|
||||
shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f));
|
||||
geode_1->addDrawable(shape.get());
|
||||
|
||||
shape = new ShapeDrawable(new Sphere(Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get());
|
||||
shape->setColor(Vec4(0.6f, 0.8f, 0.8f, 1.0f));
|
||||
geode_2->addDrawable(shape.get());
|
||||
|
||||
shape = new ShapeDrawable(new Box(Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get());
|
||||
shape->setColor(Vec4(0.4f, 0.9f, 0.3f, 1.0f));
|
||||
geode_2->addDrawable(shape.get());
|
||||
|
||||
shape = new ShapeDrawable(new Cone(Vec3(0.0f, 0.0f, -3.0f), radius, height), hints.get());
|
||||
shape->setColor(Vec4(0.2f, 0.5f, 0.7f, 1.0f));
|
||||
geode_2->addDrawable(shape.get());
|
||||
|
||||
shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, 3.0f), radius, height), hints.get());
|
||||
shape->setColor(Vec4(1.0f, 0.3f, 0.3f, 1.0f));
|
||||
geode_2->addDrawable(shape.get());
|
||||
|
||||
shape = new ShapeDrawable(new Box(Vec3(0.0f, 3.0f, 0.0f), 2, 0.1f, 2), hints.get());
|
||||
shape->setColor(Vec4(0.8f, 0.8f, 0.4f, 1.0f));
|
||||
geode_3->addDrawable(shape.get());
|
||||
|
||||
// material
|
||||
ref_ptr<Material> matirial = new Material;
|
||||
matirial->setColorMode(Material::DIFFUSE);
|
||||
matirial->setAmbient(Material::FRONT_AND_BACK, Vec4(0, 0, 0, 1));
|
||||
matirial->setSpecular(Material::FRONT_AND_BACK, Vec4(1, 1, 1, 1));
|
||||
matirial->setShininess(Material::FRONT_AND_BACK, 64.0f);
|
||||
scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), StateAttribute::ON);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
|
||||
class UpdateCameraAndTexGenCallback : public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
|
||||
UpdateCameraAndTexGenCallback(osg::MatrixTransform* light_transform, osg::CameraNode* cameraNode, osg::TexGenNode* texgenNode):
|
||||
_light_transform(light_transform),
|
||||
_cameraNode(cameraNode),
|
||||
_texgenNode(texgenNode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
// first update subgraph to make sure objects are all moved into postion
|
||||
traverse(node,nv);
|
||||
|
||||
// now compute the camera's view and projection matrix to point at the shadower (the camera's children)
|
||||
osg::BoundingSphere bs;
|
||||
for(unsigned int i=0; i<_cameraNode->getNumChildren(); ++i)
|
||||
{
|
||||
bs.expandBy(_cameraNode->getChild(i)->getBound());
|
||||
}
|
||||
|
||||
if (!bs.valid())
|
||||
{
|
||||
osg::notify(osg::WARN) << "bb invalid"<<_cameraNode.get()<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
osg::Vec3 position = _light_transform->getMatrix().getTrans();
|
||||
|
||||
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;
|
||||
|
||||
_cameraNode->setReferenceFrame(osg::CameraNode::ABSOLUTE_RF);
|
||||
_cameraNode->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
|
||||
_cameraNode->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 = _cameraNode->getViewMatrix() *
|
||||
_cameraNode->getProjectionMatrix() *
|
||||
osg::Matrix::translate(1.0,1.0,1.0) *
|
||||
osg::Matrix::scale(0.5f,0.5f,0.5f);
|
||||
|
||||
_texgenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
|
||||
_texgenNode->getTexGen()->setPlanesFromMatrix(MVPT);
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~UpdateCameraAndTexGenCallback() {}
|
||||
|
||||
osg::ref_ptr<osg::MatrixTransform> _light_transform;
|
||||
osg::ref_ptr<osg::CameraNode> _cameraNode;
|
||||
osg::ref_ptr<osg::TexGenNode> _texgenNode;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
//
|
||||
char fragmentShaderSource_noBaseTexture[] =
|
||||
"uniform sampler2DShadow shadowTexture; \n"
|
||||
"uniform vec2 ambientBias; \n"
|
||||
"\n"
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n"
|
||||
"}\n";
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
//
|
||||
char fragmentShaderSource_withBaseTexture[] =
|
||||
"uniform sampler2D baseTexture; \n"
|
||||
"uniform sampler2DShadow shadowTexture; \n"
|
||||
"uniform vec2 ambientBias; \n"
|
||||
"\n"
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n"
|
||||
" gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n"
|
||||
"}\n";
|
||||
|
||||
|
||||
osg::Group* createShadowedScene(osg::Node* shadowed,osg::MatrixTransform* light_transform, unsigned int unit)
|
||||
{
|
||||
osg::Group* group = new osg::Group;
|
||||
|
||||
unsigned int tex_width = 1024;
|
||||
unsigned int tex_height = 1024;
|
||||
|
||||
osg::Texture2D* texture = new osg::Texture2D;
|
||||
texture->setTextureSize(tex_width, tex_height);
|
||||
|
||||
texture->setInternalFormat(GL_DEPTH_COMPONENT);
|
||||
texture->setShadowComparison(true);
|
||||
texture->setShadowTextureMode(Texture::LUMINANCE);
|
||||
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
|
||||
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
|
||||
|
||||
// set up the render to texture camera.
|
||||
{
|
||||
|
||||
// create the camera
|
||||
osg::CameraNode* camera = new osg::CameraNode;
|
||||
|
||||
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
|
||||
camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
|
||||
camera->setComputeNearFarMode(osg::CameraNode::DO_NOT_COMPUTE_NEAR_FAR);
|
||||
|
||||
// set viewport
|
||||
camera->setViewport(0,0,tex_width,tex_height);
|
||||
|
||||
osg::StateSet* _local_stateset = camera->getOrCreateStateSet();
|
||||
|
||||
_local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
|
||||
|
||||
float factor = 0.0f;
|
||||
float units = 1.0f;
|
||||
|
||||
ref_ptr<PolygonOffset> polygon_offset = new PolygonOffset;
|
||||
polygon_offset->setFactor(factor);
|
||||
polygon_offset->setUnits(units);
|
||||
_local_stateset->setAttribute(polygon_offset.get(), StateAttribute::ON | StateAttribute::OVERRIDE);
|
||||
_local_stateset->setMode(GL_POLYGON_OFFSET_FILL, StateAttribute::ON | StateAttribute::OVERRIDE);
|
||||
|
||||
ref_ptr<CullFace> cull_face = new CullFace;
|
||||
cull_face->setMode(CullFace::FRONT);
|
||||
_local_stateset->setAttribute(cull_face.get(), StateAttribute::ON | StateAttribute::OVERRIDE);
|
||||
_local_stateset->setMode(GL_CULL_FACE, StateAttribute::ON | StateAttribute::OVERRIDE);
|
||||
|
||||
|
||||
// set the camera to render before the main camera.
|
||||
camera->setRenderOrder(osg::CameraNode::PRE_RENDER);
|
||||
|
||||
// tell the camera to use OpenGL frame buffer object where supported.
|
||||
camera->setRenderTargetImplementation(osg::CameraNode::FRAME_BUFFER_OBJECT);
|
||||
|
||||
// attach the texture and use it as the color buffer.
|
||||
camera->attach(osg::CameraNode::DEPTH_BUFFER, texture);
|
||||
|
||||
// add subgraph to render
|
||||
camera->addChild(shadowed);
|
||||
|
||||
group->addChild(camera);
|
||||
|
||||
// create the texgen node to project the tex coords onto the subgraph
|
||||
osg::TexGenNode* texgenNode = new osg::TexGenNode;
|
||||
texgenNode->setTextureUnit(unit);
|
||||
group->addChild(texgenNode);
|
||||
|
||||
// set an update callback to keep moving the camera and tex gen in the right direction.
|
||||
group->setUpdateCallback(new UpdateCameraAndTexGenCallback(light_transform, camera, texgenNode));
|
||||
}
|
||||
|
||||
|
||||
// set the shadowed subgraph so that it uses the texture and tex gen settings.
|
||||
{
|
||||
osg::Group* shadowedGroup = new osg::Group;
|
||||
shadowedGroup->addChild(shadowed);
|
||||
group->addChild(shadowedGroup);
|
||||
|
||||
osg::StateSet* stateset = shadowedGroup->getOrCreateStateSet();
|
||||
stateset->setTextureAttributeAndModes(unit,texture,osg::StateAttribute::ON);
|
||||
stateset->setTextureMode(unit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
|
||||
stateset->setTextureMode(unit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
|
||||
stateset->setTextureMode(unit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
|
||||
|
||||
stateset->setTextureMode(unit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
|
||||
|
||||
osg::Program* program = new osg::Program;
|
||||
stateset->setAttribute(program);
|
||||
|
||||
if (unit==0)
|
||||
{
|
||||
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
|
||||
program->addShader(fragment_shader);
|
||||
|
||||
osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit);
|
||||
stateset->addUniform(shadowTextureSampler);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture);
|
||||
program->addShader(fragment_shader);
|
||||
|
||||
osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
|
||||
stateset->addUniform(baseTextureSampler);
|
||||
|
||||
osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit);
|
||||
stateset->addUniform(shadowTextureSampler);
|
||||
}
|
||||
|
||||
osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f));
|
||||
stateset->addUniform(ambientBias);
|
||||
|
||||
}
|
||||
|
||||
// add the shadower and shadowed.
|
||||
group->addChild(light_transform);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// use an ArgumentParser object to manage the program arguments.
|
||||
ArgumentParser arguments(&argc, argv);
|
||||
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");
|
||||
@@ -430,10 +28,6 @@ int main(int argc, char** argv)
|
||||
// get details on keyboard and mouse bindings used by the viewer.
|
||||
viewer.getUsage(*arguments. getApplicationUsage());
|
||||
|
||||
bool withBaseTexture = true;
|
||||
while(arguments.read("--with-base-texture")) { withBaseTexture = true; }
|
||||
while(arguments.read("--no-base-texture")) { withBaseTexture = false; }
|
||||
|
||||
// if user request help write it out to cout.
|
||||
if (arguments.read("-h") || arguments.read("--help"))
|
||||
{
|
||||
@@ -451,31 +45,22 @@ int main(int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ref_ptr<MatrixTransform> scene = new MatrixTransform;
|
||||
scene->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(125.0),1.0,0.0,0.0));
|
||||
|
||||
ref_ptr<Group> shadowed_scene = _create_scene();
|
||||
if (!shadowed_scene.valid()) return 1;
|
||||
|
||||
ref_ptr<MatrixTransform> light_transform = _create_lights();
|
||||
if (!light_transform.valid()) return 1;
|
||||
|
||||
ref_ptr<Group> shadowedScene;
|
||||
|
||||
|
||||
if (withBaseTexture)
|
||||
osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
|
||||
if (!model)
|
||||
{
|
||||
shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")), osg::StateAttribute::ON);
|
||||
shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),1);
|
||||
}
|
||||
else
|
||||
{
|
||||
shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),0);
|
||||
osg::notify(osg::NOTICE)<<"No model loaded, please specify a model to load."<<std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
scene->addChild(shadowedScene.get());
|
||||
|
||||
osg::ref_ptr<osgShadow::OccluderGeometry> occluder = new osgShadow::OccluderGeometry;
|
||||
occluder->computeOccluderGeometry(model.get());
|
||||
|
||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
|
||||
geode->addDrawable(occluder.get());
|
||||
|
||||
viewer.setSceneData(scene.get());
|
||||
viewer.setSceneData(geode.get());
|
||||
|
||||
// create the windows and run the threads.
|
||||
viewer.realize();
|
||||
|
||||
@@ -79,7 +79,9 @@ class OSG_EXPORT Material : public StateAttribute
|
||||
|
||||
virtual bool getModeUsage(ModeUsage& usage) const
|
||||
{
|
||||
usage.usesMode(GL_COLOR_MATERIAL);
|
||||
// note, since Material does it's own glEnable/glDisable of GL_COLOR_MATERIAL
|
||||
// we shouldn't declare usage of that mode, so commenting out the below usage.
|
||||
// usage.usesMode(GL_COLOR_MATERIAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,14 +68,16 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable
|
||||
|
||||
|
||||
/** Compute an occluder geometry containing all the geometry in specified subgraph.*/
|
||||
void computeOccluderGeometry(osg::Node* subgraph, float sampleRatio=1.0f);
|
||||
void computeOccluderGeometry(osg::Node* subgraph, osg::Matrix* matrix=0, float sampleRatio=1.0f);
|
||||
|
||||
/** Compute an occluder geometry containing the geometry in specified drawable.*/
|
||||
void computeOccluderGeometry(osg::Drawable* drawable, float sampleRatio=1.0f);
|
||||
void computeOccluderGeometry(osg::Drawable* drawable, osg::Matrix* matrix=0, float sampleRatio=1.0f);
|
||||
|
||||
/** Render the occluder geometry. */
|
||||
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
|
||||
|
||||
/** Compute the bounding box around occluder geometry.*/
|
||||
virtual osg::BoundingBox computeBound() const;
|
||||
|
||||
protected :
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
*/
|
||||
|
||||
#include <osgShadow/OccluderGeometry>
|
||||
#include <osg/Notify>
|
||||
#include <osg/Geode>
|
||||
#include <osg/io_utils>
|
||||
#include <osg/TriangleFunctor>
|
||||
#include <osg/TriangleIndexFunctor>
|
||||
|
||||
using namespace osgShadow;
|
||||
|
||||
@@ -26,14 +31,215 @@ OccluderGeometry::OccluderGeometry(const OccluderGeometry& oc, const osg::CopyOp
|
||||
}
|
||||
|
||||
|
||||
void OccluderGeometry::computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)
|
||||
class CollectOccludersVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
CollectOccludersVisitor(OccluderGeometry* oc, osg::Matrix* matrix, float ratio):
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
|
||||
_oc(oc),
|
||||
_ratio(ratio)
|
||||
{
|
||||
if (matrix) pushMatrix(*matrix);
|
||||
}
|
||||
|
||||
void apply(osg::Node& node)
|
||||
{
|
||||
if (node.getStateSet()) pushState(node.getStateSet());
|
||||
|
||||
traverse(node);
|
||||
|
||||
if (node.getStateSet()) popState();
|
||||
}
|
||||
|
||||
void apply(osg::Transform& transform)
|
||||
{
|
||||
if (transform.getStateSet()) pushState(transform.getStateSet());
|
||||
|
||||
osg::Matrix matrix;
|
||||
if (!_matrixStack.empty()) matrix = _matrixStack.back();
|
||||
|
||||
transform.computeLocalToWorldMatrix(matrix,this);
|
||||
|
||||
pushMatrix(matrix);
|
||||
|
||||
traverse(transform);
|
||||
|
||||
popMatrix();
|
||||
|
||||
if (transform.getStateSet()) popState();
|
||||
}
|
||||
|
||||
void apply(osg::Geode& geode)
|
||||
{
|
||||
if (geode.getStateSet()) pushState(geode.getStateSet());
|
||||
|
||||
for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
|
||||
{
|
||||
osg::Drawable* drawable = geode.getDrawable(i);
|
||||
|
||||
if (drawable->getStateSet()) pushState(drawable->getStateSet());
|
||||
|
||||
apply(geode.getDrawable(i));
|
||||
|
||||
if (drawable->getStateSet()) popState();
|
||||
}
|
||||
|
||||
if (geode.getStateSet()) popState();
|
||||
}
|
||||
|
||||
void pushState(osg::StateSet* stateset)
|
||||
{
|
||||
osg::StateAttribute::GLModeValue prevBlendModeValue = _blendModeStack.empty() ? osg::StateAttribute::GLModeValue(osg::StateAttribute::INHERIT) : _blendModeStack.back();
|
||||
osg::StateAttribute::GLModeValue newBlendModeValue = stateset->getMode(GL_BLEND);
|
||||
|
||||
if (!(newBlendModeValue & osg::StateAttribute::PROTECTED) &&
|
||||
(prevBlendModeValue & osg::StateAttribute::OVERRIDE) )
|
||||
{
|
||||
newBlendModeValue = prevBlendModeValue;
|
||||
}
|
||||
|
||||
_blendModeStack.push_back(newBlendModeValue);
|
||||
}
|
||||
|
||||
void popState()
|
||||
{
|
||||
_blendModeStack.pop_back();
|
||||
}
|
||||
|
||||
void pushMatrix(osg::Matrix& matrix)
|
||||
{
|
||||
_matrixStack.push_back(matrix);
|
||||
}
|
||||
|
||||
void popMatrix()
|
||||
{
|
||||
_matrixStack.pop_back();
|
||||
}
|
||||
|
||||
void apply(osg::Drawable* drawable)
|
||||
{
|
||||
osg::StateAttribute::GLModeValue blendModeValue = _blendModeStack.empty() ? osg::StateAttribute::GLModeValue(osg::StateAttribute::INHERIT) : _blendModeStack.back();
|
||||
if (blendModeValue & osg::StateAttribute::ON)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Ignoring transparent drawable."<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
_oc->computeOccluderGeometry(drawable, (_matrixStack.empty() ? 0 : &_matrixStack.back()), _ratio);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
OccluderGeometry* _oc;
|
||||
|
||||
typedef std::vector<osg::Matrix> MatrixStack;
|
||||
typedef std::vector<osg::StateAttribute::GLModeValue> ModeStack;
|
||||
|
||||
float _ratio;
|
||||
MatrixStack _matrixStack;
|
||||
ModeStack _blendModeStack;
|
||||
|
||||
};
|
||||
|
||||
void OccluderGeometry::computeOccluderGeometry(osg::Node* subgraph, osg::Matrix* matrix, float sampleRatio)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)"<<std::endl;
|
||||
|
||||
CollectOccludersVisitor cov(this, matrix, sampleRatio);
|
||||
subgraph->accept(cov);
|
||||
|
||||
osg::notify(osg::NOTICE)<<"done"<<std::endl;
|
||||
}
|
||||
|
||||
void OccluderGeometry::computeOccluderGeometry(osg::Drawable* drawable, float sampleRatio)
|
||||
struct TriangleIndexCollector
|
||||
{
|
||||
OccluderGeometry::Vec3List& _vertices;
|
||||
OccluderGeometry::UIntList& _triangleIndices;
|
||||
unsigned int _baseIndex;
|
||||
|
||||
TriangleIndexCollector(OccluderGeometry::Vec3List& vertices, OccluderGeometry::UIntList& triangleIndices):
|
||||
_vertices(vertices),
|
||||
_triangleIndices(triangleIndices)
|
||||
{
|
||||
_baseIndex = _vertices.size();
|
||||
}
|
||||
|
||||
inline void operator()(unsigned int p1, unsigned int p2, unsigned int p3)
|
||||
{
|
||||
_triangleIndices.push_back(_baseIndex + p1);
|
||||
_triangleIndices.push_back(_baseIndex + p2);
|
||||
_triangleIndices.push_back(_baseIndex + p3);
|
||||
}
|
||||
|
||||
};
|
||||
typedef osg::TriangleIndexFunctor<TriangleIndexCollector> TriangleIndexCollectorFunctor;
|
||||
|
||||
struct TriangleCollector
|
||||
{
|
||||
OccluderGeometry::Vec3List& _vertices;
|
||||
OccluderGeometry::UIntList& _triangleIndices;
|
||||
|
||||
typedef std::vector<const osg::Vec3*> VertexPointers;
|
||||
VertexPointers _vertexPointers;
|
||||
|
||||
OccluderGeometry::Vec3List _tempoaryTriangleVertices;
|
||||
|
||||
TriangleCollector(OccluderGeometry::Vec3List& vertices, OccluderGeometry::UIntList& triangleIndices):
|
||||
_vertices(vertices),
|
||||
_triangleIndices(triangleIndices)
|
||||
{
|
||||
}
|
||||
|
||||
// bool intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r)
|
||||
inline void operator () (const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3, bool treatVertexDataAsTemporary)
|
||||
{
|
||||
if (treatVertexDataAsTemporary)
|
||||
{
|
||||
_tempoaryTriangleVertices.push_back(v1);
|
||||
_tempoaryTriangleVertices.push_back(v2);
|
||||
_tempoaryTriangleVertices.push_back(v3);
|
||||
}
|
||||
else
|
||||
{
|
||||
_vertexPointers.push_back(&v1);
|
||||
_vertexPointers.push_back(&v2);
|
||||
_vertexPointers.push_back(&v3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
typedef osg::TriangleFunctor<TriangleCollector> TriangleCollectorFunctor;
|
||||
|
||||
void OccluderGeometry::computeOccluderGeometry(osg::Drawable* drawable, osg::Matrix* matrix, float sampleRatio)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)"<<std::endl;
|
||||
if (matrix)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<" matrix"<<*matrix<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<" no matrix"<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void OccluderGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"drawImplementation(osg::RenderInfo& renderInfo)"<<std::endl;
|
||||
}
|
||||
|
||||
osg::BoundingBox OccluderGeometry::computeBound() const
|
||||
{
|
||||
osg::BoundingBox bb;
|
||||
for(Vec3List::const_iterator itr = _vertices.begin();
|
||||
itr != _vertices.end();
|
||||
++itr)
|
||||
{
|
||||
bb.expandBy(*itr);
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user