bool AntiSquish::computeUnSquishedMatrix(const osg::NodeVisitor* nv, osg::Matrix& unsquished) const { OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _cacheLock ); if ( !nv ) { if ( !_cacheDirty ) { unsquished = _cache; return true; } return false; } osg::NodePath np = nv->getNodePath(); // Remove the last node which is the anti squish node itself. np.pop_back(); // Get the accumulated modeling matrix. const osg::Matrix localToWorld = osg::computeLocalToWorld(np); if ( !_cacheDirty && _cacheLocalToWorld==localToWorld ) { unsquished = _cache; return true; } osg::Vec3d t, s; osg::Quat r, so; localToWorld.decompose(t, r, s, so); // Let's take an average of the scale. double av = (s[0] + s[1] + s[2])/3.0; s[0] = av; s[1] = av; s[2]=av; if (av == 0) return false; // // Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position] // OR [SO]^[S][SO][R][T][LOCALTOWORLD]^ // if (_usePivot) { unsquished.postMultTranslate(-_pivot); osg::Matrix tmps, invtmps; so.get(tmps); if (!invtmps.invert(tmps)) return false; //SO^ unsquished.postMult(invtmps); //S unsquished.postMultScale(s); //SO unsquished.postMult(tmps); //R unsquished.postMultRotate(r); //T unsquished.postMultTranslate(t); osg::Matrix invltw; if (!invltw.invert(localToWorld)) return false; // LTW^ unsquished.postMult( invltw ); // Position if (_usePosition) unsquished.postMultTranslate(_position); else unsquished.postMultTranslate(_pivot); } else { osg::Matrix tmps, invtmps; so.get(tmps); if (!invtmps.invert(tmps)) return false; unsquished.postMult(invtmps); unsquished.postMultScale(s); unsquished.postMult(tmps); unsquished.postMultRotate(r); unsquished.postMultTranslate(t); osg::Matrix invltw; if (!invltw.invert(localToWorld)) return false; unsquished.postMult( invltw ); } if (unsquished.isNaN()) return false; _cache = unsquished; _cacheLocalToWorld = localToWorld; _cacheDirty = false; //As Transform::computeBounde calls us without a node-path it relies on //The cache. Hence a new _cache affects the bound. const_cast<AntiSquish*>(this)->dirtyBound(); return true; }