NIF bullet loader fix for incorrect collision shapes (credit goes to Chris, he asked me to push this)

actorid
scrawl 12 years ago
parent b52df83d84
commit f4749f10da

@ -43,25 +43,14 @@ http://www.gnu.org/licenses/ .
typedef unsigned char ubyte; typedef unsigned char ubyte;
using namespace NifBullet; namespace NifBullet
{
ManualBulletShapeLoader::~ManualBulletShapeLoader() ManualBulletShapeLoader::~ManualBulletShapeLoader()
{ {
} }
btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m)
{
Ogre::Quaternion oquat(m);
btQuaternion quat;
quat.setW(oquat.w);
quat.setX(oquat.x);
quat.setY(oquat.y);
quat.setZ(oquat.z);
return quat;
}
btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v)
{ {
return btVector3(v[0], v[1], v[2]); return btVector3(v[0], v[1], v[2]);
@ -90,7 +79,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
return; return;
} }
// The first record is assumed to be the root node // The first record is assumed to be the root node
Nif::Record *r = nif.getRecord(0); Nif::Record *r = nif.getRecord(0);
assert(r != NULL); assert(r != NULL);
@ -106,13 +94,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
bool hasCollisionNode = hasRootCollisionNode(node); bool hasCollisionNode = hasRootCollisionNode(node);
//do a first pass //do a first pass
handleNode(node,0,NULL,hasCollisionNode,false,false); handleNode(node,0,hasCollisionNode,false,false);
//if collide = false, then it does a second pass which create a shape for raycasting. //if collide = false, then it does a second pass which create a shape for raycasting.
if(cShape->mCollide == false) if(cShape->mCollide == false)
{ handleNode(node,0,hasCollisionNode,false,true);
handleNode(node,0,NULL,hasCollisionNode,false,true);
}
//cShape->collide = hasCollisionNode&&cShape->collide; //cShape->collide = hasCollisionNode&&cShape->collide;
@ -129,9 +115,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
delete m_meshInterface; delete m_meshInterface;
} }
}; };
if(mBoundingBox != NULL) if(mBoundingBox != NULL)
cShape->Shape = mBoundingBox; cShape->Shape = mBoundingBox;
else else
{ {
currentShape = new TriangleMeshShape(mTriMesh,true); currentShape = new TriangleMeshShape(mTriMesh,true);
@ -141,34 +127,30 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node)
{ {
if (node->recType == Nif::RC_NiNode) if(node->recType == Nif::RC_RootCollisionNode)
return true;
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
if(ninode)
{ {
Nif::NodeList &list = ((Nif::NiNode*)node)->children; const Nif::NodeList &list = ninode->children;
int n = list.length(); for(size_t i = 0;i < list.length();i++)
for (int i=0; i<n; i++)
{ {
if (!list[i].empty()) if(!list[i].empty())
{ {
if(hasRootCollisionNode(list[i].getPtr())) return true;; if(hasRootCollisionNode(list[i].getPtr()))
return true;
} }
} }
} }
else if (node->recType == Nif::RC_NiTriShape)
{
return false;
}
else if(node->recType == Nif::RC_RootCollisionNode)
{
return true;
}
return false; return false;
} }
void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) bool hasCollisionNode, bool isCollisionNode,
bool raycastingOnly)
{ {
// Accumulate the flags from all the child nodes. This works for all // Accumulate the flags from all the child nodes. This works for all
// the flags we currently use, at least. // the flags we currently use, at least.
flags |= node->flags; flags |= node->flags;
@ -209,70 +191,36 @@ void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags,
} }
} }
Nif::Transformation childTrafo = node->trafo;
if (parentTrafo)
{
// Get a non-const reference to the node's data, since we're
// overwriting it. TODO: Is this necessary?
// For both position and rotation we have that:
// final_vector = old_vector + old_rotation*new_vector*old_scale
childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale;
// Merge the rotations together
childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation;
// Scale
childTrafo.scale *= parentTrafo->scale;
}
if(node->hasBounds) if(node->hasBounds)
{ {
btVector3 boxsize = getbtVector(node->boundXYZ);
cShape->boxTranslation = node->boundPos; cShape->boxTranslation = node->boundPos;
cShape->boxRotation = node->boundRot; cShape->boxRotation = node->boundRot;
mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ));
mBoundingBox = new btBoxShape(boxsize);
} }
if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode))
// For NiNodes, loop through children
if (node->recType == Nif::RC_NiNode)
{
Nif::NodeList const &list = ((Nif::NiNode const *)node)->children;
int n = list.length();
for (int i=0; i<n; i++)
{
if (!list[i].empty())
{
handleNode(list[i].getPtr(), flags,&childTrafo,hasCollisionNode,isCollisionNode,raycastingOnly);
}
}
}
else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode))
{ {
cShape->mCollide = !(flags&0x800); cShape->mCollide = !(flags&0x800);
handleNiTriShape(dynamic_cast<Nif::NiTriShape const *>(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); handleNiTriShape(static_cast<const Nif::NiTriShape*>(node), flags, node->getWorldTransform(), raycastingOnly);
} }
else if(node->recType == Nif::RC_RootCollisionNode)
// For NiNodes, loop through children
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
if(ninode)
{ {
Nif::NodeList &list = ((Nif::NiNode*)node)->children; isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode);
int n = list.length();
for (int i=0; i<n; i++) const Nif::NodeList &list = ninode->children;
for(size_t i = 0;i < list.length();i++)
{ {
if (!list[i].empty()) if(!list[i].empty())
handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly);
} }
} }
} }
void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform,
bool raycastingOnly) bool raycastingOnly)
{ {
assert(shape != NULL); assert(shape != NULL);
@ -296,18 +244,14 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int
return; return;
Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiTriShapeData *data = shape->data.getPtr();
const std::vector<Ogre::Vector3> &vertices = data->vertices; const std::vector<Ogre::Vector3> &vertices = data->vertices;
const Ogre::Matrix3 &rot = shape->trafo.rotation; const short *triangles = &data->triangles[0];
const Ogre::Vector3 &pos = shape->trafo.pos;
float scale = shape->trafo.scale * parentScale;
short* triangles = &data->triangles[0];
for(size_t i = 0;i < data->triangles.size();i+=3) for(size_t i = 0;i < data->triangles.size();i+=3)
{ {
Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale; Ogre::Vector3 b1 = transform*vertices[triangles[i+0]];
Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale; Ogre::Vector3 b2 = transform*vertices[triangles[i+1]];
Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale; Ogre::Vector3 b3 = transform*vertices[triangles[i+2]];
mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z));
} }
} }
@ -320,3 +264,5 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr
return; return;
OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this);
} }
} // namespace NifBullet

@ -51,19 +51,18 @@ namespace NifBullet
class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader
{ {
public: public:
ManualBulletShapeLoader():resourceGroup("General"){} ManualBulletShapeLoader():resourceGroup("General"){}
virtual ~ManualBulletShapeLoader(); virtual ~ManualBulletShapeLoader();
void warn(std::string msg) void warn(const std::string &msg)
{ {
std::cerr << "NIFLoader: Warn:" << msg << "\n"; std::cerr << "NIFLoader: Warn:" << msg << "\n";
} }
void fail(std::string msg) void fail(const std::string &msg)
{ {
std::cerr << "NIFLoader: Fail: "<< msg << std::endl; std::cerr << "NIFLoader: Fail: "<< msg << std::endl;
assert(1); abort();
} }
/** /**
@ -79,31 +78,26 @@ public:
void load(const std::string &name,const std::string &group); void load(const std::string &name,const std::string &group);
private: private:
btQuaternion getbtQuat(Ogre::Matrix3 const &m);
btVector3 getbtVector(Ogre::Vector3 const &v); btVector3 getbtVector(Ogre::Vector3 const &v);
/** /**
*Parse a node. *Parse a node.
*/ */
void handleNode(Nif::Node const *node, int flags, void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly);
const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly);
/** /**
*Helper function *Helper function
*/ */
bool hasRootCollisionNode(Nif::Node const * node); bool hasRootCollisionNode(const Nif::Node *node);
/** /**
*convert a NiTriShape to a bullet trishape. *convert a NiTriShape to a bullet trishape.
*/ */
void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly);
std::string resourceName; std::string resourceName;
std::string resourceGroup; std::string resourceGroup;
OEngine::Physic::BulletShape* cShape;//current shape OEngine::Physic::BulletShape* cShape;//current shape
btTriangleMesh *mTriMesh; btTriangleMesh *mTriMesh;
btBoxShape *mBoundingBox; btBoxShape *mBoundingBox;

Loading…
Cancel
Save