diff --git a/CMakeLists.txt b/CMakeLists.txt index 0785ef28c..cde53f27a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ if (${OGRE_VERSION} VERSION_LESS "1.9") message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org") endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) find_package(MyGUI REQUIRED) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9006c16ef..555105e35 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -210,36 +210,49 @@ namespace } }; - // Custom node used to have a transform always oriented towards the camera. Can have translation and scale + // NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. - class BillboardNode : public osg::MatrixTransform + class BillboardCallback : public osg::NodeCallback { public: - BillboardNode() : osg::MatrixTransform() {} - BillboardNode(const BillboardNode& copy, const osg::CopyOp& copyop) - : osg::MatrixTransform(copy, copyop) {} - BillboardNode(const osg::Matrix& matrix) - : osg::MatrixTransform(matrix) {} + BillboardCallback() + { + } + BillboardCallback(const BillboardCallback& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + { + } - META_Node(NifOsg, BillboardNode) + META_Object(NifOsg, BillboardCallback) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (_referenceFrame==RELATIVE_RF) + osgUtil::CullVisitor* cv = dynamic_cast(nv); + osg::MatrixTransform* billboardNode = dynamic_cast(node); + if (billboardNode && cv) { - const NifOsg::NodeUserData* userdata = static_cast(getUserDataContainer()->getUserObject(0)); + osg::Matrix modelView = *cv->getModelViewMatrix(); - matrix.preMult(_matrix); - matrix.setRotate(osg::Quat()); - matrix(0,0) = userdata->mScale; - matrix(1,1) = userdata->mScale; - matrix(2,2) = userdata->mScale; - } - else // absolute - { - matrix = _matrix; + // attempt to preserve scale + float mag[3]; + for (int i=0;i<3;++i) + { + mag[i] = std::sqrt(modelView(0,i) * modelView(0,i) + modelView(1,i) * modelView(1,i) + modelView(2,i) * modelView(2,i)); + } + + modelView.setRotate(osg::Quat()); + modelView(0,0) = mag[0]; + modelView(1,1) = mag[1]; + modelView(2,2) = mag[2]; + + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); + + traverse(node, nv); + + cv->popModelViewMatrix(); } - return true; + else + traverse(node, nv); } }; @@ -639,11 +652,7 @@ namespace NifOsg std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { osg::ref_ptr transformNode; - if (nifNode->recType == Nif::RC_NiBillboardNode) - { - transformNode = new BillboardNode(toMatrix(nifNode->trafo)); - } - else if (createSkeleton) + if (createSkeleton) { osgAnimation::Bone* bone = new osgAnimation::Bone; transformNode = bone; @@ -655,6 +664,10 @@ namespace NifOsg { transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); } + if (nifNode->recType == Nif::RC_NiBillboardNode) + { + transformNode->addCullCallback(new BillboardCallback); + } if (parentNode) parentNode->addChild(transformNode);