From 429a258df031ff8ba1d4a68db9965217ca9f6652 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 25 Mar 2015 14:38:27 -0700 Subject: [PATCH 01/19] enable hover when far above floor --- libraries/physics/src/CharacterController.cpp | 65 ++++++++++++++++--- libraries/physics/src/CharacterController.h | 2 + 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index e84df7d644..84dcf25212 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -40,6 +40,24 @@ static btVector3 getNormalizedVector(const btVector3& v) { return n; } +class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { +public: + btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : + btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { + m_me = me; + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { + if (rayResult.m_collisionObject == m_me) { + return 1.0; + } + return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); + } +protected: + btCollisionObject* m_me; +}; + + class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) @@ -215,6 +233,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _jumpSpeed = 7.0f; _wasOnGround = false; _wasJumping = false; + _isHovering = true; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; _pendingFlags = 0; @@ -325,6 +344,27 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl return penetration; } +void CharacterController::scanDown(btCollisionWorld* world) { + // we test with downward raycast and if we don't find floor close enough then turn on "hover" + btKinematicClosestNotMeRayResultCallback callback(_ghostObject); + callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; + callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; + + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + btVector3 start = _currentPosition; + const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight; // closest possible floor for disabling hover + const btScalar MIN_HOVER_HEIGHT = 2.0f + _halfHeight; // distance to floor for enabling hover + btVector3 end = start - MAX_SCAN_HEIGHT * up; + + world->rayTest(start, end, callback); + bool wasHovering = _isHovering; + if (!callback.hasHit()) { + _isHovering = true; + } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { + _isHovering = false; + } +} + void CharacterController::stepUp(btCollisionWorld* world) { // phase 1: up @@ -495,7 +535,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; _currentPosition = _targetPosition; - btVector3 oldPosition = _currentPosition; step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; @@ -510,7 +549,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - _currentPosition = oldPosition - _lastStepUp * up; + //_currentPosition = oldPosition; _lastStepUp = 0.0f; } } else { @@ -581,14 +620,19 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar return; // no motion } - _wasOnGround = onGround(); - // Update fall velocity. - _verticalVelocity -= _gravity * dt; - if (_verticalVelocity > _jumpSpeed) { - _verticalVelocity = _jumpSpeed; - } else if (_verticalVelocity < -_maxFallSpeed) { - _verticalVelocity = -_maxFallSpeed; + if (_isHovering) { + _wasOnGround = false; + const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f; + _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE); + } else { + _wasOnGround = onGround(); + _verticalVelocity -= _gravity * dt; + if (_verticalVelocity > _jumpSpeed) { + _verticalVelocity = _jumpSpeed; + } else if (_verticalVelocity < -_maxFallSpeed) { + _verticalVelocity = -_maxFallSpeed; + } } _verticalOffset = _verticalVelocity * dt; @@ -600,6 +644,8 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // (2) step the character forward // (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started + scanDown(collisionWorld); + stepUp(collisionWorld); // compute substep and decrement total interval @@ -711,6 +757,7 @@ void CharacterController::setEnabled(bool enabled) { // Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit. // Setting the ADD bit here works for all cases so we don't even bother checking other bits. _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; + _isHovering = true; } else { // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case // it was previously set by something else (e.g. an UPDATE_SHAPE event). diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 323529b1cd..f604e60c31 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -82,6 +82,7 @@ protected: bool _enabled; bool _wasOnGround; bool _wasJumping; + bool _isHovering; btScalar _velocityTimeInterval; uint32_t _pendingFlags; @@ -95,6 +96,7 @@ protected: btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal); bool recoverFromPenetration(btCollisionWorld* collisionWorld); + void scanDown(btCollisionWorld* collisionWorld); void stepUp(btCollisionWorld* collisionWorld); void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove); From 716e9bfe4fdfaf15c2e86aee33a2d0e28daae264 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Mar 2015 15:40:48 +0100 Subject: [PATCH 02/19] Hint order for FST files --- interface/src/ModelPackager.cpp | 2 + interface/src/ModelPackager.h | 2 - interface/src/ModelPropertiesDialog.cpp | 1 + interface/src/ModelPropertiesDialog.h | 13 --- libraries/fbx/src/FBXReader.cpp | 68 -------------- libraries/fbx/src/FBXReader.h | 6 -- libraries/fbx/src/FSTReader.cpp | 96 ++++++++++++++++++++ libraries/fbx/src/FSTReader.h | 36 ++++++++ libraries/render-utils/src/GeometryCache.cpp | 1 + 9 files changed, 136 insertions(+), 89 deletions(-) create mode 100644 libraries/fbx/src/FSTReader.cpp create mode 100644 libraries/fbx/src/FSTReader.h diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 49d4ae566f..f552d67a98 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "ModelSelector.h" #include "ModelPropertiesDialog.h" diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index c62388f196..2c90395e56 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -15,8 +15,6 @@ #include #include -#include - #include "ui/ModelsBrowser.h" class ModelPackager : public QObject { diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index de98407a2a..81fe9ce7fd 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "ModelPropertiesDialog.h" diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index 65c5be6c21..5af4d173f1 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -23,19 +23,6 @@ class QComboBox; class QCheckBox; class QVBoxLayout; -static const QString NAME_FIELD = "name"; -static const QString FILENAME_FIELD = "filename"; -static const QString TEXDIR_FIELD = "texdir"; -static const QString LOD_FIELD = "lod"; -static const QString JOINT_INDEX_FIELD = "jointIndex"; -static const QString SCALE_FIELD = "scale"; -static const QString TRANSLATION_X_FIELD = "tx"; -static const QString TRANSLATION_Y_FIELD = "ty"; -static const QString TRANSLATION_Z_FIELD = "tz"; -static const QString JOINT_FIELD = "joint"; -static const QString FREE_JOINT_FIELD = "freeJoint"; -static const QString BLENDSHAPE_FIELD = "bs"; - /// A dialog that allows customization of various model properties. class ModelPropertiesDialog : public QDialog { Q_OBJECT diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index a2c217c97d..1cd3bba73a 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -458,41 +458,6 @@ FBXNode parseFBX(QIODevice* device) { return top; } -QVariantHash parseMapping(QIODevice* device) { - QVariantHash properties; - - QByteArray line; - while (!(line = device->readLine()).isEmpty()) { - if ((line = line.trimmed()).startsWith('#')) { - continue; // comment - } - QList sections = line.split('='); - if (sections.size() < 2) { - continue; - } - QByteArray name = sections.at(0).trimmed(); - if (sections.size() == 2) { - properties.insertMulti(name, sections.at(1).trimmed()); - - } else if (sections.size() == 3) { - QVariantHash heading = properties.value(name).toHash(); - heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed()); - properties.insert(name, heading); - - } else if (sections.size() >= 4) { - QVariantHash heading = properties.value(name).toHash(); - QVariantList contents; - for (int i = 2; i < sections.size(); i++) { - contents.append(sections.at(i).trimmed()); - } - heading.insertMulti(sections.at(1).trimmed(), contents); - properties.insert(name, heading); - } - } - - return properties; -} - QVector createVec3Vector(const QVector& doubleVector) { QVector values; for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) { @@ -2473,39 +2438,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, return geometry; } -QVariantHash readMapping(const QByteArray& data) { - QBuffer buffer(const_cast(&data)); - buffer.open(QIODevice::ReadOnly); - return parseMapping(&buffer); -} - -QByteArray writeMapping(const QVariantHash& mapping) { - QBuffer buffer; - buffer.open(QIODevice::WriteOnly); - for (QVariantHash::const_iterator first = mapping.constBegin(); first != mapping.constEnd(); first++) { - QByteArray key = first.key().toUtf8() + " = "; - QVariantHash hashValue = first.value().toHash(); - if (hashValue.isEmpty()) { - buffer.write(key + first.value().toByteArray() + "\n"); - continue; - } - for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { - QByteArray extendedKey = key + second.key().toUtf8(); - QVariantList listValue = second.value().toList(); - if (listValue.isEmpty()) { - buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); - continue; - } - buffer.write(extendedKey); - for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { - buffer.write(" = " + third->toByteArray()); - } - buffer.write("\n"); - } - } - return buffer.data(); -} - FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index ecce607575..6cb6b19c05 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -261,12 +261,6 @@ public: Q_DECLARE_METATYPE(FBXGeometry) -/// Reads an FST mapping from the supplied data. -QVariantHash readMapping(const QByteArray& data); - -/// Writes an FST mapping to a byte array. -QByteArray writeMapping(const QVariantHash& mapping); - /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp new file mode 100644 index 0000000000..397de2bd2a --- /dev/null +++ b/libraries/fbx/src/FSTReader.cpp @@ -0,0 +1,96 @@ +// +// FSTReader.cpp +// +// +// Created by Clement on 3/26/15. +// Copyright 2015 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 "FSTReader.h" + +QVariantHash parseMapping(QIODevice* device) { + QVariantHash properties; + + QByteArray line; + while (!(line = device->readLine()).isEmpty()) { + if ((line = line.trimmed()).startsWith('#')) { + continue; // comment + } + QList sections = line.split('='); + if (sections.size() < 2) { + continue; + } + QByteArray name = sections.at(0).trimmed(); + if (sections.size() == 2) { + properties.insertMulti(name, sections.at(1).trimmed()); + + } else if (sections.size() == 3) { + QVariantHash heading = properties.value(name).toHash(); + heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed()); + properties.insert(name, heading); + + } else if (sections.size() >= 4) { + QVariantHash heading = properties.value(name).toHash(); + QVariantList contents; + for (int i = 2; i < sections.size(); i++) { + contents.append(sections.at(i).trimmed()); + } + heading.insertMulti(sections.at(1).trimmed(), contents); + properties.insert(name, heading); + } + } + + return properties; +} + +QVariantHash readMapping(const QByteArray& data) { + QBuffer buffer(const_cast(&data)); + buffer.open(QIODevice::ReadOnly); + return parseMapping(&buffer); +} + +QByteArray writeMapping(const QVariantHash& mapping) { + static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD + << TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD + << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; + QBuffer buffer; + auto writeVariant = [&buffer](QVariantHash::const_iterator& it) { + QByteArray key = it.key().toUtf8() + " = "; + QVariantHash hashValue = it.value().toHash(); + if (hashValue.isEmpty()) { + buffer.write(key + it.value().toByteArray() + "\n"); + return; + } + for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { + QByteArray extendedKey = key + second.key().toUtf8(); + QVariantList listValue = second.value().toList(); + if (listValue.isEmpty()) { + buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); + continue; + } + buffer.write(extendedKey); + for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { + buffer.write(" = " + third->toByteArray()); + } + buffer.write("\n"); + } + }; + buffer.open(QIODevice::WriteOnly); + + for (auto key : PREFERED_ORDER) { + auto it = mapping.find(key); + if (it != mapping.constEnd()) { + writeVariant(it); + } + } + + for (auto it = mapping.constBegin(); it != mapping.constEnd(); it++) { + if (!PREFERED_ORDER.contains(it.key())) { + writeVariant(it); + } + } + return buffer.data(); +} \ No newline at end of file diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h new file mode 100644 index 0000000000..59559dea74 --- /dev/null +++ b/libraries/fbx/src/FSTReader.h @@ -0,0 +1,36 @@ +// +// FSTReader.h +// +// +// Created by Clement on 3/26/15. +// Copyright 2015 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_FSTReader_h +#define hifi_FSTReader_h + +#include + +static const QString NAME_FIELD = "name"; +static const QString FILENAME_FIELD = "filename"; +static const QString TEXDIR_FIELD = "texdir"; +static const QString LOD_FIELD = "lod"; +static const QString JOINT_INDEX_FIELD = "jointIndex"; +static const QString SCALE_FIELD = "scale"; +static const QString TRANSLATION_X_FIELD = "tx"; +static const QString TRANSLATION_Y_FIELD = "ty"; +static const QString TRANSLATION_Z_FIELD = "tz"; +static const QString JOINT_FIELD = "joint"; +static const QString FREE_JOINT_FIELD = "freeJoint"; +static const QString BLENDSHAPE_FIELD = "bs"; + +/// Reads an FST mapping from the supplied data. +QVariantHash readMapping(const QByteArray& data); + +/// Writes an FST mapping to a byte array. +QByteArray writeMapping(const QVariantHash& mapping); + +#endif // hifi_FSTReader_h \ No newline at end of file diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 29f76291ea..e60409e36f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "TextureCache.h" From c26b499671091e638ed7f01788c6269af94a9862 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Mar 2015 15:58:18 +0100 Subject: [PATCH 03/19] Add forgotten include --- libraries/fbx/src/FSTReader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 397de2bd2a..4f882d4bd8 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "FSTReader.h" QVariantHash parseMapping(QIODevice* device) { From 858dbeb674445c9f1530bec5f84dd5482ea932f7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 13:23:15 -0700 Subject: [PATCH 04/19] remove one line of cruft --- libraries/physics/src/CharacterController.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..fb2457083a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { From 0ef4022e9400abbdb3b06d49b01937259007c8b7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 15:14:46 -0700 Subject: [PATCH 05/19] tweak gravity and step heights of controller --- libraries/physics/src/CharacterController.cpp | 25 ++++++++----------- libraries/physics/src/CharacterController.h | 3 ++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..f243deffaa 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -228,9 +228,9 @@ CharacterController::CharacterController(AvatarData* avatarData) { _velocityTimeInterval = 0.0f; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _gravity = 9.8f; + _gravity = 5.0f; // slower than Earth's _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. - _jumpSpeed = 7.0f; + _jumpSpeed = 5.0f; _wasOnGround = false; _wasJumping = false; _isHovering = true; @@ -352,8 +352,8 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); btVector3 start = _currentPosition; - const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight; // closest possible floor for disabling hover - const btScalar MIN_HOVER_HEIGHT = 2.0f + _halfHeight; // distance to floor for enabling hover + const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight + _radius; // closest possible floor for disabling hover + const btScalar MIN_HOVER_HEIGHT = 3.0f + _halfHeight + _radius; // distance to floor for enabling hover btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); @@ -374,7 +374,7 @@ void CharacterController::stepUp(btCollisionWorld* world) { btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin)); - _targetPosition = _currentPosition + up * _stepHeight; + _targetPosition = _currentPosition + up * _stepUpHeight; end.setIdentity(); end.setOrigin(_targetPosition); @@ -392,15 +392,15 @@ void CharacterController::stepUp(btCollisionWorld* world) { // Only modify the position if the hit was a slope and not a wall or ceiling. if (callback.m_hitNormalWorld.dot(up) > 0.0f) { - _lastStepUp = _stepHeight * callback.m_closestHitFraction; + _lastStepUp = _stepUpHeight * callback.m_closestHitFraction; _currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction); } else { - _lastStepUp = _stepHeight; + _lastStepUp = _stepUpHeight; _currentPosition = _targetPosition; } } else { _currentPosition = _targetPosition; - _lastStepUp = _stepHeight; + _lastStepUp = _stepUpHeight; } } @@ -524,6 +524,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else if (!_wasJumping) { // sweep again for floor within downStep threshold + step = -_stepDownHeight * up; StepDownConvexResultCallback callback2 (_ghostObject, up, _currentPosition, step, @@ -535,7 +536,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; _currentPosition = _targetPosition; - step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; start.setOrigin(_currentPosition); @@ -549,7 +549,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - //_currentPosition = oldPosition; _lastStepUp = 0.0f; } } else { @@ -819,10 +818,8 @@ void CharacterController::updateShapeIfNecessary() { _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm - // (the function is approximately 2*_stepHeight) - _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + _stepUpHeight = _radius + 0.25f * _halfHeight + 0.1f; + _stepDownHeight = _radius; // create new shape _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index f604e60c31..b31c4855ea 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -59,7 +59,8 @@ protected: btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization) btScalar _gravity; - btScalar _stepHeight; // height of stepUp prior to stepForward + btScalar _stepUpHeight; // height of stepUp prior to stepForward + btScalar _stepDownHeight; // height of stepDown btScalar _addedMargin;//@todo: remove this and fix the code From 8a951e0dd3fc8bba4dc08c078c53743a31226dfb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 15:16:57 -0700 Subject: [PATCH 06/19] minor cleanup --- libraries/physics/src/CharacterController.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f243deffaa..34c2f51b03 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -43,18 +43,18 @@ static btVector3 getNormalizedVector(const btVector3& v) { class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : - btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { - m_me = me; + btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) { + _me = me; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { - if (rayResult.m_collisionObject == m_me) { - return 1.0; + if (rayResult.m_collisionObject == _me) { + return 1.0f; } return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); } protected: - btCollisionObject* m_me; + btCollisionObject* _me; }; @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { From 6cff99f9d6253749fae2b25a87734f55c0d9b141 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 26 Mar 2015 16:36:46 -0700 Subject: [PATCH 07/19] menu and display tweaks --- interface/src/Application.cpp | 10 +++------- interface/src/Menu.cpp | 14 +++++++------- interface/src/Menu.h | 6 +----- interface/src/devices/TV3DManager.cpp | 9 ++------- interface/src/ui/ApplicationOverlay.cpp | 13 +------------ interface/src/ui/ApplicationOverlay.h | 2 +- 6 files changed, 15 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc8fa08c4e..8cd36b501f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -789,7 +789,7 @@ void Application::paintGL() { DependencyManager::get()->render(); - if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + { PerformanceTimer perfTimer("renderOverlay"); _applicationOverlay.renderOverlay(true); _applicationOverlay.displayOverlayTexture(); @@ -1127,13 +1127,10 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } break; - case Qt::Key_Slash: - Menu::getInstance()->triggerOption(MenuOption::UserInterface); - break; case Qt::Key_P: Menu::getInstance()->triggerOption(MenuOption::FirstPerson); break; - case Qt::Key_Percent: + case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); break; case Qt::Key_Plus: @@ -3019,8 +3016,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs _nodeBoundsDisplay.draw(); // Render the world box - if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) && - Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { PerformanceTimer perfTimer("worldBox"); renderWorldBox(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8d3c01320f..2ec5c12ca0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -230,7 +230,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H, false, @@ -259,14 +258,13 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - addDisabledActionAndSeparator(viewMenu, "Stats"); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog())); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, dialogsManager.data(), SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, dialogsManager.data(), SLOT(octreeStatsDetails())); - addActionToQMenuAndActionHash(viewMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); + QMenu* developerMenu = addMenu("Developer"); @@ -538,10 +536,12 @@ Menu::Menu() { statsRenderer.data(), SLOT(toggleShowInjectedStreams())); -#ifndef Q_OS_MAC QMenu* helpMenu = addMenu("Help"); - QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp); - connect(helpAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); + addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); + +#ifndef Q_OS_MAC + QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp); + connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); #endif } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 60fe5d4cd2..b3d2d548df 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -184,12 +184,10 @@ namespace MenuOption { const QString Mirror = "Mirror"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; - const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString NoFaceTracking = "None"; const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity"; - const QString OctreeStats = "Voxel and Entity Statistics"; + const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; - const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString Pair = "Pair"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; @@ -233,7 +231,6 @@ namespace MenuOption { const QString ScriptEditor = "Script Editor..."; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; const QString ShowBordersEntityNodes = "Show Entity Nodes"; - const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowIKConstraints = "Show IK Constraints"; const QString SimpleShadows = "Simple"; const QString SixenseEnabled = "Enable Hydra Support"; @@ -251,7 +248,6 @@ namespace MenuOption { const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; const QString PackageModel = "Package Model"; - const QString UserInterface = "User Interface"; const QString Visage = "Visage"; const QString Wireframe = "Wireframe"; } diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index b5f57301f1..f082c6de47 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -104,7 +104,6 @@ void TV3DManager::display(Camera& whichCamera) { // We only need to render the overlays to a texture once, then we just render the texture as a quad // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); - const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface); DependencyManager::get()->prepare(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -135,9 +134,7 @@ void TV3DManager::display(Camera& whichCamera) { eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0)); Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO); - if (displayOverlays) { - applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); - } + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); _activeEye = NULL; } glPopMatrix(); @@ -166,9 +163,7 @@ void TV3DManager::display(Camera& whichCamera) { eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0)); Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO); - if (displayOverlays) { - applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); - } + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); _activeEye = NULL; } glPopMatrix(); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 0c5941366f..d9adaf02e6 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -176,18 +176,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { _textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight(); //Handle fading and deactivation/activation of UI - if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { - _alpha += FADE_SPEED; - if (_alpha > 1.0f) { - _alpha = 1.0f; - } - } else { - _alpha -= FADE_SPEED; - if (_alpha <= 0.0f) { - _alpha = 0.0f; - } - } - + // Render 2D overlay glMatrixMode(GL_PROJECTION); glDisable(GL_DEPTH_TEST); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 64161e4a31..58b79adcda 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -114,7 +114,7 @@ private: quint64 _lastMouseMove; bool _magnifier; - float _alpha; + float _alpha = 1.0f; float _oculusUIRadius; float _trailingAudioLoudness; From 821ac605f5dc8cd93cf8460f456defe05b099041 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 19:48:52 -0700 Subject: [PATCH 08/19] smoother motion on steps faster motion when "flying" cleanup of MyAvatar::updatePosition() --- interface/src/avatar/MyAvatar.cpp | 136 +++--------------- interface/src/avatar/MyAvatar.h | 1 - libraries/physics/src/CharacterController.cpp | 55 ++++--- libraries/physics/src/CharacterController.h | 6 +- 4 files changed, 63 insertions(+), 135 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2f42544f28..aa36748f0c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -174,11 +174,7 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - if (isPhysicsEnabled()) { - updatePositionWithPhysics(deltaTime); - } else { - updatePosition(deltaTime); - } + updatePosition(deltaTime); } { @@ -1258,128 +1254,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe return localVelocity + motorEfficiency * deltaVelocity; } -const float NEARBY_FLOOR_THRESHOLD = 5.0f; - void MyAvatar::updatePosition(float deltaTime) { - - // check for floor by casting a ray straight down from avatar's position - float heightAboveFloor = FLT_MAX; - bool hasFloor = false; - const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); - const float maxFloorDistance = boundingShape.getBoundingRadius() * NEARBY_FLOOR_THRESHOLD; - - RayIntersectionInfo intersection; - // NOTE: avatar is center of PhysicsSimulation, so rayStart is the origin for the purposes of the raycast - intersection._rayStart = glm::vec3(0.0f); - intersection._rayDirection = - _worldUpDirection; - intersection._rayLength = 4.0f * boundingShape.getBoundingRadius(); - - // velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc - glm::vec3 velocity = _velocity; - - bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; - if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { - const float MAX_SPEED_UNDER_GRAVITY = 2.0f * _scale * MAX_WALKING_SPEED; - if (pushingUp || glm::length2(velocity) > MAX_SPEED_UNDER_GRAVITY * MAX_SPEED_UNDER_GRAVITY) { - // we're pushing up or moving quickly, so disable gravity - setLocalGravity(glm::vec3(0.0f)); - hasFloor = false; - } else { - if (heightAboveFloor > maxFloorDistance) { - // disable local gravity when floor is too far away - setLocalGravity(glm::vec3(0.0f)); - hasFloor = false; - } else { - // enable gravity - setLocalGravity(-_worldUpDirection); - } - } - } - - bool zeroDownwardVelocity = false; - bool gravityEnabled = (glm::length2(_gravity) > EPSILON); - if (gravityEnabled) { - const float SLOP = 0.002f; - if (heightAboveFloor < SLOP) { - if (heightAboveFloor < 0.0) { - // Gravity is in effect so we assume that the avatar is colliding against the world and we need - // to lift avatar out of floor, but we don't want to do it too fast (keep it smooth). - float distanceToLift = glm::min(-heightAboveFloor, MAX_WALKING_SPEED * deltaTime); - - // We don't use applyPositionDelta() for this lift distance because we don't want the avatar - // to come flying out of the floor. Instead we update position directly, and set a boolean - // that will remind us later to zero any downward component of the velocity. - _position += distanceToLift * _worldUpDirection; - } - zeroDownwardVelocity = true; - } - if (!zeroDownwardVelocity) { - velocity += (deltaTime * GRAVITY_EARTH) * _gravity; - } - } - - // rotate velocity into camera frame - glm::quat rotation = getHead()->getCameraOrientation(); - glm::vec3 localVelocity = glm::inverse(rotation) * velocity; - - // apply motors in camera frame - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); - newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - - // rotate back into world-frame - velocity = rotation * newLocalVelocity; - - // apply thrust - velocity += _thrust * deltaTime; - _thrust = glm::vec3(0.0f); - - // remove downward velocity so we don't push into floor - if (zeroDownwardVelocity) { - float verticalSpeed = glm::dot(velocity, _worldUpDirection); - if (verticalSpeed < 0.0f || !pushingUp) { - velocity -= verticalSpeed * _worldUpDirection; - } - } - - // cap avatar speed - float speed = glm::length(velocity); - if (speed > MAX_AVATAR_SPEED) { - velocity *= MAX_AVATAR_SPEED / speed; - speed = MAX_AVATAR_SPEED; - } - - // update position - if (speed > MIN_AVATAR_SPEED) { - applyPositionDelta(deltaTime * velocity); - } - - // update _moving flag based on speed - const float MOVING_SPEED_THRESHOLD = 0.01f; - _moving = speed > MOVING_SPEED_THRESHOLD; - - measureMotionDerivatives(deltaTime); -} - -void MyAvatar::updatePositionWithPhysics(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; - bool hasFloor = false; - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); + bool isOnGround = _characterController.onGround(); + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - // cap avatar speed - float speed = glm::length(newLocalVelocity); - if (speed > MAX_WALKING_SPEED) { - newLocalVelocity *= MAX_WALKING_SPEED / speed; - } - // rotate back into world-frame _velocity = rotation * newLocalVelocity; _velocity += _thrust * deltaTime; _thrust = glm::vec3(0.0f); + + // cap avatar speed + float speed = glm::length(_velocity); + if (speed > MAX_AVATAR_SPEED) { + _velocity *= MAX_AVATAR_SPEED / speed; + speed = MAX_AVATAR_SPEED; + } + + if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) { + // update position ourselves + applyPositionDelta(deltaTime * _velocity); + measureMotionDerivatives(deltaTime); + } // else physics will move avatar later + + // update _moving flag based on speed + const float MOVING_SPEED_THRESHOLD = 0.01f; + _moving = speed > MOVING_SPEED_THRESHOLD; + } void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a37d1c6a30..320a3179bc 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -234,7 +234,6 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); - void updatePositionWithPhysics(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 34c2f51b03..aa0d109732 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -231,8 +231,8 @@ CharacterController::CharacterController(AvatarData* avatarData) { _gravity = 5.0f; // slower than Earth's _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. _jumpSpeed = 5.0f; - _wasOnGround = false; - _wasJumping = false; + _isOnGround = false; + _isJumping = false; _isHovering = true; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; @@ -450,12 +450,12 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt btScalar margin = _convexShape->getMargin(); _convexShape->setMargin(margin + _addedMargin); - const btScalar MIN_STEP_DISTANCE = 0.0001f; + const btScalar MIN_STEP_DISTANCE_SQUARED = 1.0e-6f; btVector3 step = _targetPosition - _currentPosition; btScalar stepLength2 = step.length2(); int maxIter = 10; - while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) { + while (stepLength2 > MIN_STEP_DISTANCE_SQUARED && maxIter-- > 0) { start.setOrigin(_currentPosition); end.setOrigin(_targetPosition); @@ -516,12 +516,14 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt end.setOrigin(_targetPosition); _ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + _isOnGround = false; if (callback.hasHit()) { _currentPosition += callback.m_closestHitFraction * step; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _wasJumping = false; - } else if (!_wasJumping) { + _isJumping = false; + _isOnGround = true; + } else if (!_isJumping) { // sweep again for floor within downStep threshold step = -_stepDownHeight * up; StepDownConvexResultCallback callback2 (_ghostObject, @@ -545,9 +547,10 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _currentPosition += callback2.m_closestHitFraction * step; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _wasJumping = false; + _isJumping = false; + _isOnGround = true; } else { - // nothing to step down on, so remove the stepUp effect + // nothing to step down on _lastStepUp = 0.0f; } } else { @@ -571,8 +574,8 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, void CharacterController::reset(btCollisionWorld* collisionWorld) { _verticalVelocity = 0.0; _verticalOffset = 0.0; - _wasOnGround = false; - _wasJumping = false; + _isOnGround = false; + _isJumping = false; _walkDirection.setValue(0,0,0); _velocityTimeInterval = 0.0; @@ -620,11 +623,9 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // Update fall velocity. if (_isHovering) { - _wasOnGround = false; const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f; _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE); } else { - _wasOnGround = onGround(); _verticalVelocity -= _gravity * dt; if (_verticalVelocity > _jumpSpeed) { _verticalVelocity = _jumpSpeed; @@ -649,6 +650,7 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // compute substep and decrement total interval btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval; _velocityTimeInterval -= dt; + _stepDt += dt; // stepForward substep btVector3 move = _walkDirection * dtMoving; @@ -673,7 +675,7 @@ void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) { } bool CharacterController::canJump() const { - return onGround(); + return _isOnGround; } void CharacterController::jump() { @@ -698,7 +700,7 @@ btScalar CharacterController::getMaxSlope() const { } bool CharacterController::onGround() const { - return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f; + return _isOnGround; } void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { @@ -761,6 +763,7 @@ void CharacterController::setEnabled(bool enabled) { // it was previously set by something else (e.g. an UPDATE_SHAPE event). _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + _isOnGround = false; } _enabled = enabled; } @@ -842,9 +845,12 @@ void CharacterController::preSimulation(btScalar timeStep) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (canJump()) { _verticalVelocity = _jumpSpeed; - _wasJumping = true; + _isJumping = true; } } + // remember last position so we can throttle the total motion from the next step + _lastPosition = position; + _stepDt = 0.0f; } } @@ -852,9 +858,24 @@ void CharacterController::postSimulation() { if (_enabled) { const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); - glm::vec3 offset = rotation * _shapeLocalOffset; + glm::vec3 position = bulletToGLM(avatarTransform.getOrigin()); + + // cap the velocity of the step so that the character doesn't POP! so hard on steps + glm::vec3 finalStep = position - _lastPosition; + btVector3 finalVelocity = _walkDirection; + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + finalVelocity += _verticalVelocity * up; + const btScalar MAX_RESOLUTION_SPEED = 5.0f; // m/sec + btScalar maxStepLength = glm::max(MAX_RESOLUTION_SPEED, 2.0f * finalVelocity.length()) * _stepDt; + btScalar stepLength = glm::length(finalStep); + if (stepLength > maxStepLength) { + position = _lastPosition + (maxStepLength / stepLength) * finalStep; + // NOTE: we don't need to move ghostObject to throttled position unless + // we want to support do async ray-traces/collision-queries against character + } + _avatarData->setOrientation(rotation); - _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + _avatarData->setPosition(position - rotation * _shapeLocalOffset); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index b31c4855ea..ec7d9426f4 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -72,6 +72,7 @@ protected: btVector3 _currentPosition; btQuaternion _currentRotation; btVector3 _targetPosition; + glm::vec3 _lastPosition; btScalar _lastStepUp; ///keep track of the contact manifolds @@ -81,10 +82,11 @@ protected: btVector3 _floorNormal; // points from object to character bool _enabled; - bool _wasOnGround; - bool _wasJumping; + bool _isOnGround; + bool _isJumping; bool _isHovering; btScalar _velocityTimeInterval; + btScalar _stepDt; uint32_t _pendingFlags; glm::vec3 _shapeLocalOffset; From daaba330d5e99efe704dc02be7bccc81aab445f0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Mar 2015 14:41:32 +0100 Subject: [PATCH 09/19] Turn lambda into helper function --- libraries/fbx/src/FSTReader.cpp | 47 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 4f882d4bd8..82a8c338f0 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -54,44 +54,45 @@ QVariantHash readMapping(const QByteArray& data) { return parseMapping(&buffer); } +void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) { + QByteArray key = it.key().toUtf8() + " = "; + QVariantHash hashValue = it.value().toHash(); + if (hashValue.isEmpty()) { + buffer.write(key + it.value().toByteArray() + "\n"); + return; + } + for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { + QByteArray extendedKey = key + second.key().toUtf8(); + QVariantList listValue = second.value().toList(); + if (listValue.isEmpty()) { + buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); + continue; + } + buffer.write(extendedKey); + for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { + buffer.write(" = " + third->toByteArray()); + } + buffer.write("\n"); + } +}; + QByteArray writeMapping(const QVariantHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD << TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; QBuffer buffer; - auto writeVariant = [&buffer](QVariantHash::const_iterator& it) { - QByteArray key = it.key().toUtf8() + " = "; - QVariantHash hashValue = it.value().toHash(); - if (hashValue.isEmpty()) { - buffer.write(key + it.value().toByteArray() + "\n"); - return; - } - for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { - QByteArray extendedKey = key + second.key().toUtf8(); - QVariantList listValue = second.value().toList(); - if (listValue.isEmpty()) { - buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); - continue; - } - buffer.write(extendedKey); - for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { - buffer.write(" = " + third->toByteArray()); - } - buffer.write("\n"); - } - }; buffer.open(QIODevice::WriteOnly); for (auto key : PREFERED_ORDER) { auto it = mapping.find(key); if (it != mapping.constEnd()) { - writeVariant(it); + writeVariant(buffer, it); } } for (auto it = mapping.constBegin(); it != mapping.constEnd(); it++) { if (!PREFERED_ORDER.contains(it.key())) { - writeVariant(it); + writeVariant(buffer, it); } } return buffer.data(); From e16c8852fb1b379717b87b9e52d19641559f0db8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Mar 2015 14:43:09 +0100 Subject: [PATCH 10/19] extra ; --- libraries/fbx/src/FSTReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 82a8c338f0..f1ffe11996 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -74,7 +74,7 @@ void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) { } buffer.write("\n"); } -}; +} QByteArray writeMapping(const QVariantHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD From b9b2c30bba5f78cad7fb3a38eb9a46a3e4108005 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Mar 2015 09:01:44 -0700 Subject: [PATCH 11/19] use QObject::deleteLater() not explicit delete --- libraries/networking/src/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 5858c0926d..46c6418c63 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -282,7 +282,7 @@ void AccountManager::processReply() { } else { passErrorToCallback(requestReply); } - delete requestReply; + requestReply->deleteLater(); } void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { From c9f4f4626bea7d49f6e8dcf2f430e37f011765df Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 27 Mar 2015 09:21:32 -0700 Subject: [PATCH 12/19] Update default light color to (150,150,150) --- examples/edit.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 52e565f3f9..96b31cdce0 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -387,9 +387,7 @@ var toolBar = (function () { position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_LIGHT_DIMENSIONS), DEFAULT_LIGHT_DIMENSIONS), dimensions: DEFAULT_LIGHT_DIMENSIONS, isSpotlight: false, - diffuseColor: { red: 255, green: 255, blue: 255 }, - ambientColor: { red: 255, green: 255, blue: 255 }, - specularColor: { red: 0, green: 0, blue: 0 }, + color: { red: 150, green: 150, blue: 150 }, constantAttenuation: 1, linearAttenuation: 0, From 83af2feded2590f462075a65798b378359727b9d Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Fri, 27 Mar 2015 09:33:19 -0700 Subject: [PATCH 13/19] Remove reference to FBX files Remove reference to FBX files --- examples/edit.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 52e565f3f9..07cd17c0ff 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -88,13 +88,7 @@ var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode"; var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain." var modelURLs = [ - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed7.fbx" + "Insert the URL to your FBX" ]; var mode = 0; From be5fdbf2175afc894166c1d12d1a559706519f94 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Mar 2015 13:36:20 -0700 Subject: [PATCH 14/19] enable avatar collisions by default also remove old gravity features --- interface/src/Application.cpp | 11 ---- interface/src/Menu.cpp | 4 +- interface/src/Menu.h | 3 +- interface/src/avatar/MyAvatar.cpp | 50 ++----------------- interface/src/avatar/MyAvatar.h | 11 +--- libraries/avatars/src/AvatarData.h | 12 +---- libraries/physics/src/CharacterController.cpp | 30 ++++++----- libraries/physics/src/CharacterController.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 4 -- 9 files changed, 27 insertions(+), 99 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8cd36b501f..99777d22bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -987,12 +987,6 @@ void Application::keyPressEvent(QKeyEvent* event) { resetSensors(); break; - case Qt::Key_G: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::ObeyEnvironmentalGravity); - } - break; - case Qt::Key_A: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); @@ -1165,10 +1159,6 @@ void Application::keyPressEvent(QKeyEvent* event) { break; } - case Qt::Key_Comma: { - _myAvatar->togglePhysicsEnabled(); - } - default: event->ignore(); break; @@ -2192,7 +2182,6 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); - _myAvatar->preSimulation(); _physicsEngine.stepSimulation(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2ec5c12ca0..5867dd29e2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -201,9 +201,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, - avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::StandOnNearbyFloors, 0, true, + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, avatar, SLOT(updateMotionBehavior())); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, avatar, SLOT(updateMotionBehavior())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b3d2d548df..a4e644f20f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -153,6 +153,7 @@ namespace MenuOption { const QString EchoServerAudio = "Echo Server Audio"; const QString EditEntitiesHelp = "Edit Entities Help..."; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString EnableCharacterController = "Enable avatar collisions"; const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; const QString EnableVRMode = "Enable VR Mode"; const QString Entities = "Entities"; @@ -185,7 +186,6 @@ namespace MenuOption { const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString NoFaceTracking = "None"; - const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity"; const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; @@ -236,7 +236,6 @@ namespace MenuOption { const QString SixenseEnabled = "Enable Hydra Support"; const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString SixenseLasers = "Enable Sixense UI Lasers"; - const QString StandOnNearbyFloors = "Stand on nearby floors"; const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; const QString Stars = "Stars"; const QString Stats = "Stats"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index aa36748f0c..26b777b35b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -81,7 +81,6 @@ MyAvatar::MyAvatar() : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), - _enablePhysics(false), _characterController(this), _lookAtTargetAvatar(), _shouldRender(true), @@ -101,6 +100,7 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); + _characterController.setEnabled(true); } MyAvatar::~MyAvatar() { @@ -147,10 +147,6 @@ void MyAvatar::update(float deltaTime) { head->setAudioLoudness(audio->getLastInputLoudness()); head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); - if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) { - setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition())); - } - simulate(deltaTime); if (_feetTouchFloor) { _skeletonModel.updateStandingFoot(); @@ -480,26 +476,6 @@ void MyAvatar::loadLastRecording() { _player->loadRecording(_recorder->getRecording()); } -void MyAvatar::setLocalGravity(glm::vec3 gravity) { - _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; - // Environmental and Local gravities are incompatible. Since Local is being set here - // the environmental setting must be removed. - _motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - setGravity(gravity); -} - -void MyAvatar::setGravity(const glm::vec3& gravity) { - _gravity = gravity; - - // use the gravity to determine the new world up direction, if possible - float gravityLength = glm::length(gravity); - if (gravityLength > EPSILON) { - _worldUpDirection = _gravity / -gravityLength; - } - // NOTE: the else case here it to leave _worldUpDirection unchanged - // so it continues to point opposite to the previous gravity setting. -} - AnimationHandlePointer MyAvatar::addAnimationHandle() { AnimationHandlePointer handle = _skeletonModel.createAnimationHandle(); _animationHandles.append(handle); @@ -1276,7 +1252,7 @@ void MyAvatar::updatePosition(float deltaTime) { speed = MAX_AVATAR_SPEED; } - if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) { + if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { // update position ourselves applyPositionDelta(deltaTime * _velocity); measureMotionDerivatives(deltaTime); @@ -1402,23 +1378,6 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, void MyAvatar::updateMotionBehavior() { Menu* menu = Menu::getInstance(); - if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) { - _motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - // Environmental and Local gravities are incompatible. Environmental setting trumps local. - _motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY; - } else { - _motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - } - if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) { - setGravity(glm::vec3(0.0f)); - } - if (menu->isOptionChecked(MenuOption::StandOnNearbyFloors)) { - _motionBehaviors |= AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - // standing on floors requires collision with voxels - // TODO: determine what to do with this now that voxels are gone - } else { - _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - } if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) { _motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED; } else { @@ -1429,6 +1388,7 @@ void MyAvatar::updateMotionBehavior() { } else { _motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; } + _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController)); _feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations); } @@ -1487,10 +1447,6 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { return palm->getPosition(); } -void MyAvatar::preSimulation() { - _characterController.setEnabled(_enablePhysics); -} - void MyAvatar::clearDriveKeys() { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { _driveKeys[i] = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 320a3179bc..99c0bdb5df 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -25,7 +25,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale) Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame) - Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setLocalGravity) + //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) public: MyAvatar(); @@ -44,13 +44,11 @@ public: // setters void setLeanScale(float scale) { _leanScale = scale; } - void setLocalGravity(glm::vec3 gravity); void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); } // getters float getLeanScale() const { return _leanScale; } - glm::vec3 getGravity() const { return _gravity; } Q_INVOKABLE glm::vec3 getDefaultEyePosition() const; bool getShouldRenderLocally() const { return _shouldRender; } float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } @@ -148,11 +146,6 @@ public: const RecorderPointer getRecorder() const { return _recorder; } const PlayerPointer getPlayer() const { return _player; } - - void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } - bool isPhysicsEnabled() { return _enablePhysics; } - void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } - void preSimulation(); public slots: void increaseSize(); @@ -209,7 +202,6 @@ private: int _scriptedMotorFrame; quint32 _motionBehaviors; - bool _enablePhysics; CharacterController _characterController; QWeakPointer _lookAtTargetAvatar; @@ -236,7 +228,6 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); - void setGravity(const glm::vec3& gravity); }; #endif // hifi_MyAvatar_h diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a2feb98798..2bbd2ee386 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -61,21 +61,13 @@ typedef unsigned long long quint64; const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0; const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1; -const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 2; -const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 3; -const quint32 AVATAR_MOTION_STAND_ON_NEARBY_FLOORS = 1U << 4; - const quint32 AVATAR_MOTION_DEFAULTS = AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED | - AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED | - AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; // these bits will be expanded as features are exposed const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = - AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED | - AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | - AVATAR_MOTION_OBEY_LOCAL_GRAVITY | - AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; // Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index aa0d109732..40b9076a6a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -217,9 +217,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { assert(avatarData); _avatarData = avatarData; - // cache the "PhysicsEnabled" state of _avatarData _enabled = false; - _ghostObject = NULL; _convexShape = NULL; @@ -730,10 +728,12 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do } else { - // we always need to: REMOVE when UPDATE_SHAPE, to avoid deleting shapes out from under the PhysicsEngine - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION - | PENDING_FLAG_UPDATE_SHAPE; - // but only need to ADD back when we happen to be enabled + if (_dynamicsWorld) { + // must REMOVE from world prior to shape update + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + } + _pendingFlags |= PENDING_FLAG_UPDATE_SHAPE; + // only need to ADD back when we happen to be enabled if (_enabled) { _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; } @@ -759,9 +759,9 @@ void CharacterController::setEnabled(bool enabled) { _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; _isHovering = true; } else { - // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case - // it was previously set by something else (e.g. an UPDATE_SHAPE event). - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + if (_dynamicsWorld) { + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; _isOnGround = false; } @@ -777,17 +777,23 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } _dynamicsWorld = world; if (_dynamicsWorld) { - _pendingFlags &= ~ (PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_JUMP); + _pendingFlags &= ~ PENDING_FLAG_JUMP; _dynamicsWorld->addCollisionObject(getGhostObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); _dynamicsWorld->addAction(this); reset(_dynamicsWorld); + } + } + if (_dynamicsWorld) { + if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { + // shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set + _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION; } else { - _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; + _pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION; } } else { - _pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION); + _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index ec7d9426f4..6751277c83 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -166,6 +166,7 @@ public: bool needsRemoval() const; bool needsAddition() const; void setEnabled(bool enabled); + bool isEnabled() const { return _enabled; } void setDynamicsWorld(btDynamicsWorld* world); void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 716af1d188..831db73a0a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -360,10 +360,6 @@ void ScriptEngine::init() { globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS))); - - globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); - globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); - } QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { From bee8c0e2377f5e3a9a06f538cb894084a2ccf189 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Mar 2015 13:56:03 -0700 Subject: [PATCH 15/19] "hover" if the "jump" key is held down long enough --- libraries/physics/src/CharacterController.cpp | 15 +++++++++++++++ libraries/physics/src/CharacterController.h | 1 + 2 files changed, 16 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 40b9076a6a..09c6b5599f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -232,6 +232,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _isOnGround = false; _isJumping = false; _isHovering = true; + _jumpToHoverStart = 0; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; _pendingFlags = 0; @@ -678,6 +679,20 @@ bool CharacterController::canJump() const { void CharacterController::jump() { _pendingFlags |= PENDING_FLAG_JUMP; + + // check for case where user is holding down "jump" key... + // we'll eventually tansition to "hover" + if (!_isHovering) { + if (!_isJumping) { + _jumpToHoverStart = usecTimestampNow(); + } else { + quint64 now = usecTimestampNow(); + const quint64 JUMP_TO_HOVER_PERIOD = USECS_PER_SECOND; + if (now - _jumpToHoverStart < JUMP_TO_HOVER_PERIOD) { + _isHovering = true; + } + } + } } void CharacterController::setGravity(btScalar gravity) { diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 6751277c83..eeaa5836dd 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -85,6 +85,7 @@ protected: bool _isOnGround; bool _isJumping; bool _isHovering; + quint64 _jumpToHoverStart; btScalar _velocityTimeInterval; btScalar _stepDt; uint32_t _pendingFlags; From 1ee797efa4f1258b4567b81a6b7ec8b90fed03ac Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 27 Mar 2015 13:59:52 -0700 Subject: [PATCH 16/19] Fix authorization of API calls in XMLHttpRequest --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 8755527860..f408e2001d 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -207,7 +207,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(33) == "https://metaverse.highfidelity.com/api/") { + if (url.toLower().left(39) == "https://metaverse.highfidelity.com/api/") { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) { From 0fd17b3303865a587b2f251ec20594e03eb59040 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Fri, 27 Mar 2015 14:40:16 -0700 Subject: [PATCH 17/19] editEntities.js --> edit.js --- interface/resources/html/interface-welcome.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/html/interface-welcome.html b/interface/resources/html/interface-welcome.html index ed905eb392..26ae6ff5c0 100644 --- a/interface/resources/html/interface-welcome.html +++ b/interface/resources/html/interface-welcome.html @@ -138,7 +138,7 @@

Import models

- Use the editEntitles.js script to
+ Use the edit.js script to
add FBX models in-world. You
can use grids and fine tune
placement-related parameters
From 1821683453f8bab2f83850aa71154ba062af0c1c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 27 Mar 2015 14:44:35 -0700 Subject: [PATCH 18/19] fix bug in default avatars --- libraries/avatars/src/AvatarData.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a2feb98798..20366e590f 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -365,8 +365,8 @@ protected: HeadData* _headData; HandData* _handData; - QUrl _faceModelURL = DEFAULT_HEAD_MODEL_URL; - QUrl _skeletonModelURL = DEFAULT_BODY_MODEL_URL; + QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit + QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit QVector _attachmentData; QString _displayName; From c45676041941ae3e2c6985f10f895a3df5155ff6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 27 Mar 2015 15:24:55 -0700 Subject: [PATCH 19/19] Extract API URL into a const --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index f408e2001d..3054472a3c 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -22,6 +22,8 @@ #include "XMLHttpRequestClass.h" #include "ScriptEngine.h" +const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/"; + Q_DECLARE_METATYPE(QByteArray*) XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : @@ -207,7 +209,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(39) == "https://metaverse.highfidelity.com/api/") { + if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) {