unsigned int Forest::onCollideJumper(unsigned int id, Matrix4f* matrix, void* data) { Forest* __this = reinterpret_cast<Forest*>( data ); // determine obb of instance NxBox instanceOBB = calculateOBB( __this->_canopyBatch->getBatchScheme()->lodGeometry[0], *matrix, __this->_desc.collScale ); __this->_debugBoxes.push_back( instanceOBB ); // collide obbs if( NxBoxBoxIntersect( instanceOBB, __this->_jumperOBB ) ) { Jumper* jumper = dynamic_cast<Jumper*>( __this->_currentJumper ); // add impulse to jumper body NxVec3 linearVelocity = __this->_currentJumperActor->getLinearVelocity(); NxVec3 impulse = linearVelocity * getCore()->getRandToolkit()->getUniform( __this->_desc.minImpulseFactor, __this->_desc.maxImpulseFactor ) * -1; NxVec3 localPos( __this->_jumperOBB.extents.x * getCore()->getRandToolkit()->getUniform( -1, 1 ), __this->_jumperOBB.extents.y * getCore()->getRandToolkit()->getUniform( -1, 1 ), __this->_jumperOBB.extents.z * getCore()->getRandToolkit()->getUniform( -1, 1 ) ); __this->_currentJumperActor->addForceAtLocalPos( impulse, localPos, NX_IMPULSE ); // damage jumper jumper->damage( __this->_desc.damageFactor * impulse.magnitude(), 0.0f, linearVelocity.magnitude() ); // play rustle sound __this->playRustleSound( __this->_currentJumperCollision->getFrame()->getPos() ); } return id; }
unsigned int Forest::onCollideCanopy(unsigned int id, Matrix4f* matrix, void* data) { Forest* __this = reinterpret_cast<Forest*>( data ); // determine obb of instance NxBox instanceOBB = calculateOBB( __this->_canopyBatch->getBatchScheme()->lodGeometry[0], *matrix, __this->_desc.collScale ); __this->_debugBoxes.push_back( instanceOBB ); // collide obbs if( NxBoxBoxIntersect( instanceOBB, __this->_canopyOBB ) ) { CanopySimulator* canopy = dynamic_cast<CanopySimulator*>( __this->_currentCanopy ); // calculate intersection details float volume; NxVec3 globalIntersectionCenter; calculateIntersectionDetails( instanceOBB, __this->_canopyOBB, volume, globalIntersectionCenter ); assert( volume <= 1.0f ); // add force to canopy NxVec3 linearVelocity = __this->_currentCanopyActor->getLinearVelocity(); float linearVelocityMagnitude = linearVelocity.magnitude(); linearVelocity.normalize(); NxVec3 force = linearVelocity * 0.2f * sqr( linearVelocityMagnitude ) * __this->_currentCanopyInfo->square * -volume; __this->_currentCanopyActor->addForceAtPos( force, globalIntersectionCenter, NX_FORCE ); // damage canopy canopy->rip( __this->_desc.ripFactor * force.magnitude() ); // entangle canopy if( volume > __this->_desc.entangleFactor ) { canopy->entangle( globalIntersectionCenter ); __this->playSqueakSound( wrap( globalIntersectionCenter ) ); } else { __this->playRustleSound( wrap( globalIntersectionCenter ) ); } } return id; }
void ParticlePhysics::update() { if(!data->physics) return; data->actorBaseList.clear(); data->fluidBaseList.clear(); // Update physics actors { for(PhysicsActorList::iterator it = data->physicsActorList.begin(); it != data->physicsActorList.end(); ++it) { PhysicsActor *actor = *it; if(!actor->actor) continue; /* if(actor->actor) { VC3 velocity; actor->actor->getVelocity(velocity); float len = velocity.GetLength(); if(len > 1) { velocity /= len; actor->actor->setVelocity(velocity); } } */ #ifndef PHYSX_GRAVITY if(actor->force.GetSquareLength() > 0.01f) { if(!actor->forceUpdate && ++actor->sleepCounter % 10 == 0) { VC3 currentPos; actor->getPosition(currentPos); VC3 currentAngular; actor->actor->getAngularVelocity(currentAngular); if( currentPos.GetSquareRangeTo(actor->lastPosition1) < 0.00001f || currentAngular.GetSquareRangeTo(actor->lastAngular1) < 0.00001f || currentPos.GetSquareRangeTo(actor->lastPosition2) < 0.00001f || currentAngular.GetSquareRangeTo(actor->lastAngular2) < 0.00001f) { if(!actor->actor->isSleeping()) actor->actor->putToSleep(); } actor->lastPosition2 = actor->lastPosition1; actor->lastAngular2 = actor->lastAngular1; actor->lastPosition1 = currentPos; actor->lastAngular1 = currentAngular; } if(actor->forceUpdate || !actor->actor->isSleeping()) actor->actor->addVelocityChange(actor->force); actor->force = VC3(); } #else if(actor->forceUpdate) { VC3 base; actor->actor->getVelocity(base); VC3 newForce = base; newForce += actor->force; float len = newForce.GetSquareLength(); if(len > MAX_VELOCITY * MAX_VELOCITY) { len = sqrtf(len); newForce /= len; newForce *= MAX_VELOCITY; } newForce -= base; actor->actor->addVelocityChange(newForce); { QUAT rot; rotateToward(VC3(0, 1.f, 0), actor->force.GetNormalized(), rot); VC3 test(rot.x, rot.y, rot.z); test.x += ((float)(rand() - RAND_MAX/2) / (float)RAND_MAX/2); test.z += ((float)(rand() - RAND_MAX/2) / (float)RAND_MAX/2); if(test.GetSquareLength() > 0.001f) test.Normalize(); test *= 2.f; actor->actor->setAngularVelocity(test * 2.f); } actor->force = VC3(); } #endif actor->forceUpdate = false; } physics::resetFluidParticleCount(); for(FluidActorList::iterator it = data->fluidActorList.begin(); it != data->fluidActorList.end(); ++it) { PhysicsFluid *fluid = *it; if(!fluid->fluid) continue; if(fluid->addAmount) { fluid->fluid->addParticles(&fluid->buffer[0], fluid->addAmount); fluid->buffer.clear(); fluid->addAmount = 0; } fluid->fluid->setAcceleration(fluid->acceleration); fluid->fluid->update(); //fluid->renderFlag = false; } } /* // Meshes { for(MeshList::iterator it = data->meshList.begin(); it != data->meshList.end(); ++it) { MeshData &convex = *it; boost::shared_ptr<PhysicsMesh> mesh = convex.mesh.lock(); if(!mesh) continue; filesystem::FB_FILE *fp = filesystem::fb_fopen(convex.filename.c_str(), "rb"); if(!fp) { physics::Cooker cooker; cooker.cookApproxConvex(convex.filename.c_str(), convex.object); } else filesystem::fb_fclose(fp); mesh->mesh = data->physics->createConvexMesh(convex.filename.c_str()); } data->meshList.clear(); } */ // Actors { /* if(actorList.size() + physicsActorList.size() > MAX_ACTOR_AMOUNT) { boost::shared_ptr<PhysicsActor> nullActor; return nullActor; } */ bool sort = false; int createAmount = data->actorList.size(); if(createAmount > data->maxParticleSpawnAmount) { createAmount = data->maxParticleSpawnAmount; sort = true; } if(createAmount + data->createdActors > data->maxParticleAmount) { sort = true; createAmount = data->maxParticleAmount - data->createdActors; } if(sort) std::sort(data->actorList.begin(), data->actorList.end(), ActorListSorter()); // For collision test #ifdef PHYSX_SPAWN_TEST std::vector<BoxStruct> previousBoxes; #endif int index = 0; for(ActorList::iterator it = data->actorList.begin(); it != data->actorList.end(); ++it) { ActorData &convex = *it; if(convex.createDelayCounter++ >= MAX_WAIT_FOR_CREATE) continue; boost::shared_ptr<PhysicsActor> actor = convex.actor.lock(); if(!actor) continue; boost::shared_ptr<PhysicsMesh> mesh = convex.mesh.lock(); if(!mesh) continue; /* //VC3 boxCenter = mesh->localPosition + actor->position; VC3 boxCenter = mesh->localPosition; actor->rotation.RotateVector(boxCenter); boxCenter += actor->position; // Test to previous tick physics if(data->physics->checkOverlapOBB(boxCenter, mesh->size, actor->rotation, physics::PhysicsLib::CollisionStatic)) { convex.actor.reset(); convex.mesh.reset(); continue; } */ #ifdef PHYSX_SPAWN_TEST BoxStruct currentBox; currentBox.center.set(boxCenter.x, boxCenter.y, boxCenter.z); currentBox.extents.set(mesh->size.x, mesh->size.y, mesh->size.z); QUAT r = actor->rotation.GetInverse(); NxQuat quat; quat.setXYZW(r.x, r.y, r.z, r.w); currentBox.rotation.fromQuat(quat); // Test to previous tick physics if(data->physics->checkOverlapOBB(boxCenter, mesh->size, actor->rotation)) continue; bool hit = false; for(unsigned int i = 0; i < previousBoxes.size(); ++i) { const BoxStruct &b = previousBoxes[i]; if(NxBoxBoxIntersect(currentBox.extents, currentBox.center, currentBox.rotation, b.extents, b.center, b.rotation, true)) { hit = true; break; } } if(hit) continue; #endif // Don't create too many particles if(index++ >= createAmount) break; /* boost::shared_ptr<physics::ConvexActor> convexActor = data->physics->createConvexActor(mesh->mesh, actor->position); if(convexActor) { convexActor->setRotation(actor->rotation); convexActor->setVelocity(convex.velocity); convexActor->setAngularVelocity(convex.angularVelocity); convexActor->setMass(convex.mass); convexActor->setCollisionGroup(2); //convexActor->enableFeature(physics::ActorBase::DISABLE_GRAVITY, true); actor->actor = convexActor; } */ boost::shared_ptr<physics::BoxActor> boxActor = data->physics->createBoxActor(mesh->size, actor->position, mesh->localPosition); if(boxActor) { ++data->createdActors; boxActor->setRotation(actor->rotation); boxActor->setVelocity(convex.velocity); boxActor->setAngularVelocity(convex.angularVelocity); boxActor->setMass(convex.mass); boxActor->setCollisionGroup(convex.collisionGroup); #ifndef PHYSX_GRAVITY boxActor->enableFeature(physics::ActorBase::DISABLE_GRAVITY, true); #endif boxActor->setIntData(convex.soundGroup); actor->actor = boxActor; #ifdef PHYSX_SPAWN_TEST previousBoxes.push_back(currentBox); #endif } } int size = data->actorList.size(); for(int i = index; i < size; ++i) { data->actorList[i].createDelayCounter++; } if(index < size) { for(int i = 0; i < size - index; ++i) data->actorList[i] = data->actorList[i + index]; data->actorList.resize(size - index); } else data->actorList.clear(); } // Fluids { for(FluidList::iterator it = data->fluidList.begin(); it != data->fluidList.end(); ++it) { FluidData &fluidData = *it; boost::shared_ptr<PhysicsFluid> fluid = fluidData.fluid.lock(); if(!fluid) continue; boost::shared_ptr<physics::Fluid> fluidActor = data->physics->createFluid(physics::PhysicsLib::FluidType(fluidData.type), fluidData.maxParticles, fluidData.fluidStaticRestitution, fluidData.fluidStaticAdhesion, fluidData.fluidDynamicRestitution, fluidData.fluidDynamicAdhesion, fluidData.fluidDamping, fluidData.fluidStiffness, fluidData.fluidViscosity, fluidData.fluidKernelRadiusMultiplier, fluidData.fluidRestParticlesPerMeter, fluidData.fluidRestDensity, fluidData.fluidMotionLimit, fluidData.fluidPacketSizeMultiplier, fluidData.collisionGroup); fluid->fluid = fluidActor; fluid->lib = data; } data->fluidList.clear(); } }