| #pragma comment(lib,
"PhysXLoader.lib") #pragma comment(lib, "NxCooking.lib") #pragma comment(lib, "Irrlicht.lib") #include <NxPhysics.h> #include <NxCooking.h> #include <Stream.h> #include <irrlicht.h> |
| class CPhysXAnimatedMeshSceneNode : public IAnimatedMeshSceneNode; |
| private: // NEW STUFF NxActor *Actor; bool PhysXControlled; |
| virtual bool
isPhysXControlled() const { return PhysXControlled; } virtual void setPhysXControlled(const bool &controlled) { PhysXControlled = controlled; } |
| CPhysXAnimatedMeshSceneNode(IAnimatedMesh*
mesh, NxActor* actor, ISceneNode* parent, ISceneManager*
mgr, s32 id, const core::vector3df& position = core::vector3df(0,0,0), const core::vector3df& rotation = core::vector3df(0,0,0), const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); /***** moving along... you can find the rest of the code in the source :) ****/ void CPhysXAnimatedMeshSceneNode::OnPreRender() { if (IsVisible) { // reorient/reposition the scene node every frame if (Actor && !Actor->isSleeping() && PhysXControlled) { // this code's from the Beginner Lesson 101 tutorial /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ // modified to use for a irrlicht matrix4 NxMat34 pose = Actor->getGlobalPose(); const NxVec3 pos = pose.t; const NxMat33 orient = pose.M; core::matrix4 irrMat; // a 4x4 matrix in the irrlicht engine orient.getColumnMajorStride4(&irrMat.M[0]); pos.get(&irrMat.M[12]); //clear the elements we don't need: irrMat.M[3] = irrMat.M[7] = irrMat.M[11] = 0.0f; irrMat.M[15] = 1.0f; // with that newly made matrix, let's use it to transform/rotate the node setPosition(irrMat.getTranslation()); setRotation(irrMat.getRotationDegrees()); } // because this node supports rendering of mixed mode meshes consisting of // transparent and solid material at the same time, we need to go through all // materials, check of what type they are and register this node for the right // render pass according to that. video::IVideoDriver* driver = SceneManager->getVideoDriver(); PassCount = 0; int transparentCount = 0; int solidCount = 0; // count transparent and solid materials in this scene node for (u32 i=0; i<Materials.size(); ++i) { video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); if (rnd && rnd->isTransparent()) ++transparentCount; else ++solidCount; if (solidCount && transparentCount) break; } // register according to material types counted //! but first, check if it's in our camera's frustum before we decide we want to register for rendering if (SceneManager->getActiveCamera()->getViewFrustrum()->getBoundingBox().isPointInside(getPosition())) { if (solidCount) SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); if (transparentCount) SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); } } ISceneNode::OnPreRender(); if (IsVisible) for (s32 i=0; i<(s32)JointChildSceneNodes.size(); ++i) if (JointChildSceneNodes[i]) JointChildSceneNodes[i]->OnPreRender(); } |
| IAnimatedMeshSceneNode*
addPhysXAnimatedMeshSceneNode(IAnimatedMesh* mesh, NxActor* actor,
ISceneNode* parent=0, s32 id=-1, const core::vector3df& position = core::vector3df(0,0,0), const core::vector3df& rotation = core::vector3df(0,0,0), const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) { if (!mesh) return 0; if (!parent) parent = smgr->getRootSceneNode(); IAnimatedMeshSceneNode* node = new CPhysXAnimatedMeshSceneNode(mesh, actor, parent, smgr, id, position, rotation, scale); node->drop(); return node; } |
| // Physics SDK globals NxPhysicsSDK* gPhysicsSDK = NULL; // pointer to the SDK NxScene* gScene = NULL; // pointer to the scene NxVec3 gDefaultGravity(0,-9.81f,0); // NxVec3 representing gravity // Force globals NxVec3 gForceVec(0,0,0); NxReal gForceStrength = 75000000.0f; // some force big enough to toss them balls and boxes around IAnimatedMesh *cubeMesh, *sphereMesh; // pointers to the actual cube and sphere meshes ITexture *texture0, *texture1; // pointers to their textures //////////////////////////////////////////////////////// // function to initialize PhysX bool InitNx() { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ // Create the physics SDK gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION); if (!gPhysicsSDK) return false; // Set the physics parameters gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.0f); // usually 0.02 // Set the debug visualization parameters gPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 1); gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES, 1); gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES, 1); // Create the scene NxSceneDesc sceneDesc; sceneDesc.gravity = gDefaultGravity; sceneDesc.broadPhase = NX_BROADPHASE_COHERENT; sceneDesc.collisionDetection = true; gScene = gPhysicsSDK->createScene(sceneDesc); if (!gScene) return false; // Create the default material NxMaterial* defaultMaterial = gScene->getMaterialFromIndex(0); defaultMaterial->setRestitution(0.125f); //! 0.5 defaultMaterial->setStaticFriction(0.5f); //! 0.5 defaultMaterial->setDynamicFriction(0.5f); //! 0.5 // Get the current time UpdateTime(); // Start the first frame of the simulation StartPhysics(); return true; } // run this to close it void ReleaseNx() { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ if (gScene) { //GetPhysicsResults(); // Make sure to fetchResults() before shutting down gPhysicsSDK->releaseScene(*gScene); } if (gPhysicsSDK) gPhysicsSDK->release(); } |
| NxReal UpdateTime() { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ NxReal deltaTime; #ifndef LINUX static __int64 gTime,gLastTime; __int64 freq; QueryPerformanceCounter((LARGE_INTEGER *)&gTime); // Get current count QueryPerformanceFrequency((LARGE_INTEGER *)&freq); // Get processor freq deltaTime = (double)(gTime - gLastTime)/(double)freq; #else static clock_t gTime, gLastTime; gTime = clock(); deltaTime = (NxReal)((double)(gTime - gLastTime) / 1000000.0f); #endif gLastTime = gTime; return deltaTime; } // run this every frame void StartPhysics() { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ // Update the time step NxReal deltaTime = UpdateTime(); // Start collision and dynamics for delta time since the last frame gScene->simulate(deltaTime * 5.0f); // i multiply by five for more faster, realistic looking dynamics gScene->flushStream(); } // this too void GetPhysicsResults() { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ // Get results from gScene->simulate(deltaTime) while (!gScene->fetchResults(NX_RIGID_BODY_FINISHED, false)); } |
| NxActor* CreateBox(const
core::vector3df &pos, const core::vector3df &scale =
core::vector3df(1.0f,1.0f,1.0f)) { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ // function slightly modified to modify dimensions/scale // Add a single-shape actor to the scene NxActorDesc actorDesc; NxBodyDesc bodyDesc; bodyDesc.angularDamping = 0.5f; // The actor has one shape, a box, 1m on a side NxBoxShapeDesc boxDesc; boxDesc.dimensions.set(scale.X,scale.Y,scale.Z); // should be 0.5 actorDesc.shapes.pushBack(&boxDesc); actorDesc.body = &bodyDesc; actorDesc.density = 1.0f; actorDesc.globalPose.t = NxVec3(pos.X,pos.Y,pos.Z); return gScene->createActor(actorDesc); } NxActor* CreateSphere(const core::vector3df &pos, const f32 &radius = 1.0f) { /* Ageia and PhysX, both stylized and non-stylized, are trademarks or registered trademarks of Ageia Technologies Inc. Copyright 2006 Ageia Technologies Inc. */ // function slightly modified to create spheres // Add a single-shape actor to the scene NxActorDesc actorDesc; NxBodyDesc bodyDesc; bodyDesc.angularDamping = 0.5f; // The actor has one shape, a box, 1m on a side NxSphereShapeDesc sphereDesc; sphereDesc.radius = radius; // should be 0.5 actorDesc.shapes.pushBack(&sphereDesc); actorDesc.body = &bodyDesc; actorDesc.density = 1.0f; actorDesc.globalPose.t = NxVec3(pos.X,pos.Y,pos.Z); return gScene->createActor(actorDesc); } |
| NxActor
*CreateQuake3Map(IAnimatedMesh *q3map, const vector3df &pos =
vector3df(0.0f,0.0f,0.0f), const core::vector3df &scale =
core::vector3df(1.0f,1.0f,1.0f)) { if (!q3map) return NULL; // retrieve how many meshes there are irr::s32 meshBufferCount = q3map->getMesh(0)->getMeshBufferCount(); core::array<NxVec3> vertices; // used for allocating vertices core::array<NxU32> indices; // used for allocating indices NxU32 tempIndexCount = 0; // used for offsetting indices for (int i = 0; i < meshBufferCount; ++i) { // pointer to the map's mesh buffer IMeshBuffer *mb = q3map->getMesh(0)->getMeshBuffer(i); // for every mesh buffer s32 numVertices = mb->getVertexCount(); // get vertex num every mesh buffer s32 numIndices = mb->getIndexCount(); // get index num every mesh buffer video::S3DVertex2TCoords *mbVertices = (irr::video::S3DVertex2TCoords*)mb->getVertices(); // get pointer to vertices in the mesh buffer irr::u16 *mbIndices = mb->getIndices(); // get pointer to indices in the mesh buffer for (int j = 0; j < numVertices; ++j) // push vertices into an array vertices.push_back(NxVec3(mbVertices[j].Pos.X * scale.X, mbVertices[j].Pos.Y * scale.Y, mbVertices[j].Pos.Z * scale.Z)); for (int j = 0; j < numIndices; ++j) // push indices into an array indices.push_back(NxU32(mbIndices[j]) + tempIndexCount); // the q3 map when loaded into irrlicht, is divided into multiply mesh buffers. // we want the sum of all mesh buffer indices. this way, when it's loaded into physx // it's offsetted correctly instead of the bug i previously had where it indices only // pointed to the first 400 or whatever vertices because each set of indices pointed to only // its own pair of vertices in the mesh buffer. tempIndexCount += numIndices; } NxPMap q3mapPMap; q3mapPMap.dataSize = 0; q3mapPMap.data = NULL; NxTriangleMeshDesc mapMeshDesc; // mesh description // Build physical model mapMeshDesc.numVertices = vertices.size(); mapMeshDesc.numTriangles = indices.size() / 3; mapMeshDesc.pointStrideBytes = sizeof(NxVec3); mapMeshDesc.triangleStrideBytes = 3*sizeof(NxU32); mapMeshDesc.points = vertices.const_pointer(); mapMeshDesc.triangles = indices.const_pointer(); mapMeshDesc.flags = 0; cout << endl << mapMeshDesc.numVertices << " vertices.\n"; cout << indices.size() << " indices.\n"; cout << mapMeshDesc.numTriangles << " triangles.\n"; MemoryWriteBuffer buf; NxCookTriangleMesh(mapMeshDesc, buf); MemoryReadBuffer readBuffer(buf.data); NxTriangleMesh *q3mapTriangleMesh = gPhysicsSDK->createTriangleMesh(readBuffer); // PMap stuff // Try loading PMAP from disk fstream file("q3map.pmap",ios::in|ios::binary|ios::ate); if (!file.good()) // if the file doesn't exist, we write ourselves a new PMAP { file.close(); // close it. it failed :( file.clear();// CLEAR THEM FLAGS!! (so we can attempt opening again properly) cout << "Please wait while precomputing pmap...\n"; file.open("q3map.pmap",ios::out|ios::binary|ios::trunc); if(NxCreatePMap(q3mapPMap, *q3mapTriangleMesh, 64)) { // The pmap has successfully been created, save it to disk for later use if (file.good()) { cout << "writing data size:\t" << q3mapPMap.dataSize << endl; file.write((char*)q3mapPMap.data, q3mapPMap.dataSize); } else cout << "Unable to write to file.\n"; //assign pmap to mesh q3mapTriangleMesh->loadPMap(q3mapPMap); // sdk created data => sdk deletes it NxReleasePMap(q3mapPMap); } file.close(); } else { cout << "Found pmap and using it...\n"; // Found pmap file q3mapPMap.dataSize = file.tellg(); //getFileSize("q3map.pmap"); file.seekg(0,ios::beg); cout << "reading data size:\t" << q3mapPMap.dataSize << endl; q3mapPMap.data = new NxU8[q3mapPMap.dataSize]; file.read((char*)q3mapPMap.data, q3mapPMap.dataSize);//fread(q3mapPMap.data, q3mapPMap.dataSize, 1, fp); file.close(); //assign pmap to mesh q3mapTriangleMesh->loadPMap(q3mapPMap); //we created data => we delete it delete [] q3mapPMap.data; } NxTriangleMeshShapeDesc mapMeshShapeDesc; mapMeshShapeDesc.meshData = q3mapTriangleMesh; NxActorDesc actorDesc; actorDesc.shapes.pushBack(&mapMeshShapeDesc); actorDesc.globalPose.t = NxVec3(pos.X,pos.Y,pos.Z); indices.clear(); vertices.clear(); return gScene->createActor(actorDesc); } |
| irr::u16 sphereOrCube = 0; bool createShape(const vector3df &position = camera->getPosition(), const vector3df &target = camera->getTarget(), const bool &applyForce = true) { NxActor *newActor; // pointer to newly created object IAnimatedMeshSceneNode *newNode; // pointer to its scene node core::vector3df irrDir = (target - position).normalize(); // get and normalize the direction f32 dim = 20.0f; // the typical dimension/radius is 20 // we're either shooting out cubes or spheres if (!(sphereOrCube % 2)) { newActor = CreateBox(position, vector3df(dim,dim,dim)); if (!newActor) return false; newNode = addPhysXAnimatedMeshSceneNode(cubeMesh,newActor); newNode->setMaterialTexture(0, texture0); } else { newActor = CreateSphere(position,dim); if (!newActor) return false; newNode = addPhysXAnimatedMeshSceneNode(sphereMesh,newActor); newNode->setMaterialTexture(0, texture1); } newNode->setMaterialFlag(EMF_LIGHTING, true); newNode->setScale(core::vector3df(dim,dim,dim)); //newNode->addShadowVolumeSceneNode(); if (applyForce) ApplyForceToActor(newActor,NxVec3(irrDir.X, irrDir.Y, irrDir.Z),gForceStrength); // apply force to "shoot" it return true; } |
