Readded animated collision shape support

c++11
scrawl 10 years ago
parent 19988d5e45
commit 65f0195c71

@ -25,6 +25,11 @@ namespace MWPhysics
public: public:
virtual ~PtrHolder() {} virtual ~PtrHolder() {}
void updatePtr(const MWWorld::Ptr& updated)
{
mPtr = updated;
}
protected: protected:
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
}; };

@ -9,10 +9,12 @@
#include <components/nifbullet/bulletshapemanager.hpp> #include <components/nifbullet/bulletshapemanager.hpp>
#include <components/nifbullet/bulletnifloader.hpp> #include <components/nifbullet/bulletnifloader.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/esm/loadgmst.hpp> #include <components/esm/loadgmst.hpp>
#include <components/nifosg/particle.hpp> // FindRecIndexVisitor
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -24,7 +26,6 @@
#include "../mwrender/bulletdebugdraw.hpp" #include "../mwrender/bulletdebugdraw.hpp"
//#include "../apps/openmw/mwrender/animation.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -35,57 +36,6 @@
#include "convert.hpp" #include "convert.hpp"
#include "trace.h" #include "trace.h"
namespace
{
/*
void animateCollisionShapes (std::map<OEngine::Physic::RigidBody*, OEngine::Physic::AnimatedShapeInstance>& map, btDynamicsWorld* dynamicsWorld)
{
for (std::map<OEngine::Physic::RigidBody*, OEngine::Physic::AnimatedShapeInstance>::iterator it = map.begin();
it != map.end(); ++it)
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->first->mName);
if (ptr.isEmpty()) // Shouldn't happen
throw std::runtime_error("can't find Ptr");
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if (!animation)
continue;
OEngine::Physic::AnimatedShapeInstance& instance = it->second;
std::map<int, int>& shapes = instance.mAnimatedShapes;
for (std::map<int, int>::iterator shapeIt = shapes.begin();
shapeIt != shapes.end(); ++shapeIt)
{
const std::string& mesh = animation->getObjectRootName();
int boneHandle = NifOgre::NIFSkeletonLoader::lookupOgreBoneHandle(mesh, shapeIt->first);
Ogre::Node* bone = animation->getNode(boneHandle);
if (bone == NULL)
continue;
btCompoundShape* compound = static_cast<btCompoundShape*>(instance.mCompound);
btTransform trans;
trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling());
trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation()));
compound->getChildShape(shapeIt->second)->setLocalScaling(
compound->getLocalScaling() *
BtOgre::Convert::toBullet(bone->_getDerivedScale()));
compound->updateChildTransform(shapeIt->second, trans);
}
// needed because we used btDynamicsWorld::setForceUpdateAllAabbs(false)
dynamicsWorld->updateSingleAabb(it->first);
}
}
*/
}
namespace MWPhysics namespace MWPhysics
{ {
@ -569,11 +519,6 @@ namespace MWPhysics
setOrigin(btVector3(pos[0], pos[1], pos[2])); setOrigin(btVector3(pos[0], pos[1], pos[2]));
} }
void updatePtr(const MWWorld::Ptr& updated)
{
mPtr = updated;
}
void setScale(float scale) void setScale(float scale)
{ {
mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale)); mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale));
@ -594,6 +539,47 @@ namespace MWPhysics
return mCollisionObject.get(); return mCollisionObject.get();
} }
void animateCollisionShapes(btDynamicsWorld* dynamicsWorld)
{
if (mShapeInstance->mAnimatedShapes.empty())
return;
assert (mShapeInstance->getCollisionShape()->isCompound());
btCompoundShape* compound = dynamic_cast<btCompoundShape*>(mShapeInstance->getCollisionShape());
for (std::map<int, int>::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it)
{
int recIndex = it->first;
int shapeIndex = it->second;
NifOsg::FindRecIndexVisitor visitor(recIndex);
mPtr.getRefData().getBaseNode()->accept(visitor);
if (!visitor.mFound)
{
std::cerr << "animateCollisionShapes: Can't find node " << recIndex << std::endl;
return;
}
osg::NodePath path = visitor.mFoundPath;
path.erase(path.begin());
osg::Matrixf matrix = osg::computeLocalToWorld(path);
osg::Vec3f scale = matrix.getScale();
matrix.orthoNormalize(matrix);
btTransform transform;
transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling());
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference
compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale));
compound->updateChildTransform(shapeIndex, transform);
}
dynamicsWorld->updateSingleAabb(mCollisionObject.get());
}
private: private:
std::auto_ptr<btCollisionObject> mCollisionObject; std::auto_ptr<btCollisionObject> mCollisionObject;
osg::ref_ptr<NifBullet::BulletShapeInstance> mShapeInstance; osg::ref_ptr<NifBullet::BulletShapeInstance> mShapeInstance;
@ -601,8 +587,8 @@ namespace MWPhysics
// --------------------------------------------------------------- // ---------------------------------------------------------------
PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr<osg::Group> parentNode) PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
: mShapeManager(new NifBullet::BulletShapeManager(vfs)) : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager()))
, mTimeAccum(0.0f) , mTimeAccum(0.0f)
, mWaterEnabled(false) , mWaterEnabled(false)
, mWaterHeight(0) , mWaterHeight(0)
@ -795,6 +781,27 @@ namespace MWPhysics
} }
} }
void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated)
{
ObjectMap::iterator found = mObjects.find(old);
if (found != mObjects.end())
{
Object* obj = found->second;
obj->updatePtr(updated);
mObjects.erase(found);
mObjects.insert(std::make_pair(updated, obj));
}
ActorMap::iterator foundActor = mActors.find(old);
if (foundActor != mActors.end())
{
Actor* actor = foundActor->second;
actor->updatePtr(updated);
mActors.erase(foundActor);
mActors.insert(std::make_pair(updated, actor));
}
}
void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr)
{ {
ObjectMap::iterator found = mObjects.find(ptr); ObjectMap::iterator found = mObjects.find(ptr);
@ -955,7 +962,8 @@ namespace MWPhysics
void PhysicsSystem::stepSimulation(float dt) void PhysicsSystem::stepSimulation(float dt)
{ {
//animateCollisionShapes(mEngine->mAnimatedShapes, mDynamicsWorld); for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it)
it->second->animateCollisionShapes(mDynamicsWorld);
// We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs.
mDynamicsWorld->stepSimulation(static_cast<btScalar>(dt), 1, 1 / 60.0f); mDynamicsWorld->stepSimulation(static_cast<btScalar>(dt), 1, 1 / 60.0f);

@ -26,9 +26,9 @@ namespace NifBullet
class BulletShapeManager; class BulletShapeManager;
} }
namespace VFS namespace Resource
{ {
class Manager; class ResourceSystem;
} }
class btSequentialImpulseConstraintSolver; class btSequentialImpulseConstraintSolver;
@ -45,7 +45,7 @@ namespace MWPhysics
class PhysicsSystem class PhysicsSystem
{ {
public: public:
PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr<osg::Group> parentNode); PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode);
~PhysicsSystem (); ~PhysicsSystem ();
void enableWater(float height); void enableWater(float height);
@ -61,8 +61,7 @@ namespace MWPhysics
void updateRotation (const MWWorld::Ptr& ptr); void updateRotation (const MWWorld::Ptr& ptr);
void updatePosition (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr);
// TODO void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated);
//void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated);
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);

@ -17,7 +17,6 @@
#include <components/compiler/locals.hpp> #include <components/compiler/locals.hpp>
#include <components/esm/cellid.hpp> #include <components/esm/cellid.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
#include <boost/math/special_functions/sign.hpp> #include <boost/math/special_functions/sign.hpp>
@ -158,7 +157,7 @@ namespace MWWorld
mStartCell (startCell), mStartupScript(startupScript), mStartCell (startCell), mStartupScript(startupScript),
mScriptsEnabled(true) mScriptsEnabled(true)
{ {
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode); mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode);
//mPhysEngine = mPhysics->getEngine(); //mPhysEngine = mPhysics->getEngine();
#if 0 #if 0
mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine));

@ -46,6 +46,11 @@ BulletNifLoader::~BulletNifLoader()
{ {
} }
void BulletNifLoader::setAnimatedNodes(const std::set<std::string> &animatedNodes)
{
mAnimatedNodes = animatedNodes;
}
osg::ref_ptr<BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr nif) osg::ref_ptr<BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr nif)
{ {
mShape = new BulletShape; mShape = new BulletShape;
@ -84,20 +89,6 @@ osg::ref_ptr<BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr nif)
} }
else else
{ {
/*
// Have to load controlled nodes from the .kf
mControlledNodes.clear();
std::string kfname = mResourceName.substr(0, mResourceName.length()-7);
Misc::StringUtils::toLower(kfname);
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
kfname.replace(kfname.size()-4, 4, ".kf");
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname))
{
Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname));
//extractControlledNodes(kf, mControlledNodes);
}
*/
bool autogenerated = hasAutoGeneratedCollision(node); bool autogenerated = hasAutoGeneratedCollision(node);
handleNode(node, 0, autogenerated, false, autogenerated); handleNode(node, 0, autogenerated, false, autogenerated);
@ -181,7 +172,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags,
&& (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) && (node->controller->flags & Nif::NiNode::ControllerFlag_Active))
isAnimated = true; isAnimated = true;
if (mControlledNodes.find(node->name) != mControlledNodes.end()) if (mAnimatedNodes.find(node->name) != mAnimatedNodes.end())
isAnimated = true; isAnimated = true;
isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode);
@ -238,7 +229,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags,
for(size_t i = 0;i < list.length();i++) for(size_t i = 0;i < list.length();i++)
{ {
if(!list[i].empty()) if(!list[i].empty())
handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated); handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated, autogenerated);
} }
} }
} }
@ -267,7 +258,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
if (!shape->skin.empty()) if (!shape->skin.empty())
isAnimated = false; isAnimated = false;
/*
if (isAnimated) if (isAnimated)
{ {
if (!mCompoundShape) if (!mCompoundShape)
@ -311,7 +301,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
mCompoundShape->addChildShape(trans, childShape); mCompoundShape->addChildShape(trans, childShape);
} }
else else
*/
{ {
if (!mStaticMesh) if (!mStaticMesh)
mStaticMesh = new btTriangleMesh(false); mStaticMesh = new btTriangleMesh(false);
@ -414,6 +403,8 @@ BulletShapeInstance::BulletShapeInstance(osg::ref_ptr<BulletShape> source)
mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents;
mCollisionBoxTranslate = source->mCollisionBoxTranslate; mCollisionBoxTranslate = source->mCollisionBoxTranslate;
mAnimatedShapes = source->mAnimatedShapes;
if (source->mCollisionShape) if (source->mCollisionShape)
mCollisionShape = duplicateCollisionShape(source->mCollisionShape); mCollisionShape = duplicateCollisionShape(source->mCollisionShape);
} }

@ -107,6 +107,8 @@ public:
abort(); abort();
} }
void setAnimatedNodes(const std::set<std::string>& animatedNodes);
osg::ref_ptr<BulletShape> load(const Nif::NIFFilePtr file); osg::ref_ptr<BulletShape> load(const Nif::NIFFilePtr file);
private: private:
@ -122,7 +124,7 @@ private:
btTriangleMesh* mStaticMesh; btTriangleMesh* mStaticMesh;
std::set<std::string> mControlledNodes; std::set<std::string> mAnimatedNodes;
osg::ref_ptr<BulletShape> mShape; osg::ref_ptr<BulletShape> mShape;
}; };

@ -4,11 +4,14 @@
#include <components/nifbullet/bulletnifloader.hpp> #include <components/nifbullet/bulletnifloader.hpp>
#include <components/resource/scenemanager.hpp>
namespace NifBullet namespace NifBullet
{ {
BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager)
: mVFS(vfs) : mVFS(vfs)
, mSceneManager(sceneManager)
{ {
} }
@ -31,7 +34,20 @@ osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(const std::
// TODO: add support for non-NIF formats // TODO: add support for non-NIF formats
std::string kfname = normalized;
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
kfname.replace(kfname.size()-4, 4, ".kf");
std::set<std::string> animatedNodes;
if (mVFS->exists(kfname))
{
osg::ref_ptr<const NifOsg::KeyframeHolder> keyframes = mSceneManager->getKeyframes(normalized);
for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin();
it != keyframes->mKeyframeControllers.end(); ++it)
animatedNodes.insert(it->first);
}
BulletNifLoader loader; BulletNifLoader loader;
loader.setAnimatedNodes(animatedNodes);
// might be worth sharing NIFFiles with SceneManager in some way // might be worth sharing NIFFiles with SceneManager in some way
shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)));

@ -11,6 +11,11 @@ namespace VFS
class Manager; class Manager;
} }
namespace Resource
{
class SceneManager;
}
namespace NifBullet namespace NifBullet
{ {
@ -20,13 +25,15 @@ namespace NifBullet
class BulletShapeManager class BulletShapeManager
{ {
public: public:
BulletShapeManager(const VFS::Manager* vfs); BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager);
~BulletShapeManager(); ~BulletShapeManager();
osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name); osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name);
private: private:
const VFS::Manager* mVFS; const VFS::Manager* mVFS;
// need to load keyframes to know what nodes are going to be animated
Resource::SceneManager* mSceneManager;
typedef std::map<std::string, osg::ref_ptr<BulletShape> > Index; typedef std::map<std::string, osg::ref_ptr<BulletShape> > Index;
Index mIndex; Index mIndex;

@ -18,7 +18,8 @@ namespace SceneUtil
{ {
setCopyFlags(osg::CopyOp::DEEP_COPY_NODES setCopyFlags(osg::CopyOp::DEEP_COPY_NODES
// Controller might need different inputs per scene instance // Controller might need different inputs per scene instance
| osg::CopyOp::DEEP_COPY_CALLBACKS); | osg::CopyOp::DEEP_COPY_CALLBACKS
| osg::CopyOp::DEEP_COPY_USERDATA);
} }
osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const

Loading…
Cancel
Save