Merge branch 'timoore/optimizations' into next

Some changes aimed at reducing the cost of the huge scene graph.
This commit is contained in:
Tim Moore
2012-07-20 00:37:39 +02:00
4 changed files with 180 additions and 59 deletions
+3 -1
View File
@@ -314,7 +314,9 @@ OptimizeModelPolicy::OptimizeModelPolicy(const string& extension) :
_osgOptions(Optimizer::SHARE_DUPLICATE_STATE _osgOptions(Optimizer::SHARE_DUPLICATE_STATE
| Optimizer::MERGE_GEOMETRY | Optimizer::MERGE_GEOMETRY
| Optimizer::FLATTEN_STATIC_TRANSFORMS | Optimizer::FLATTEN_STATIC_TRANSFORMS
| Optimizer::TRISTRIP_GEOMETRY) | Optimizer::INDEX_MESH
| Optimizer::VERTEX_POSTTRANSFORM
| Optimizer::VERTEX_PRETRANSFORM)
{ {
} }
+137 -55
View File
@@ -12,6 +12,7 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <OpenThreads/Atomic>
#include <OpenThreads/Mutex> #include <OpenThreads/Mutex>
#include <OpenThreads/ReentrantMutex> #include <OpenThreads/ReentrantMutex>
#include <OpenThreads/ScopedLock> #include <OpenThreads/ScopedLock>
@@ -42,6 +43,7 @@
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/structure/SGBinding.hxx> #include <simgear/structure/SGBinding.hxx>
#include <simgear/scene/material/EffectGeode.hxx> #include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/EffectCullVisitor.hxx>
#include <simgear/scene/util/OsgMath.hxx> #include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx> #include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/SGSceneUserData.hxx> #include <simgear/scene/util/SGSceneUserData.hxx>
@@ -655,7 +657,9 @@ public:
SGExpressiond const* animationValue) : SGExpressiond const* animationValue) :
_condition(condition), _condition(condition),
_animationValue(animationValue) _animationValue(animationValue)
{ } {
setName("SGTranslateAnimation::UpdateCallback");
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{ {
if (!_condition || _condition->test()) { if (!_condition || _condition->test()) {
@@ -722,60 +726,129 @@ SGTranslateAnimation::createAnimationGroup(osg::Group& parent)
// Implementation of rotate/spin animation // Implementation of rotate/spin animation
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
class SGRotateAnimation::UpdateCallback : public osg::NodeCallback { //Cull callback
class RotAnimCallback : public osg::NodeCallback
{
public: public:
UpdateCallback(SGCondition const* condition, RotAnimCallback(SGCondition const* condition,
SGExpressiond const* animationValue) : SGExpressiond const* animationValue,
_condition(condition), double initialValue = 0.0) :
_animationValue(animationValue) _condition(condition),
{ } _animationValue(animationValue),
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) _initialValue(initialValue),
{ _lastValue(0.0)
if (!_condition || _condition->test()) { { }
SGRotateTransform* transform; virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
transform = static_cast<SGRotateTransform*>(node);
transform->setAngleDeg(_animationValue->getValue());
}
traverse(node, nv);
}
public: public:
SGSharedPtr<SGCondition const> _condition; SGSharedPtr<SGCondition const> _condition;
SGSharedPtr<SGExpressiond const> _animationValue; SGSharedPtr<SGExpressiond const> _animationValue;
double _initialValue;
double _lastValue;
}; };
class SGRotateAnimation::SpinUpdateCallback : public osg::NodeCallback { void RotAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
using namespace osg;
SGRotateTransform* transform = static_cast<SGRotateTransform*>(node);
EffectCullVisitor* cv = dynamic_cast<EffectCullVisitor*>(nv);
if (!cv)
return;
double angle = 0.0;
if (!_condition || _condition->test()) {
angle = _animationValue->getValue() - _initialValue;
_lastValue = angle;
} else {
angle = _lastValue;
}
const SGVec3d& sgcenter = transform->getCenter();
const SGVec3d& sgaxis = transform->getAxis();
Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2])
* Matrixd::rotate(SGMiscd::deg2rad(angle), sgaxis[0], sgaxis[1], sgaxis[2])
* Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2])
* *cv->getModelViewMatrix();
ref_ptr<RefMatrix> refmat = new RefMatrix(mat);
cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame());
traverse(transform, nv);
cv->popModelViewMatrix();
}
// Cull callback
class SpinAnimCallback : public osg::NodeCallback {
public: public:
SpinUpdateCallback(SGCondition const* condition, SpinAnimCallback(SGCondition const* condition,
SGExpressiond const* animationValue) : SGExpressiond const* animationValue,
double initialValue = 0.0) :
_condition(condition), _condition(condition),
_animationValue(animationValue), _animationValue(animationValue),
_lastTime(-1) _initialValue(initialValue)
{ } {}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
{
if (!_condition || _condition->test()) {
SGRotateTransform* transform;
transform = static_cast<SGRotateTransform*>(node);
double t = nv->getFrameStamp()->getReferenceTime();
double dt = 0;
if (0 <= _lastTime)
dt = t - _lastTime;
_lastTime = t;
double velocity_rpms = _animationValue->getValue()/60;
double angle = transform->getAngleDeg();
angle += dt*velocity_rpms*360;
angle -= 360*floor(angle/360);
transform->setAngleDeg(angle);
}
traverse(node, nv);
}
public: public:
SGSharedPtr<SGCondition const> _condition; SGSharedPtr<SGCondition const> _condition;
SGSharedPtr<SGExpressiond const> _animationValue; SGSharedPtr<SGExpressiond const> _animationValue;
double _lastTime; double _initialValue;
protected:
// This cull callback can run in different threads if there is
// more than one camera. It is probably safe to overwrite the
// reference values in multiple threads, but we'll provide a
// threadsafe way to manage those values just to be safe.
struct ReferenceValues {
ReferenceValues(double t, double rot, double vel)
: _time(t), _rotation(rot), _rotVelocity(vel)
{
}
double _time;
double _rotation;
double _rotVelocity;
};
OpenThreads::AtomicPtr _referenceValues;
}; };
void SpinAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
using namespace osg;
SGRotateTransform* transform = static_cast<SGRotateTransform*>(node);
EffectCullVisitor* cv = dynamic_cast<EffectCullVisitor*>(nv);
if (!cv)
return;
if (!_condition || _condition->test()) {
double t = nv->getFrameStamp()->getReferenceTime();
double rps = _animationValue->getValue() / 60.0;
ReferenceValues* refval = static_cast<ReferenceValues*>(_referenceValues.get());
if (!refval || refval->_rotVelocity != rps) {
ReferenceValues* newref = 0;
if (!refval) {
// initialization
newref = new ReferenceValues(t, 0.0, rps);
} else {
double newRot = refval->_rotation + (t - refval->_time) * refval->_rotVelocity;
newref = new ReferenceValues(t, newRot, rps);
}
if (_referenceValues.assign(newref, refval)) {
delete refval;
}
refval = newref;
}
double rotation = refval->_rotation + (t - refval->_time) * rps;
double intPart;
double rot = modf(rotation, &intPart);
double angle = rot * 2.0 * osg::PI;
const SGVec3d& sgcenter = transform->getCenter();
const SGVec3d& sgaxis = transform->getAxis();
Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2])
* Matrixd::rotate(angle, sgaxis[0], sgaxis[1], sgaxis[2])
* Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2])
* *cv->getModelViewMatrix();
ref_ptr<RefMatrix> refmat = new RefMatrix(mat);
cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame());
traverse(transform, nv);
cv->popModelViewMatrix();
} else {
traverse(transform, nv);
}
}
SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) : SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot) SGAnimation(configNode, modelRoot)
@@ -792,7 +865,6 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
_initialValue = _animationValue->getValue(); _initialValue = _animationValue->getValue();
else else
_initialValue = 0; _initialValue = 0;
_center = SGVec3d::zeros(); _center = SGVec3d::zeros();
if (configNode->hasValue("axis/x1-m")) { if (configNode->hasValue("axis/x1-m")) {
SGVec3d v1, v2; SGVec3d v1, v2;
@@ -823,12 +895,12 @@ SGRotateAnimation::createAnimationGroup(osg::Group& parent)
SGRotateTransform* transform = new SGRotateTransform; SGRotateTransform* transform = new SGRotateTransform;
transform->setName("rotate animation"); transform->setName("rotate animation");
if (_isSpin) { if (_isSpin) {
SpinUpdateCallback* uc; SpinAnimCallback* cc;
uc = new SpinUpdateCallback(_condition, _animationValue); cc = new SpinAnimCallback(_condition, _animationValue, _initialValue);
transform->setUpdateCallback(uc); transform->setCullCallback(cc);
} else if (_animationValue || !_animationValue->isConst()) { } else if (_animationValue || !_animationValue->isConst()) {
UpdateCallback* uc = new UpdateCallback(_condition, _animationValue); RotAnimCallback* cc = new RotAnimCallback(_condition, _animationValue, _initialValue);
transform->setUpdateCallback(uc); transform->setCullCallback(cc);
} }
transform->setCenter(_center); transform->setCenter(_center);
transform->setAxis(_axis); transform->setAxis(_axis);
@@ -851,6 +923,7 @@ public:
_animationValue[0] = animationValue[0]; _animationValue[0] = animationValue[0];
_animationValue[1] = animationValue[1]; _animationValue[1] = animationValue[1];
_animationValue[2] = animationValue[2]; _animationValue[2] = animationValue[2];
setName("SGScaleAnimation::UpdateCallback");
} }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{ {
@@ -1373,7 +1446,9 @@ public:
_maxAnimationValue(maxAnimationValue), _maxAnimationValue(maxAnimationValue),
_minStaticValue(minValue), _minStaticValue(minValue),
_maxStaticValue(maxValue) _maxStaticValue(maxValue)
{} {
setName("SGRangeAnimation::UpdateCallback");
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{ {
osg::LOD* lod = static_cast<osg::LOD*>(node); osg::LOD* lod = static_cast<osg::LOD*>(node);
@@ -1629,7 +1704,9 @@ public:
UpdateCallback(const SGPropertyNode* configNode, const SGExpressiond* v) : UpdateCallback(const SGPropertyNode* configNode, const SGExpressiond* v) :
_prev_value(-1), _prev_value(-1),
_animationValue(v) _animationValue(v)
{ } {
setName("SGBlendAnimation::UpdateCallback");
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{ {
double blend = _animationValue->getValue(); double blend = _animationValue->getValue();
@@ -1708,6 +1785,7 @@ public:
rNode->getDoubleValue( "max", 1)); rNode->getDoubleValue( "max", 1));
} }
} }
setName("SGTimedAnimation::UpdateCallback");
} }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{ {
@@ -1796,7 +1874,9 @@ class SGShadowAnimation::UpdateCallback : public osg::NodeCallback {
public: public:
UpdateCallback(const SGCondition* condition) : UpdateCallback(const SGCondition* condition) :
_condition(condition) _condition(condition)
{} {
setName("SGShadowAnimation::UpdateCallback");
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{ {
if (_condition->test()) if (_condition->test())
@@ -1889,7 +1969,9 @@ class SGTexTransformAnimation::UpdateCallback :
public: public:
UpdateCallback(const SGCondition* condition) : UpdateCallback(const SGCondition* condition) :
_condition(condition) _condition(condition)
{ } {
setName("SGTexTransformAnimation::UpdateCallback");
}
virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor*) virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor*)
{ {
if (!_condition || _condition->test()) { if (!_condition || _condition->test()) {
-2
View File
@@ -136,8 +136,6 @@ public:
SGPropertyNode* modelRoot); SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual osg::Group* createAnimationGroup(osg::Group& parent);
private: private:
class UpdateCallback;
class SpinUpdateCallback;
SGSharedPtr<const SGCondition> _condition; SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGExpressiond> _animationValue; SGSharedPtr<const SGExpressiond> _animationValue;
SGVec3d _axis; SGVec3d _axis;
+40 -1
View File
@@ -35,6 +35,7 @@
#include <osg/Math> #include <osg/Math>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osg/Matrix> #include <osg/Matrix>
#include <osg/NodeVisitor>
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
#include <osgDB/FileUtils> #include <osgDB/FileUtils>
@@ -281,6 +282,42 @@ struct TreeTransformer
Matrix mat; Matrix mat;
}; };
// We may end up with a quadtree with many empty leaves. One might say
// that we should avoid constructing the leaves in the first place,
// but this node visitor tries to clean up after the fact.
struct QuadTreeCleaner : public osg::NodeVisitor
{
QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
void apply(LOD& lod)
{
for (int i = lod.getNumChildren() - 1; i >= 0; --i) {
EffectGeode* geode = dynamic_cast<EffectGeode*>(lod.getChild(i));
if (!geode)
continue;
bool geodeEmpty = true;
for (unsigned j = 0; j < geode->getNumDrawables(); ++j) {
const Geometry* geom = dynamic_cast<Geometry*>(geode->getDrawable(j));
if (!geom) {
geodeEmpty = false;
break;
}
for (unsigned k = 0; k < geom->getNumPrimitiveSets(); k++) {
const PrimitiveSet* ps = geom->getPrimitiveSet(k);
if (ps->getNumIndices() > 0) {
geodeEmpty = false;
break;
}
}
}
if (geodeEmpty)
lod.removeChildren(i, 1);
}
}
};
// This actually returns a MatrixTransform node. If we rotate the whole // This actually returns a MatrixTransform node. If we rotate the whole
// forest into the local Z-up coordinate system we can reuse the // forest into the local Z-up coordinate system we can reuse the
// primitive tree geometry for all the forests of the same type. // primitive tree geometry for all the forests of the same type.
@@ -342,8 +379,10 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
} }
forestList.clear(); forestList.clear();
QuadTreeCleaner cleaner;
mt->accept(cleaner);
return mt; return mt;
} }
} }