Пример #1
0
	void PlaypenApp::createObject(const std::string& material, ObjectType type)
	{
		switch(type)
		{
			case OBJECT_TYPE_BOX:
			{
				Ogre::Vector3 boxDim(5, 5, 5);
				opal::Solid* s = mSimulator->createSolid();
				s->setPosition(mCreationPoint);
				opal::BoxShapeData data;
				data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);
				s->addShape(data);
				createPhysicalEntityBox("", material, boxDim, s);
				break;
			}
			case OBJECT_TYPE_SPHERE:
			{
				Ogre::Real radius = 3; // testing
				opal::Solid* s = mSimulator->createSolid();
				s->setPosition(mCreationPoint);
				opal::SphereShapeData data;
				data.radius = radius;
				data.material.density = 1; // testing
				s->addShape(data);
				createPhysicalEntitySphere("", material, radius, s);
				break;
			}
			case OBJECT_TYPE_WALL:
			{
				opal::Matrix44r m;
				m.rotate(45, 0, 1, 0);
				m.translate(0, 0, -23);
				createWall(6, 8, opal::Vec3r(3, 1.5, 1.5), m, material);
				break;
			}
			case OBJECT_TYPE_TOWER:
			{
				createTower(2, 2, 15, opal::Vec3r(3, 1.5, 1.5), 
					opal::Matrix44r(), material);
				break;
			}
			case OBJECT_TYPE_RAGDOLL:
			{
				opal::Blueprint ragdollBP;
				opal::loadFile(ragdollBP, "../../data/blueprints/ragdoll.xml");
				opal::Matrix44r transform;
				transform.translate(mCreationPoint[0], mCreationPoint[1] - 5, 
					mCreationPoint[2]);

				// Instantiate the Blueprint.
				opal::BlueprintInstance instance;
				mSimulator->instantiateBlueprint(instance, ragdollBP, transform, 16);

				unsigned int i=0;
				for (i=0; i<instance.getNumSolids(); ++i)
				{
					opal::Solid* s = instance.getSolid(i);
					const opal::SolidData& data = s->getData();
					unsigned int j=0;
					for (j=0; j<data.getNumShapes(); ++j)
					{
						opal::ShapeData* shapeData = data.getShapeData(j);

						switch(shapeData->getType())
						{
							case opal::BOX_SHAPE:
							{
								opal::Vec3r dim = 
									((opal::BoxShapeData*)shapeData)->dimensions;
								Ogre::Vector3 boxDim(dim[0], dim[1], dim[2]);
								createPhysicalEntityBox("", material, 
									boxDim, s);
								break;
							}
							case opal::SPHERE_SHAPE:
							{
								opal::real r = 
									((opal::SphereShapeData*)shapeData)->radius;
								createPhysicalEntitySphere("", 
									material, r, s);
								break;
							}
							case opal::CAPSULE_SHAPE:
							{
								opal::real r = 
									((opal::CapsuleShapeData*)shapeData)->radius;
								opal::real l = 
									((opal::CapsuleShapeData*)shapeData)->length;
								createPhysicalEntityCapsule("", 
									material, r, l, s);
								break;
							}
							default:
								assert(false);
						}
					}
				}
				break;
			}
			default:
				assert(false);
				break;
		}
	}
Пример #2
0
	void PlaypenApp::setupInitialPhysicalEntities()
	{
		opal::Matrix44r m;

		// Create a static box for a ground plane.
		Ogre::Vector3 boxDim(70, 16, 70);
		opal::Solid* s = mSimulator->createSolid();
		s->setStatic(true);
		s->setPosition(0, -8, 0);
		opal::BoxShapeData data;
		data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);
		s->addShape(data);
		createPhysicalEntityBox("ground", "Plastic/Gray", boxDim, s);

		// Setup the "object creation tube".
		boxDim.x = 1;
		boxDim.y = 20;
		boxDim.z = 10;
		data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);

		s = mSimulator->createSolid();
		s->setStatic(true);
		m.makeTranslation(mCreationPoint[0] + 0.5 * boxDim.z, 
			mCreationPoint[1], mCreationPoint[2] + 0.5 * boxDim.x);
		s->setTransform(m);
		s->addShape(data);
		createPhysicalEntityBox("tube0", "Plastic/LightGray", boxDim, s);

		s = mSimulator->createSolid();
		s->setStatic(true);
		m.makeTranslation(mCreationPoint[0] - 0.5 * boxDim.z, 
			mCreationPoint[1], mCreationPoint[2] - 0.5 * boxDim.x);
		s->setTransform(m);
		s->addShape(data);
		createPhysicalEntityBox("tube1", "Plastic/LightGray", boxDim, s);

		s = mSimulator->createSolid();
		s->setStatic(true);
		m.makeRotation(90, 0, 1, 0);
		m.translate(-mCreationPoint[2] + 0.5 * boxDim.z, mCreationPoint[1], 
			mCreationPoint[0] + 0.5 * boxDim.x);
		s->setTransform(m);
		s->addShape(data);
		createPhysicalEntityBox("tube2", "Plastic/LightGray", boxDim, s);

		s = mSimulator->createSolid();
		s->setStatic(true);
		m.makeRotation(90, 0, 1, 0);
		m.translate(-mCreationPoint[2] - 0.5 * boxDim.z, mCreationPoint[1], 
			mCreationPoint[0] - 0.5 * boxDim.x);
		s->setTransform(m);
		s->addShape(data);
		createPhysicalEntityBox("tube3", "Plastic/LightGray", boxDim, s);

		// Make a slide under the object creation tube.
		boxDim.x = 60;
		boxDim.y = 1;
		boxDim.z = 15;
		data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);
		data.material.friction = 0.00001;
		s = mSimulator->createSolid();
		s->setStatic(true);
		m.makeTranslation(mCreationPoint[0], mCreationPoint[1] - 33, 
			mCreationPoint[2]);
		m.rotate(-45, 0, 1, 0);
		m.translate(0.3 * boxDim.x, 0, 0);
		m.rotate(-30, 0, 0, 1);
		s->setTransform(m);
		s->addShape(data);
		createPhysicalEntityBox("slide", "Plastic/DarkGray", boxDim, s);
	}
Пример #3
0
	void Update(float elapsed)
	{
		float maxTime = GetPortFloat(&m_actInfo, EIP_Duration);
		float percent = maxTime > FLT_EPSILON ? elapsed / maxTime : 1.0f;
		if(percent >= 1.0f)
		{
			m_actInfo.pGraph->SetRegularlyUpdated(m_actInfo.myID, false);
			m_triggered = false;
			return;
		}

		Vec3 N = GetPortVec3(&m_actInfo, EIP_Normal);

		float rangeMin = GetPortFloat(&m_actInfo, EIP_RangeMin);
		float rangeMax = GetPortFloat(&m_actInfo, EIP_RangeMax);
		const float range = rangeMax - rangeMin;
		Vec3 boxDim(rangeMax, rangeMax, rangeMax);
		Vec3 ptmin = m_effectCenter - boxDim;
		Vec3 ptmax = m_effectCenter + boxDim;

		float speed = GetPortFloat(&m_actInfo, EIP_Speed);
		float waveFront = elapsed * speed;

		float decay = GetPortFloat(&m_actInfo, EIP_Decay);
		if(decay > FLT_EPSILON) decay = 1.0f / decay;

		float force = GetPortFloat(&m_actInfo, EIP_Force);
		force = pow_tpl(force * (1-percent), decay);

		float amplitude = GetPortFloat(&m_actInfo, EIP_Amplitude);
		amplitude = pow_tpl(amplitude * (1-percent), decay);

		if (gEnv->bMultiplayer) // Turned off for performance and network issues
		{
			return;
		}

		IPhysicalEntity** pEntityList = NULL;
		static const int iObjTypes = ent_rigid | ent_sleeping_rigid | ent_living;// | ent_allocate_list;
		int numEntities = gEnv->pPhysicalWorld->GetEntitiesInBox(ptmin, ptmax, pEntityList, iObjTypes);
		AABB bounds;
		for(int i=0; i<numEntities; ++i)
		{
			IPhysicalEntity* pPhysicalEntity = pEntityList[i];
			IEntity* pEntity = static_cast<IEntity*>(pPhysicalEntity->GetForeignData(PHYS_FOREIGN_ID_ENTITY));

			// Has the entity already been affected?
			if(pEntity)
			{
				bool affected = stl::find(m_entitiesAffected, pEntity->GetId());
				if(!affected)
				{
					IEntityPhysicalProxy* pPhysicalProxy = static_cast<IEntityPhysicalProxy*>(pEntity->GetProxy(ENTITY_PROXY_PHYSICS));
					if(pPhysicalProxy)
					{
						pPhysicalProxy->GetWorldBounds(bounds);
						Vec3 p = bounds.GetCenter();
						Vec3 v = p - m_effectCenter;
						float distFromCenter = v.GetLength() + FLT_EPSILON;
						if(distFromCenter < rangeMax)
						{
							if(waveFront > distFromCenter) // has the wavefront passed the entity?
							{
								//pPhysicalEntity->GetStatus(&dyn);

								// normalize v, cheaper than another sqrt
								v /= distFromCenter;

								Vec3 dir = N + v * force;
								static bool usePos = false;
								float impulse = 1.0f - (max(0.0f, distFromCenter - rangeMin) / range);
								impulse = impulse * amplitude;// / dyn.mass;
								if(impulse > FLT_EPSILON)
								{
									pPhysicalProxy->AddImpulse(-1, p, dir * impulse, usePos, 1.0f);
									m_entitiesAffected.push_back(pEntity->GetId());
								}
							}
						}
					}
				}
			}
		}
	}
Пример #4
0
NxActor* CreateConvex(const NxVec3 &pos, int flag)
{
   NxActorDesc actorDesc;
    NxBodyDesc bodyDesc;
	
	NxVec3 boxDim(1,0.8,1.5);
    // Pyramid
     NxVec3 verts[8] =	{	NxVec3(boxDim.x,      -boxDim.y, -boxDim.z), 
							NxVec3(-boxDim.x,     -boxDim.y, -boxDim.z), 
							NxVec3(-boxDim.x,     -boxDim.y, boxDim.z),
							NxVec3(boxDim.x,      -boxDim.y, boxDim.z), 
							NxVec3(boxDim.x*0.5,  boxDim.y,  -boxDim.z*0.5), 
							NxVec3(-boxDim.x*0.5, boxDim.y,  -boxDim.z*0.5),
							NxVec3(-boxDim.x*0.5, boxDim.y,  boxDim.z*0.5), 
							NxVec3(boxDim.x*0.5,  boxDim.y,  boxDim.z*0.5)
						};


	// Create descriptor for convex mesh
	 if (!convexDesc)
	 {
		convexDesc = new  NxConvexMeshDesc();
		assert(convexDesc);
	 }

    convexDesc->numVertices			= 8;
    convexDesc->pointStrideBytes	= sizeof(NxVec3);
    convexDesc->points				= verts;
	convexDesc->flags				= NX_CF_COMPUTE_CONVEX;

	NxConvexShapeDesc convexShapeDesc;
	convexShapeDesc.localPose.t		= NxVec3(0, 2.0f, boxDim.z * 0.4);
	convexShapeDesc.userData		= convexDesc;
 
	NxInitCooking();
	// Cooking from memory
    MemoryWriteBuffer buf;
    bool status = NxCookConvexMesh(*convexDesc, buf);
	//
	// Please note about the created Convex Mesh, user needs to release it when no one uses it to save memory. It can be detected
	// by API "meshData->getReferenceCount() == 0". And, the release API is "gPhysicsSDK->releaseConvexMesh(*convexShapeDesc.meshData);"
	//
	NxConvexMesh *pMesh			= gPhysicsSDK->createConvexMesh(MemoryReadBuffer(buf.data));
	assert(pMesh);
    convexShapeDesc.meshData	= pMesh;
	NxCloseCooking();

    if (pMesh)
    {
        // Save mesh in userData for drawing.
		pMesh->saveToDesc(*convexDesc);
		//
		NxActorDesc actorDesc;
		assert(convexShapeDesc.isValid());
		actorDesc.shapes.pushBack(&convexShapeDesc);
		if (0 == flag)
		{	//Dynamic actor
			bodyDesc.flags	   |= NX_BF_DISABLE_GRAVITY;
			actorDesc.body		= &bodyDesc;
			actorDesc.density	= 1.0f;
		}
		else if (1 == flag)
		{	//Static actor
			actorDesc.body		= NULL;
			actorDesc.density	= 1.0f;
		}
		else if (2 == flag)
		{	// Kinematic actor
			bodyDesc.flags	   |= NX_BF_KINEMATIC;
			actorDesc.body		= &bodyDesc;
			actorDesc.density	= 1.0f;
		}

		actorDesc.globalPose.t  = pos; //NxVec3(6.5f, 0.0f, 0.0f);
		assert(actorDesc.isValid());
		NxActor* actor = gScene->createActor(actorDesc);
		assert(actor);	
		return actor;
    }

    return NULL;
}
Пример #5
0
	bool PlaypenApp::processUnbufferedKeyInput(Ogre::Real dt)
	{
		// Check if we should quit looping.
		if(mKeyboard->isKeyDown(OIS::KC_ESCAPE) 
			|| mKeyboard->isKeyDown(OIS::KC_Q))
		{
			return false;
		}

		// Check if we should pause physics.
		if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0)
		{
			mPaused = !mPaused;

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.5;
		}

		// Reset the scene.
		if(mKeyboard->isKeyDown(OIS::KC_R))
		{
			// Make sure the PhysicalCamera isn't grabbing anything.
			mPhysicalCamera->release();
			destroyAllPhysicalEntities();
			setupInitialPhysicalEntities();
		}

		// Create various types of objects when the number keys are 
		// pressed.

		// Create a box.
		if(mKeyboard->isKeyDown(OIS::KC_1) && mTimeUntilNextToggle <= 0)
		{
			Ogre::Vector3 boxDim(3, 3, 3);
			opal::Solid* s = mSimulator->createSolid();
			s->setPosition(mCreationPoint);
			opal::BoxShapeData data;
			data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);
			s->addShape(data);
			createPhysicalEntityBox("", "Plastic/Yellow", boxDim, s);

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a sphere.
		if(mKeyboard->isKeyDown(OIS::KC_2) && mTimeUntilNextToggle <= 0)
		{
			Ogre::Real radius = 2;
			opal::Solid* s = mSimulator->createSolid();
			s->setPosition(mCreationPoint);
			opal::SphereShapeData data;
			data.radius = radius;
			s->addShape(data);
			createPhysicalEntitySphere("", "Plastic/Purple", radius, s);

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a capsule.
		if(mKeyboard->isKeyDown(OIS::KC_3) && mTimeUntilNextToggle <= 0)
		{
			Ogre::Real radius = 2;
			Ogre::Real length = 5;
			opal::Solid* s = mSimulator->createSolid();
			s->setPosition(mCreationPoint);
			opal::CapsuleShapeData data;
			data.radius = radius;
			data.length = length;
			s->addShape(data);
			createPhysicalEntityCapsule("", "Plastic/Red", radius, length, s);

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a cylinder.
		if(mKeyboard->isKeyDown(OIS::KC_4) && mTimeUntilNextToggle <= 0)
		{
			Ogre::Real radius = 3;
			Ogre::Real length = 5;
			opal::Solid* s = mSimulator->createSolid();
			s->setPosition(mCreationPoint);
			opal::CylinderShapeData data;
			data.radius = radius;
			data.length = length;
			s->addShape(data);
			createPhysicalEntityCylinder("", "Plastic/Blue", radius, length, s);

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a long box.
		if(mKeyboard->isKeyDown(OIS::KC_5) && mTimeUntilNextToggle <= 0)
		{
			Ogre::Vector3 boxDim(2, 10, 3);
			opal::Solid* s = mSimulator->createSolid();
			s->setPosition(mCreationPoint);
			opal::BoxShapeData data;
			data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);
			data.material.density = 10;
			s->addShape(data);
			createPhysicalEntityBox("", "Plastic/Green", boxDim, s);

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		//// Create a log.
		//if(mKeyboard->isKeyDown(OIS::KC_6) && mTimeUntilNextToggle <= 0)
		//{
		//	Ogre::Real logScale = 9;
		//	Ogre::Vector3 boxDim(0.4243, 0.4243, 2);
		//	boxDim *= logScale;
		//	opal::Solid* s = mSimulator->createSolid();
		//	opal::Matrix44r m;
		//	m.rotate(90, 1, 0, 0);
		//	s->setTransform(m);
		//	s->setPosition(mCreationPoint);
		//	opal::BoxShapeData data;
		//	data.dimensions.set(boxDim[0], boxDim[1], boxDim[2]);
		//	s->addShape(data);

		//	std::string name = generateUniqueName();
		//	Ogre::SceneNode* sn = mSceneMgr->getRootSceneNode()->
		//		createChildSceneNode(name);
		//	sn->scale(logScale, logScale, logScale);
		//	Entity* e = mSceneMgr->createEntity(name, "log.mesh");
		//	e->setNormaliseNormals(true);
		//	e->setMaterialName("Textured/Wood");
		//	sn->attachObject(e);
		//	createPhysicalEntity(name, sn, s);

		//	// Reset the timer for toggle keys.
		//	mTimeUntilNextToggle = 0.3;
		//}

		// Create a knot.
		if(mKeyboard->isKeyDown(OIS::KC_6) && mTimeUntilNextToggle <= 0)
		{
			opalSamples::PhysicalEntity* pe = createPhysicalEntityMesh("", 
				"knot.mesh", "Textured/RustedMetal", false, 0.1);
			pe->getSolid()->setPosition(opal::Point3r(0, 40, 0));

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a wall.
		if(mKeyboard->isKeyDown(OIS::KC_7) && mTimeUntilNextToggle <= 0)
		{
			opal::Matrix44r m;
			m.rotate(45, 0, 1, 0);
			m.translate(0, 0, -23);
			createWall(6, 8, opal::Vec3r(3, 1.5, 1.5), m);

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a tower.
		if(mKeyboard->isKeyDown(OIS::KC_8) && mTimeUntilNextToggle <= 0)
		{
			createTower(2, 2, 15, opal::Vec3r(3, 1.5, 1.5));

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.3;
		}

		// Create a ragdoll.
		if(mKeyboard->isKeyDown(OIS::KC_9) && mTimeUntilNextToggle <= 0)
		{
			opal::Blueprint ragdollBP;
			opal::loadFile(ragdollBP, "../data/blueprints/ragdoll.xml");
			opal::Matrix44r transform;
			transform.translate(mCreationPoint[0], mCreationPoint[1] - 5, 
				mCreationPoint[2]);

			// Instantiate the Blueprint.
			opal::BlueprintInstance instance;
			mSimulator->instantiateBlueprint(instance, ragdollBP, transform, 16);

			unsigned int i=0;
			for (i=0; i<instance.getNumSolids(); ++i)
			{
				opal::Solid* s = instance.getSolid(i);
				const opal::SolidData& data = s->getData();
				unsigned int j=0;
				for (j=0; j<data.getNumShapes(); ++j)
				{
					opal::ShapeData* shapeData = data.getShapeData(j);

					switch(shapeData->getType())
					{
						case opal::BOX_SHAPE:
						{
							opal::Vec3r dim = 
								((opal::BoxShapeData*)shapeData)->dimensions;
							Ogre::Vector3 boxDim(dim[0], dim[1], dim[2]);
							createPhysicalEntityBox("", "Plastic/LightBlue", 
								boxDim, s);
							break;
						}
						case opal::SPHERE_SHAPE:
						{
							opal::real r = 
								((opal::SphereShapeData*)shapeData)->radius;
							createPhysicalEntitySphere("", 
								"Plastic/LightBlue", r, s);
							break;
						}
						case opal::CAPSULE_SHAPE:
						{
							opal::real r = 
								((opal::CapsuleShapeData*)shapeData)->radius;
							opal::real l = 
								((opal::CapsuleShapeData*)shapeData)->length;
							createPhysicalEntityCapsule("", 
								"Plastic/LightBlue", r, l, s);
							break;
						}
						default:
							assert(false);
					}
				}
			}

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.5;
		}

		// The following code updates the camera's position.
		opal::Vec3r cameraDir(0, 0, 0);
		bool cameraMoved = false;

		if (mKeyboard->isKeyDown(OIS::KC_LEFT) 
			|| mKeyboard->isKeyDown(OIS::KC_A))
		{
			// Move camera left.
			cameraDir[0] -= (dt * mMoveSpeed);
			cameraMoved = true;
		}

		if (mKeyboard->isKeyDown(OIS::KC_RIGHT) 
			|| mKeyboard->isKeyDown(OIS::KC_D))
		{
			// Move camera right.
			cameraDir[0] += (dt * mMoveSpeed);
			cameraMoved = true;
		}

		if (mKeyboard->isKeyDown(OIS::KC_UP) 
			|| mKeyboard->isKeyDown(OIS::KC_W))
		{
			// Move camera forward.
			cameraDir[2] -= (dt * mMoveSpeed);
			cameraMoved = true;
		}

		if (mKeyboard->isKeyDown(OIS::KC_DOWN) 
			|| mKeyboard->isKeyDown(OIS::KC_S))
		{
			// Move camera backward.
			cameraDir[2] += (dt * mMoveSpeed);
			cameraMoved = true;
		}

		if (!cameraMoved)
		{
			// Slow physical camera motion if necessary.
		}

		// Use the camera dir vector to translate the camera.
		mPhysicalCamera->moveRelative(cameraDir);

		// Toggle shadows.
		if(mKeyboard->isKeyDown(OIS::KC_H) && mTimeUntilNextToggle <= 0)
		{
			mUseShadows = !mUseShadows;

			if (mUseShadows)
			{
				mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
			}
			else
			{
				mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
			}

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.5;
		}

		// Toggle second light source.
		if(mKeyboard->isKeyDown(OIS::KC_L) && mTimeUntilNextToggle <= 0)
		{
			Ogre::Light* light1 = mSceneMgr->getLight("light1");

			if (light1->isVisible())
			{
				light1->setVisible(false);
			}
			else
			{
				light1->setVisible(true);
			}

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.5;
		}

		// Toggle GUI.
		if (mKeyboard->isKeyDown(OIS::KC_G) && mTimeUntilNextToggle <= 0)
		{
			mStatsOn = !mStatsOn;
			showDebugOverlay(mStatsOn);
			mTimeUntilNextToggle = 1;
		}

		// Handy screenshot saving procedure.
		if (mKeyboard->isKeyDown(OIS::KC_SYSRQ) 
			&& mTimeUntilNextToggle <= 0)
		{
			char tmp[20];
			sprintf(tmp, "screenshot_%d.png", ++mNumScreenShots);
			ExampleApplication::mWindow->writeContentsToFile(tmp);
			mDebugText = String("Wrote ") + tmp;

			// Reset the timer for toggle keys.
			mTimeUntilNextToggle = 0.5;
		}

		// Return true to continue looping.
		return true;
	}
Пример #6
0
NxActor* CreateLander(NxVec3 position)
{
	NxActor* actor=NULL;
	switch (gLanderType)
	{
		case CAPSULE_LANDER:
			actor = CreateCapsuleGrain(position,gLanderMass/pow(gLanderSize.x,3.0f),gLanderSize.x);
			break;
		case SPHERE_LANDER:
			actor = CreateSphericalGrain(position,gLanderMass/pow(gLanderSize.x,3.0f),gLanderSize.x);
			break;
		case ROLY_POLY:
			{// Two slightly offset spheres, one heavy, one slightly smaller, and hollow
				NxActorDesc actorDesc;
				NxBodyDesc bodyDesc;
				NxReal radius=gLanderSize.x;

				// The bottom "roly"
				NxSphereShapeDesc rolyDesc;
				rolyDesc.radius=radius*gLanderSize.z; // relative to top hemisphere
				rolyDesc.localPose.t=NxVec3(0.0f,radius,0.0f);
				rolyDesc.materialIndex=gLanderDownMaterial->getMaterialIndex(); // note: both hemispheres use "down" material
				rolyDesc.mass=1; // relative to top hemisphere
				rolyDesc.skinWidth=radius/60;
				rolyDesc.name="downside";
				actorDesc.shapes.pushBack(&rolyDesc);

				// The top "poly"
				NxSphereShapeDesc polyDesc;
				polyDesc.radius=radius;
				polyDesc.localPose.t=NxVec3(0.0f,radius+gLanderSize.y,0.0f);
				polyDesc.materialIndex=gLanderDownMaterial->getMaterialIndex(); // note: both hemispheres use "down" material
				polyDesc.mass=1;
				polyDesc.skinWidth=radius/60;
				polyDesc.name="upside";
				actorDesc.shapes.pushBack(&polyDesc);

				// The weight
				NxSphereShapeDesc wDesc;
				wDesc.radius=radius/10;
				wDesc.localPose.t=NxVec3(0.0f,wDesc.radius,0.0f);
				wDesc.materialIndex=gLanderDownMaterial->getMaterialIndex(); // note: this is irrelevant
				wDesc.mass=gRPWeight; // relative to top hemisphere
				wDesc.skinWidth=radius/120;
				wDesc.name="weight";
				actorDesc.shapes.pushBack(&wDesc);

				// the lander
				bodyDesc.mass=gLanderMass;
				actorDesc.body=&bodyDesc;
				actorDesc.globalPose.t=position;
				assert(actorDesc.isValid());
				actor=gScene->createActor(actorDesc);
				assert(actor);
				actor->setName("~lander");
				//actor->raiseBodyFlag(NX_BF_KINEMATIC);

				break;
			}
		case SHAPED_CHARGE:
			{// Two flat plates, like a two-layer ruler, one heavy and absorbing, one hollow and elastic
				NxActorDesc actorDesc;
				NxBodyDesc bodyDesc;
				NxVec3 boxDim=gLanderSize/2; // remember NxShapeDesc.dimension is the "radius"
				boxDim.y/=2; // remember we're going to stack two of these

				// The down side
				NxBoxShapeDesc downsideDesc;
				downsideDesc.dimensions.set(boxDim);
				downsideDesc.localPose.t=NxVec3(0.0f,boxDim.y,0.0f);
				downsideDesc.materialIndex=gLanderDownMaterial->getMaterialIndex();
				downsideDesc.density=gLanderMassRatio;
				downsideDesc.skinWidth=boxDim.y/60;
				downsideDesc.name="downside";
				actorDesc.shapes.pushBack(&downsideDesc);

				// The up side
				NxBoxShapeDesc upsideDesc;
				upsideDesc.dimensions.set(boxDim);
				upsideDesc.localPose.t=NxVec3(0.0f,3.0*boxDim.y,0.0f);
				upsideDesc.materialIndex=gLanderUpMaterial->getMaterialIndex();
				upsideDesc.density=1;
				upsideDesc.skinWidth=boxDim.y/60;
				upsideDesc.name="upside";
				actorDesc.shapes.pushBack(&upsideDesc);

				// The Lander
				bodyDesc.mass=gLanderMass;
				actorDesc.body = &bodyDesc;
				actorDesc.globalPose.t	= position;
				assert(actorDesc.isValid());
				actor = gScene->createActor(actorDesc);	
				assert(actor);
				actor->setName("~lander");

				break;
			}
		case CUBESAT:
			{// JPL's new fad, comes in units of 10x10x10 cm
				NxActorDesc actorDesc;
				NxBodyDesc bodyDesc;
				NxVec3 boxDim(0.05); // remember NxShapeDesc.dimension is the "radius"

				// U1 - the dead weight
				NxBoxShapeDesc U1Desc;
				U1Desc.dimensions.set(boxDim);
				U1Desc.localPose.t=NxVec3(0.0f,boxDim.y,0.0f);
				U1Desc.materialIndex=gLanderDownMaterial->getMaterialIndex();
				U1Desc.mass=10*gLanderMass;
				U1Desc.skinWidth=boxDim.y/60;
				U1Desc.name="U1";
				actorDesc.shapes.pushBack(&U1Desc);

				// U2
				NxBoxShapeDesc U2Desc;
				U2Desc.dimensions.set(boxDim);
				U2Desc.localPose.t=NxVec3(0.0f,3.0*boxDim.y,0.0f);
				U2Desc.materialIndex=gLanderUpMaterial->getMaterialIndex();
				U2Desc.mass=gLanderMass;
				U2Desc.skinWidth=boxDim.y/60;
				U2Desc.name="U2";
				actorDesc.shapes.pushBack(&U2Desc);

				// U3
				NxBoxShapeDesc U3Desc;
				U3Desc.dimensions.set(boxDim);
				U3Desc.localPose.t=NxVec3(0.0f,5.0*boxDim.y,0.0f);
				U3Desc.materialIndex=gLanderUpMaterial->getMaterialIndex();
				U3Desc.mass=gLanderMass;
				U3Desc.skinWidth=boxDim.y/60;
				U3Desc.name="U3";
				actorDesc.shapes.pushBack(&U3Desc);

				// The Cubesat
				bodyDesc.mass=gLanderMass;
				actorDesc.body = &bodyDesc;
				actorDesc.globalPose.t	= position;
				assert(actorDesc.isValid());
				actor = gScene->createActor(actorDesc);	
				assert(actor);
				actor->setName("~lander");
				break;
			}
		default:
			printf("Error: unknown lander type\n");
			break;
	}

	return actor;
}