fix(physics): motor joint updates with paramB

This commit is contained in:
maelstrom 2025-09-02 00:06:36 +02:00
parent 3a6fb2ada2
commit 78d2466efd
8 changed files with 84 additions and 28 deletions

View file

@ -17,6 +17,9 @@ void JointInstance::OnAncestryChanged(nullable std::shared_ptr<Instance>, nullab
Update(); Update();
} }
void JointInstance::OnPartParamsUpdated() {
}
void JointInstance::Update() { void JointInstance::Update() {
// To keep it simple compared to our previous algorithm, this one is pretty barebones: // To keep it simple compared to our previous algorithm, this one is pretty barebones:
// 1. Every time we update, (whether our parent changed, or a property), destroy the current joints // 1. Every time we update, (whether our parent changed, or a property), destroy the current joints

View file

@ -3,7 +3,6 @@
#include "objects/base/instance.h" #include "objects/base/instance.h"
#include "../annotation.h" #include "../annotation.h"
#include <memory> #include <memory>
#include <optional>
#include "datatypes/cframe.h" #include "datatypes/cframe.h"
#include "physics/world.h" #include "physics/world.h"
@ -12,6 +11,8 @@
#include "objects/part/part.h" #include "objects/part/part.h"
#endif #endif
#define DEF_PROP_PHYS DEF_PROP_(on_update=onUpdated)
class BasePart; class BasePart;
class Workspace; class Workspace;
@ -33,12 +34,15 @@ protected:
virtual void buildJoint() = 0; virtual void buildJoint() = 0;
public: public:
void Update(); void Update();
virtual void OnPartParamsUpdated();
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part0; DEF_PROP_PHYS std::weak_ptr<BasePart> part0;
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part1; DEF_PROP_PHYS std::weak_ptr<BasePart> part1;
DEF_PROP_(on_update=onUpdated) CFrame c0; DEF_PROP_PHYS CFrame c0;
DEF_PROP_(on_update=onUpdated) CFrame c1; DEF_PROP_PHYS CFrame c1;
JointInstance(const InstanceType*); JointInstance(const InstanceType*);
~JointInstance(); ~JointInstance();
}; };
#undef DEF_PROP_PHYS

View file

@ -21,8 +21,14 @@ void RotateV::buildJoint() {
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse()); CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
part1.lock()->cframe = newFrame; part1.lock()->cframe = newFrame;
// Do NOT use Abs() in this scenario. For some reason that breaks it // Do NOT use Abs() in this scenario. For some reason that breaks it
PhysRotatingJointInfo jointInfo(c0, c1, true); float vel = part0.lock()->GetSurfaceParamB(-c0.LookVector().Unit()) * 6.28;
PhysRotatingJointInfo jointInfo(c0, c1, vel);
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock()); this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
jointWorkspace = workspace; jointWorkspace = workspace;
}
void RotateV::OnPartParamsUpdated() {
float vel = part0.lock()->GetSurfaceParamB(-c0.LookVector().Unit()) * 6.28;
this->joint.setAngularVelocity(vel);
} }

View file

@ -13,6 +13,8 @@ public:
RotateV(); RotateV();
~RotateV(); ~RotateV();
void OnPartParamsUpdated() override;
static inline std::shared_ptr<RotateV> New() { return std::make_shared<RotateV>(); }; static inline std::shared_ptr<RotateV> New() { return std::make_shared<RotateV>(); };
static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); }; static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); };
}; };

View file

@ -70,6 +70,15 @@ void BasePart::onUpdated(std::string property) {
BreakJoints(); BreakJoints();
} }
void BasePart::onParamUpdated(std::string property) {
// Send signal to joints to update themselves
for (std::weak_ptr<JointInstance> joint : primaryJoints) {
if (joint.expired()) continue;
joint.lock()->OnPartParamsUpdated();
}
}
// Expands provided extents to fit point // Expands provided extents to fit point
static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) { static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) {
*min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z())); *min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z()));

View file

@ -14,6 +14,10 @@
#include "objects/pvinstance.h" #include "objects/pvinstance.h"
#include "physics/world.h" #include "physics/world.h"
// Common macro for part properties
#define DEF_PROP_PHYS DEF_PROP_(on_update=onUpdated)
#define DEF_PROP_PHYSPARAM DEF_PROP_(on_update=onParamUpdated)
// For easy construction from C++. Maybe should be removed? // For easy construction from C++. Maybe should be removed?
struct PartConstructParams { struct PartConstructParams {
Vector3 position; Vector3 position;
@ -51,19 +55,20 @@ protected:
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override; virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override;
void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) override; void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) override;
void onUpdated(std::string); void onUpdated(std::string);
void onParamUpdated(std::string);
BasePart(const InstanceType*); BasePart(const InstanceType*);
BasePart(const InstanceType*, PartConstructParams params); BasePart(const InstanceType*, PartConstructParams params);
public: public:
DEF_PROP_CATEGORY(DATA) DEF_PROP_CATEGORY(DATA)
DEF_PROP_(on_update=onUpdated) Vector3 velocity; DEF_PROP_PHYS Vector3 velocity;
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]] [[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
CFrame cframe; CFrame cframe;
DEF_PROP_CATEGORY(PART) DEF_PROP_CATEGORY(PART)
// Special compatibility changes for this property were made in // Special compatibility changes for this property were made in
// Instance::Serialize // Instance::Serialize
DEF_PROP_(on_update=onUpdated) Vector3 size; DEF_PROP_PHYS Vector3 size;
DEF_PROP_CATEGORY(APPEARANCE) DEF_PROP_CATEGORY(APPEARANCE)
DEF_PROP Color3 color; DEF_PROP Color3 color;
@ -71,8 +76,8 @@ public:
DEF_PROP float reflectance = 0.f; DEF_PROP float reflectance = 0.f;
DEF_PROP_CATEGORY(BEHAVIOR) DEF_PROP_CATEGORY(BEHAVIOR)
DEF_PROP_(on_update=onUpdated) bool anchored = false; DEF_PROP_PHYS bool anchored = false;
DEF_PROP_(on_update=onUpdated) bool canCollide = true; DEF_PROP_PHYS bool canCollide = true;
DEF_PROP bool locked = false; DEF_PROP bool locked = false;
DEF_PROP_CATEGORY(SURFACE) DEF_PROP_CATEGORY(SURFACE)
@ -84,19 +89,19 @@ public:
DEF_PROP SurfaceType backSurface = SurfaceType::Smooth; DEF_PROP SurfaceType backSurface = SurfaceType::Smooth;
DEF_PROP_CATEGORY(SURFACE_INPUT) DEF_PROP_CATEGORY(SURFACE_INPUT)
DEF_PROP float topParamA = -0.5; DEF_PROP_PHYSPARAM float topParamA = -0.5;
DEF_PROP float bottomParamA = -0.5; DEF_PROP_PHYSPARAM float bottomParamA = -0.5;
DEF_PROP float leftParamA = -0.5; DEF_PROP_PHYSPARAM float leftParamA = -0.5;
DEF_PROP float rightParamA = -0.5; DEF_PROP_PHYSPARAM float rightParamA = -0.5;
DEF_PROP float frontParamA = -0.5; DEF_PROP_PHYSPARAM float frontParamA = -0.5;
DEF_PROP float backParamA = -0.5; DEF_PROP_PHYSPARAM float backParamA = -0.5;
DEF_PROP float topParamB = 0.5; DEF_PROP_PHYSPARAM float topParamB = 0.5;
DEF_PROP float bottomParamB = 0.5; DEF_PROP_PHYSPARAM float bottomParamB = 0.5;
DEF_PROP float leftParamB = 0.5; DEF_PROP_PHYSPARAM float leftParamB = 0.5;
DEF_PROP float rightParamB = 0.5; DEF_PROP_PHYSPARAM float rightParamB = 0.5;
DEF_PROP float frontParamB = 0.5; DEF_PROP_PHYSPARAM float frontParamB = 0.5;
DEF_PROP float backParamB = 0.5; DEF_PROP_PHYSPARAM float backParamB = 0.5;
DEF_SIGNAL SignalSource Touched; DEF_SIGNAL SignalSource Touched;
DEF_SIGNAL SignalSource TouchEnded; DEF_SIGNAL SignalSource TouchEnded;
@ -117,4 +122,7 @@ public:
// Calculate size of axis-aligned bounding box // Calculate size of axis-aligned bounding box
Vector3 GetAABB(); Vector3 GetAABB();
}; };
#undef DEF_PROP_PHYS
#undef DEF_PROP_PHYSPARAM

View file

@ -229,9 +229,8 @@ PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart>
// settings.mMotorSettings = JPH::MotorSettings(1.0f, 1.0f); // settings.mMotorSettings = JPH::MotorSettings(1.0f, 1.0f);
constraint = settings.Create(*part0->rigidBody.bodyImpl, *part1->rigidBody.bodyImpl); constraint = settings.Create(*part0->rigidBody.bodyImpl, *part1->rigidBody.bodyImpl);
if (info->motorized) { if (info->motorized) {
float vel = part0->GetSurfaceParamB(-info->c0.LookVector().Unit()) * 6.28;
static_cast<JPH::HingeConstraint*>(constraint)->SetMotorState(JPH::EMotorState::Velocity); static_cast<JPH::HingeConstraint*>(constraint)->SetMotorState(JPH::EMotorState::Velocity);
static_cast<JPH::HingeConstraint*>(constraint)->SetTargetAngularVelocity(-vel); static_cast<JPH::HingeConstraint*>(constraint)->SetTargetAngularVelocity(-info->initialVelocity);
} }
} else { } else {
panic(); panic();
@ -241,6 +240,14 @@ PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart>
return { constraint }; return { constraint };
} }
// WATCH OUT! This should only be called for HingeConstraints.
// Can't use dynamic_cast because TwoBodyConstraint is not virtual
void PhysJoint::setAngularVelocity(float velocity) {
JPH::HingeConstraint* constraint = static_cast<JPH::HingeConstraint*>(jointImpl);
if (!constraint) return;
constraint->SetTargetAngularVelocity(-velocity);
}
void PhysWorld::destroyJoint(PhysJoint joint) { void PhysWorld::destroyJoint(PhysJoint joint) {
worldImpl.RemoveConstraint(joint.jointImpl); worldImpl.RemoveConstraint(joint.jointImpl);
} }

View file

@ -17,13 +17,30 @@ class BasePart;
class PhysWorld; class PhysWorld;
struct PhysJointInfo { virtual ~PhysJointInfo() = default; protected: PhysJointInfo() = default; }; struct PhysJointInfo { virtual ~PhysJointInfo() = default; protected: PhysJointInfo() = default; };
struct PhysFixedJointInfo : PhysJointInfo { CFrame c0; CFrame c1; inline PhysFixedJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1) {} };
struct PhysRotatingJointInfo : PhysJointInfo { CFrame c0; CFrame c1; bool motorized; inline PhysRotatingJointInfo(CFrame c0, CFrame c1, bool motorized = false) : c0(c0), c1(c1), motorized(motorized) {} }; struct PhysFixedJointInfo : PhysJointInfo {
CFrame c0;
CFrame c1;
inline PhysFixedJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1) {}
};
struct PhysRotatingJointInfo : PhysJointInfo {
CFrame c0;
CFrame c1;
bool motorized;
float initialVelocity;
inline PhysRotatingJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1), motorized(false), initialVelocity(0.f){}
inline PhysRotatingJointInfo(CFrame c0, CFrame c1, float initialVelocity) : c0(c0), c1(c1), motorized(true), initialVelocity(initialVelocity) {}
};
class PhysWorld; class PhysWorld;
struct PhysJoint { struct PhysJoint {
public: public:
JPH::TwoBodyConstraint* jointImpl; JPH::TwoBodyConstraint* jointImpl;
void setAngularVelocity(float velocity);
}; };
struct RaycastResult; struct RaycastResult;