Intergrated Martin Kada's impostor test program with the old test

program.
This commit is contained in:
Robert Osfield 2002-11-07 14:13:51 +00:00
parent 71bea99ba2
commit 93f3378b86
5 changed files with 725 additions and 132 deletions

View File

@ -2,6 +2,7 @@ TOPDIR = ../../..
include $(TOPDIR)/Make/makedefs include $(TOPDIR)/Make/makedefs
CXXFILES =\ CXXFILES =\
TestManipulator.cpp\
osgimpostor.cpp\ osgimpostor.cpp\
LIBS += $(OSG_LIBS) $(GLUT_LIB) $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) LIBS += $(OSG_LIBS) $(GLUT_LIB) $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)

View File

@ -1,26 +0,0 @@
Note: Using sgv with Peformer (for IRIX and Linux users only)
=============================================================
If you find problems with loading .pfb files its likely that its due to undefined
symbols. This isn't a problem with the OSG implementation, but alas the only
current solution is to directly link you app with the Performer libraries. The
Makefile contains two library list. In Makefile you'll see something like :
#note, use this library list when using the Performer osgPlugin.
#LIBS = ${PFLIBS} -losgGLUT -losgDB -losg -lGLU -lGL -lm -lXmu -lX11 -lXi
#note, standard library list.
LIBS = -losgGLUT -losgDB -losg -lGLU -lGL -lm -lXmu -lX11 -lXi
Simple comment in the LIBS line with PFLIBS and comment out the standard LIBS,
then :
make clean
make
Hopefully the Performer distribution will eventually work as a dynamic plugin
but until that day we're stuck with this 'hack'...
Robert Osfield,
March 2001.

View File

@ -0,0 +1,385 @@
#include "TestManipulator.h"
#include <osg/Types>
#include <osg/Notify>
using namespace osg;
using namespace osgGA;
TestManipulator::TestManipulator()
{
_modelScale = 0.01f;
_minimumZoomScale = 0.05f;
_thrown = false;
_distance = 1.0f;
}
TestManipulator::~TestManipulator()
{
}
void TestManipulator::setNode(osg::Node* node)
{
_node = node;
if (_node.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_modelScale = boundingSphere._radius;
}
}
const osg::Node* TestManipulator::getNode() const
{
return _node.get();
}
osg::Node* TestManipulator::getNode()
{
return _node.get();
}
/*ea*/
void TestManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us)
{
if(_node.get() && _camera.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_camera->setView(
osg::Vec3(0.0f, 0.0f, 20.0f),
osg::Vec3(0.0f, 1.0f, 20.0f),
osg::Vec3(0.0f, 0.0f, 1.0f));
computeLocalDataFromCamera();
us.requestRedraw();
}
}
void TestManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& )
{
flushMouseEventStack();
computeLocalDataFromCamera();
}
bool TestManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
if(!_camera.get()) return false;
switch(ea.getEventType())
{
case(GUIEventAdapter::PUSH):
{
flushMouseEventStack();
addMouseEvent(ea);
if (calcMovement()) us.requestRedraw();
us.requestContinuousUpdate(false);
_thrown = false;
return true;
}
case(GUIEventAdapter::RELEASE):
{
if (ea.getButtonMask()==0)
{
if (isMouseMoving())
{
if (calcMovement())
{
us.requestRedraw();
us.requestContinuousUpdate(true);
_thrown = true;
}
}
else
{
flushMouseEventStack();
addMouseEvent(ea);
if (calcMovement()) us.requestRedraw();
us.requestContinuousUpdate(false);
_thrown = false;
}
}
else
{
flushMouseEventStack();
addMouseEvent(ea);
if (calcMovement()) us.requestRedraw();
us.requestContinuousUpdate(false);
_thrown = false;
}
return true;
}
case(GUIEventAdapter::DRAG):
{
addMouseEvent(ea);
if (calcMovement()) us.requestRedraw();
us.requestContinuousUpdate(false);
_thrown = false;
return true;
}
case(GUIEventAdapter::MOVE):
{
return false;
}
case(GUIEventAdapter::KEYBOARD):
if (ea.getKey()==' ')
{
flushMouseEventStack();
_thrown = false;
home(ea,us);
us.requestRedraw();
us.requestContinuousUpdate(false);
return true;
} else if (ea.getKey()=='+')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f);
return true;
}
else if (ea.getKey()=='-')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f);
return true;
}
// this is quick hack to test out othographic projection.
// else if (ea.getKey()=='O')
// {
// float dist = _camera->getLookDistance();
// _camera->setOrtho(-dist,dist,-dist,dist,-dist,dist);
// return true;
// }
return false;
case(GUIEventAdapter::FRAME):
_camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_LOOK_DISTANCE);
if (_thrown)
{
if (calcMovement()) us.requestRedraw();
return true;
}
return false;
default:
return false;
}
}
bool TestManipulator::isMouseMoving()
{
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
static const float velocity = 100.0f;
float dx = _ga_t0->getX()-_ga_t1->getX();
float dy = _ga_t0->getY()-_ga_t1->getY();
float len = sqrtf(dx*dx+dy*dy);
float dt = _ga_t0->time()-_ga_t1->time();
return (len>dt*velocity);
}
void TestManipulator::flushMouseEventStack()
{
_ga_t1 = NULL;
_ga_t0 = NULL;
}
void TestManipulator::addMouseEvent(const GUIEventAdapter& ea)
{
_ga_t1 = _ga_t0;
_ga_t0 = &ea;
}
void TestManipulator::computeLocalDataFromCamera()
{
// maths from gluLookAt/osg::Matrix::makeLookAt
osg::Vec3 f(_camera->getCenterPoint()-_camera->getEyePoint());
f.normalize();
osg::Vec3 s(f^_camera->getUpVector());
s.normalize();
osg::Vec3 u(s^f);
u.normalize();
osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0f,
s[1], u[1], -f[1], 0.0f,
s[2], u[2], -f[2], 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
_center = _camera->getCenterPoint();
_distance = _camera->getLookDistance();
_rotation.set(rotation_matrix);
_rotation = _rotation.inverse();
}
void TestManipulator::computeCameraFromLocalData()
{
osg::Matrix new_rotation;
new_rotation.makeRotate(_rotation);
osg::Vec3 up = osg::Vec3(0.0f,1.0f,0.0) * new_rotation;
osg::Vec3 eye = (osg::Vec3(0.0f,0.0f,_distance) * new_rotation) + _center;
_camera->setLookAt(eye,_center,up);
}
bool TestManipulator::calcMovement()
{
// return if less then two events have been added.
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
float dx = _ga_t0->getX()-_ga_t1->getX();
float dy = _ga_t0->getY()-_ga_t1->getY();
// return if there is no movement.
if (dx==0 && dy==0) return false;
float focalLength = (_camera->getCenterPoint()-_camera->getEyePoint()).length();
unsigned int buttonMask = _ga_t1->getButtonMask();
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
// rotate camera.
float rx0 = (_ga_t0->getXmax()-_ga_t0->getXmin())/2.0f;
osg::Quat new_rotate;
float xRot = dx / rx0;
new_rotate.makeRotate(xRot / 5.0f, osg::Vec3(0.0f, 0.0f, 1.0f));
_rotation = _rotation*new_rotate;
computeCameraFromLocalData();
return true;
}
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
{
// pan model.
osg::Vec3 dv = osg::Vec3(0.0f, 0.0f, 1.0f) * dy;
_center += dv;
computeCameraFromLocalData();
return true;
}
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
osg::Vec3 uv = _camera->getUpVector();
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 fv = uv ^ sv;
osg::Vec3 dv = fv*dy-sv*dx;
_center += dv;
computeCameraFromLocalData();
return true;
}
return false;
}
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
const float TRACKBALLSIZE = 0.8f;
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void TestManipulator::trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y)
{
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
osg::Vec3 uv = _camera->getUpVector();
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 lv = _camera->getLookVector();
osg::Vec3 p1 = sv*p1x+uv*p1y-lv*tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y);
osg::Vec3 p2 = sv*p2x+uv*p2y-lv*tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y);
/*
* Now, we want the cross product of P1 and P2
*/
axis = p2^p1;
axis.normalize();
/*
* Figure out how much to rotate around that axis.
*/
float t = (p2-p1).length() / (2.0*TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0) t = 1.0;
if (t < -1.0) t = -1.0;
angle = inRadians(asin(t));
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
float TestManipulator::tb_project_to_sphere(float r, float x, float y)
{
float d, t, z;
d = sqrt(x*x + y*y);
/* Inside sphere */
if (d < r * 0.70710678118654752440)
{
z = sqrt(r*r - d*d);
} /* On hyperbola */
else
{
t = r / 1.41421356237309504880;
z = t*t / d;
}
return z;
}

View File

@ -0,0 +1,84 @@
//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
//Distributed under the terms of the GNU Library General Public License (LGPL)
//as published by the Free Software Foundation.
#ifndef OSGGA_TESTMANIPULATOR
#define OSGGA_TESTMANIPULATOR 1
#include <osgGA/CameraManipulator>
namespace osgGA{
class TestManipulator : public CameraManipulator
{
public:
TestManipulator();
virtual ~TestManipulator();
/** Attach a node to the manipulator.
Automatically detaches previously attached node.
setNode(NULL) detaches previously nodes.
Is ignored by manipulators which do not require a reference model.*/
virtual void setNode(osg::Node*);
/** Return node if attached.*/
virtual const osg::Node* getNode() const;
/** Return node if attached.*/
virtual osg::Node* getNode();
/** Move the camera to the default position.
May be ignored by manipulators if home functionality is not appropriate.*/
virtual void home(const GUIEventAdapter& ea,GUIActionAdapter& us);
/** Start/restart the manipulator.*/
virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us);
/** handle events, return true if handled, false otherwise.*/
virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us);
private:
/** Reset the internal GUIEvent stack.*/
void flushMouseEventStack();
/** Add the current mouse GUIEvent to internal stack.*/
void addMouseEvent(const GUIEventAdapter& ea);
void computeLocalDataFromCamera();
void computeCameraFromLocalData();
/** For the give mouse movement calculate the movement of the camera.
Return true is camera has moved and a redraw is required.*/
bool calcMovement();
void trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y);
float tb_project_to_sphere(float r, float x, float y);
/** Check the speed at which the mouse is moving.
If speed is below a threshold then return false, otherwise return true.*/
bool isMouseMoving();
// Internal event stack comprising last three mouse events.
osg::ref_ptr<const GUIEventAdapter> _ga_t1;
osg::ref_ptr<const GUIEventAdapter> _ga_t0;
osg::ref_ptr<osg::Node> _node;
float _modelScale;
float _minimumZoomScale;
bool _thrown;
osg::Vec3 _center;
osg::Quat _rotation;
float _distance;
};
}
#endif

View File

@ -1,146 +1,295 @@
#include <osg/Geometry>
#include <osg/Impostor> #include <osg/Impostor>
#include <osg/Notify> #include <osg/Material>
#include <osg/MatrixTransform>
#include <osg/Quat>
#include <osgUtil/InsertImpostorsVisitor>
#include <osgDB/Registry>
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator> #include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator> #include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator> #include <osgGA/DriveManipulator>
#include <osgUtil/InsertImpostorsVisitor>
#include <osgGLUT/glut> #include <osgGLUT/glut>
#include <osgGLUT/Viewer> #include <osgGLUT/Viewer>
#include <osg/Quat> #include "TestManipulator.h"
void write_usage(std::ostream& out,const std::string& name)
#include <iostream>
#include <list>
// container storing all house nodes
typedef osg::ref_ptr<osg::Node> NodePtr;
typedef std::list<NodePtr> NodeContainer;
typedef NodeContainer::iterator NodeIterator;
NodeContainer nodes;
//
osg::Group * Root = 0;
const int HOUSES_SIZE = 25000; // total number of houses
double XDim = 5000.0f; // area dimension +/- XDim
double ZDim = 5000.0f; // area dimension +/- YDim
int GridX = 20; // number of grids in x direction
int GridY = 20; // number of grids in y direction
bool UseImpostor = true; // use impostor (or do not use)
float Threshold = 3000.0f; // distance where impostor are shown
// create houses and store nodes in container
void CreateHouses()
{ {
out << std::endl; int i;
out <<"usage:"<< std::endl;
out <<" "<<name<<" [options] infile1 [infile2 ...]"<< std::endl; GLubyte indices[48] = {
out << std::endl; 0, 2, 1,
out <<"options:"<< std::endl; 3, 2, 0,
out <<" -l libraryName - load plugin of name libraryName"<< std::endl; 0, 4, 7,
out <<" i.e. -l osgdb_pfb"<< std::endl; 7, 3, 0,
out <<" Useful for loading reader/writers which can load"<< std::endl; 0, 1, 5,
out <<" other file formats in addition to its extension."<< std::endl; 5, 4, 0,
out <<" -e extensionName - load reader/wrter plugin for file extension"<< std::endl; 1, 6, 5,
out <<" i.e. -e pfb"<< std::endl; 2, 6, 1,
out <<" Useful short hand for specifying full library name as"<< std::endl; 2, 3, 7,
out <<" done with -l above, as it automatically expands to"<< std::endl; 2, 7, 6,
out <<" the full library name appropriate for each platform."<< std::endl; 4, 8, 7,
out <<std::endl; 5, 6, 9,
out <<" -stereo - switch on stereo rendering, using the default of,"<< std::endl; 4, 5, 8,
out <<" ANAGLYPHIC or the value set in the OSG_STEREO_MODE "<< std::endl; 8, 5, 9,
out <<" environmental variable. See doc/stereo.html for "<< std::endl; 6, 7, 8,
out <<" further details on setting up accurate stereo "<< std::endl; 8, 9, 6
out <<" for your system. "<< std::endl; };
out <<" -stereo ANAGLYPHIC - switch on anaglyphic(red/cyan) stereo rendering."<< std::endl;
out <<" -stereo QUAD_BUFFER - switch on quad buffered stereo rendering."<< std::endl; // use the same color, normal and indices for all houses.
out <<std::endl; osg::Vec4Array* colors = new osg::Vec4Array(1);
out <<" -stencil - use a visual with stencil buffer enabled, this "<< std::endl; (*colors)[0] = osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
out <<" also allows the depth complexity statistics mode"<< std::endl;
out <<" to be used (press 'p' three times to cycle to it)."<< std::endl; // normals
out << std::endl; osg::Vec3Array * normals = new osg::Vec3Array(16);
(*normals)[0] = osg::Vec3( 0.0f, -0.0f, -1.0f);
(*normals)[1] = osg::Vec3( 0.0f, -0.0f, -1.0f);
(*normals)[2] = osg::Vec3( 0.0f, -1.0f, 0.0f);
(*normals)[3] = osg::Vec3( 0.0f, -1.0f, 0.0f);
(*normals)[4] = osg::Vec3( 1.0f, -0.0f, 0.0f);
(*normals)[5] = osg::Vec3( 1.0f, -0.0f, 0.0f);
(*normals)[6] = osg::Vec3( 0.0f, 1.0f, 0.0f);
(*normals)[7] = osg::Vec3( 0.0f, 1.0f, 0.0f);
(*normals)[8] = osg::Vec3(-1.0f, -0.0f, 0.0f);
(*normals)[9] = osg::Vec3(-1.0f, -0.0f, 0.0f);
(*normals)[10] = osg::Vec3( 0.0f, -0.928477f, 0.371391f);
(*normals)[11] = osg::Vec3( 0.0f, 0.928477f, 0.371391f);
(*normals)[12] = osg::Vec3( 0.707107f, 0.0f, 0.707107f);
(*normals)[13] = osg::Vec3( 0.707107f, 0.0f, 0.707107f);
(*normals)[14] = osg::Vec3(-0.707107f, 0.0f, 0.707107f);
(*normals)[15] = osg::Vec3(-0.707107f, 0.0f, 0.707107f);
// coordIndices
osg::UByteArray* coordIndices = new osg::UByteArray(48,indices);
// share the primtive set.
osg::PrimitiveSet* primitives = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,48);
for (int q = 0; q < HOUSES_SIZE; q++)
{
float xPos = ((static_cast<double> (rand()) /
static_cast<double> (RAND_MAX))
* 2.0 * XDim) - XDim;
float yPos = ((static_cast<double> (rand()) /
static_cast<double> (RAND_MAX))
* 2 * ZDim) - ZDim;
float scale = 10.0f;
osg::Vec3 offset(xPos,yPos,0.0f);
// coords
osg::Vec3Array* coords = new osg::Vec3Array(10);
(*coords)[0] = osg::Vec3( 0.5f, -0.7f, 0.0f);
(*coords)[1] = osg::Vec3( 0.5f, 0.7f, 0.0f);
(*coords)[2] = osg::Vec3(-0.5f, 0.7f, 0.0f);
(*coords)[3] = osg::Vec3(-0.5f, -0.7f, 0.0f);
(*coords)[4] = osg::Vec3( 0.5f, -0.7f, 1.0f);
(*coords)[5] = osg::Vec3( 0.5f, 0.7f, 1.0f);
(*coords)[6] = osg::Vec3(-0.5f, 0.7f, 1.0f);
(*coords)[7] = osg::Vec3(-0.5f, -0.7f, 1.0f);
(*coords)[8] = osg::Vec3( 0.0f, -0.5f, 1.5f);
(*coords)[9] = osg::Vec3( 0.0f, 0.5f, 1.5f);
for (i = 0; i < 10; i++)
{
(*coords)[i] = (*coords)[i] * scale + offset;
}
// create geometry
osg::Geometry * geometry = new osg::Geometry();
geometry->addPrimitiveSet(primitives);
geometry->setVertexArray(coords);
geometry->setVertexIndices(coordIndices);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
geometry->setNormalArray(normals);
geometry->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
osg::Geode * geode = new osg::Geode();
geode->addDrawable(geometry);
nodes.push_back(geode);
}
} }
void LayoutAsGrid()
{
// calculate bounding box
osg::BoundingBox bbox;
for (NodeIterator node = nodes.begin(); node != nodes.end(); ++node)
bbox.expandBy((*node)->getBound());
// setup grid information
osg::Group ** groups = new osg::Group*[GridX * GridY];
for (int i = 0; i < GridX * GridY; i++)
groups[i] = new osg::Group();
float xGridStart = bbox.xMin();
float xGridSize = (bbox.xMax() - bbox.xMin()) / GridX;
float yGridStart = bbox.yMin();
float yGridSize = (bbox.yMax() - bbox.yMin()) / GridY;
// arrange buildings into right grid
for (NodeIterator nodeIter = nodes.begin(); nodeIter != nodes.end(); ++nodeIter)
{
osg::Node * node = nodeIter->get();
osg::Vec3 center = node->getBound().center();
int x = (int)floor((center.x() - xGridStart) / xGridSize);
int z = (int)floor((center.y() - yGridStart) / yGridSize);
groups[z * GridX + x]->addChild(node);
}
// add nodes to building root
for (int i = 0; i < GridX * GridY; i++)
{
osg::StateSet * stateset = new osg::StateSet();
osg::Material * material = new osg::Material();
osg::Vec4 color = osg::Vec4(
0.5f + (static_cast<double> (rand()) / (2.0*static_cast<double> (RAND_MAX))),
0.5f + (static_cast<double> (rand()) / (2.0*static_cast<double> (RAND_MAX))),
0.5f + (static_cast<double> (rand()) / ( 2.0*static_cast<double>(RAND_MAX))),
1.0f);
material->setAmbient(osg::Material::FRONT_AND_BACK, color);
material->setDiffuse(osg::Material::FRONT_AND_BACK, color);
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
groups[i]->setStateSet(stateset);
if (UseImpostor)
{
osg::Impostor * impostor = new osg::Impostor();
impostor->setImpostorThreshold(static_cast<float> (Threshold));
impostor->addChild(groups[i]);
impostor->setRange(0, 0.0f, 1e7f);
impostor->setCenter(groups[i]->getBound().center());
Root->addChild(impostor);
}
else
{
Root->addChild(groups[i]);
}
}
delete[] groups;
}
int main( int argc, char **argv ) int main( int argc, char **argv )
{ {
// initialize the GLUT
glutInit( &argc, argv ); glutInit( &argc, argv );
osgGLUT::Viewer viewer;
if (argc<2)
{
write_usage(osg::notify(osg::NOTICE),argv[0]);
return 0;
}
// create the commandline args. // create the commandline args.
std::vector<std::string> commandLine; std::vector<std::string> commandLine;
for(int i=1;i<argc;++i) commandLine.push_back(argv[i]); for(int i=1;i<argc;++i) commandLine.push_back(argv[i]);
osg::Timer timer;
osg::Timer_t before_load = timer.tick();
// initialize the viewer.
osgGLUT::Viewer viewer;
viewer.setWindowTitle(argv[0]);
// configure the viewer from the commandline arguments, and eat any
// parameters that have been matched.
viewer.readCommandLine(commandLine);
// configure the plugin registry from the commandline arguments, and
// eat any parameters that have been matched.
osgDB::readCommandLine(commandLine);
// load the nodes from the commandline arguments. // load the nodes from the commandline arguments.
osg::Node* model = osgDB::readNodeFiles(commandLine); osg::Node* model = osgDB::readNodeFiles(commandLine);
if (!model) if (model)
{ {
// write_usage(osg::notify(osg::NOTICE),argv[0]); // the osgUtil::InsertImpostorsVisitor used lower down to insert impostors
return 1; // only operators on subclass of Group's, if the model top node is not
} // a group then it won't be able to insert an impostor. We therefore
// manually insert an impostor above the model.
if (dynamic_cast<osg::Group*>(model)==0)
// the osgUtil::InsertImpostorsVisitor used lower down to insert impostors
// only operators on subclass of Group's, if the model top node is not
// a group then it won't be able to insert an impostor. We therefore
// manually insert an impostor above the model.
if (dynamic_cast<osg::Group*>(model)==0)
{
const osg::BoundingSphere& bs = model->getBound();
if (bs.valid())
{ {
const osg::BoundingSphere& bs = model->getBound();
if (bs.valid())
{
osg::Impostor* impostor = new osg::Impostor; osg::Impostor* impostor = new osg::Impostor;
// standard LOD settings // standard LOD settings
impostor->addChild(model); impostor->addChild(model);
impostor->setRange(0,0.0f,1e7f); impostor->setRange(0,0.0f,1e7f);
impostor->setCenter(bs.center()); impostor->setCenter(bs.center());
// impostor specfic settings. // impostor specfic settings.
impostor->setImpostorThresholdToBound(5.0f); impostor->setImpostorThresholdToBound(5.0f);
model = impostor;
model = impostor;
}
} }
}
// we insert an impostor node above the model, so we keep a handle
// on the rootnode of the model, the is required since the
// InsertImpostorsVisitor can add a new root in automatically and
// we would know about it, other than by following the parent path
// up from model. This is really what should be done, but I'll pass
// on it right now as it requires a getRoots() method to be added to
// osg::Node, and we're about to make a release so no new features!
osg::Group* rootnode = new osg::Group;
rootnode->addChild(model);
// now insert impostors in the model using the InsertImpostorsVisitor.
osgUtil::InsertImpostorsVisitor ov;
// traverse the model and collect all osg::Group's and osg::LOD's.
// however, don't traverse the rootnode since we want to keep it as
// the start of traversal, otherwise the insertImpostor could insert
// and Impostor above the current root, making it nolonger a root!
model->accept(ov);
// insert the Impostors above groups and LOD's
ov.insertImpostors();
osg::Timer_t after_load = timer.tick(); // we insert an impostor node above the model, so we keep a handle
std::cout << "Time for load = "<<timer.delta_s(before_load,after_load)<<" seconds"<< std::endl; // on the rootnode of the model, the is required since the
// InsertImpostorsVisitor can add a new root in automatically and
// we would know about it, other than by following the parent path
// up from model. This is really what should be done, but I'll pass
// on it right now as it requires a getRoots() method to be added to
// osg::Node, and we're about to make a release so no new features!
osg::Group* rootnode = new osg::Group;
rootnode->addChild(model);
// now insert impostors in the model using the InsertImpostorsVisitor.
osgUtil::InsertImpostorsVisitor ov;
// traverse the model and collect all osg::Group's and osg::LOD's.
// however, don't traverse the rootnode since we want to keep it as
// the start of traversal, otherwise the insertImpostor could insert
// and Impostor above the current root, making it nolonger a root!
model->accept(ov);
// insert the Impostors above groups and LOD's
ov.insertImpostors();
}
else
{
// no user model so we'll create our own world.
model = Root = new osg::Group();
CreateHouses();
LayoutAsGrid();
}
// add model to viewer. // add model to viewer.
viewer.addViewport( rootnode ); viewer.addViewport(model);
// register trackball, flight and drive. // register trackball, flight and drive.
viewer.registerCameraManipulator(new osgGA::TestManipulator);
viewer.registerCameraManipulator(new osgGA::TrackballManipulator); viewer.registerCameraManipulator(new osgGA::TrackballManipulator);
viewer.registerCameraManipulator(new osgGA::FlightManipulator); viewer.registerCameraManipulator(new osgGA::FlightManipulator);
viewer.registerCameraManipulator(new osgGA::DriveManipulator); viewer.registerCameraManipulator(new osgGA::DriveManipulator);