refactor(physics): refactored joint code
This commit is contained in:
parent
7352b53a94
commit
4c0f24066c
19 changed files with 123 additions and 153 deletions
|
@ -24,8 +24,8 @@ std::array<HandleFace, 6> HandleFace::Faces { HandleFace::XPos, HandleFace::XNeg
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
// Shitty solution
|
// Shitty solution
|
||||||
static rp3d::PhysicsCommon common;
|
static rp::PhysicsCommon common;
|
||||||
static rp3d::PhysicsWorld* world = common.createPhysicsWorld();
|
static rp::PhysicsWorld* world = common.createPhysicsWorld();
|
||||||
|
|
||||||
std::shared_ptr<BasePart> getHandleAdornee() {
|
std::shared_ptr<BasePart> getHandleAdornee() {
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
|
@ -52,15 +52,15 @@ CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos) {
|
||||||
return adornee->cframe.Rotation() + newPartPos;
|
return adornee->cframe.Rotation() + newPartPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<HandleFace> raycastHandle(rp3d::Ray ray) {
|
std::optional<HandleFace> raycastHandle(rp::Ray ray) {
|
||||||
for (HandleFace face : HandleFace::Faces) {
|
for (HandleFace face : HandleFace::Faces) {
|
||||||
CFrame cframe = getHandleCFrame(face);
|
CFrame cframe = getHandleCFrame(face);
|
||||||
// Implement manual detection via boxes instead of... this shit
|
// Implement manual detection via boxes instead of... this shit
|
||||||
// This code also hardly works, and is not good at all... Hooo nope.
|
// This code also hardly works, and is not good at all... Hooo nope.
|
||||||
rp3d::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position());
|
rp::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position());
|
||||||
body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp3d::Transform::identity());
|
body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp::Transform::identity());
|
||||||
|
|
||||||
rp3d::RaycastInfo info;
|
rp::RaycastInfo info;
|
||||||
if (body->raycast(ray, info)) {
|
if (body->raycast(ray, info)) {
|
||||||
world->destroyRigidBody(body);
|
world->destroyRigidBody(body);
|
||||||
return face;
|
return face;
|
||||||
|
|
|
@ -40,7 +40,7 @@ std::shared_ptr<BasePart> getHandleAdornee();
|
||||||
CFrame getHandleCFrame(HandleFace face);
|
CFrame getHandleCFrame(HandleFace face);
|
||||||
CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos);
|
CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos);
|
||||||
Vector3 handleSize(HandleFace face);
|
Vector3 handleSize(HandleFace face);
|
||||||
std::optional<HandleFace> raycastHandle(rp3d::Ray ray);
|
std::optional<HandleFace> raycastHandle(rp::Ray ray);
|
||||||
|
|
||||||
// Gets the cframe of the handle local to the center of the selected objects
|
// Gets the cframe of the handle local to the center of the selected objects
|
||||||
CFrame getLocalHandleCFrame(HandleFace face);
|
CFrame getLocalHandleCFrame(HandleFace face);
|
||||||
|
|
|
@ -18,40 +18,40 @@ JointInstance::~JointInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointInstance::OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) {
|
void JointInstance::OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) {
|
||||||
// Destroy and rebuild the joint, it's the simplest solution that actually works
|
Update();
|
||||||
|
|
||||||
breakJoint();
|
|
||||||
buildJoint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointInstance::onUpdated(std::string property) {
|
void JointInstance::Update() {
|
||||||
// Add ourselves to the attached parts, or remove, if applicable
|
// 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
|
||||||
|
// 2. If the new configuration is valid, rebuild our joints
|
||||||
|
|
||||||
// Parts differ, delete
|
if (!jointWorkspace.expired()) {
|
||||||
if (part0 != oldPart0 && !oldPart0.expired()) {
|
jointWorkspace.lock()->DestroyJoint(joint);
|
||||||
oldPart0.lock()->untrackJoint(shared<JointInstance>());
|
if (!oldPart0.expired())
|
||||||
|
oldPart0.lock()->untrackJoint(shared<JointInstance>());
|
||||||
|
if (!oldPart1.expired())
|
||||||
|
oldPart1.lock()->untrackJoint(shared<JointInstance>());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part1 != oldPart1 && !oldPart1.expired()) {
|
|
||||||
oldPart1.lock()->untrackJoint(shared<JointInstance>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parts differ, add
|
|
||||||
if (part0 != oldPart0 && !part0.expired()) {
|
|
||||||
part0.lock()->trackJoint(shared<JointInstance>());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part1 != oldPart1 && !part1.expired()) {
|
|
||||||
part1.lock()->trackJoint(shared<JointInstance>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy and rebuild the joint, if applicable
|
|
||||||
|
|
||||||
breakJoint();
|
|
||||||
buildJoint();
|
|
||||||
|
|
||||||
oldPart0 = part0;
|
oldPart0 = part0;
|
||||||
oldPart1 = part1;
|
oldPart1 = part1;
|
||||||
|
|
||||||
|
// Don't build the joint if we're not part of either a workspace or JointsService
|
||||||
|
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
||||||
|
|
||||||
|
// If either part is invalid or they are part of separate worlds, fail
|
||||||
|
if (part0.expired()
|
||||||
|
|| part1.expired()
|
||||||
|
|| !workspaceOfPart(part0.lock())
|
||||||
|
|| !workspaceOfPart(part1.lock())
|
||||||
|
|| workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())
|
||||||
|
) return;
|
||||||
|
|
||||||
|
// TODO: Add joint continuity check here
|
||||||
|
|
||||||
|
// Finally, build the joint
|
||||||
|
buildJoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> JointInstance::workspaceOfPart(std::shared_ptr<BasePart> part) {
|
nullable std::shared_ptr<Workspace> JointInstance::workspaceOfPart(std::shared_ptr<BasePart> part) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
|
#include "physics/world.h"
|
||||||
|
|
||||||
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
||||||
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
||||||
|
@ -22,14 +23,16 @@ class DEF_INST_ABSTRACT JointInstance : public Instance {
|
||||||
protected:
|
protected:
|
||||||
// The workspace the joint was created in, if it exists
|
// The workspace the joint was created in, if it exists
|
||||||
std::weak_ptr<Workspace> jointWorkspace;
|
std::weak_ptr<Workspace> jointWorkspace;
|
||||||
|
PhysJoint joint;
|
||||||
|
|
||||||
void OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) override;
|
void OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) override;
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> workspaceOfPart(std::shared_ptr<BasePart>);
|
nullable std::shared_ptr<Workspace> workspaceOfPart(std::shared_ptr<BasePart>);
|
||||||
void onUpdated(std::string property);
|
inline void onUpdated(std::string property) { Update(); };
|
||||||
|
|
||||||
virtual void buildJoint() = 0;
|
virtual void buildJoint() = 0;
|
||||||
virtual void breakJoint() = 0;
|
|
||||||
public:
|
public:
|
||||||
|
void Update();
|
||||||
|
|
||||||
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part0;
|
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part0;
|
||||||
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part1;
|
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part1;
|
||||||
|
|
|
@ -13,35 +13,16 @@ Rotate::~Rotate() {
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
void Rotate::buildJoint() {
|
void Rotate::buildJoint() {
|
||||||
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
|
||||||
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
|
||||||
|
|
||||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
|
||||||
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && workspace() != nullptr) return;
|
|
||||||
|
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
workspace->SyncPartPhysics(part1.lock());
|
part1.lock()->UpdateProperty("CFrame");
|
||||||
|
|
||||||
// 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
|
||||||
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
PhysJointHingeInfo jointInfo((part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||||
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->CreateJoint(jointInfo));
|
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
|
|
||||||
// part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10);
|
|
||||||
// part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
|
||||||
// part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01);
|
|
||||||
// part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01);
|
|
||||||
}
|
|
||||||
|
|
||||||
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
|
||||||
void Rotate::breakJoint() {
|
|
||||||
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
|
||||||
if (!this->joint || jointWorkspace.expired()) return;
|
|
||||||
|
|
||||||
jointWorkspace.lock()->DestroyJoint(this->joint);
|
|
||||||
this->joint = nullptr;
|
|
||||||
}
|
}
|
|
@ -10,10 +10,7 @@ namespace reactphysics3d { class HingeJoint; }
|
||||||
class DEF_INST Rotate : public JointInstance {
|
class DEF_INST Rotate : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
reactphysics3d::HingeJoint* joint = nullptr;
|
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
virtual void breakJoint() override;
|
|
||||||
public:
|
public:
|
||||||
Rotate();
|
Rotate();
|
||||||
~Rotate();
|
~Rotate();
|
||||||
|
|
|
@ -15,39 +15,16 @@ RotateV::~RotateV() {
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
void RotateV::buildJoint() {
|
void RotateV::buildJoint() {
|
||||||
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
|
||||||
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
|
||||||
|
|
||||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
|
||||||
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && workspace() != nullptr) return;
|
|
||||||
|
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
||||||
|
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
workspace->SyncPartPhysics(part1.lock());
|
part1.lock()->UpdateProperty("CFrame");
|
||||||
// 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
|
||||||
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
PhysJointMotorInfo jointInfo((part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||||
|
|
||||||
jointInfo.isCollisionEnabled = false;
|
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
||||||
|
|
||||||
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->CreateJoint(jointInfo));
|
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
|
|
||||||
|
|
||||||
// part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10);
|
|
||||||
// part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
|
||||||
// part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01);
|
|
||||||
// part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotateV::breakJoint() {
|
|
||||||
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
|
||||||
if (!this->joint || jointWorkspace.expired()) return;
|
|
||||||
|
|
||||||
jointWorkspace.lock()->DestroyJoint(this->joint);
|
|
||||||
this->joint = nullptr;
|
|
||||||
}
|
}
|
|
@ -9,10 +9,7 @@ namespace reactphysics3d { class HingeJoint; }
|
||||||
class DEF_INST RotateV : public JointInstance {
|
class DEF_INST RotateV : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
reactphysics3d::HingeJoint* joint = nullptr;
|
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
virtual void breakJoint() override;
|
|
||||||
public:
|
public:
|
||||||
RotateV();
|
RotateV();
|
||||||
~RotateV();
|
~RotateV();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
|
#include "physics/world.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <reactphysics3d/constraint/FixedJoint.h>
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
#include <reactphysics3d/engine/PhysicsWorld.h>
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
@ -17,30 +18,15 @@ Snap::~Snap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Snap::buildJoint() {
|
void Snap::buildJoint() {
|
||||||
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
|
||||||
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
|
||||||
|
|
||||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
|
||||||
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
|
||||||
|
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
workspace->SyncPartPhysics(part1.lock());
|
part1.lock()->UpdateProperty("CFrame");
|
||||||
|
|
||||||
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
PhysJointSnapInfo jointInfo((c0.Inverse() * c1).Position());
|
||||||
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->CreateJoint(jointInfo));
|
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
|
||||||
void Snap::breakJoint() {
|
|
||||||
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
|
||||||
if (!this->joint || jointWorkspace.expired()) return;
|
|
||||||
|
|
||||||
jointWorkspace.lock()->DestroyJoint(this->joint);
|
|
||||||
this->joint = nullptr;
|
|
||||||
}
|
|
|
@ -10,10 +10,7 @@ namespace reactphysics3d { class FixedJoint; }
|
||||||
class DEF_INST Snap : public JointInstance {
|
class DEF_INST Snap : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
reactphysics3d::FixedJoint* joint = nullptr;
|
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
virtual void breakJoint() override;
|
|
||||||
public:
|
public:
|
||||||
Snap();
|
Snap();
|
||||||
~Snap();
|
~Snap();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
|
#include "physics/world.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <reactphysics3d/constraint/FixedJoint.h>
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
#include <reactphysics3d/engine/PhysicsWorld.h>
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
@ -17,30 +18,15 @@ Weld::~Weld() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weld::buildJoint() {
|
void Weld::buildJoint() {
|
||||||
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
|
||||||
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
|
||||||
|
|
||||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
|
||||||
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && workspace() != nullptr) return;
|
|
||||||
|
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
workspace->SyncPartPhysics(part1.lock());
|
part1.lock()->UpdateProperty("CFrame");
|
||||||
|
|
||||||
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
PhysJointWeldInfo jointInfo((c0.Inverse() * c1).Position());
|
||||||
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->CreateJoint(jointInfo));
|
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
|
||||||
void Weld::breakJoint() {
|
|
||||||
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
|
||||||
if (!this->joint || jointWorkspace.expired()) return;
|
|
||||||
|
|
||||||
jointWorkspace.lock()->DestroyJoint(this->joint);
|
|
||||||
this->joint = nullptr;
|
|
||||||
}
|
|
|
@ -10,10 +10,7 @@ namespace reactphysics3d { class FixedJoint; }
|
||||||
class DEF_INST Weld : public JointInstance {
|
class DEF_INST Weld : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
reactphysics3d::FixedJoint* joint = nullptr;
|
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
virtual void breakJoint() override;
|
|
||||||
public:
|
public:
|
||||||
Weld();
|
Weld();
|
||||||
~Weld();
|
~Weld();
|
||||||
|
|
|
@ -51,6 +51,7 @@ void BasePart::OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
||||||
|
BreakJoints();
|
||||||
oldWorkspace->RemoveBody(shared<BasePart>());
|
oldWorkspace->RemoveBody(shared<BasePart>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,8 +283,6 @@ void BasePart::MakeJoints() {
|
||||||
joint->c1 = contact1;
|
joint->c1 = contact1;
|
||||||
dataModel()->GetService<JointsService>()->AddChild(joint);
|
dataModel()->GetService<JointsService>()->AddChild(joint);
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
|
|
||||||
Logger::debugf("Made joint between %s and %s!\n", name.c_str(), otherPart->name.c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,6 @@ void WedgePart::createWedgeShape(rp::PhysicsCommon* common) {
|
||||||
rp::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
|
rp::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
|
||||||
|
|
||||||
// Create the convex mesh
|
// Create the convex mesh
|
||||||
std::vector<rp3d::Message> messages;
|
std::vector<rp::Message> messages;
|
||||||
// wedgePhysMesh = common->createConvexMesh(polygonVertexArray, messages);
|
// wedgePhysMesh = common->createConvexMesh(polygonVertexArray, messages);
|
||||||
}
|
}
|
|
@ -68,14 +68,3 @@ void Workspace::PhysicsStep(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::DestroyJoint(rp::Joint* joint) {
|
|
||||||
// physicsWorld->destroyJoint(joint);
|
|
||||||
}
|
|
||||||
|
|
||||||
rp::Joint* Workspace::CreateJoint(const rp::JointInfo& jointInfo) {
|
|
||||||
// rp::Joint* joint = physicsWorld->createJoint(jointInfo);
|
|
||||||
|
|
||||||
// return joint;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
|
@ -32,6 +32,7 @@ class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
||||||
std::mutex contactQueueLock;
|
std::mutex contactQueueLock;
|
||||||
|
|
||||||
std::shared_ptr<PhysWorld> physicsWorld;
|
std::shared_ptr<PhysWorld> physicsWorld;
|
||||||
|
friend PhysWorld;
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
void OnRun() override;
|
void OnRun() override;
|
||||||
|
@ -52,8 +53,8 @@ public:
|
||||||
inline void RemoveBody(std::shared_ptr<BasePart> part) { physicsWorld->removeBody(part); }
|
inline void RemoveBody(std::shared_ptr<BasePart> part) { physicsWorld->removeBody(part); }
|
||||||
void SyncPartPhysics(std::shared_ptr<BasePart> part);
|
void SyncPartPhysics(std::shared_ptr<BasePart> part);
|
||||||
|
|
||||||
rp::Joint* CreateJoint(const rp::JointInfo& jointInfo);
|
inline PhysJoint CreateJoint(PhysJointInfo& info, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) { return physicsWorld->createJoint(info, part0, part1); }
|
||||||
void DestroyJoint(rp::Joint* joint);
|
inline void DestroyJoint(PhysJoint joint) { physicsWorld->destroyJoint(joint); }
|
||||||
|
|
||||||
void PhysicsStep(float deltaTime);
|
void PhysicsStep(float deltaTime);
|
||||||
inline std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); }
|
inline std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); }
|
||||||
|
|
|
@ -4,15 +4,19 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/part/basepart.h"
|
#include "objects/part/basepart.h"
|
||||||
#include "physics/util.h"
|
#include "physics/util.h"
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include "reactphysics3d/constraint/HingeJoint.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
#include <memory>
|
||||||
|
#include "objects/service/workspace.h"
|
||||||
|
|
||||||
rp3d::PhysicsCommon physicsCommon;
|
rp::PhysicsCommon physicsCommon;
|
||||||
|
|
||||||
PhysWorld::PhysWorld() : physicsEventListener(this) {
|
PhysWorld::PhysWorld() : physicsEventListener(this) {
|
||||||
worldImpl = physicsCommon.createPhysicsWorld();
|
worldImpl = physicsCommon.createPhysicsWorld();
|
||||||
|
|
||||||
worldImpl->setGravity(rp::Vector3(0, -196.2, 0));
|
worldImpl->setGravity(rp::Vector3(0, -196.2, 0));
|
||||||
// world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS);
|
// world->setContactsPositionCorrectionTechnique(rp::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS);
|
||||||
// physicsWorld->setNbIterationsPositionSolver(2000);
|
// physicsWorld->setNbIterationsPositionSolver(2000);
|
||||||
// physicsWorld->setNbIterationsVelocitySolver(2000);
|
// physicsWorld->setNbIterationsVelocitySolver(2000);
|
||||||
// physicsWorld->setSleepLinearVelocity(10);
|
// physicsWorld->setSleepLinearVelocity(10);
|
||||||
|
@ -192,3 +196,39 @@ std::optional<const RaycastResult> PhysWorld::castRay(Vector3 point, Vector3 rot
|
||||||
worldImpl->raycast(ray, &rayHit, categoryMaskBits);
|
worldImpl->raycast(ray, &rayHit, categoryMaskBits);
|
||||||
return rayHit.getNearestHit();
|
return rayHit.getNearestHit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) {
|
||||||
|
// error checking
|
||||||
|
if (part0->rigidBody == nullptr
|
||||||
|
|| part1->rigidBody == nullptr
|
||||||
|
|| !part0->workspace()
|
||||||
|
|| !part1->workspace()
|
||||||
|
|| part0->workspace()->physicsWorld != shared_from_this()
|
||||||
|
|| part1->workspace()->physicsWorld != shared_from_this()
|
||||||
|
) { 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));
|
||||||
|
} else if (PhysJointWeldInfo* info = dynamic_cast<PhysJointWeldInfo*>(&type)) {
|
||||||
|
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint));
|
||||||
|
} else if (PhysJointSnapInfo* info = dynamic_cast<PhysJointSnapInfo*>(&type)) {
|
||||||
|
return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint));
|
||||||
|
} else if (PhysJointHingeInfo* info = dynamic_cast<PhysJointHingeInfo*>(&type)) {
|
||||||
|
return worldImpl->createJoint(rp::HingeJointInfo(part0->rigidBody, part1->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);
|
||||||
|
implInfo.isCollisionEnabled = false;
|
||||||
|
return worldImpl->createJoint(implInfo);
|
||||||
|
|
||||||
|
// part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10);
|
||||||
|
// part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
||||||
|
// part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01);
|
||||||
|
// part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01);
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(); // Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysWorld::destroyJoint(PhysJoint joint) {
|
||||||
|
|
||||||
|
}
|
|
@ -39,7 +39,23 @@ class PhysicsEventListener : public rp::EventListener {
|
||||||
void onTrigger(const rp::OverlapCallback::CallbackData&) override;
|
void onTrigger(const rp::OverlapCallback::CallbackData&) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhysWorld : std::enable_shared_from_this<PhysWorld> {
|
struct PhysJointInfo { virtual ~PhysJointInfo() = default; protected: PhysJointInfo() = default; };
|
||||||
|
struct PhysJointGlueInfo : PhysJointInfo { Vector3 anchorPoint; inline PhysJointGlueInfo(Vector3 anchorPoint) : anchorPoint(anchorPoint) {} };
|
||||||
|
struct PhysJointWeldInfo : PhysJointInfo { Vector3 anchorPoint; inline PhysJointWeldInfo(Vector3 anchorPoint) : anchorPoint(anchorPoint) {} };
|
||||||
|
struct PhysJointSnapInfo : PhysJointInfo { Vector3 anchorPoint; inline PhysJointSnapInfo(Vector3 anchorPoint) : anchorPoint(anchorPoint) {} };
|
||||||
|
struct PhysJointHingeInfo : PhysJointInfo { Vector3 anchorPoint; Vector3 rotationAxis; inline PhysJointHingeInfo(Vector3 anchorPoint, Vector3 rotationAxis) : anchorPoint(anchorPoint), rotationAxis(rotationAxis) {} };
|
||||||
|
struct PhysJointMotorInfo : PhysJointInfo { Vector3 anchorPoint; Vector3 rotationAxis; inline PhysJointMotorInfo(Vector3 anchorPoint, Vector3 rotationAxis) : anchorPoint(anchorPoint), rotationAxis(rotationAxis) {} };
|
||||||
|
|
||||||
|
class PhysWorld;
|
||||||
|
class PhysJoint {
|
||||||
|
rp::Joint* joint;
|
||||||
|
inline PhysJoint(rp::Joint* joint) : joint(joint) {}
|
||||||
|
friend PhysWorld;
|
||||||
|
public:
|
||||||
|
inline PhysJoint() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PhysWorld : public std::enable_shared_from_this<PhysWorld> {
|
||||||
rp::PhysicsWorld* worldImpl;
|
rp::PhysicsWorld* worldImpl;
|
||||||
PhysicsEventListener physicsEventListener;
|
PhysicsEventListener physicsEventListener;
|
||||||
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
||||||
|
@ -52,6 +68,10 @@ public:
|
||||||
|
|
||||||
void addBody(std::shared_ptr<BasePart>);
|
void addBody(std::shared_ptr<BasePart>);
|
||||||
void removeBody(std::shared_ptr<BasePart>);
|
void removeBody(std::shared_ptr<BasePart>);
|
||||||
|
|
||||||
|
PhysJoint createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1);
|
||||||
|
void destroyJoint(PhysJoint joint);
|
||||||
|
|
||||||
inline const std::list<std::shared_ptr<BasePart>>& getSimulatedBodies() { return simulatedBodies; }
|
inline const std::list<std::shared_ptr<BasePart>>& getSimulatedBodies() { return simulatedBodies; }
|
||||||
void syncBodyProperties(std::shared_ptr<BasePart>);
|
void syncBodyProperties(std::shared_ptr<BasePart>);
|
||||||
std::optional<const RaycastResult> castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits);
|
std::optional<const RaycastResult> castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits);
|
||||||
|
|
|
@ -323,7 +323,7 @@ void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) {
|
||||||
|
|
||||||
std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
|
std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
|
||||||
if (!editorToolHandles.active) return std::nullopt;
|
if (!editorToolHandles.active) return std::nullopt;
|
||||||
return ::raycastHandle(rp3d::Ray(glmToRp(camera.cameraPos), glmToRp(glm::normalize(pointDir)) * 50000));
|
return ::raycastHandle(rp::Ray(glmToRp(camera.cameraPos), glmToRp(glm::normalize(pointDir)) * 50000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue