From Ravi Mathur, "OK I have been away for a looong time, but still occasionally watching from a distance, and saw the bug people have reported about the DepthPartitionNode not handling scaled models properly.

I believe this is now fixed ... I have attached the new DistanceAccumulator.cpp, along with a modified example file that uses a PositionAttitudeTransform to draw the Earth's orbit around the Sun."
This commit is contained in:
Robert Osfield 2009-04-09 14:25:14 +00:00
parent 38b02a26a9
commit fddaaf0d00
2 changed files with 136 additions and 40 deletions

View File

@ -34,9 +34,13 @@ bool precedes(const DistanceAccumulator::DistancePair &a,
else return false;
}
/** Computes distance betwen a point and the viewpoint of a matrix */
/** Computes distance (in z direction) betwen a point and the viewer's eye,
given by a view matrix */
double distance(const osg::Vec3 &coord, const osg::Matrix& matrix)
{
// Here we are taking only the z coordinate of the point transformed
// by the matrix, ie coord*matrix. The negative sign is because we
// want to consider into the screen as INCREASING distance.
return -( coord[0]*matrix(0,2) + coord[1]*matrix(1,2) +
coord[2]*matrix(2,2) + matrix(3,2) );
}
@ -99,19 +103,57 @@ bool CURRENT_CLASS::shouldContinueTraversal(osg::Node &node)
// Allow traversal to continue if we haven't reached maximum depth.
bool keepTraversing = (_currentDepth < _maxDepth);
const osg::BoundingSphere &bs = node.getBound();
osg::BoundingSphere bs = node.getBound();
double zNear = 0.0, zFar = 0.0;
// Make sure bounding sphere is valid and within viewing volume
// Make sure bounding sphere is valid
if(bs.valid())
{
// Make sure bounding sphere is within the viewing volume
if(!_localFrusta.back().contains(bs)) keepTraversing = false;
else
else // Compute near and far planes for this node
{
// Compute near and far planes for this node
zNear = distance(bs._center, _viewMatrices.back());
zFar = zNear + bs._radius;
zNear -= bs._radius;
// Since the view matrix could involve complex transformations,
// we need to determine a new BoundingSphere that would encompass
// the transformed BoundingSphere.
const osg::Matrix &l2w = _viewMatrices.back();
// Get the transformed x-axis of the BoundingSphere
osg::Vec3d newX = bs._center;
newX.x() += bs._radius; // Get X-edge of bounding sphere
newX = newX * l2w;
// Get the transformed y-axis of the BoundingSphere
osg::Vec3d newY = bs._center;
newY.y() += bs._radius; // Get Y-edge of bounding sphere
newY = newY * l2w;
// Get the transformed z-axis of the BoundingSphere
osg::Vec3d newZ = bs._center;
newZ.z() += bs._radius; // Get Z-edge of bounding sphere
newZ = newZ * l2w;
// Get the transformed center of the BoundingSphere
bs._center = bs._center * l2w;
// Compute lengths of transformed x, y, and z axes
double newXLen = (newX - bs._center).length();
double newYLen = (newY - bs._center).length();
double newZLen = (newZ - bs._center).length();
// The encompassing radius is the max of the transformed lengths
bs._radius = newXLen;
if(newYLen > bs._radius) bs._radius = newYLen;
if(newZLen > bs._radius) bs._radius = newZLen;
// Now we can compute the near & far planes, noting that for
// complex view transformations (ie. involving scales) the new
// BoundingSphere may be bigger than the original one.
// Note that the negative sign on the bounding sphere center is
// because we want distance to increase INTO the screen.
zNear = -bs._center.z() - bs._radius;
zFar = -bs._center.z() + bs._radius;
// If near/far ratio is big enough, then we don't need to keep
// traversing children of this node.
@ -130,9 +172,9 @@ void CURRENT_CLASS::apply(osg::Node &node)
if(shouldContinueTraversal(node))
{
// Traverse this node
_currentDepth++;
++_currentDepth;
traverse(node);
_currentDepth--;
--_currentDepth;
}
}
@ -145,9 +187,9 @@ void CURRENT_CLASS::apply(osg::Projection &proj)
pushLocalFrustum();
// Traverse the group
_currentDepth++;
++_currentDepth;
traverse(proj);
_currentDepth--;
--_currentDepth;
// Reload original matrix and frustum
_localFrusta.pop_back();
@ -171,9 +213,9 @@ void CURRENT_CLASS::apply(osg::Transform &transform)
pushLocalFrustum();
}
_currentDepth++;
++_currentDepth;
traverse(transform);
_currentDepth--;
--_currentDepth;
if(pushMatrix)
{
@ -195,7 +237,7 @@ void CURRENT_CLASS::apply(osg::Geode &geode)
double zNear, zFar;
// Handle each drawable in this geode
for(unsigned int i = 0; i < geode.getNumDrawables(); i++)
for(unsigned int i = 0; i < geode.getNumDrawables(); ++i)
{
drawable = geode.getDrawable(i);
@ -268,7 +310,7 @@ void CURRENT_CLASS::computeCameraPairs()
// pairs (called combined pairs) will not overlap.
PairList combinedPairs;
DistancePair currPair = _distancePairs.front();
for(i = _distancePairs.begin(); i != _distancePairs.end(); i++)
for(i = _distancePairs.begin(); i != _distancePairs.end(); ++i)
{
// Current distance pair does not overlap current combined pair, so
// save the current combined pair and start a new one.
@ -290,7 +332,7 @@ void CURRENT_CLASS::computeCameraPairs()
double currNearLimit, numSegs, new_ratio;
double ratio_invlog = 1.0/log(_nearFarRatio);
unsigned int temp;
for(i = combinedPairs.begin(); i != combinedPairs.end(); i++)
for(i = combinedPairs.begin(); i != combinedPairs.end(); ++i)
{
currPair = *i; // Save current view segment
@ -311,7 +353,7 @@ void CURRENT_CLASS::computeCameraPairs()
}
// See if the closest view segment can absorb other combined pairs
for(j = i+1; j != combinedPairs.end(); j++)
for(j = i+1; j != combinedPairs.end(); ++j)
{
// No other distance pairs can be included
if(j->first < currNearLimit) break;

View File

@ -38,33 +38,87 @@ osg::Node* createScene()
// Create the Earth, in blue
osg::ShapeDrawable *earth_sd = new osg::ShapeDrawable;
osg::Sphere* earth_sphere = new osg::Sphere;
earth_sphere->setName("EarthSphere");
earth_sphere->setRadius(r_earth);
earth_sd->setShape(earth_sphere);
earth_sd->setColor(osg::Vec4(0, 0, 1.0, 1.0));
osg::Geode* earth = new osg::Geode;
earth->setName("earth");
earth->addDrawable(earth_sd);
osg::Geode* earth_geode = new osg::Geode;
earth_geode->setName("EarthGeode");
earth_geode->addDrawable(earth_sd);
// Create the Sun, in yellow
osg::ShapeDrawable *sun_sd = new osg::ShapeDrawable;
osg::Sphere* sun_sphere = new osg::Sphere;
sun_sphere->setName("SunSphere");
sun_sphere->setRadius(r_sun);
sun_sd->setShape(sun_sphere);
sun_sd->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
osg::Geode* sun_geode = new osg::Geode;
sun_geode->setName("sun");
sun_geode->setName("SunGeode");
sun_geode->addDrawable(sun_sd);
// Move the sun behind the earth
osg::PositionAttitudeTransform *pat = new osg::PositionAttitudeTransform;
pat->setPosition(osg::Vec3d(0.0, AU, 0.0));
pat->addChild(sun_geode);
osg::Geometry * unitCircle = new osg::Geometry();
{
osg::Vec4Array * colours = new osg::Vec4Array(1);
(*colours)[0] = osg::Vec4d(1.0,1.0,1.0,1.0);
unitCircle->setColorArray(colours);
unitCircle->setColorBinding(osg::Geometry::BIND_OVERALL);
const unsigned int n_points = 1024;
osg::Vec3Array * coords = new osg::Vec3Array(n_points);
const double dx = 2.0*M_PI/n_points;
double s,c;
for (unsigned int j=0; j<n_points; ++j) {
s = sin(dx*j);
c = cos(dx*j);
(*coords)[j].set(osg::Vec3d(c,s,0.0));
}
unitCircle->setVertexArray(coords);
unitCircle->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
unitCircle->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,n_points));
}
osg::Geometry *axes = new osg::Geometry;
{
osg::Vec4Array *colours = new osg::Vec4Array(1);
(*colours)[0] = osg::Vec4d(1.0,0.0,0.0,1.0);
axes->setColorArray(colours);
axes->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::Vec3Array *coords = new osg::Vec3Array(6);
(*coords)[0].set(osg::Vec3d(0.0, 0.0, 0.0));
(*coords)[1].set(osg::Vec3d(0.5, 0.0, 0.0));
(*coords)[2].set(osg::Vec3d(0.0, 0.0, 0.0));
(*coords)[3].set(osg::Vec3d(0.0, 0.5, 0.0));
(*coords)[4].set(osg::Vec3d(0.0, 0.0, 0.0));
(*coords)[5].set(osg::Vec3d(0.0, 0.0, 0.5));
axes->setVertexArray(coords);
axes->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
axes->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
}
// Earth orbit
osg::Geode * earthOrbitGeode = new osg::Geode;
earthOrbitGeode->addDrawable(unitCircle);
earthOrbitGeode->addDrawable(axes);
earthOrbitGeode->setName("EarthOrbitGeode");
osg::PositionAttitudeTransform * earthOrbitPAT = new osg::PositionAttitudeTransform;
earthOrbitPAT->setScale(osg::Vec3d(AU,AU,AU));
earthOrbitPAT->setPosition(osg::Vec3d(0.0, AU, 0.0));
earthOrbitPAT->addChild(earthOrbitGeode);
earthOrbitPAT->setName("EarthOrbitPAT");
osg::Group* scene = new osg::Group;
scene->addChild(earth);
scene->setName("SceneGroup");
scene->addChild(earth_geode);
scene->addChild(pat);
pat->addChild(sun_geode);
scene->addChild(earthOrbitPAT);
return scene;
}