// M23.11.W5.Cull.Occluder.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
//osg
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/PolygonMode>
#include <osg/PolygonOffset>
#include <osg/OccluderNode>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/AnimationPathManipulator>
//osgAnimation
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/Channel>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/StackedTranslateElement>
#include <osgAnimation/StackedRotateAxisElement>
//osgAnimation-skeleton
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/UpdateBone>
#include <osgAnimation/StackedTransform>
#include <osgAnimation/StackedTranslateElement>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/TimelineAnimationManager>
#include <osgAnimation/ActionStripAnimation>
#include <osgAnimation/ActionBlendIn>
#include <osgAnimation/ActionBlendOut>
#include <osgAnimation/ActionAnimation>
//osglib
#pragma comment(lib,"OpenThreads_d.lib")
#pragma comment(lib,"osg_d.lib")
#pragma comment(lib,"osgDB_d.lib")
#pragma comment(lib,"osgFX_d.lib")
#pragma comment(lib,"osgGA_d.lib")
#pragma comment(lib,"osgUtil_d.lib")
#pragma comment(lib,"osgViewer_d.lib")
#pragma comment(lib,"osgShadow_d.lib")
#pragma comment(lib,"osgAnimation_d.lib")
osg::Node* createOccluder(const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3, const osg::Vec3& v4, float holeRatio = -1.0f)
{
// create an occluder which will sit alongside the loaded model.
osg::OccluderNode* occluderNode = new osg::OccluderNode;
// create the convex planar occluder
osg::ConvexPlanarOccluder* cpo = new osg::ConvexPlanarOccluder;
// attach it to the occluder node.
occluderNode->setOccluder(cpo);
occluderNode->setName("occluder");
// set the occluder up for the front face of the bounding box.
osg::ConvexPlanarPolygon& occluder = cpo->getOccluder();
occluder.add(v1);
occluder.add(v2);
occluder.add(v3);
occluder.add(v4);
// create a hole at the center of the occluder if needed.
if (holeRatio > 0.0f)
{
// create hole.
float ratio = holeRatio;
float one_minus_ratio = 1 - ratio;
osg::Vec3 center = (v1 + v2 + v3 + v4)*0.25f;
osg::Vec3 v1dash = v1*ratio + center*one_minus_ratio;
osg::Vec3 v2dash = v2*ratio + center*one_minus_ratio;
osg::Vec3 v3dash = v3*ratio + center*one_minus_ratio;
osg::Vec3 v4dash = v4*ratio + center*one_minus_ratio;
osg::ConvexPlanarPolygon hole;
hole.add(v1dash);
hole.add(v2dash);
hole.add(v3dash);
hole.add(v4dash);
cpo->addHole(hole);
}
osg::Geode* geode = new osg::Geode;
// 绘制出遮挡面、以及遮挡面上留的洞口
{// create a drawable for occluder.
osg::Geometry* geom = new osg::Geometry;
osg::Vec3Array* coords = new osg::Vec3Array(occluder.getVertexList().begin(), occluder.getVertexList().end());
std::vector<osg::ConvexPlanarPolygon> & vHole = cpo->getHoleList();
geom->setVertexArray(coords);
osg::Vec4Array* colors = new osg::Vec4Array(1);
(*colors)[0].set(0.0f, 1.0f, 1.0f, 0.5f);
geom->setColorArray(colors, osg::Array::BIND_OVERALL);
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
geode->addDrawable(geom);
osg::StateSet* stateset = new osg::StateSet;
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
//stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN);
geom->setStateSet(stateset);
for (const auto & planar : vHole)
{
// create a drawable for occluder.
osg::Geometry* geomhole = new osg::Geometry;
osg::Vec3Array* coordshole = new osg::Vec3Array(planar.getVertexList().begin(), planar.getVertexList().end());
geomhole->setVertexArray(coordshole);
geomhole->setColorArray(colors, osg::Array::BIND_OVERALL);
geomhole->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
geode->addDrawable(geomhole);
osg::StateSet* statesethole = new osg::StateSet;
osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
statesethole->setAttributeAndModes(polymode, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
geomhole->setStateSet(statesethole);
}
}
// add the occluder geode as a child of the occluder,
// as the occluder can't self occlude its subgraph the
// geode will never be occluded by this occluder.
occluderNode->addChild(geode);
return occluderNode;
}
osg::Group* createOccludersAroundModel(osg::Node* model)
{
osg::Group* scene = new osg::Group;
scene->setName("rootgroup");
// add the loaded model into a the scene group.
scene->addChild(model);
model->setName("model");
// get the bounding volume of the model.
const osg::BoundingSphere bs = model->getBound();
// create a bounding box around the sphere.
osg::BoundingBox bb;
bb.expandBy(bs);
// 包围盒的6个面当做 遮挡面
// front
scene->addChild(createOccluder(bb.corner(0),bb.corner(1),bb.corner(5),bb.corner(4)));
// right side
scene->addChild(createOccluder(bb.corner(1),bb.corner(3),bb.corner(7),bb.corner(5)));
// left side
scene->addChild(createOccluder(bb.corner(2),bb.corner(0),bb.corner(4),bb.corner(6)));
// back side
scene->addChild(createOccluder(bb.corner(3),bb.corner(2),bb.corner(6),bb.corner(7)));
// bottom side
scene->addChild(createOccluder(bb.corner(1),bb.corner(0),bb.corner(2),bb.corner(3)));
// top side
// create a hole half the size of the occluder.
scene->addChild(createOccluder(bb.corner(5),bb.corner(4),bb.corner(6),bb.corner(7), 0.5));
return scene;
}
int main(int argc, char* argv[])
{
osg::ArgumentParser psr(&argc, argv);
osgViewer::Viewer viewer(psr);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
osg::ref_ptr<osg::Node> loadedmodel = osgDB::readRefNodeFile("Data/cow.osg");
osg::ref_ptr<osg::Group> rootnode = createOccludersAroundModel(loadedmodel.get());
viewer.setSceneData(rootnode);
viewer.run();
return 0;
}
运行效果:
模拟从洞口往盒子里看 如图
模拟从盒子不带洞口的面往里看