//-----------------------------------------------------------------------------
//  CalcBBox
//-----------------------------------------------------------------------------
NxBox   CPhysicModelSimple::CalcBBox (void) const
{
    NxBounds3   bounds;
    for (int i = 0; i < (int)m_ActorDesc.shapes.size(); i++)
    {
        NxShapeDesc* pShapeDesc = m_ActorDesc.shapes[i];
        switch (pShapeDesc->getType())
        {
            case NX_SHAPE_BOX:
			{
				NxBoxShapeDesc* pBoxShape = (NxBoxShapeDesc*) pShapeDesc;
				NxBox shapeBBox (pBoxShape->localPose.t, pBoxShape->dimensions, pBoxShape->localPose.M);
				NxBounds3 shapeBounds;
				shapeBounds.boundsOfOBB( shapeBBox.rot, shapeBBox.center, shapeBBox.extents );
				bounds.combine (shapeBounds);
			}
            break;
            case NX_SHAPE_SPHERE:
			{
				NxSphereShapeDesc* pSphereShape = (NxSphereShapeDesc*) pShapeDesc;
				NxBox shapeBBox (pSphereShape->localPose.t, NxVec3(pSphereShape->radius), pSphereShape->localPose.M);
				NxBounds3 shapeBounds;
				shapeBounds.boundsOfOBB( shapeBBox.rot, shapeBBox.center, shapeBBox.extents );
				bounds.combine (shapeBounds);
			}
            break;
            default:
                // Caso no soportado
                assert(0);
            break;
        }
    }

    NxBox   result;
    bounds.getCenter (result.center);
    bounds.getExtents (result.extents);
    return result;
}
Example #2
0
bool PxBody::init(   PhysicsCollision *shape, 
                     F32 mass,
                     U32 bodyFlags,
                     SceneObject *obj, 
                     PhysicsWorld *world )
{
   AssertFatal( obj, "PxBody::init - Got a null scene object!" );
   AssertFatal( world, "PxBody::init - Got a null world!" );
   AssertFatal( dynamic_cast<PxWorld*>( world ), "PxBody::init - The world is the wrong type!" );
   AssertFatal( shape, "PxBody::init - Got a null collision shape!" );
   AssertFatal( dynamic_cast<PxCollision*>( shape ), "PxBody::init - The collision shape is the wrong type!" );
   AssertFatal( !((PxCollision*)shape)->getShapes().empty(), "PxBody::init - Got empty collision shape!" );
	 
   // Cleanup any previous actor.
   _releaseActor();

   mWorld = (PxWorld*)world;
   mColShape = (PxCollision*)shape;
   mBodyFlags = bodyFlags;

   NxActorDesc actorDesc;
   NxBodyDesc bodyDesc;

   const bool isKinematic = mBodyFlags & BF_KINEMATIC;
   const bool isTrigger = mBodyFlags & BF_TRIGGER;
   const bool isDebris = mBodyFlags & BF_DEBRIS;

   if ( isKinematic )
   {
      // Kinematics are dynamics... so they need
      // a body description.
      actorDesc.body = &bodyDesc;
      bodyDesc.mass = getMax( mass, 1.0f );
	   bodyDesc.flags	|= NX_BF_KINEMATIC;
   }
   else if ( mass > 0.0f )
   {
      // We have mass so its a dynamic.
      actorDesc.body = &bodyDesc;
      bodyDesc.mass = mass;
   }

   if ( isTrigger )
      actorDesc.flags |= NX_AF_DISABLE_RESPONSE;

   // Add all the shapes.
   const Vector<NxShapeDesc*> &shapes = mColShape->getShapes();
   for ( U32 i=0; i < shapes.size(); i++ )
   {
      NxShapeDesc *desc = shapes[i];

      // If this hits then something is broken with 
      // this descrption... check all the fields to be
      // sure their values are correctly filled out.
      AssertFatal( desc->isValid(), "PxBody::init - Got invalid shape description!" );

      if ( isTrigger )
         desc->group = 31;

      if ( isDebris )
         desc->group = 30;

      actorDesc.shapes.push_back( desc );
   }

   // This sucks, but it has to happen if we want
   // to avoid write lock errors from PhysX right now.
   mWorld->releaseWriteLock();

   mActor = mWorld->getScene()->createActor( actorDesc );
   mIsEnabled = true;

   if ( isDebris )
      mActor->setDominanceGroup( 31 );

   mUserData.setObject( obj );
   mUserData.setBody( this );
   mActor->userData = &mUserData;

   return true;
}
Example #3
0
/** Returns bounds description associated with the Novodex shape description. */
Bounds::Desc::Ptr PhysScene::createBoundsDesc(const NxShapeDesc &nxShapeDesc) {
	// check if bound description has been already created
	BoundsDescMap::const_iterator pos = boundsDescMap.find(&nxShapeDesc);
	if (pos != boundsDescMap.end())
		return pos->second;

	Bounds::Desc::Ptr pBoundsDesc;

	// check if description is valid
	if (!nxShapeDesc.isValid())
		throw MsgPhysSceneNxShapeDescInvalidDesc(Message::LEVEL_ERROR, "PhysScene::createBoundsDesc(): invalid Novodex shape description");

	NxShapeDescPtr nxShapeDescPtr;

	if (nxShapeDesc.getType() == NX_SHAPE_PLANE) {
		const NxPlaneShapeDesc *pDescSrc = dynamic_cast<const NxPlaneShapeDesc*>(&nxShapeDesc);
		if (pDescSrc != NULL) {
			NxPlaneShapeDesc *pDescDst = new NxPlaneShapeDesc();
			nxShapeDescPtr.reset(pDescDst);
			::memcpy(pDescDst, pDescSrc, sizeof(NxPlaneShapeDesc));
			pBoundsDesc = createBoundsDesc(pDescDst);
		}
	}
	else if (nxShapeDesc.getType() == NX_SHAPE_SPHERE) {
		const NxSphereShapeDesc *pDescSrc = dynamic_cast<const NxSphereShapeDesc*>(&nxShapeDesc);
		if (pDescSrc != NULL) {
			NxSphereShapeDesc *pDescDst = new NxSphereShapeDesc();
			nxShapeDescPtr.reset(pDescDst);
			::memcpy(pDescDst, pDescSrc, sizeof(NxSphereShapeDesc));
			pBoundsDesc = createBoundsDesc(pDescDst);
		}
	}
	else if (nxShapeDesc.getType() == NX_SHAPE_BOX) {
		const NxBoxShapeDesc *pDescSrc = dynamic_cast<const NxBoxShapeDesc*>(&nxShapeDesc);
		if (pDescSrc != NULL) {
			NxBoxShapeDesc *pDescDst = new NxBoxShapeDesc();
			nxShapeDescPtr.reset(pDescDst);
			::memcpy(pDescDst, pDescSrc, sizeof(NxBoxShapeDesc));
			pBoundsDesc = createBoundsDesc(pDescDst);
		}
	}
	else if (nxShapeDesc.getType() == NX_SHAPE_CONVEX) {
		const NxConvexShapeDesc *pDescSrc = dynamic_cast<const NxConvexShapeDesc*>(&nxShapeDesc);
		if (pDescSrc != NULL) {
			NxConvexShapeDesc *pDescDst = new NxConvexShapeDesc();
			nxShapeDescPtr.reset(pDescDst);
			::memcpy(pDescDst, pDescSrc, sizeof(NxConvexShapeDesc));
			pBoundsDesc = createBoundsDesc(pDescDst); // Access to PhysX
		}
	}
	else {
		ASSERT(false)
	}

	if (pBoundsDesc == NULL)
		throw MsgSceneBoundsDescCreate(Message::LEVEL_ERROR, "PhysScene::createBoundsDesc(): failed to create bounds description");

	nxShapeDescMap[pBoundsDesc.get()] = nxShapeDescPtr;
	boundsDescMap[nxShapeDescPtr.get()] = pBoundsDesc;

	return pBoundsDesc;
}
Example #4
0
/*
  Use the shape of node to create Bullet shape for the actor. ActorNode is the main Max node.
*/
btCollisionShape* MxActor::createShape(NxActorDesc& actorDesc, ccMaxNode* node, ccMaxNode* actorNode)
{
	actorDesc.localPose.IdentityMatrix();

	btCollisionShape* shape = NULL;

	const TimeValue t = ccMaxWorld::MaxTime();
	Matrix3 nodePose = node->PhysicsNodePoseTM;

//	MaxMsgBox(NULL, _T("createShape"), _T("Error"), MB_OK);

	int geomType = MxUserPropUtils::GetUserPropInt(m_node, "GeometryType",1);
	NxShapeType type = node->ShapeType;

	//first apply manual overrides
	switch (geomType)
	{
	case 2:
		{
			type = NX_SHAPE_SPHERE;
			break;
		}
	case 3:
		{
			type = NX_SHAPE_BOX;
			break;
		}
	case 4:
		{
			type = NX_SHAPE_CAPSULE;
			break;
		}
	case 5:
		{
			type = NX_SHAPE_CONVEX;
			break;
		}
	case 6:
		{
			type = NX_SHAPE_MESH;
			break;
		}
	default:
		{
			
		}
	};

	actorDesc.localPose = node->PhysicsNodePoseTM * actorNode->PhysicsNodePoseTMInv;

	switch (type)
	{
	case NX_SHAPE_SPHERE:
		{
			btScalar radius = node->PrimaryShapePara.Radius;
			shape = new btSphereShape(radius);
			break;
		};
	case NX_SHAPE_BOX:
		{
			//adjust for difference in pivot points between 3ds max and Bullet (Bullet uses the box center)
			Matrix3 offset;
			offset.IdentityMatrix();
			offset.SetTrans(2,node->PrimaryShapePara.BoxDimension.z());

			actorDesc.localPose = actorDesc.localPose * offset;

			shape = new btBoxShape(node->PrimaryShapePara.BoxDimension.absolute());

			break;
		}
	case NX_SHAPE_CAPSULE:
		{

			char bla[1024];
			sprintf(bla,"capsule not properly supported yet, radius=%f,height=%f",node->PrimaryShapePara.Radius,node->PrimaryShapePara.Height);
			MaxMsgBox(NULL, _T(bla), _T("Error"), MB_OK);

			shape = new btCapsuleShape(node->PrimaryShapePara.Radius,node->PrimaryShapePara.Height);
			break;
		}

	case NX_SHAPE_CONVEX:
		{
			if(m_proxyNode)
			{
				MaxMsgBox(NULL, _T("Error: convex shape proxy not supported (yet)"), _T("Error"), MB_OK);
				//d->meshData = MxUtils::nodeToNxConvexMesh(proxyMesh);
				//Matrix3 pose = nodePose * actorNode->PhysicsNodePoseTMInv;
				//d->localPose = MxMathUtils::MaxMatrixToNx(pose);
			}
			else
			{
				if(node->SimpleMesh.numFaces > 255)
				{
					MaxMsgBox(NULL, _T("Error: number of vertices in a convex shape should be less than 256"), _T("Error"), MB_OK);
					//warning/Error
				} else
				{

					BOOL needDel = FALSE;
					TriObject* tri = MxUtils::GetTriObjectFromNode(node->GetMaxNode(),0.f,needDel);
					if (tri)
					{
						int numVerts = tri->NumPoints();
						btConvexHullShape* convexHull = new btConvexHullShape();
						
						//for center of mass computation, simplify and assume mass is at the vertices
						btCompoundShape* compound = new btCompoundShape();
						btSphereShape sphere(0.1);
						btTransform tr;
						tr.setIdentity();
						btAlignedObjectArray<btScalar> masses;
						btScalar childMass = actorDesc.mass/(btScalar)numVerts;


						for (int i=0;i<numVerts;i++)
						{
							btVector3 pt(tri->GetPoint(i).x,tri->GetPoint(i).y,tri->GetPoint(i).z);
							convexHull->addPoint(pt);
							tr.setOrigin(pt);
							compound->addChildShape(tr,&sphere);
							masses.push_back(childMass);
						}
						
						btTransform principal;
						btVector3 inertia;
						compound->calculatePrincipalAxisTransform(&masses[0],principal,inertia);

						
						delete compound;

						btTransform principalInv = principal.inverse();
						compound = new btCompoundShape();
						compound->addChildShape(principalInv,convexHull);
						shape = compound;

						Matrix3 offset;
						bullet2Max(principal,offset);
						actorDesc.localPose = actorDesc.localPose * offset;


						if (needDel)
							delete tri;
					}
					
					

				}
				//d->meshData = MxUtils::nodeToNxConvexMesh(node->SimpleMesh);
				//Matrix3 pose = nodePose * actorNode->PhysicsNodePoseTMInv;
				//d->localPose = MxMathUtils::MaxMatrixToNx(pose);
			}
			break;
		}
	case 	NX_SHAPE_MESH:
		{

			

			BOOL needDel = FALSE;
			TriObject* tri = MxUtils::GetTriObjectFromNode(node->GetMaxNode(),0.f,needDel);

			if (tri)
			{
				int numVerts = tri->NumPoints();
				btTriangleMesh* meshInterface = new btTriangleMesh();
				Mesh& mesh = tri->GetMesh();

				if (mesh.getNumFaces()>0)
				{
					for (int i=0;i<mesh.getNumFaces();i++)
					{
						Point3 p0=tri->GetPoint(mesh.faces[i].v[0]);
						Point3 p1=tri->GetPoint(mesh.faces[i].v[1]);
						Point3 p2=tri->GetPoint(mesh.faces[i].v[2]);

						meshInterface->addTriangle( btVector3(p0.x,p0.y,p0.z),btVector3(p1.x,p1.y,p1.z),btVector3(p2.x,p2.y,p2.z));
					}

					
					if (actorDesc.mass>0)
					{
//						MaxMsgBox(NULL, _T("btGImpactMeshShape"), _T("Error"), MB_OK);

						btGImpactMeshShape* trimesh = new btGImpactMeshShape(meshInterface);
						shape = trimesh;

					} else
					{

//						MaxMsgBox(NULL, _T("btBvhTriangleMeshShape"), _T("Error"), MB_OK);
						btBvhTriangleMeshShape* trimesh = new btBvhTriangleMeshShape(meshInterface,true);
						shape = trimesh;
					}
					
					
				} else
				{
					MaxMsgBox(NULL, _T("Error: no faces"), _T("Error"), MB_OK);
				}
				if (needDel)
					delete tri;
				
			} else
			{
				MaxMsgBox(NULL, _T("Error: couldn't GetTriObjectFromNode"), _T("Error"), MB_OK);
			}

			break;
		}

	default:
		{
			MaxMsgBox(NULL, _T("unknown shape type"), _T("Error"), MB_OK);
		}
	};


#if 0
	NxShapeDesc* pd = NULL;
	NxShapeType type = node->ShapeType;
	PxSimpleMesh proxyMesh;
	Matrix3 nodePose = node->PhysicsNodePoseTM;
	if(m_proxyNode)
	{
		// for proxy, using mesh
		//type = NX_SHAPE_MESH;
		proxyMesh.clone(node->SimpleMesh);
		Point3 pos = nodePose.GetRow(3);
		pos = pos + ProxyDistance;
		nodePose.SetRow(3, pos);
	}
	if((type == NX_SHAPE_MESH) && (Interactivity != RB_STATIC))
	{
		type = NX_SHAPE_CONVEX;
	}
	//
	/*
	bool NeedCCDSkeleton = (Interactivity != RB_STATIC) && (MxUserPropUtils::GetUserPropBool(node->GetMaxNode(), "EnableCCD", false));
	if(NeedCCDSkeleton) 
	{
		NxPhysicsSDK* psdk = gPluginData->getPhysicsSDK();
		psdk->setParameter(NX_CONTINUOUS_CD, 1);
		psdk->setParameter(NX_CCD_EPSILON, 0.01f);
	}
	*/


	// create CCD skeleton for the shape
	//TODO("implement CCD skeleton creation");
	PX_CCD_SKELETON ccdType = (PX_CCD_SKELETON) MxUserPropUtils::GetUserPropInt(node->GetMaxNode(), "px_shape_ccdtype", 1);
	switch(type)
	{
	
	default:
		if (gCurrentstream) gCurrentstream->printf("Unable to create a shape of node \"%s\", unknown shape type: %d.\n", node->GetMaxNode()->GetName(), type);
		return false;
	}
	// load property settings and material things.
	//LoadShapeProperties(*pd, node->GetMaxNode());
	//CCD flag

	pd->name = node->GetMaxNode()->GetName();
	pd->userData = node;
	//
	bool isvalid = pd->isValid();
	actorDesc.shapes.push_back(pd);
#endif

	return shape;
}