diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index bdd40e245..df912728b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -468,6 +468,7 @@ namespace NifOsg nif->fail("First root was not a node, but a " + r->recName); osg::ref_ptr skel = new osgAnimation::Skeleton; + skel->setDefaultUpdateCallback(); // validates the skeleton hierarchy skel->addChild(handleNode(nifNode, true, std::map(), 0, 0, false, textKeys)); return skel; @@ -609,8 +610,7 @@ namespace NifOsg { if(!children[i].empty()) { - // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) - transformNode->insertChild(0, + transformNode->addChild( handleNode(children[i].getPtr(), createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode)); } } @@ -1077,11 +1077,18 @@ namespace NifOsg osg::ref_ptr geometry (new osg::Geometry); triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + // Note the RigGeometry's UpdateCallback uses the skeleton space bone matrix, so the bone UpdateCallback has to be fired first. + // For this to work properly, all bones used for skinning a RigGeometry need to be created before that RigGeometry. + // All NIFs I've checked seem to conform to this restriction, perhaps Gamebryo update method works similarly. + // If a file violates this assumption, the worst that could happen is the bone position being a frame late. + // If this happens, we should get a warning from the Skeleton's validation update callback on the error log. osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); + // Slightly expand the bounding box to account for movement of the bones // For more accuracy the skinning should be relative to the parent of the first skinned bone, // rather than the root bone. + // TODO: calculate a correct bounding box based on the bone positions every frame in a ComputeBoundingBoxCallback osg::BoundingBox box = geometry->getBound(); box.expandBy(box._min-(box._max-box._min)/2); box.expandBy(box._max+(box._max-box._min)/2);