From 59950236d3cb777aed2e4a72e06928cc5b153b38 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 22 Apr 2017 16:22:00 -0700 Subject: [PATCH] attempt to make hinge motor work better --- .../physics/src/ObjectConstraintHinge.cpp | 118 ++++++++++++++++-- libraries/physics/src/ObjectConstraintHinge.h | 35 ++++++ 2 files changed, 144 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/ObjectConstraintHinge.cpp b/libraries/physics/src/ObjectConstraintHinge.cpp index 6c55d9c5dd..c3044c5431 100644 --- a/libraries/physics/src/ObjectConstraintHinge.cpp +++ b/libraries/physics/src/ObjectConstraintHinge.cpp @@ -48,6 +48,50 @@ QList ObjectConstraintHinge::getRigidBodies() { return result; } +void ObjectConstraintHinge::prepareForPhysicsSimulation() { + // setting the motor velocity doesn't appear to work for anyone. constantly adjusting the + // target angle seems to work. + // https://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7020 + uint64_t now = usecTimestampNow(); + withWriteLock([&]{ + btHingeConstraint* constraint = static_cast(_constraint); + if (!constraint) { + return; + } + if (_previousMotorTime == 0) { + _previousMotorTime = now; + return; + } + if (_motorVelocity != 0.0f) { + if (_startMotorTime == 0) { + _startMotorTime = now; + } + float dt = (float)(now - _previousMotorTime) / (float)USECS_PER_SECOND; + float t = (float)(now - _startMotorTime) / (float)USECS_PER_SECOND; + float motorTarget = _motorVelocity * t; + while (motorTarget > PI) { + motorTarget -= PI; + } + while (motorTarget < PI) { + motorTarget += PI; + } + if (!_motorEnabled) { + constraint->enableMotor(true); + _motorEnabled = true; + } + constraint->setMaxMotorImpulse(_maxImpulse); + constraint->setMotorTarget(motorTarget, dt); + } else if (_motorTargetTimeScale > 0.0f) { + // XXX + } else if (_motorEnabled) { + constraint->enableMotor(false); + _motorEnabled = false; + _startMotorTime = 0; + } + _previousMotorTime = now; + }); +} + void ObjectConstraintHinge::updateHinge() { btHingeConstraint* constraint { nullptr }; float low; @@ -56,28 +100,45 @@ void ObjectConstraintHinge::updateHinge() { float biasFactor; float relaxationFactor; float motorVelocity; + float motorTarget; + float motorTargetTimeScale; + float maxImpulse; withReadLock([&]{ constraint = static_cast(_constraint); low = _low; high = _high; - softness = _softness; + maxImpulse = _maxImpulse; biasFactor = _biasFactor; relaxationFactor = _relaxationFactor; + + // under the hood, motorTarget sets a veloctiy and must be called repeatedly to maintain + // a velocity. _motorTargetTimeScale of 0.0f means the target isn't set. motorVelocity is + // only considered when motorTarget isn't set. motorVelocity = _motorVelocity; + motorTarget = _motorTarget; + motorTargetTimeScale = _motorTargetTimeScale; + softness = _softness; }); if (!constraint) { return; } - constraint->setLimit(low, high, softness, biasFactor, relaxationFactor); - if (motorVelocity != 0.0f) { - constraint->setMotorTargetVelocity(motorVelocity); - constraint->enableMotor(true); - } else { - constraint->enableMotor(false); - } + // constraint->setLimit(low, high, softness, biasFactor, relaxationFactor); + // if (motorTargetTimeScale > 0.0f) { + // qDebug() << "--- setting motor target:" << motorTarget << motorTargetTimeScale; + // constraint->setMotorTarget(motorTarget, motorTargetTimeScale); + // constraint->enableMotor(true); + // withWriteLock([&]{ + // _motorTargetTimeScale = 0.0f; // it's a one-shot. + // }); + // } else if (motorVelocity != 0.0f) { + // // constraint->setMotorTargetVelocity(motorVelocity); + // // constraint->enableMotor(true); + // } else { + // constraint->enableMotor(false); + // } } @@ -151,6 +212,9 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) { float biasFactor; float relaxationFactor; float motorVelocity; + float motorTarget; + float motorTargetTimeScale; + float maxImpulse; bool needUpdate = false; bool somethingChanged = ObjectDynamic::updateArguments(arguments); @@ -224,6 +288,27 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) { motorVelocity = _motorVelocity; } + ok = true; + motorTarget = EntityDynamicInterface::extractFloatArgument("hinge constraint", arguments, + "motorTarget", ok, false); + if (!ok) { + motorTarget = _motorTarget; + } + + ok = true; + motorTargetTimeScale = EntityDynamicInterface::extractFloatArgument("hinge constraint", arguments, + "motorTargetTimeScale", ok, false); + if (!ok) { + motorTargetTimeScale = _motorTargetTimeScale; + } + + ok = true; + maxImpulse = EntityDynamicInterface::extractFloatArgument("hinge constraint", arguments, "maxImpulse", ok, false); + if (!ok) { + maxImpulse = _maxImpulse; + } + + if (somethingChanged || pivotInA != _pivotInA || axisInA != _axisInA || @@ -235,7 +320,10 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) { softness != _softness || biasFactor != _biasFactor || relaxationFactor != _relaxationFactor || - motorVelocity != _motorVelocity) { + motorVelocity != _motorVelocity || + motorTarget != _motorTarget || + motorTargetTimeScale != _motorTargetTimeScale || + maxImpulse != _maxImpulse) { // something changed needUpdate = true; } @@ -254,6 +342,9 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) { _biasFactor = biasFactor; _relaxationFactor = relaxationFactor; _motorVelocity = motorVelocity; + _motorTarget = motorTarget; + _motorTargetTimeScale = motorTargetTimeScale; + _maxImpulse = maxImpulse; _active = true; @@ -285,6 +376,9 @@ QVariantMap ObjectConstraintHinge::getArguments() { arguments["biasFactor"] = _biasFactor; arguments["relaxationFactor"] = _relaxationFactor; arguments["motorVelocity"] = _motorVelocity; + arguments["motorTarget"] = _motorTarget; + arguments["motorTargetTimeScale"] = _motorTargetTimeScale; + arguments["maxImpulse"] = _maxImpulse; arguments["angle"] = static_cast(_constraint)->getHingeAngle(); // [-PI,PI] } }); @@ -315,6 +409,9 @@ QByteArray ObjectConstraintHinge::serialize() const { dataStream << _tag; dataStream << _motorVelocity; + dataStream << _motorTarget; + dataStream << _motorTargetTimeScale; + dataStream << _maxImpulse; }); return serializedConstraintArguments; @@ -357,6 +454,9 @@ void ObjectConstraintHinge::deserialize(QByteArray serializedArguments) { dataStream >> _tag; dataStream >> _motorVelocity; + dataStream >> _motorTarget; + dataStream >> _motorTargetTimeScale; + dataStream >> _maxImpulse; _active = true; }); diff --git a/libraries/physics/src/ObjectConstraintHinge.h b/libraries/physics/src/ObjectConstraintHinge.h index 7d2cac7511..3dbd3e8152 100644 --- a/libraries/physics/src/ObjectConstraintHinge.h +++ b/libraries/physics/src/ObjectConstraintHinge.h @@ -21,6 +21,8 @@ public: ObjectConstraintHinge(const QUuid& id, EntityItemPointer ownerEntity); virtual ~ObjectConstraintHinge(); + virtual void prepareForPhysicsSimulation() override; + virtual bool updateArguments(QVariantMap arguments) override; virtual QVariantMap getArguments() override; @@ -44,10 +46,43 @@ protected: float _low { -2.0f * PI }; float _high { 2.0f * PI }; + + // https://gamedev.stackexchange.com/questions/71436/what-are-the-parameters-for-bthingeconstraintsetlimit + // + // softness: a negative measure of the friction that determines how much the hinge rotates for a given force. A high + // softness would make the hinge rotate easily like it's oiled then. + // biasFactor: an offset for the relaxed rotation of the hinge. It won't be right in the middle of the low and high angles + // anymore. 1.0f is the neural value. + // relaxationFactor: a measure of how much force is applied internally to bring the hinge in its central rotation. + // This is right in the middle of the low and high angles. For example, consider a western swing door. After + // walking through it will swing in both directions but at the end it stays right in the middle. + + // http://javadoc.jmonkeyengine.org/com/jme3/bullet/joints/HingeJoint.html + // + // _softness - the factor at which the velocity error correction starts operating, i.e. a softness of 0.9 means that + // the vel. corr starts at 90% of the limit range. + // _biasFactor - the magnitude of the position correction. It tells you how strictly the position error (drift) is + // corrected. + // _relaxationFactor - the rate at which velocity errors are corrected. This can be seen as the strength of the + // limits. A low value will make the the limits more spongy. + + + float _maxImpulse { 1.0f }; + float _softness { 0.9f }; + float _biasFactor { 0.3f }; + float _relaxationFactor { 1.0f }; + float _motorVelocity { 0.0f }; + float _motorTarget { 0.0f }; + float _motorTargetTimeScale { 0.0f }; + + uint64_t _startMotorTime { 0 }; + uint64_t _previousMotorTime { 0 }; + + bool _motorEnabled { false }; }; #endif // hifi_ObjectConstraintHinge_h