refactor(physics): refactored part code into PhysRigidBody

This commit is contained in:
maelstrom 2025-08-19 21:22:19 +02:00
parent 4c0f24066c
commit 577ad312b8
9 changed files with 86 additions and 87 deletions

View file

@ -27,15 +27,14 @@ BasePart::BasePart(const InstanceType* type, PartConstructParams params): PVInst
BasePart::~BasePart() {
// This relies on physicsCommon still existing. Be very careful.
if (this->rigidBody && workspace() != nullptr) {
if (workspace() != nullptr) {
workspace()->RemoveBody(shared<BasePart>());
}
}
void BasePart::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) {
if (this->rigidBody)
this->rigidBody->setIsActive(workspace() != nullptr);
this->rigidBody.setActive(workspace() != nullptr);
if (workspace() != nullptr)
workspace()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));

View file

@ -1,6 +1,5 @@
#pragma once
#include <list>
#include <memory>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
@ -10,16 +9,10 @@
#include "datatypes/vector.h"
#include "objects/base/instance.h"
#include "enum/surface.h"
#include <mutex>
#include <optional>
#include <reactphysics3d/body/RigidBody.h>
#include <reactphysics3d/engine/PhysicsCommon.h>
#include <reactphysics3d/reactphysics3d.h>
#include <vector>
#include "objects/annotation.h"
#include "objects/pvinstance.h"
namespace rp = reactphysics3d;
#include "physics/world.h"
// For easy construction from C++. Maybe should be removed?
struct PartConstructParams {
@ -59,8 +52,6 @@ protected:
void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) override;
void onUpdated(std::string);
virtual void updateCollider(rp::PhysicsCommon* common) = 0;
BasePart(const InstanceType*);
BasePart(const InstanceType*, PartConstructParams params);
public:
@ -110,7 +101,7 @@ public:
DEF_SIGNAL SignalSource Touched;
DEF_SIGNAL SignalSource TouchEnded;
rp::RigidBody* rigidBody = nullptr;
PhysRigidBody rigidBody;
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
float GetSurfaceParamA(Vector3 face);

View file

@ -4,39 +4,11 @@
#include <glm/common.hpp>
Part::Part(): BasePart(&TYPE) {
_lastShape = shape;
_lastSize = size;
}
Part::Part(PartConstructParams params): BasePart(&TYPE, params) {
_lastShape = shape;
_lastSize = size;
}
void Part::updateCollider(rp::PhysicsCommon* common) {
rp::CollisionShape* physShape;
if (shape == PartType::Ball) {
physShape = common->createSphereShape(glm::min(size.X(), size.Y(), size.Z()) * 0.5f);
} else if (shape == PartType::Block) {
physShape = common->createBoxShape(glmToRp(size * glm::vec3(0.5f)));
}
// Recreate the rigidbody if the shape changes
if (rigidBody->getNbColliders() > 0 && (_lastShape != shape || _lastSize != size)) {
// TODO: This causes Touched to get called twice. Fix this.
rigidBody->removeCollider(rigidBody->getCollider(0));
rigidBody->addCollider(physShape, rp::Transform());
}
if (rigidBody->getNbColliders() == 0)
rigidBody->addCollider(physShape, rp::Transform());
_lastShape = shape;
_lastSize = size;
Part::Part(PartConstructParams params): BasePart(&TYPE, params) {
}
Vector3 Part::GetEffectiveSize() {
return shape == PartType::Ball ? (Vector3)glm::vec3(glm::min(size.X(), size.Y(), size.Z())) : size;
}

View file

@ -6,11 +6,7 @@
class DEF_INST Part : public BasePart {
AUTOGEN_PREAMBLE
PartType _lastShape;
Vector3 _lastSize;
protected:
void updateCollider(rp::PhysicsCommon* common) override;
public:
Part();

View file

@ -12,21 +12,21 @@ WedgePart::WedgePart(PartConstructParams params): BasePart(&TYPE, params) {
}
void WedgePart::updateCollider(rp::PhysicsCommon* common) {
Logger::fatalError("Wedges are currently disabled! Please do not use them or your editor may crash\n");
rp::ConvexMeshShape* shape = common->createConvexMeshShape(wedgePhysMesh, glmToRp(size * glm::vec3(0.5f)));
// void WedgePart::updateCollider(rp::PhysicsCommon* common) {
// Logger::fatalError("Wedges are currently disabled! Please do not use them or your editor may crash\n");
// rp::ConvexMeshShape* shape = common->createConvexMeshShape(wedgePhysMesh, glmToRp(size * glm::vec3(0.5f)));
// Recreate the rigidbody if the shape changes
if (rigidBody->getNbColliders() > 0
&& dynamic_cast<rp::ConvexMeshShape*>(rigidBody->getCollider(0)->getCollisionShape())->getScale() != shape->getScale()) {
// TODO: This causes Touched to get called twice. Fix this.
rigidBody->removeCollider(rigidBody->getCollider(0));
rigidBody->addCollider(shape, rp::Transform());
}
// // Recreate the rigidbody if the shape changes
// if (rigidBody->getNbColliders() > 0
// && dynamic_cast<rp::ConvexMeshShape*>(rigidBody->getCollider(0)->getCollisionShape())->getScale() != shape->getScale()) {
// // TODO: This causes Touched to get called twice. Fix this.
// rigidBody->removeCollider(rigidBody->getCollider(0));
// rigidBody->addCollider(shape, rp::Transform());
// }
if (rigidBody->getNbColliders() == 0)
rigidBody->addCollider(shape, rp::Transform());
}
// if (rigidBody->getNbColliders() == 0)
// rigidBody->addCollider(shape, rp::Transform());
// }
void WedgePart::createWedgeShape(rp::PhysicsCommon* common) {
// https://www.reactphysics3d.com/documentation/index.html#creatingbody

View file

@ -7,7 +7,6 @@ class DEF_INST_(hidden) WedgePart : public BasePart {
AUTOGEN_PREAMBLE
protected:
void updateCollider(rp::PhysicsCommon* common) override;
static void createWedgeShape(rp::PhysicsCommon* common);
friend Workspace;

View file

@ -61,7 +61,7 @@ PartAssembly PartAssembly::FromSelection(std::shared_ptr<Selection> selection) {
void PartAssembly::SetCollisionsEnabled(bool enabled) {
for (auto part : parts) {
part->rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled);
part->rigidBody.setCollisionsEnabled(enabled);
}
}

View file

@ -5,7 +5,7 @@
#include "objects/part/basepart.h"
#include "physics/util.h"
#include <reactphysics3d/constraint/FixedJoint.h>
#include "reactphysics3d/constraint/HingeJoint.h"
#include <reactphysics3d/constraint/HingeJoint.h>
#include "timeutil.h"
#include <memory>
#include "objects/service/workspace.h"
@ -78,12 +78,12 @@ void PhysWorld::step(float deltaTime) {
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
for (std::shared_ptr<BasePart> part : simulatedBodies) {
if (!part->rigidBody) continue;
if (!part->rigidBody.rigidBody) continue;
// Sync properties
const rp::Transform& transform = part->rigidBody->getTransform();
const rp::Transform& transform = part->rigidBody.rigidBody->getTransform();
part->cframe = CFrame(transform);
part->velocity = part->rigidBody->getLinearVelocity();
part->velocity = part->rigidBody.rigidBody->getLinearVelocity();
// part->rigidBody->enableGravity(true);
// RotateV/Motor joint
@ -93,7 +93,7 @@ void PhysWorld::step(float deltaTime) {
std::shared_ptr<JointInstance> motor = joint.lock()->CastTo<JointInstance>().expect();
float rate = motor->part0.lock()->GetSurfaceParamB(-motor->c0.LookVector().Unit()) * 30;
// part->rigidBody->enableGravity(false);
part->rigidBody->setAngularVelocity(-(motor->part0.lock()->cframe * motor->c0).LookVector() * rate);
part->rigidBody.rigidBody->setAngularVelocity(-(motor->part0.lock()->cframe * motor->c0).LookVector() * rate);
}
}
@ -111,32 +111,32 @@ void PhysWorld::removeBody(std::shared_ptr<BasePart> part) {
void PhysWorld::syncBodyProperties(std::shared_ptr<BasePart> part) {
rp::Transform transform = part->cframe;
if (!part->rigidBody) {
part->rigidBody = worldImpl->createRigidBody(transform);
if (!part->rigidBody.rigidBody) {
part->rigidBody.rigidBody = worldImpl->createRigidBody(transform);
} else {
part->rigidBody->setTransform(transform);
part->rigidBody.rigidBody->setTransform(transform);
}
part->updateCollider(&physicsCommon);
part->rigidBody.updateCollider(part);
part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC);
part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11);
part->rigidBody.rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC);
part->rigidBody.rigidBody->getCollider(0)->setCollisionCategoryBits(0b11);
part->rigidBody->getCollider(0)->setIsSimulationCollider(part->canCollide);
part->rigidBody->getCollider(0)->setIsTrigger(!part->canCollide);
part->rigidBody.rigidBody->getCollider(0)->setIsSimulationCollider(part->canCollide);
part->rigidBody.rigidBody->getCollider(0)->setIsTrigger(!part->canCollide);
rp::Material& material = part->rigidBody->getCollider(0)->getMaterial();
rp::Material& material = part->rigidBody.rigidBody->getCollider(0)->getMaterial();
material.setFrictionCoefficient(0.35);
material.setMassDensity(1.f);
//https://github.com/DanielChappuis/reactphysics3d/issues/170#issuecomment-691514860
part->rigidBody->updateMassFromColliders();
part->rigidBody->updateLocalInertiaTensorFromColliders();
part->rigidBody.rigidBody->updateMassFromColliders();
part->rigidBody.rigidBody->updateLocalInertiaTensorFromColliders();
part->rigidBody->setLinearVelocity(part->velocity);
part->rigidBody.rigidBody->setLinearVelocity(part->velocity);
// part->rigidBody->setMass(density * part->size.x * part->size.y * part->size.z);
part->rigidBody->setUserData(&*part);
part->rigidBody.rigidBody->setUserData(&*part);
}
// Ray-casting
@ -199,8 +199,8 @@ std::optional<const RaycastResult> PhysWorld::castRay(Vector3 point, Vector3 rot
PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) {
// error checking
if (part0->rigidBody == nullptr
|| part1->rigidBody == nullptr
if (part0->rigidBody.rigidBody == nullptr
|| part1->rigidBody.rigidBody == nullptr
|| !part0->workspace()
|| !part1->workspace()
|| part0->workspace()->physicsWorld != shared_from_this()
@ -208,15 +208,15 @@ PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart>
) { Logger::fatalError("Failed to create joint between two parts due to the call being invalid"); panic(); };
if (PhysJointGlueInfo* info = dynamic_cast<PhysJointGlueInfo*>(&type)) {
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint));
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint));
} else if (PhysJointWeldInfo* info = dynamic_cast<PhysJointWeldInfo*>(&type)) {
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint));
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint));
} else if (PhysJointSnapInfo* info = dynamic_cast<PhysJointSnapInfo*>(&type)) {
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint));
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint));
} else if (PhysJointHingeInfo* info = dynamic_cast<PhysJointHingeInfo*>(&type)) {
return worldImpl->createJoint(rp::HingeJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint, info->rotationAxis));
return worldImpl->createJoint(rp::HingeJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint, info->rotationAxis));
} else if (PhysJointMotorInfo* info = dynamic_cast<PhysJointMotorInfo*>(&type)) {
auto implInfo = rp::HingeJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint, info->rotationAxis);
auto implInfo = rp::HingeJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint, info->rotationAxis);
implInfo.isCollisionEnabled = false;
return worldImpl->createJoint(implInfo);
@ -230,5 +230,30 @@ PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart>
}
void PhysWorld::destroyJoint(PhysJoint joint) {
worldImpl->destroyJoint(joint.joint);
}
void PhysRigidBody::updateCollider(std::shared_ptr<BasePart> bPart) {
if (std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(bPart)) {
rp::CollisionShape* physShape;
if (part->shape == PartType::Ball) {
physShape = physicsCommon.createSphereShape(glm::min(part->size.X(), part->size.Y(), part->size.Z()) * 0.5f);
} else if (part->shape == PartType::Block) {
physShape = physicsCommon.createBoxShape(glmToRp(part->size * glm::vec3(0.5f)));
}
// Recreate the rigidbody if the shape changes
if (rigidBody->getNbColliders() > 0 && (_lastShape != part->shape || _lastSize != part->size)) {
// TODO: This causes Touched to get called twice. Fix this.
rigidBody->removeCollider(rigidBody->getCollider(0));
rigidBody->addCollider(physShape, rp::Transform());
}
if (rigidBody->getNbColliders() == 0)
rigidBody->addCollider(physShape, rp::Transform());
_lastShape = part->shape;
_lastSize = part->size;
}
}

View file

@ -1,6 +1,8 @@
#pragma once
#include "datatypes/vector.h"
#include "enum/part.h"
#include "reactphysics3d/body/RigidBody.h"
#include <functional>
#include <list>
#include <memory>
@ -55,6 +57,21 @@ public:
inline PhysJoint() {}
};
class PhysRigidBody {
rp::RigidBody* rigidBody = nullptr;
inline PhysRigidBody(rp::RigidBody* rigidBody) : rigidBody(rigidBody) {}
Vector3 _lastSize;
PartType _lastShape;
friend PhysWorld;
public:
inline PhysRigidBody() {}
inline void setActive(bool active) { if (!rigidBody) return; rigidBody->setIsActive(active); }
inline void setCollisionsEnabled(bool enabled) { if (!rigidBody) return; rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled); }
void updateCollider(std::shared_ptr<BasePart>);
};
class PhysWorld : public std::enable_shared_from_this<PhysWorld> {
rp::PhysicsWorld* worldImpl;
PhysicsEventListener physicsEventListener;