mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 10:07:58 +02:00
allow hinge constraint between two entities
This commit is contained in:
parent
7695d2ac05
commit
afa8fc161b
8 changed files with 156 additions and 25 deletions
|
@ -42,6 +42,7 @@ public:
|
||||||
EntityDynamicType getType() const { return _type; }
|
EntityDynamicType getType() const { return _type; }
|
||||||
virtual bool isAction() const { return false; }
|
virtual bool isAction() const { return false; }
|
||||||
virtual bool isConstraint() const { return false; }
|
virtual bool isConstraint() const { return false; }
|
||||||
|
virtual bool isReadyForAdd() const { return true; }
|
||||||
|
|
||||||
bool isActive() { return _active; }
|
bool isActive() { return _active; }
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
#include "QVariantGLM.h"
|
#include "QVariantGLM.h"
|
||||||
|
|
||||||
|
#include "EntityTree.h"
|
||||||
#include "ObjectConstraintHinge.h"
|
#include "ObjectConstraintHinge.h"
|
||||||
|
|
||||||
#include "PhysicsLogging.h"
|
#include "PhysicsLogging.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ const uint16_t ObjectConstraintHinge::constraintVersion = 1;
|
||||||
ObjectConstraintHinge::ObjectConstraintHinge(const QUuid& id, EntityItemPointer ownerEntity) :
|
ObjectConstraintHinge::ObjectConstraintHinge(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||||
ObjectConstraint(DYNAMIC_TYPE_HINGE, id, ownerEntity),
|
ObjectConstraint(DYNAMIC_TYPE_HINGE, id, ownerEntity),
|
||||||
_pivotInA(glm::vec3(0.0f)),
|
_pivotInA(glm::vec3(0.0f)),
|
||||||
_axis(glm::vec3(0.0f))
|
_axisInA(glm::vec3(0.0f))
|
||||||
{
|
{
|
||||||
#if WANT_DEBUG
|
#if WANT_DEBUG
|
||||||
qCDebug(physics) << "ObjectConstraintHinge::ObjectConstraintHinge";
|
qCDebug(physics) << "ObjectConstraintHinge::ObjectConstraintHinge";
|
||||||
|
@ -36,8 +36,23 @@ ObjectConstraintHinge::~ObjectConstraintHinge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
btTypedConstraint* ObjectConstraintHinge::getConstraint() {
|
btTypedConstraint* ObjectConstraintHinge::getConstraint() {
|
||||||
if (_constraint) {
|
btHingeConstraint* constraint { nullptr };
|
||||||
return _constraint;
|
QUuid otherEntityID;
|
||||||
|
glm::vec3 pivotInA;
|
||||||
|
glm::vec3 axisInA;
|
||||||
|
glm::vec3 pivotInB;
|
||||||
|
glm::vec3 axisInB;
|
||||||
|
|
||||||
|
withReadLock([&]{
|
||||||
|
constraint = static_cast<btHingeConstraint*>(_constraint);
|
||||||
|
pivotInA = _pivotInA;
|
||||||
|
axisInA = _axisInA;
|
||||||
|
otherEntityID = _otherEntityID;
|
||||||
|
pivotInB = _pivotInB;
|
||||||
|
axisInB = _axisInB;
|
||||||
|
});
|
||||||
|
if (constraint) {
|
||||||
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
btRigidBody* rigidBodyA = getRigidBody();
|
btRigidBody* rigidBodyA = getRigidBody();
|
||||||
|
@ -48,22 +63,67 @@ btTypedConstraint* ObjectConstraintHinge::getConstraint() {
|
||||||
|
|
||||||
bool useReferenceFrameA { false };
|
bool useReferenceFrameA { false };
|
||||||
|
|
||||||
btTransform rigidBodyAFrame(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f), glmToBullet(_pivotInA));
|
if (!otherEntityID.isNull()) {
|
||||||
|
// This hinge is between two entities... find the other rigid body.
|
||||||
|
EntityItemPointer otherEntity = getEntityByID(otherEntityID);
|
||||||
|
if (!otherEntity) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
btHingeConstraint* constraint = new btHingeConstraint(*rigidBodyA, rigidBodyAFrame, useReferenceFrameA);
|
void* otherPhysicsInfo = otherEntity->getPhysicsInfo();
|
||||||
// constraint->setAngularOnly(true);
|
if (!otherPhysicsInfo) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ObjectMotionState* otherMotionState = static_cast<ObjectMotionState*>(otherPhysicsInfo);
|
||||||
|
if (!otherMotionState) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
btRigidBody* rigidBodyB = otherMotionState->getRigidBody();
|
||||||
|
if (!rigidBodyB) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
btVector3 axisInA = glmToBullet(_axis);
|
btTransform rigidBodyAFrame(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f), glmToBullet(pivotInA));
|
||||||
constraint->setAxis(axisInA);
|
btTransform rigidBodyBFrame(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f), glmToBullet(pivotInB));
|
||||||
|
|
||||||
_constraint = constraint;
|
constraint = new btHingeConstraint(*rigidBodyA, *rigidBodyB,
|
||||||
return constraint;
|
rigidBodyAFrame, rigidBodyBFrame,
|
||||||
|
useReferenceFrameA);
|
||||||
|
|
||||||
|
btVector3 bulletAxisInA = glmToBullet(axisInA);
|
||||||
|
constraint->setAxis(bulletAxisInA);
|
||||||
|
|
||||||
|
withWriteLock([&]{
|
||||||
|
_otherEntity = otherEntity; // save weak-pointer to the other entity
|
||||||
|
_constraint = constraint;
|
||||||
|
});
|
||||||
|
|
||||||
|
return constraint;
|
||||||
|
} else {
|
||||||
|
// This hinge is between an entity and the world-frame.
|
||||||
|
btTransform rigidBodyAFrame(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f), glmToBullet(pivotInA));
|
||||||
|
|
||||||
|
constraint = new btHingeConstraint(*rigidBodyA, rigidBodyAFrame, useReferenceFrameA);
|
||||||
|
// constraint->setAngularOnly(true);
|
||||||
|
|
||||||
|
btVector3 bulletAxisInA = glmToBullet(axisInA);
|
||||||
|
constraint->setAxis(bulletAxisInA);
|
||||||
|
|
||||||
|
withWriteLock([&]{
|
||||||
|
_otherEntity.reset();
|
||||||
|
_constraint = constraint;
|
||||||
|
});
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) {
|
bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) {
|
||||||
glm::vec3 pivotInA;
|
glm::vec3 pivotInA;
|
||||||
glm::vec3 axis;
|
glm::vec3 axisInA;
|
||||||
|
QUuid otherEntityID;
|
||||||
|
glm::vec3 pivotInB;
|
||||||
|
glm::vec3 axisInB;
|
||||||
|
|
||||||
bool needUpdate = false;
|
bool needUpdate = false;
|
||||||
bool somethingChanged = ObjectDynamic::updateArguments(arguments);
|
bool somethingChanged = ObjectDynamic::updateArguments(arguments);
|
||||||
|
@ -75,14 +135,35 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = true;
|
ok = true;
|
||||||
axis = EntityDynamicInterface::extractVec3Argument("hinge constraint", arguments, "axis", ok, false);
|
axisInA = EntityDynamicInterface::extractVec3Argument("hinge constraint", arguments, "axis", ok, false);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
axis = _axis;
|
axisInA = _axisInA;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
otherEntityID = QUuid(EntityDynamicInterface::extractStringArgument("hinge constraint",
|
||||||
|
arguments, "otherEntityID", ok, false));
|
||||||
|
if (!ok) {
|
||||||
|
otherEntityID = QUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
pivotInB = EntityDynamicInterface::extractVec3Argument("hinge constraint", arguments, "otherPivot", ok, false);
|
||||||
|
if (!ok) {
|
||||||
|
pivotInB = _pivotInB;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
axisInB = EntityDynamicInterface::extractVec3Argument("hinge constraint", arguments, "otherAxis", ok, false);
|
||||||
|
if (!ok) {
|
||||||
|
axisInB = _axisInB;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (somethingChanged ||
|
if (somethingChanged ||
|
||||||
pivotInA != _pivotInA ||
|
pivotInA != _pivotInA ||
|
||||||
axis != _axis) {
|
axisInA != _axisInA ||
|
||||||
|
pivotInB != _pivotInB ||
|
||||||
|
axisInB != _axisInB) {
|
||||||
// something changed
|
// something changed
|
||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +172,11 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) {
|
||||||
if (needUpdate) {
|
if (needUpdate) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_pivotInA = pivotInA;
|
_pivotInA = pivotInA;
|
||||||
_axis = axis;
|
_axisInA = axisInA;
|
||||||
|
_otherEntityID = otherEntityID;
|
||||||
|
_pivotInB = pivotInB;
|
||||||
|
_axisInB = axisInB;
|
||||||
|
|
||||||
_active = true;
|
_active = true;
|
||||||
|
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
|
@ -110,7 +195,10 @@ QVariantMap ObjectConstraintHinge::getArguments() {
|
||||||
QVariantMap arguments = ObjectDynamic::getArguments();
|
QVariantMap arguments = ObjectDynamic::getArguments();
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
arguments["pivot"] = glmToQMap(_pivotInA);
|
arguments["pivot"] = glmToQMap(_pivotInA);
|
||||||
arguments["axis"] = glmToQMap(_axis);
|
arguments["axis"] = glmToQMap(_axisInA);
|
||||||
|
arguments["otherEntityID"] = _otherEntityID;
|
||||||
|
arguments["otherPivot"] = glmToQMap(_pivotInB);
|
||||||
|
arguments["otherAxis"] = glmToQMap(_axisInB);
|
||||||
});
|
});
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +213,10 @@ QByteArray ObjectConstraintHinge::serialize() const {
|
||||||
|
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
dataStream << _pivotInA;
|
dataStream << _pivotInA;
|
||||||
dataStream << _axis;
|
dataStream << _axisInA;
|
||||||
|
dataStream << _otherEntityID;
|
||||||
|
dataStream << _pivotInB;
|
||||||
|
dataStream << _axisInB;
|
||||||
dataStream << localTimeToServerTime(_expires);
|
dataStream << localTimeToServerTime(_expires);
|
||||||
dataStream << _tag;
|
dataStream << _tag;
|
||||||
});
|
});
|
||||||
|
@ -153,7 +244,10 @@ void ObjectConstraintHinge::deserialize(QByteArray serializedArguments) {
|
||||||
|
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
dataStream >> _pivotInA;
|
dataStream >> _pivotInA;
|
||||||
dataStream >> _axis;
|
dataStream >> _axisInA;
|
||||||
|
dataStream >> _otherEntityID;
|
||||||
|
dataStream >> _pivotInB;
|
||||||
|
dataStream >> _axisInB;
|
||||||
|
|
||||||
quint64 serverExpires;
|
quint64 serverExpires;
|
||||||
dataStream >> serverExpires;
|
dataStream >> serverExpires;
|
||||||
|
|
|
@ -33,7 +33,12 @@ protected:
|
||||||
static const uint16_t constraintVersion;
|
static const uint16_t constraintVersion;
|
||||||
|
|
||||||
glm::vec3 _pivotInA;
|
glm::vec3 _pivotInA;
|
||||||
glm::vec3 _axis;
|
glm::vec3 _axisInA;
|
||||||
|
|
||||||
|
QUuid _otherEntityID;
|
||||||
|
EntityItemWeakPointer _otherEntity;
|
||||||
|
glm::vec3 _pivotInB;
|
||||||
|
glm::vec3 _axisInB;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ObjectConstraintHinge_h
|
#endif // hifi_ObjectConstraintHinge_h
|
||||||
|
|
|
@ -106,6 +106,20 @@ void ObjectDynamic::removeFromSimulation(EntitySimulationPointer simulation) con
|
||||||
simulation->removeDynamic(myID);
|
simulation->removeDynamic(myID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityItemPointer ObjectDynamic::getEntityByID(EntityItemID entityID) const {
|
||||||
|
EntityItemPointer ownerEntity;
|
||||||
|
withReadLock([&]{
|
||||||
|
ownerEntity = _ownerEntity.lock();
|
||||||
|
});
|
||||||
|
EntityTreeElementPointer element = ownerEntity ? ownerEntity->getElement() : nullptr;
|
||||||
|
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
||||||
|
if (!tree) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return tree->findEntityByID(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
btRigidBody* ObjectDynamic::getRigidBody() {
|
btRigidBody* ObjectDynamic::getRigidBody() {
|
||||||
ObjectMotionState* motionState = nullptr;
|
ObjectMotionState* motionState = nullptr;
|
||||||
withReadLock([&]{
|
withReadLock([&]{
|
||||||
|
|
|
@ -47,6 +47,7 @@ protected:
|
||||||
quint64 localTimeToServerTime(quint64 timeValue) const;
|
quint64 localTimeToServerTime(quint64 timeValue) const;
|
||||||
quint64 serverTimeToLocalTime(quint64 timeValue) const;
|
quint64 serverTimeToLocalTime(quint64 timeValue) const;
|
||||||
|
|
||||||
|
EntityItemPointer getEntityByID(EntityItemID entityID) const;
|
||||||
virtual btRigidBody* getRigidBody();
|
virtual btRigidBody* getRigidBody();
|
||||||
virtual glm::vec3 getPosition() override;
|
virtual glm::vec3 getPosition() override;
|
||||||
virtual void setPosition(glm::vec3 position) override;
|
virtual void setPosition(glm::vec3 position) override;
|
||||||
|
|
|
@ -346,6 +346,7 @@ void PhysicalEntitySimulation::addDynamic(EntityDynamicPointer dynamic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicalEntitySimulation::applyDynamicChanges() {
|
void PhysicalEntitySimulation::applyDynamicChanges() {
|
||||||
|
QList<EntityDynamicPointer> dynamicsFailedToAdd;
|
||||||
if (_physicsEngine) {
|
if (_physicsEngine) {
|
||||||
// FIXME put fine grain locking into _physicsEngine
|
// FIXME put fine grain locking into _physicsEngine
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
|
@ -354,9 +355,16 @@ void PhysicalEntitySimulation::applyDynamicChanges() {
|
||||||
}
|
}
|
||||||
foreach (EntityDynamicPointer dynamicToAdd, _dynamicsToAdd) {
|
foreach (EntityDynamicPointer dynamicToAdd, _dynamicsToAdd) {
|
||||||
if (!_dynamicsToRemove.contains(dynamicToAdd->getID())) {
|
if (!_dynamicsToRemove.contains(dynamicToAdd->getID())) {
|
||||||
_physicsEngine->addDynamic(dynamicToAdd);
|
if (!_physicsEngine->addDynamic(dynamicToAdd)) {
|
||||||
|
dynamicsFailedToAdd += dynamicToAdd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// applyDynamicChanges will clear _dynamicsToRemove and _dynamicsToAdd
|
||||||
EntitySimulation::applyDynamicChanges();
|
EntitySimulation::applyDynamicChanges();
|
||||||
|
// put back the ones that couldn't yet be added
|
||||||
|
foreach (EntityDynamicPointer dynamicFailedToAdd, dynamicsFailedToAdd) {
|
||||||
|
addDynamic(dynamicFailedToAdd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,12 +555,17 @@ EntityDynamicPointer PhysicsEngine::getDynamicByID(const QUuid& dynamicID) const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::addDynamic(EntityDynamicPointer dynamic) {
|
bool PhysicsEngine::addDynamic(EntityDynamicPointer dynamic) {
|
||||||
assert(dynamic);
|
assert(dynamic);
|
||||||
|
|
||||||
|
if (!dynamic->isReadyForAdd()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const QUuid& dynamicID = dynamic->getID();
|
const QUuid& dynamicID = dynamic->getID();
|
||||||
if (_objectDynamics.contains(dynamicID)) {
|
if (_objectDynamics.contains(dynamicID)) {
|
||||||
if (_objectDynamics[dynamicID] == dynamic) {
|
if (_objectDynamics[dynamicID] == dynamic) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
removeDynamic(dynamic->getID());
|
removeDynamic(dynamic->getID());
|
||||||
}
|
}
|
||||||
|
@ -572,13 +577,16 @@ void PhysicsEngine::addDynamic(EntityDynamicPointer dynamic) {
|
||||||
if (dynamic->isAction()) {
|
if (dynamic->isAction()) {
|
||||||
ObjectAction* objectAction = static_cast<ObjectAction*>(dynamic.get());
|
ObjectAction* objectAction = static_cast<ObjectAction*>(dynamic.get());
|
||||||
_dynamicsWorld->addAction(objectAction);
|
_dynamicsWorld->addAction(objectAction);
|
||||||
|
return true;
|
||||||
} else if (dynamic->isConstraint()) {
|
} else if (dynamic->isConstraint()) {
|
||||||
ObjectConstraint* objectConstraint = static_cast<ObjectConstraint*>(dynamic.get());
|
ObjectConstraint* objectConstraint = static_cast<ObjectConstraint*>(dynamic.get());
|
||||||
btTypedConstraint* constraint = objectConstraint->getConstraint();
|
btTypedConstraint* constraint = objectConstraint->getConstraint();
|
||||||
if (constraint) {
|
if (constraint) {
|
||||||
_dynamicsWorld->addConstraint(constraint);
|
_dynamicsWorld->addConstraint(constraint);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "PhysicsEngine::addDynamic of constraint failed"; // XXX
|
// perhaps not all the rigid bodies are available, yet
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public:
|
||||||
void dumpNextStats() { _dumpNextStats = true; }
|
void dumpNextStats() { _dumpNextStats = true; }
|
||||||
|
|
||||||
EntityDynamicPointer getDynamicByID(const QUuid& dynamicID) const;
|
EntityDynamicPointer getDynamicByID(const QUuid& dynamicID) const;
|
||||||
void addDynamic(EntityDynamicPointer dynamic);
|
bool addDynamic(EntityDynamicPointer dynamic);
|
||||||
void removeDynamic(const QUuid dynamicID);
|
void removeDynamic(const QUuid dynamicID);
|
||||||
void forEachDynamic(std::function<void(EntityDynamicPointer)> actor);
|
void forEachDynamic(std::function<void(EntityDynamicPointer)> actor);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue