// SPDX-FileCopyrightText: 2021 Jorrit Rouwe // SPDX-License-Identifier: MIT #include #include #include #include #include #include #include #include #include JPH_IMPLEMENT_RTTI_VIRTUAL(SensorTest) { JPH_ADD_BASE_CLASS(SensorTest, Test) } SensorTest::~SensorTest() { // Destroy the ragdoll mRagdoll->RemoveFromPhysicsSystem(); mRagdoll = nullptr; } void SensorTest::Initialize() { // Floor CreateFloor(); // Sensor BodyCreationSettings sensor_settings(new SphereShape(10.0f), Vec3(0, 10, 0), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING); sensor_settings.mIsSensor = true; Body &sensor = *mBodyInterface->CreateBody(sensor_settings); JPH_IF_DEBUG(sensor.SetDebugName("Sensor");) mSensorID = sensor.GetID(); mBodyInterface->AddBody(mSensorID, EActivation::DontActivate); // Dynamic bodies for (int i = 0; i < 10; ++i) { Body &body = *mBodyInterface->CreateBody(BodyCreationSettings(new BoxShape(Vec3(0.1f, 0.5f, 0.2f)), Vec3(-15.0f + i * 3.0f, 25, 0), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING)); JPH_IF_DEBUG(body.SetDebugName("Body " + ConvertToString(i))); mBodyInterface->AddBody(body.GetID(), EActivation::Activate); } // Load ragdoll Ref ragdoll_settings = RagdollLoader::sLoad("Assets/Human.tof", EMotionType::Dynamic); if (ragdoll_settings == nullptr) FatalError("Could not load ragdoll"); // Load animation Ref animation; if (!ObjectStreamIn::sReadObject("Assets/Human/Dead_Pose1.tof", animation)) FatalError("Could not open animation"); // Create pose SkeletonPose ragdoll_pose; ragdoll_pose.SetSkeleton(ragdoll_settings->GetSkeleton()); animation->Sample(0.0f, ragdoll_pose); SkeletonPose::JointState &root = ragdoll_pose.GetJoint(0); root.mTranslation = Vec3(0, 30, 0); ragdoll_pose.CalculateJointMatrices(); // Create ragdoll mRagdoll = ragdoll_settings->CreateRagdoll(1, nullptr, mPhysicsSystem); mRagdoll->SetPose(ragdoll_pose); mRagdoll->AddToPhysicsSystem(EActivation::Activate); } void SensorTest::PrePhysicsUpdate(const PreUpdateParams &inParams) { lock_guard lock(mMutex); Vec3 center(0, 10, 0); float centrifugal_force = 10.0f; Vec3 gravity = mPhysicsSystem->GetGravity(); for (const BodyAndCount &body_and_count : mBodiesInSensor) { BodyLockWrite body_lock(mPhysicsSystem->GetBodyLockInterface(), body_and_count.mBodyID); if (body_lock.Succeeded()) { Body &body = body_lock.GetBody(); // Calculate centrifugal acceleration Vec3 acceleration = center - body.GetPosition(); float length = acceleration.Length(); if (length > 0.0f) acceleration *= centrifugal_force / length; else acceleration = Vec3::sZero(); // Draw acceleration mDebugRenderer->DrawArrow(body.GetPosition(), body.GetPosition() + acceleration, Color::sGreen, 0.1f); // Cancel gravity acceleration -= gravity; // Apply as force body.AddForce(acceleration / body.GetMotionProperties()->GetInverseMass()); } } } void SensorTest::OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) { // Check which body is the sensor BodyID body_id; if (inBody1.GetID() == mSensorID) body_id = inBody2.GetID(); else if (inBody2.GetID() == mSensorID) body_id = inBody1.GetID(); else return; // Add to list and make sure that the list remains sorted for determinism (contacts can be added from multiple threads) lock_guard lock(mMutex); BodyAndCount body_and_count { body_id, 1 }; BodiesInSensor::iterator b = lower_bound(mBodiesInSensor.begin(), mBodiesInSensor.end(), body_and_count); if (b != mBodiesInSensor.end() && b->mBodyID == body_id) { // This is the right body, increment reference b->mCount++; return; } mBodiesInSensor.insert(b, body_and_count); } void SensorTest::OnContactRemoved(const SubShapeIDPair &inSubShapePair) { // Check which body is the sensor BodyID body_id; if (inSubShapePair.GetBody1ID() == mSensorID) body_id = inSubShapePair.GetBody2ID(); else if (inSubShapePair.GetBody2ID() == mSensorID) body_id = inSubShapePair.GetBody1ID(); else return; // Remove from list lock_guard lock(mMutex); BodyAndCount body_and_count { body_id, 1 }; BodiesInSensor::iterator b = lower_bound(mBodiesInSensor.begin(), mBodiesInSensor.end(), body_and_count); if (b != mBodiesInSensor.end() && b->mBodyID == body_id) { // This is the right body, increment reference JPH_ASSERT(b->mCount > 0); b->mCount--; // When last reference remove from the list if (b->mCount == 0) mBodiesInSensor.erase(b); return; } JPH_ASSERT(false, "Body pair not found"); } void SensorTest::SaveState(StateRecorder &inStream) const { inStream.Write(mBodiesInSensor); } void SensorTest::RestoreState(StateRecorder &inStream) { inStream.Read(mBodiesInSensor); }