expose bullet slider constraint to javascript

This commit is contained in:
Seth Alves 2017-04-27 07:56:35 -07:00
parent fa25493a8a
commit b196dd082b
9 changed files with 489 additions and 11 deletions

View file

@ -17,6 +17,7 @@
#include <ObjectActionSpring.h>
#include <ObjectActionTravelOriented.h>
#include <ObjectConstraintHinge.h>
#include <ObjectConstraintSlider.h>
#include <LogHandler.h>
#include "InterfaceDynamicFactory.h"
@ -38,6 +39,8 @@ EntityDynamicPointer interfaceDynamicFactory(EntityDynamicType type, const QUuid
return std::make_shared<ObjectConstraintHinge>(id, ownerEntity);
case DYNAMIC_TYPE_FAR_GRAB:
return std::make_shared<AvatarActionFarGrab>(id, ownerEntity);
case DYNAMIC_TYPE_SLIDER:
return std::make_shared<ObjectConstraintSlider>(id, ownerEntity);
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity dynamic type");

View file

@ -117,6 +117,9 @@ EntityDynamicType EntityDynamicInterface::dynamicTypeFromString(QString dynamicT
if (normalizedDynamicTypeString == "fargrab") {
return DYNAMIC_TYPE_FAR_GRAB;
}
if (normalizedDynamicTypeString == "slider") {
return DYNAMIC_TYPE_SLIDER;
}
qCDebug(entities) << "Warning -- EntityDynamicInterface::dynamicTypeFromString got unknown dynamic-type name"
<< dynamicTypeString;
@ -139,6 +142,8 @@ QString EntityDynamicInterface::dynamicTypeToString(EntityDynamicType dynamicTyp
return "hinge";
case DYNAMIC_TYPE_FAR_GRAB:
return "far-grab";
case DYNAMIC_TYPE_SLIDER:
return "slider";
}
assert(false);
return "none";

View file

@ -31,7 +31,8 @@ enum EntityDynamicType {
DYNAMIC_TYPE_HOLD = 3000,
DYNAMIC_TYPE_TRAVEL_ORIENTED = 4000,
DYNAMIC_TYPE_HINGE = 5000,
DYNAMIC_TYPE_FAR_GRAB = 6000
DYNAMIC_TYPE_FAR_GRAB = 6000,
DYNAMIC_TYPE_SLIDER = 7000
};

View file

@ -49,7 +49,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return VERSION_ENTITIES_HINGE_CONSTRAINT;
return VERSION_ENTITIES_SLIDER_CONSTRAINT;
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
case PacketType::AvatarIdentity:

View file

@ -207,6 +207,7 @@ const PacketVersion VERSION_ENTITIES_SERVER_SCRIPTS = 66;
const PacketVersion VERSION_ENTITIES_PHYSICS_PACKET = 67;
const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68;
const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69;
const PacketVersion VERSION_ENTITIES_SLIDER_CONSTRAINT = 70;
enum class EntityQueryPacketVersion: PacketVersion {
JSONFilter = 18,

View file

@ -54,7 +54,7 @@ void ObjectConstraintHinge::prepareForPhysicsSimulation() {
// https://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7020
if (!isMine()) {
// XXX
// TODO
// don't activate motor for someone else's action?
// maybe don't if this interface isn't the sim owner?
return;
@ -77,11 +77,6 @@ void ObjectConstraintHinge::prepareForPhysicsSimulation() {
float t = (float)(now - _startMotorTime) / (float)USECS_PER_SECOND;
float motorTarget = _motorVelocity * t;
// // bring motorTarget into the range of [-PI, PI]
// motorTarget += PI;
// motorTarget = fmodf(motorTarget, 2.0f * PI);
// motorTarget -= PI;
if (!_motorEnabled) {
constraint->enableMotor(true);
_motorEnabled = true;
@ -90,7 +85,7 @@ void ObjectConstraintHinge::prepareForPhysicsSimulation() {
constraint->setMotorTarget(motorTarget, dt);
} else if (_motorTargetTimeScale > 0.0f) {
// XXX
// TODO -- we probably want a spring-like action here
} else if (_motorEnabled) {
constraint->enableMotor(false);
_motorEnabled = false;

View file

@ -44,8 +44,8 @@ protected:
glm::vec3 _pivotInB;
glm::vec3 _axisInB;
float _low { -2.0f * PI };
float _high { 2.0f * PI };
float _low { -TWO_PI };
float _high { TWO_PI };
// https://gamedev.stackexchange.com/questions/71436/what-are-the-parameters-for-bthingeconstraintsetlimit
//

View file

@ -0,0 +1,410 @@
//
// ObjectConstraintSlider.cpp
// libraries/physics/src
//
// Created by Seth Alves 2017-4-23
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "QVariantGLM.h"
#include "EntityTree.h"
#include "ObjectConstraintSlider.h"
#include "PhysicsLogging.h"
const uint16_t ObjectConstraintSlider::constraintVersion = 1;
ObjectConstraintSlider::ObjectConstraintSlider(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectConstraint(DYNAMIC_TYPE_SLIDER, id, ownerEntity),
_pointInA(glm::vec3(0.0f)),
_axisInA(glm::vec3(0.0f))
{
#if WANT_DEBUG
qCDebug(physics) << "ObjectConstraintSlider::ObjectConstraintSlider";
#endif
}
ObjectConstraintSlider::~ObjectConstraintSlider() {
#if WANT_DEBUG
qCDebug(physics) << "ObjectConstraintSlider::~ObjectConstraintSlider";
#endif
}
QList<btRigidBody*> ObjectConstraintSlider::getRigidBodies() {
QList<btRigidBody*> result;
result += getRigidBody();
QUuid otherEntityID;
withReadLock([&]{
otherEntityID = _otherEntityID;
});
if (!otherEntityID.isNull()) {
result += getOtherRigidBody(otherEntityID);
}
return result;
}
void ObjectConstraintSlider::prepareForPhysicsSimulation() {
}
void ObjectConstraintSlider::updateSlider() {
btSliderConstraint* constraint { nullptr };
withReadLock([&]{
// TODO -- write this
constraint = static_cast<btSliderConstraint*>(_constraint);
});
if (!constraint) {
return;
}
// constraint->setFrames (const btTransform &frameA, const btTransform &frameB);
constraint->setLowerLinLimit(_linearLow);
constraint->setUpperLinLimit(_linearHigh);
constraint->setLowerAngLimit(_angularLow);
constraint->setUpperAngLimit(_angularHigh);
}
btTypedConstraint* ObjectConstraintSlider::getConstraint() {
btSliderConstraint* constraint { nullptr };
QUuid otherEntityID;
glm::vec3 pointInA;
glm::vec3 axisInA;
glm::vec3 pointInB;
glm::vec3 axisInB;
withReadLock([&]{
constraint = static_cast<btSliderConstraint*>(_constraint);
pointInA = _pointInA;
axisInA = _axisInA;
otherEntityID = _otherEntityID;
pointInB = _pointInB;
axisInB = _axisInB;
});
if (constraint) {
return constraint;
}
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyA";
return nullptr;
}
if (!otherEntityID.isNull()) {
// This slider is between two entities... find the other rigid body.
glm::quat rotA = glm::rotation(glm::vec3(1.0f, 0.0f, 0.0f), glm::normalize(axisInA));
glm::quat rotB = glm::rotation(glm::vec3(1.0f, 0.0f, 0.0f), glm::normalize(axisInB));
btTransform frameInA(glmToBullet(rotA), glmToBullet(pointInA));
btTransform frameInB(glmToBullet(rotB), glmToBullet(pointInB));
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
if (!rigidBodyB) {
return nullptr;
}
constraint = new btSliderConstraint(*rigidBodyA, *rigidBodyB, frameInA, frameInB, true);
} else {
// This slider is between an entity and the world-frame.
glm::quat rot = glm::rotation(glm::vec3(1.0f, 0.0f, 0.0f), glm::normalize(axisInA));
btTransform frameInA(glmToBullet(rot), glmToBullet(pointInA));
constraint = new btSliderConstraint(*rigidBodyA, frameInA, true);
}
withWriteLock([&]{
_constraint = constraint;
});
// if we don't wake up rigidBodyA, we may not send the dynamicData property over the network
forceBodyNonStatic();
activateBody();
// updateSlider();
return constraint;
}
bool ObjectConstraintSlider::updateArguments(QVariantMap arguments) {
glm::vec3 pointInA;
glm::vec3 axisInA;
QUuid otherEntityID;
glm::vec3 pointInB;
glm::vec3 axisInB;
float linearLow;
float linearHigh;
float angularLow;
float angularHigh;
float linearTarget;
float linearTimeScale;
bool linearTargetSet;
float angularTarget;
float angularTimeScale;
bool angularTargetSet;
bool needUpdate = false;
bool somethingChanged = ObjectDynamic::updateArguments(arguments);
withReadLock([&]{
bool ok = true;
pointInA = EntityDynamicInterface::extractVec3Argument("slider constraint", arguments, "point", ok, false);
if (!ok) {
pointInA = _pointInA;
}
ok = true;
axisInA = EntityDynamicInterface::extractVec3Argument("slider constraint", arguments, "axis", ok, false);
if (!ok) {
axisInA = _axisInA;
}
ok = true;
otherEntityID = QUuid(EntityDynamicInterface::extractStringArgument("slider constraint",
arguments, "otherEntityID", ok, false));
if (!ok) {
otherEntityID = _otherEntityID;
}
ok = true;
pointInB = EntityDynamicInterface::extractVec3Argument("slider constraint", arguments, "otherPoint", ok, false);
if (!ok) {
pointInB = _pointInB;
}
ok = true;
axisInB = EntityDynamicInterface::extractVec3Argument("slider constraint", arguments, "otherAxis", ok, false);
if (!ok) {
axisInB = _axisInB;
}
ok = true;
linearLow = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments, "linearLow", ok, false);
if (!ok) {
linearLow = _linearLow;
}
ok = true;
linearHigh = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments, "linearHigh", ok, false);
if (!ok) {
linearHigh = _linearHigh;
}
ok = true;
angularLow = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments, "angularLow", ok, false);
if (!ok) {
angularLow = _angularLow;
}
ok = true;
angularHigh = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments, "angularHigh", ok, false);
if (!ok) {
angularHigh = _angularHigh;
}
ok = true;
linearTarget = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments,
"linearTarget", ok, false);
if (!ok) {
linearTarget = _linearTarget;
linearTargetSet = _linearTargetSet;
} else {
linearTargetSet = true;
}
ok = true;
linearTimeScale = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments,
"linearTimeScale", ok, false);
if (!ok) {
linearTimeScale = _linearTimeScale;
}
ok = true;
angularTarget = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments,
"angularTarget", ok, false);
if (!ok) {
angularTarget = _angularTarget;
angularTargetSet = _angularTargetSet;
} else {
angularTargetSet = true;
}
ok = true;
angularTimeScale = EntityDynamicInterface::extractFloatArgument("slider constraint", arguments,
"angularTimeScale", ok, false);
if (!ok) {
angularTimeScale = _angularTimeScale;
}
if (somethingChanged ||
pointInA != _pointInA ||
axisInA != _axisInA ||
otherEntityID != _otherEntityID ||
pointInB != _pointInB ||
axisInB != _axisInB ||
linearLow != _linearLow ||
linearHigh != _linearHigh ||
angularLow != _angularLow ||
angularHigh != _angularHigh ||
linearTarget != _linearTarget ||
linearTimeScale != _linearTimeScale ||
linearTargetSet != _linearTargetSet ||
angularTarget != _angularTarget ||
angularTimeScale != _angularTimeScale ||
angularTargetSet != _angularTargetSet) {
// something changed
needUpdate = true;
}
});
if (needUpdate) {
withWriteLock([&] {
_pointInA = pointInA;
_axisInA = axisInA;
_otherEntityID = otherEntityID;
_pointInB = pointInB;
_axisInB = axisInB;
_linearLow = linearLow;
_linearHigh = linearHigh;
_angularLow = angularLow;
_angularHigh = angularHigh;
_linearTarget = linearTarget;
_linearTimeScale = linearTimeScale;
_linearTargetSet = linearTargetSet;
_angularTarget = angularTarget;
_angularTimeScale = angularTimeScale;
_angularTargetSet = angularTargetSet;
_active = true;
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
updateSlider();
}
return true;
}
QVariantMap ObjectConstraintSlider::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] {
if (_constraint) {
arguments["point"] = glmToQMap(_pointInA);
arguments["axis"] = glmToQMap(_axisInA);
arguments["otherEntityID"] = _otherEntityID;
arguments["otherPoint"] = glmToQMap(_pointInB);
arguments["otherAxis"] = glmToQMap(_axisInB);
arguments["linearLow"] = _linearLow;
arguments["linearHigh"] = _linearHigh;
arguments["angularLow"] = _angularLow;
arguments["angularHigh"] = _angularHigh;
arguments["linearTarget"] = _linearTarget;
arguments["linearTimeScale"] = _linearTimeScale;
arguments["linearTargetSet"] = _linearTargetSet;
arguments["angularTarget"] = _angularTarget;
arguments["angularTimeScale"] = _angularTimeScale;
arguments["angularTargetSet"] = _angularTargetSet;
arguments["linearPosition"] = static_cast<btSliderConstraint*>(_constraint)->getLinearPos();
arguments["angularPosition"] = static_cast<btSliderConstraint*>(_constraint)->getAngularPos();
}
});
return arguments;
}
QByteArray ObjectConstraintSlider::serialize() const {
QByteArray serializedConstraintArguments;
QDataStream dataStream(&serializedConstraintArguments, QIODevice::WriteOnly);
dataStream << DYNAMIC_TYPE_SLIDER;
dataStream << getID();
dataStream << ObjectConstraintSlider::constraintVersion;
withReadLock([&] {
dataStream << localTimeToServerTime(_expires);
dataStream << _tag;
dataStream << _pointInA;
dataStream << _axisInA;
dataStream << _otherEntityID;
dataStream << _pointInB;
dataStream << _axisInB;
dataStream << _linearLow;
dataStream << _linearHigh;
dataStream << _angularLow;
dataStream << _angularHigh;
dataStream << _linearTarget;
dataStream << _linearTimeScale;
dataStream << _linearTargetSet;
dataStream << _angularTarget;
dataStream << _angularTimeScale;
dataStream << _angularTargetSet;
});
return serializedConstraintArguments;
}
void ObjectConstraintSlider::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityDynamicType type;
dataStream >> type;
assert(type == getType());
QUuid id;
dataStream >> id;
assert(id == getID());
uint16_t serializationVersion;
dataStream >> serializationVersion;
if (serializationVersion != ObjectConstraintSlider::constraintVersion) {
assert(false);
return;
}
withWriteLock([&] {
quint64 serverExpires;
dataStream >> serverExpires;
_expires = serverTimeToLocalTime(serverExpires);
dataStream >> _tag;
dataStream >> _pointInA;
dataStream >> _axisInA;
dataStream >> _otherEntityID;
dataStream >> _pointInB;
dataStream >> _axisInB;
dataStream >> _linearLow;
dataStream >> _linearHigh;
dataStream >> _angularLow;
dataStream >> _angularHigh;
dataStream >> _linearTarget;
dataStream >> _linearTimeScale;
dataStream >> _linearTargetSet;
dataStream >> _angularTarget;
dataStream >> _angularTimeScale;
dataStream >> _angularTargetSet;
_active = true;
});
}

View file

@ -0,0 +1,63 @@
//
// ObjectConstraintSlider.h
// libraries/physics/src
//
// Created by Seth Alves 2017-4-23
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ObjectConstraintSlider_h
#define hifi_ObjectConstraintSlider_h
#include "ObjectConstraint.h"
// http://bulletphysics.org/Bullet/BulletFull/classbtSliderConstraint.html
class ObjectConstraintSlider : public ObjectConstraint {
public:
ObjectConstraintSlider(const QUuid& id, EntityItemPointer ownerEntity);
virtual ~ObjectConstraintSlider();
virtual void prepareForPhysicsSimulation() override;
virtual bool updateArguments(QVariantMap arguments) override;
virtual QVariantMap getArguments() override;
virtual QByteArray serialize() const override;
virtual void deserialize(QByteArray serializedArguments) override;
virtual QList<btRigidBody*> getRigidBodies() override;
virtual btTypedConstraint* getConstraint() override;
protected:
static const uint16_t constraintVersion;
void updateSlider();
glm::vec3 _pointInA;
glm::vec3 _axisInA;
EntityItemID _otherEntityID;
glm::vec3 _pointInB;
glm::vec3 _axisInB;
float _linearLow { std::numeric_limits<float>::max() };
float _linearHigh { std::numeric_limits<float>::min() };
float _angularLow { -TWO_PI };
float _angularHigh { TWO_PI };
float _linearTarget { 0.0f };
float _linearTimeScale { 0.0f };
bool _linearTargetSet { false };
float _angularTarget { 0.0f };
float _angularTimeScale { 0.0f };
bool _angularTargetSet { false };
};
#endif // hifi_ObjectConstraintSlider_h