diff --git a/assignment-client/src/AssignmentDynamic.cpp b/assignment-client/src/AssignmentDynamic.cpp index 026bc120bb..7adbd55c39 100644 --- a/assignment-client/src/AssignmentDynamic.cpp +++ b/assignment-client/src/AssignmentDynamic.cpp @@ -53,31 +53,3 @@ QVariantMap AssignmentDynamic::getArguments() { qDebug() << "UNEXPECTED -- AssignmentDynamic::getArguments called in assignment-client."; return QVariantMap(); } - -glm::vec3 AssignmentDynamic::getPosition() { - qDebug() << "UNEXPECTED -- AssignmentDynamic::getPosition called in assignment-client."; - return glm::vec3(0.0f); -} - -glm::quat AssignmentDynamic::getRotation() { - qDebug() << "UNEXPECTED -- AssignmentDynamic::getRotation called in assignment-client."; - return glm::quat(); -} - -glm::vec3 AssignmentDynamic::getLinearVelocity() { - qDebug() << "UNEXPECTED -- AssignmentDynamic::getLinearVelocity called in assignment-client."; - return glm::vec3(0.0f); -} - -void AssignmentDynamic::setLinearVelocity(glm::vec3 linearVelocity) { - qDebug() << "UNEXPECTED -- AssignmentDynamic::setLinearVelocity called in assignment-client."; -} - -glm::vec3 AssignmentDynamic::getAngularVelocity() { - qDebug() << "UNEXPECTED -- AssignmentDynamic::getAngularVelocity called in assignment-client."; - return glm::vec3(0.0f); -} - -void AssignmentDynamic::setAngularVelocity(glm::vec3 angularVelocity) { - qDebug() << "UNEXPECTED -- AssignmentDynamic::setAngularVelocity called in assignment-client."; -} diff --git a/assignment-client/src/AssignmentDynamic.h b/assignment-client/src/AssignmentDynamic.h index 604c418c13..d0fd72533f 100644 --- a/assignment-client/src/AssignmentDynamic.h +++ b/assignment-client/src/AssignmentDynamic.h @@ -39,13 +39,6 @@ private: QByteArray _data; protected: - virtual glm::vec3 getPosition() override; - virtual glm::quat getRotation() override; - virtual glm::vec3 getLinearVelocity() override; - virtual void setLinearVelocity(glm::vec3 linearVelocity) override; - virtual glm::vec3 getAngularVelocity() override; - virtual void setAngularVelocity(glm::vec3 angularVelocity) override; - bool _active; EntityItemWeakPointer _ownerEntity; }; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 1449005246..76519466b5 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -145,7 +145,7 @@ private: std::unordered_map> _lastOtherAvatarSentJoints; uint64_t _identityChangeTimestamp; - bool _avatarSessionDisplayNameMustChange{ false }; + bool _avatarSessionDisplayNameMustChange{ true }; int _numAvatarsSentLastFrame = 0; int _numFramesSinceAdjustment = 0; diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index eb8403634a..b18599d8a9 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -56,43 +56,64 @@ "jointName": "Hips", "positionVar": "hipsPosition", "rotationVar": "hipsRotation", - "typeVar": "hipsType" + "typeVar": "hipsType", + "weightVar": "hipsWeight", + "weight": 1.0, + "flexCoefficients": [1] }, { "jointName": "RightHand", "positionVar": "rightHandPosition", "rotationVar": "rightHandRotation", - "typeVar": "rightHandType" + "typeVar": "rightHandType", + "weightVar": "rightHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.25, 0.1, 0.05, 0.01, 0.0, 0.0] }, { "jointName": "LeftHand", "positionVar": "leftHandPosition", "rotationVar": "leftHandRotation", - "typeVar": "leftHandType" + "typeVar": "leftHandType", + "weightVar": "leftHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.25, 0.1, 0.05, 0.01, 0.0, 0.0] }, { "jointName": "RightFoot", "positionVar": "rightFootPosition", "rotationVar": "rightFootRotation", - "typeVar": "rightFootType" + "typeVar": "rightFootType", + "weightVar": "rightFootWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.45, 0.45] }, { "jointName": "LeftFoot", "positionVar": "leftFootPosition", "rotationVar": "leftFootRotation", - "typeVar": "leftFootType" + "typeVar": "leftFootType", + "weightVar": "leftFootWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.45, 0.45] }, { "jointName": "Spine2", "positionVar": "spine2Position", "rotationVar": "spine2Rotation", - "typeVar": "spine2Type" + "typeVar": "spine2Type", + "weightVar": "spine2Weight", + "weight": 1.0, + "flexCoefficients": [0.45, 0.45] }, { "jointName": "Head", "positionVar": "headPosition", "rotationVar": "headRotation", - "typeVar": "headType" + "typeVar": "headType", + "weightVar": "headWeight", + "weight": 4.0, + "flexCoefficients": [1, 0.5, 0.5, 0.5, 0.5] } ] }, diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 0927d46fdf..a86defdfd7 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -132,62 +132,16 @@ Item { color: hifi.colors.textFieldLightBackground border.color: hifi.colors.blueHighlight border.width: 0 - TextInput { - id: myDisplayNameText - // Properties - text: thisNameCard.displayName - maximumLength: 256 - clip: true - // Size - width: parent.width - height: parent.height - // Anchors - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: 10 - anchors.right: parent.right - anchors.rightMargin: editGlyph.width + editGlyph.anchors.rightMargin - // Style - color: hifi.colors.darkGray - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - font.family: firaSansSemiBold.name - font.pixelSize: displayNameTextPixelSize - selectionColor: hifi.colors.blueAccent - selectedTextColor: "black" - // Text Positioning - verticalAlignment: TextInput.AlignVCenter - horizontalAlignment: TextInput.AlignLeft - autoScroll: false; - // Signals - onEditingFinished: { - if (MyAvatar.displayName !== text) { - MyAvatar.displayName = text; - UserActivityLogger.palAction("display_name_change", text); - } - cursorPosition = 0 - focus = false - myDisplayName.border.width = 0 - color = hifi.colors.darkGray - pal.currentlyEditingDisplayName = false - autoScroll = false; - } - } MouseArea { anchors.fill: parent hoverEnabled: true onClicked: { - myDisplayName.border.width = 1 - myDisplayNameText.focus ? myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX, mouseY, TextInput.CursorOnCharacter) : myDisplayNameText.selectAll(); - myDisplayNameText.focus = true - myDisplayNameText.color = "black" - pal.currentlyEditingDisplayName = true - myDisplayNameText.autoScroll = true; + myDisplayNameText.focus = true; + myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX - myDisplayNameText.anchors.leftMargin, mouseY, TextInput.CursorOnCharacter); } onDoubleClicked: { myDisplayNameText.selectAll(); myDisplayNameText.focus = true; - pal.currentlyEditingDisplayName = true - myDisplayNameText.autoScroll = true; } onEntered: myDisplayName.color = hifi.colors.lightGrayText; onExited: myDisplayName.color = hifi.colors.textFieldLightBackground; @@ -207,6 +161,54 @@ Item { verticalAlignment: Text.AlignVCenter color: hifi.colors.baseGray } + TextInput { + id: myDisplayNameText + // Properties + text: thisNameCard.displayName + maximumLength: 256 + clip: true + // Size + width: parent.width + height: parent.height + // Anchors + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.right: parent.right + anchors.rightMargin: editGlyph.width + editGlyph.anchors.rightMargin + // Style + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pixelSize: displayNameTextPixelSize + selectionColor: hifi.colors.blueAccent + selectedTextColor: "black" + // Text Positioning + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignLeft + autoScroll: false; + // Signals + onEditingFinished: { + if (MyAvatar.displayName !== text) { + MyAvatar.displayName = text; + UserActivityLogger.palAction("display_name_change", text); + } + focus = false; + } + onFocusChanged: { + if (focus === true) { + myDisplayName.border.width = 1 + color = "black" + autoScroll = true; + pal.currentlyEditingDisplayName = true + } else { + myDisplayName.border.width = 0 + color: hifi.colors.darkGray + cursorPosition = 0; + autoScroll = false; + pal.currentlyEditingDisplayName = false + } + } + } } // DisplayName container for others' cards Item { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1adb2f7c57..170a961bed 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5258,9 +5258,8 @@ void Application::nodeActivated(SharedNodePointer node) { } if (node->getType() == NodeType::AvatarMixer) { - // new avatar mixer, send off our identity packet right away + // new avatar mixer, send off our identity packet on next update loop getMyAvatar()->markIdentityDataChanged(); - getMyAvatar()->sendIdentityPacket(); getMyAvatar()->resetLastSent(); } } diff --git a/interface/src/InterfaceDynamicFactory.cpp b/interface/src/InterfaceDynamicFactory.cpp index 49edaae90f..e51f63d01b 100644 --- a/interface/src/InterfaceDynamicFactory.cpp +++ b/interface/src/InterfaceDynamicFactory.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -33,7 +32,7 @@ EntityDynamicPointer interfaceDynamicFactory(EntityDynamicType type, const QUuid case DYNAMIC_TYPE_OFFSET: return std::make_shared(id, ownerEntity); case DYNAMIC_TYPE_SPRING: - return std::make_shared(id, ownerEntity); + qDebug() << "The 'spring' Action is deprecated. Replacing with 'tractor' Action."; case DYNAMIC_TYPE_TRACTOR: return std::make_shared(id, ownerEntity); case DYNAMIC_TYPE_HOLD: diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 1306ce03ea..d47e4cfd10 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -189,6 +189,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); if (shape) { AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); + motionState->setMass(avatar->computeMass()); avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); }); _motionStates.insert(avatar.get(), motionState); _motionStatesToAddToPhysics.insert(motionState); diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 0305634400..91c83afcbd 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -19,9 +19,6 @@ AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { assert(_avatar); _type = MOTIONSTATE_TYPE_AVATAR; - if (_shape) { - _mass = 100.0f; // HACK - } } AvatarMotionState::~AvatarMotionState() { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 28d77c6964..9cf8e7747b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -239,6 +239,7 @@ MyAvatar::MyAvatar(QThread* thread, RigPointer rig) : }); connect(rig.get(), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete())); + _characterController.setDensity(_density); } MyAvatar::~MyAvatar() { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e664ab989d..394d6b2ac7 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -125,7 +125,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose) Q_PROPERTY(float energy READ getEnergy WRITE setEnergy) - Q_PROPERTY(float isAway READ getIsAway WRITE setAway) + Q_PROPERTY(bool isAway READ getIsAway WRITE setAway) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled) diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 0cdbc77626..3d98a0e604 100755 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -49,12 +49,9 @@ void MyCharacterController::updateShapeIfNecessary() { // create RigidBody if it doesn't exist if (!_rigidBody) { btCollisionShape* shape = computeShape(); - - // HACK: use some simple mass property defaults for now - const btScalar DEFAULT_AVATAR_MASS = 100.0f; - const btVector3 DEFAULT_AVATAR_INERTIA_TENSOR(30.0f, 8.0f, 30.0f); - - _rigidBody = new btRigidBody(DEFAULT_AVATAR_MASS, nullptr, shape, DEFAULT_AVATAR_INERTIA_TENSOR); + btScalar mass = 1.0f; + btVector3 inertia(1.0f, 1.0f, 1.0f); + _rigidBody = new btRigidBody(mass, nullptr, shape, inertia); } else { btCollisionShape* shape = _rigidBody->getCollisionShape(); if (shape) { @@ -63,6 +60,7 @@ void MyCharacterController::updateShapeIfNecessary() { shape = computeShape(); _rigidBody->setCollisionShape(shape); } + updateMassProperties(); _rigidBody->setSleepingThresholds(0.0f, 0.0f); _rigidBody->setAngularFactor(0.0f); @@ -331,3 +329,23 @@ void MyCharacterController::initRayShotgun(const btCollisionWorld* world) { } } } + +void MyCharacterController::updateMassProperties() { + assert(_rigidBody); + // the inertia tensor of a capsule with Y-axis of symmetry, radius R and cylinder height H is: + // Ix = density * (volumeCylinder * (H^2 / 12 + R^2 / 4) + volumeSphere * (2R^2 / 5 + H^2 / 2 + 3HR / 8)) + // Iy = density * (volumeCylinder * (R^2 / 2) + volumeSphere * (2R^2 / 5) + btScalar r2 = _radius * _radius; + btScalar h2 = 4.0f * _halfHeight * _halfHeight; + btScalar volumeSphere = 4.0f * PI * r2 * _radius / 3.0f; + btScalar volumeCylinder = TWO_PI * r2 * 2.0f * _halfHeight; + btScalar cylinderXZ = volumeCylinder * (h2 / 12.0f + r2 / 4.0f); + btScalar capsXZ = volumeSphere * (2.0f * r2 / 5.0f + h2 / 2.0f + 6.0f * _halfHeight * _radius / 8.0f); + btScalar inertiaXZ = _density * (cylinderXZ + capsXZ); + btScalar inertiaY = _density * ((volumeCylinder * r2 / 2.0f) + volumeSphere * (2.0f * r2 / 5.0f)); + btVector3 inertia(inertiaXZ, inertiaY, inertiaXZ); + + btScalar mass = _density * (volumeCylinder + volumeSphere); + + _rigidBody->setMassProps(mass, inertia); +} diff --git a/interface/src/avatar/MyCharacterController.h b/interface/src/avatar/MyCharacterController.h index 6b38736352..fd9caface2 100644 --- a/interface/src/avatar/MyCharacterController.h +++ b/interface/src/avatar/MyCharacterController.h @@ -40,8 +40,11 @@ public: /// return true if RayShotgun hits anything bool testRayShotgun(const glm::vec3& position, const glm::vec3& step, RayShotgunResult& result); + void setDensity(btScalar density) { _density = density; } + protected: void initRayShotgun(const btCollisionWorld* world); + void updateMassProperties() override; private: btConvexHullShape* computeShape() const; @@ -52,6 +55,7 @@ protected: // shotgun scan data btAlignedObjectArray _topPoints; btAlignedObjectArray _bottomPoints; + btScalar _density { 1.0f }; }; #endif // hifi_MyCharacterController_h diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 5e6927afcb..4471f11857 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -21,6 +21,39 @@ #include "SwingTwistConstraint.h" #include "AnimationLogging.h" +AnimInverseKinematics::IKTargetVar::IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, + const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector& flexCoefficientsIn) : + jointName(jointNameIn), + positionVar(positionVarIn), + rotationVar(rotationVarIn), + typeVar(typeVarIn), + weightVar(weightVarIn), + weight(weightIn), + numFlexCoefficients(flexCoefficientsIn.size()), + jointIndex(-1) +{ + numFlexCoefficients = std::min(numFlexCoefficients, (size_t)MAX_FLEX_COEFFICIENTS); + for (size_t i = 0; i < numFlexCoefficients; i++) { + flexCoefficients[i] = flexCoefficientsIn[i]; + } +} + +AnimInverseKinematics::IKTargetVar::IKTargetVar(const IKTargetVar& orig) : + jointName(orig.jointName), + positionVar(orig.positionVar), + rotationVar(orig.rotationVar), + typeVar(orig.typeVar), + weightVar(orig.weightVar), + weight(orig.weight), + numFlexCoefficients(orig.numFlexCoefficients), + jointIndex(orig.jointIndex) +{ + numFlexCoefficients = std::min(numFlexCoefficients, (size_t)MAX_FLEX_COEFFICIENTS); + for (size_t i = 0; i < numFlexCoefficients; i++) { + flexCoefficients[i] = orig.flexCoefficients[i]; + } +} + AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimNode::Type::InverseKinematics, id) { } @@ -60,26 +93,22 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con } } -void AnimInverseKinematics::setTargetVars( - const QString& jointName, - const QString& positionVar, - const QString& rotationVar, - const QString& typeVar) { +void AnimInverseKinematics::setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, + const QString& typeVar, const QString& weightVar, float weight, const std::vector& flexCoefficients) { + IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients); + // if there are dups, last one wins. bool found = false; - for (auto& targetVar: _targetVarVec) { - if (targetVar.jointName == jointName) { - // update existing targetVar - targetVar.positionVar = positionVar; - targetVar.rotationVar = rotationVar; - targetVar.typeVar = typeVar; + for (auto& targetVarIter: _targetVarVec) { + if (targetVarIter.jointName == jointName) { + targetVarIter = targetVar; found = true; break; } } if (!found) { // create a new entry - _targetVarVec.push_back(IKTargetVar(jointName, positionVar, rotationVar, typeVar)); + _targetVarVec.push_back(targetVar); } } @@ -107,10 +136,15 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot()); glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans()); + float weight = animVars.lookup(targetVar.weightVar, targetVar.weight); target.setPose(rotation, translation); target.setIndex(targetVar.jointIndex); + target.setWeight(weight); + target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients); + targets.push_back(target); + if (targetVar.jointIndex > _maxTargetIndex) { _maxTargetIndex = targetVar.jointIndex; } @@ -271,6 +305,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe // cache tip absolute position glm::vec3 tipPosition = absolutePoses[tipIndex].trans(); + size_t chainDepth = 1; + // descend toward root, pivoting each joint to get tip closer to target position while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) { // compute the two lines that should be aligned @@ -312,9 +348,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe float angle = acosf(cosAngle); const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; if (angle > MIN_ADJUSTMENT_ANGLE) { - // reduce angle by a fraction (for stability) - const float STABILITY_FRACTION = 0.5f; - angle *= STABILITY_FRACTION; + // reduce angle by a flexCoefficient + angle *= target.getFlexCoefficient(chainDepth); deltaRotation = glm::angleAxis(angle, axis); // The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's @@ -385,6 +420,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe pivotIndex = pivotsParentIndex; pivotsParentIndex = _skeleton->getParentIndex(pivotIndex); + + chainDepth++; } return lowestMovedIndex; } @@ -806,7 +843,7 @@ void AnimInverseKinematics::initConstraints() { stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST); std::vector minDots; - const float MAX_SHOULDER_SWING = PI / 20.0f; + const float MAX_SHOULDER_SWING = PI / 16.0f; minDots.push_back(cosf(MAX_SHOULDER_SWING)); stConstraint->setSwingLimits(minDots); diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index f73ed95935..74face6d0b 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -32,7 +32,8 @@ public: void loadPoses(const AnimPoseVec& poses); void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; - void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, const QString& typeVar); + void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, + const QString& typeVar, const QString& weightVar, float weight, const std::vector& flexCoefficients); virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimNode::Triggers& triggersOut) override; virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override; @@ -77,22 +78,20 @@ protected: AnimInverseKinematics(const AnimInverseKinematics&) = delete; AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete; + enum FlexCoefficients { MAX_FLEX_COEFFICIENTS = 10 }; struct IKTargetVar { - IKTargetVar(const QString& jointNameIn, - const QString& positionVarIn, - const QString& rotationVarIn, - const QString& typeVarIn) : - positionVar(positionVarIn), - rotationVar(rotationVarIn), - typeVar(typeVarIn), - jointName(jointNameIn), - jointIndex(-1) - {} + IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, + const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector& flexCoefficientsIn); + IKTargetVar(const IKTargetVar& orig); + QString jointName; QString positionVar; QString rotationVar; QString typeVar; - QString jointName; + QString weightVar; + float weight; + float flexCoefficients[MAX_FLEX_COEFFICIENTS]; + size_t numFlexCoefficients; int jointIndex; // cached joint index }; diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 6bc7342d7f..44ed8c6053 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -173,6 +173,13 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) { } \ float NAME = (float)NAME##_VAL.toDouble() +#define READ_OPTIONAL_FLOAT(NAME, JSON_OBJ, DEFAULT) \ + auto NAME##_VAL = JSON_OBJ.value(#NAME); \ + float NAME = (float)DEFAULT; \ + if (NAME##_VAL.isDouble()) { \ + NAME = (float)NAME##_VAL.toDouble(); \ + } \ + do {} while (0) static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUrl) { auto idVal = jsonObj.value("id"); @@ -470,8 +477,21 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS READ_STRING(positionVar, targetObj, id, jsonUrl, nullptr); READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr); READ_OPTIONAL_STRING(typeVar, targetObj); + READ_OPTIONAL_STRING(weightVar, targetObj); + READ_OPTIONAL_FLOAT(weight, targetObj, 1.0f); - node->setTargetVars(jointName, positionVar, rotationVar, typeVar); + auto flexCoefficientsValue = targetObj.value("flexCoefficients"); + if (!flexCoefficientsValue.isArray()) { + qCCritical(animation) << "AnimNodeLoader, bad or missing flexCoefficients array in \"targets\", id =" << id << ", url =" << jsonUrl.toDisplayString(); + return nullptr; + } + auto flexCoefficientsArray = flexCoefficientsValue.toArray(); + std::vector flexCoefficients; + for (const auto& value : flexCoefficientsArray) { + flexCoefficients.push_back((float)value.toDouble()); + } + + node->setTargetVars(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients); }; READ_OPTIONAL_STRING(solutionSource, jsonObj); diff --git a/libraries/animation/src/IKTarget.cpp b/libraries/animation/src/IKTarget.cpp index fa4030ca6d..c67c0621c3 100644 --- a/libraries/animation/src/IKTarget.cpp +++ b/libraries/animation/src/IKTarget.cpp @@ -14,6 +14,23 @@ void IKTarget::setPose(const glm::quat& rotation, const glm::vec3& translation) _pose.trans() = translation; } +void IKTarget::setFlexCoefficients(size_t numFlexCoefficientsIn, const float* flexCoefficientsIn) { + _numFlexCoefficients = std::min(numFlexCoefficientsIn, (size_t)MAX_FLEX_COEFFICIENTS); + for (size_t i = 0; i < _numFlexCoefficients; i++) { + _flexCoefficients[i] = flexCoefficientsIn[i]; + } +} + +float IKTarget::getFlexCoefficient(size_t chainDepth) const { + const float DEFAULT_FLEX_COEFFICIENT = 0.5f; + + if (chainDepth < _numFlexCoefficients) { + return _flexCoefficients[chainDepth]; + } else { + return DEFAULT_FLEX_COEFFICIENT; + } +} + void IKTarget::setType(int type) { switch (type) { case (int)Type::RotationAndPosition: diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index acb01d9861..4f464c103c 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -35,15 +35,21 @@ public: void setPose(const glm::quat& rotation, const glm::vec3& translation); void setIndex(int index) { _index = index; } void setType(int); + void setFlexCoefficients(size_t numFlexCoefficientsIn, const float* flexCoefficientsIn); + float getFlexCoefficient(size_t chainDepth) const; - // HACK: give HmdHead targets more "weight" during IK algorithm - float getWeight() const { return _type == Type::HmdHead ? HACK_HMD_TARGET_WEIGHT : 1.0f; } + void setWeight(float weight) { _weight = weight; } + float getWeight() const { return _weight; } + + enum FlexCoefficients { MAX_FLEX_COEFFICIENTS = 10 }; private: AnimPose _pose; int _index{-1}; Type _type{Type::RotationAndPosition}; - + float _weight; + float _flexCoefficients[MAX_FLEX_COEFFICIENTS]; + size_t _numFlexCoefficients; }; #endif // hifi_IKTarget_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index cb5aebe930..23db05eb73 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1088,10 +1088,12 @@ void Rig::updateHeadAnimVars(const HeadParameters& params) { // Since there is an explicit hips ik target, switch the head to use the more generic RotationAndPosition IK chain type. // this will allow the spine to bend more, ensuring that it can reach the head target position. _animVars.set("headType", (int)IKTarget::Type::RotationAndPosition); + _animVars.unset("headWeight"); // use the default weight for this target. } else { // When there is no hips IK target, use the HmdHead IK chain type. This will make the spine very stiff, // but because the IK _hipsOffset is enabled, the hips will naturally follow underneath the head. _animVars.set("headType", (int)IKTarget::Type::HmdHead); + _animVars.set("headWeight", 8.0f); } } else { _animVars.unset("headPosition"); @@ -1400,22 +1402,24 @@ void Rig::computeAvatarBoundingCapsule( AnimInverseKinematics ikNode("boundingShape"); ikNode.setSkeleton(_animSkeleton); + + // AJT: FIX ME!!!!! ensure that empty weights vector does something reasonable.... ikNode.setTargetVars("LeftHand", "leftHandPosition", "leftHandRotation", - "leftHandType"); + "leftHandType", "leftHandWeight", 1.0f, {}); ikNode.setTargetVars("RightHand", "rightHandPosition", "rightHandRotation", - "rightHandType"); + "rightHandType", "rightHandWeight", 1.0f, {}); ikNode.setTargetVars("LeftFoot", "leftFootPosition", "leftFootRotation", - "leftFootType"); + "leftFootType", "leftFootWeight", 1.0f, {}); ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation", - "rightFootType"); + "rightFootType", "rightFootWeight", 1.0f, {}); AnimPose geometryToRig = _modelOffset * _geometryOffset; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index a04a57bde1..1968a731a4 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1265,6 +1265,17 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) { radius = halfExtents.x; } +float Avatar::computeMass() { + float radius; + glm::vec3 start, end; + getCapsule(start, end, radius); + // NOTE: + // volumeOfCapsule = volumeOfCylinder + volumeOfSphere + // volumeOfCapsule = (2PI * R^2 * H) + (4PI * R^3 / 3) + // volumeOfCapsule = 2PI * R^2 * (H + 2R/3) + return _density * TWO_PI * radius * radius * (glm::length(end - start) + 2.0f * radius / 3.0f); +} + // virtual void Avatar::rebuildCollisionShape() { addPhysicsFlags(Simulation::DIRTY_SHAPE); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 1f623dde71..ae24caca29 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -195,6 +195,7 @@ public: virtual void computeShapeInfo(ShapeInfo& shapeInfo); void getCapsule(glm::vec3& start, glm::vec3& end, float& radius); + float computeMass(); using SpatiallyNestable::setPosition; virtual void setPosition(const glm::vec3& position) override; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index eebb9c2633..1f30e69820 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -52,6 +52,7 @@ const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData"; static const int TRANSLATION_COMPRESSION_RADIX = 12; static const int SENSOR_TO_WORLD_SCALE_RADIX = 10; static const float AUDIO_LOUDNESS_SCALE = 1024.0f; +static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water #define ASSERT(COND) do { if (!(COND)) { abort(); } } while(0) @@ -65,7 +66,8 @@ AvatarData::AvatarData() : _headData(NULL), _errorLogExpiry(0), _owningAvatarMixer(), - _targetVelocity(0.0f) + _targetVelocity(0.0f), + _density(DEFAULT_AVATAR_DENSITY) { setBodyPitch(0.0f); setBodyYaw(-90.0f); @@ -1588,8 +1590,6 @@ void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; _sessionDisplayName = ""; - sendIdentityPacket(); - qCDebug(avatars) << "Changing display name for avatar to" << displayName; markIdentityDataChanged(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index f248874943..ebd832537c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -629,6 +629,8 @@ public: _identityUpdatedAt = usecTimestampNow(); } + float getDensity() const { return _density; } + signals: void displayNameChanged(); @@ -785,6 +787,7 @@ protected: bool _identityDataChanged { false }; quint64 _identityUpdatedAt { 0 }; + float _density; private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); diff --git a/libraries/entities/src/EntityDynamicInterface.cpp b/libraries/entities/src/EntityDynamicInterface.cpp index 822ac1c9d6..f424c02e6e 100644 --- a/libraries/entities/src/EntityDynamicInterface.cpp +++ b/libraries/entities/src/EntityDynamicInterface.cpp @@ -43,14 +43,14 @@ | | +--------------------+ +-----------------------+ | | | | - | ObjectActionSpring | | ObjectConstraintHinge | + | ObjectActionTractor| | ObjectConstraintHinge | | (physics) | | (physics) | +--------------------+ +-----------------------+ A dynamic is a callback which is registered with bullet. A dynamic is called-back every physics -simulation step and can do whatever it wants with the various datastructures it has available. An +simulation step and can do whatever it wants with the various datastructures it has available. A dynamic, for example, can pull an EntityItem toward a point as if that EntityItem were connected to that point by a spring. @@ -60,7 +60,7 @@ script or when receiving information via an EntityTree data-stream (either over svo file). In the interface, if an EntityItem has dynamics, this EntityItem will have pointers to ObjectDynamic -subclass (like ObjectDynamicSpring) instantiations. Code in the entities library affects a dynamic-object +subclass (like ObjectDynamicTractor) instantiations. Code in the entities library affects a dynamic-object via the EntityDynamicInterface (which knows nothing about bullet). When the ObjectDynamic subclass instance is created, it is registered as a dynamic with bullet. Bullet will call into code in this instance with the btDynamicInterface every physics-simulation step. @@ -75,11 +75,11 @@ right now the AssignmentDynamic class is a place-holder. The dynamic-objects are instantiated by singleton (dependecy) subclasses of EntityDynamicFactoryInterface. In the interface, the subclass is an InterfaceDynamicFactory and it will produce things like -ObjectDynamicSpring. In an entity-server the subclass is an AssignmentDynamicFactory and it always +ObjectDynamicTractor. In an entity-server the subclass is an AssignmentDynamicFactory and it always produces AssignmentDynamics. Depending on the dynamic's type, it will have various arguments. When a script changes an argument of an -dynamic, the argument-holding member-variables of ObjectDynamicSpring (in this example) are updated and +dynamic, the argument-holding member-variables of ObjectDynamicTractor (in this example) are updated and also serialized into _dynamicData in the EntityItem. Each subclass of ObjectDynamic knows how to serialize and deserialize its own arguments. _dynamicData is what gets sent over the wire or saved in an svo file. When a packet-reader receives data for _dynamicData, it will save it in the EntityItem; this causes the @@ -103,7 +103,7 @@ EntityDynamicType EntityDynamicInterface::dynamicTypeFromString(QString dynamicT return DYNAMIC_TYPE_OFFSET; } if (normalizedDynamicTypeString == "spring") { - return DYNAMIC_TYPE_SPRING; + return DYNAMIC_TYPE_TRACTOR; } if (normalizedDynamicTypeString == "tractor") { return DYNAMIC_TYPE_TRACTOR; @@ -142,7 +142,6 @@ QString EntityDynamicInterface::dynamicTypeToString(EntityDynamicType dynamicTyp case DYNAMIC_TYPE_OFFSET: return "offset"; case DYNAMIC_TYPE_SPRING: - return "spring"; case DYNAMIC_TYPE_TRACTOR: return "tractor"; case DYNAMIC_TYPE_HOLD: diff --git a/libraries/entities/src/EntityDynamicInterface.h b/libraries/entities/src/EntityDynamicInterface.h index b27e600660..40e39eecf1 100644 --- a/libraries/entities/src/EntityDynamicInterface.h +++ b/libraries/entities/src/EntityDynamicInterface.h @@ -94,15 +94,6 @@ public: QString argumentName, bool& ok, bool required = true); protected: - virtual glm::vec3 getPosition() = 0; - // virtual void setPosition(glm::vec3 position) = 0; - virtual glm::quat getRotation() = 0; - // virtual void setRotation(glm::quat rotation) = 0; - virtual glm::vec3 getLinearVelocity() = 0; - virtual void setLinearVelocity(glm::vec3 linearVelocity) = 0; - virtual glm::vec3 getAngularVelocity() = 0; - virtual void setAngularVelocity(glm::vec3 angularVelocity) = 0; - QUuid _id; EntityDynamicType _type; bool _active { false }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a6de541958..14122594fe 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1691,14 +1691,20 @@ void EntityItem::updateVelocity(const glm::vec3& value) { setLocalVelocity(Vectors::ZERO); } } else { - const float MIN_LINEAR_SPEED = 0.001f; - if (glm::length(value) < MIN_LINEAR_SPEED) { - velocity = ENTITY_ITEM_ZERO_VEC3; - } else { - velocity = value; + float speed = glm::length(value); + if (!glm::isnan(speed)) { + const float MIN_LINEAR_SPEED = 0.001f; + const float MAX_LINEAR_SPEED = 270.0f; // 3m per step at 90Hz + if (speed < MIN_LINEAR_SPEED) { + velocity = ENTITY_ITEM_ZERO_VEC3; + } else if (speed > MAX_LINEAR_SPEED) { + velocity = (MAX_LINEAR_SPEED / speed) * value; + } else { + velocity = value; + } + setLocalVelocity(velocity); + _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } - setLocalVelocity(velocity); - _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } } } @@ -1723,8 +1729,16 @@ void EntityItem::updateGravity(const glm::vec3& value) { if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { _gravity = Vectors::ZERO; } else { - _gravity = value; - _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; + float magnitude = glm::length(value); + if (!glm::isnan(magnitude)) { + const float MAX_ACCELERATION_OF_GRAVITY = 10.0f * 9.8f; // 10g + if (magnitude > MAX_ACCELERATION_OF_GRAVITY) { + _gravity = (MAX_ACCELERATION_OF_GRAVITY / magnitude) * value; + } else { + _gravity = value; + } + _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; + } } } } @@ -1735,14 +1749,20 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { setLocalAngularVelocity(Vectors::ZERO); } else { - const float MIN_ANGULAR_SPEED = 0.0002f; - if (glm::length(value) < MIN_ANGULAR_SPEED) { - angularVelocity = ENTITY_ITEM_ZERO_VEC3; - } else { - angularVelocity = value; + float speed = glm::length(value); + if (!glm::isnan(speed)) { + const float MIN_ANGULAR_SPEED = 0.0002f; + const float MAX_ANGULAR_SPEED = 9.0f * TWO_PI; // 1/10 rotation per step at 90Hz + if (speed < MIN_ANGULAR_SPEED) { + angularVelocity = ENTITY_ITEM_ZERO_VEC3; + } else if (speed > MAX_ANGULAR_SPEED) { + angularVelocity = (MAX_ANGULAR_SPEED / speed) * value; + } else { + angularVelocity = value; + } + setLocalAngularVelocity(angularVelocity); + _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY; } - setLocalAngularVelocity(angularVelocity); - _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY; } } } diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 524fd0a88c..92ead5f616 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -210,7 +210,16 @@ PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { auto file = maybeOpenFile(); - result = file->createView(faceSize, faceOffset)->toMemoryStorage(); + if (file) { + auto storageView = file->createView(faceSize, faceOffset); + if (storageView) { + return storageView->toMemoryStorage(); + } else { + qWarning() << "Failed to get a valid storageView for faceSize=" << faceSize << " faceOffset=" << faceOffset << "out of valid file " << QString::fromStdString(_filename); + } + } else { + qWarning() << "Failed to get a valid file out of maybeOpenFile " << QString::fromStdString(_filename); + } } return result; } @@ -238,8 +247,9 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor throw std::runtime_error("Invalid level"); } - if (storage->size() != _ktxDescriptor->images[level]._imageSize) { - qWarning() << "Invalid image size: " << storage->size() << ", expected: " << _ktxDescriptor->images[level]._imageSize + auto& imageDesc = _ktxDescriptor->images[level]; + if (storage->size() != imageDesc._imageSize) { + qWarning() << "Invalid image size: " << storage->size() << ", expected: " << imageDesc._imageSize << ", level: " << level << ", filename: " << QString::fromStdString(_filename); return; } @@ -258,7 +268,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor return; } - memcpy(imageData, storage->data(), _ktxDescriptor->images[level]._imageSize); + memcpy(imageData, storage->data(), storage->size()); _minMipLevelAvailable = level; if (_offsetToMinMipKV > 0) { auto minMipKeyData = file->mutableData() + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 656cf93f34..3f220abac3 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -38,15 +38,15 @@ UInt32 numberOfArrayElements UInt32 numberOfFaces UInt32 numberOfMipmapLevels UInt32 bytesOfKeyValueData - + for each keyValuePair that fits in bytesOfKeyValueData UInt32 keyAndValueByteSize Byte keyAndValue[keyAndValueByteSize] Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)] end - + for each mipmap_level in numberOfMipmapLevels* - UInt32 imageSize; + UInt32 imageSize; for each array_element in numberOfArrayElements* for each face in numberOfFaces for each z_slice in pixelDepth* @@ -269,7 +269,7 @@ namespace ktx { COMPRESSED_RG11_EAC = 0x9272, COMPRESSED_SIGNED_RG11_EAC = 0x9273, }; - + enum class GLBaseInternalFormat : uint32_t { // GL 4.4 Table 8.11 DEPTH_COMPONENT = 0x1902, @@ -419,9 +419,9 @@ namespace ktx { using FaceOffsets = std::vector; using FaceBytes = std::vector; + const uint32_t _numFaces; // This is the byte offset from the _start_ of the image region. For example, level 0 // will have a byte offset of 0. - const uint32_t _numFaces; const size_t _imageOffset; const uint32_t _imageSize; const uint32_t _faceSize; @@ -466,7 +466,7 @@ namespace ktx { class KTX; - // A KTX descriptor is a lightweight container for all the information about a serialized KTX file, but without the + // A KTX descriptor is a lightweight container for all the information about a serialized KTX file, but without the // actual image / face data available. struct KTXDescriptor { KTXDescriptor(const Header& header, const KeyValues& keyValues, const ImageDescriptors& imageDescriptors) : header(header), keyValues(keyValues), images(imageDescriptors) {} @@ -495,7 +495,7 @@ namespace ktx { // Instead of creating a full Copy of the src data in a KTX object, the write serialization can be performed with the // following two functions // size_t sizeNeeded = KTX::evalStorageSize(header, images); - // + // // //allocate a buffer of size "sizeNeeded" or map a file with enough capacity // Byte* destBytes = new Byte[sizeNeeded]; // diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index 50f63767a0..2dcd0ea583 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -127,6 +127,7 @@ namespace ktx { size_t KTX::writeWithoutImages(Byte* destBytes, size_t destByteSize, const Header& header, const ImageDescriptors& descriptors, const KeyValues& keyValues) { // Check again that we have enough destination capacity if (!destBytes || (destByteSize < evalStorageSize(header, descriptors, keyValues))) { + qWarning() << "Destination capacity is insufficient to write KTX without images"; return 0; } @@ -149,13 +150,15 @@ namespace ktx { for (size_t i = 0; i < descriptors.size(); ++i) { auto ptr = reinterpret_cast(currentDestPtr); *ptr = descriptors[i]._imageSize; - ptr++; + #ifdef DEBUG + ptr++; for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) { *(ptr + k) = 0xFFFFFFFF; } #endif - currentDestPtr += descriptors[i]._imageSize + sizeof(uint32_t); + currentDestPtr += sizeof(uint32_t); + currentDestPtr += descriptors[i]._imageSize; } return destByteSize; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 47fc62a9b5..8683d56b6b 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -501,12 +501,19 @@ void NetworkTexture::ktxMipRequestFinished() { if (texture) { texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); - _lowestKnownPopulatedMip = _textureSource->getGPUTexture()->minAvailableMipLevel(); + + if (texture->minAvailableMipLevel() <= _ktxMipLevelRangeInFlight.first) { + _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + _ktxResourceState = WAITING_FOR_MIP_REQUEST; + } else { + qWarning(networking) << "Failed to load mip: " << _url << ":" << _ktxMipLevelRangeInFlight.first; + _ktxResourceState = FAILED_TO_LOAD; + } } else { + _ktxResourceState = WAITING_FOR_MIP_REQUEST; qWarning(networking) << "Trying to update mips but texture is null"; } finishedLoading(true); - _ktxResourceState = WAITING_FOR_MIP_REQUEST; } else { finishedLoading(false); if (handleFailedRequest(_ktxMipRequest->getResult())) { diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index e4ff1b0b44..ee240a6aac 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -112,6 +112,9 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { _dynamicsWorld = nullptr; } int16_t collisionGroup = computeCollisionGroup(); + if (_rigidBody) { + updateMassProperties(); + } if (world && _rigidBody) { // add to new world _dynamicsWorld = world; @@ -127,7 +130,9 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { _ghost.setCollisionGroupAndMask(collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ collisionGroup)); _ghost.setCollisionWorld(_dynamicsWorld); _ghost.setRadiusAndHalfHeight(_radius, _halfHeight); - _ghost.setWorldTransform(_rigidBody->getWorldTransform()); + if (_rigidBody) { + _ghost.setWorldTransform(_rigidBody->getWorldTransform()); + } } if (_dynamicsWorld) { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 0a11fad0b7..6790495ff8 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -128,6 +128,7 @@ protected: void setState(State state); #endif + virtual void updateMassProperties() = 0; void updateGravity(); void updateUpAxis(const glm::quat& rotation); bool checkForSupport(btCollisionWorld* collisionWorld); diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp deleted file mode 100644 index 0014d4e914..0000000000 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// -// ObjectActionSpring.cpp -// libraries/physics/src -// -// Created by Seth Alves 2015-6-5 -// 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 "QVariantGLM.h" - -#include "ObjectActionSpring.h" - -#include "PhysicsLogging.h" - -const float SPRING_MAX_SPEED = 10.0f; -const float MAX_SPRING_TIMESCALE = 600.0f; // 10 min is a long time - -const uint16_t ObjectActionSpring::springVersion = 1; - - -ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) : - ObjectAction(DYNAMIC_TYPE_SPRING, id, ownerEntity), - _positionalTarget(glm::vec3(0.0f)), - _desiredPositionalTarget(glm::vec3(0.0f)), - _linearTimeScale(FLT_MAX), - _positionalTargetSet(true), - _rotationalTarget(glm::quat()), - _desiredRotationalTarget(glm::quat()), - _angularTimeScale(FLT_MAX), - _rotationalTargetSet(true) { - #if WANT_DEBUG - qCDebug(physics) << "ObjectActionSpring::ObjectActionSpring"; - #endif -} - -ObjectActionSpring::~ObjectActionSpring() { - #if WANT_DEBUG - qCDebug(physics) << "ObjectActionSpring::~ObjectActionSpring"; - #endif -} - -bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, - glm::vec3& linearVelocity, glm::vec3& angularVelocity, - float& linearTimeScale, float& angularTimeScale) { - SpatiallyNestablePointer other = getOther(); - withReadLock([&]{ - linearTimeScale = _linearTimeScale; - angularTimeScale = _angularTimeScale; - - if (!_otherID.isNull()) { - if (other) { - rotation = _desiredRotationalTarget * other->getRotation(); - position = other->getRotation() * _desiredPositionalTarget + other->getPosition(); - } else { - // we should have an "other" but can't find it, so disable the spring. - linearTimeScale = FLT_MAX; - angularTimeScale = FLT_MAX; - } - } else { - rotation = _desiredRotationalTarget; - position = _desiredPositionalTarget; - } - linearVelocity = glm::vec3(); - angularVelocity = glm::vec3(); - }); - return true; -} - -bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { - auto ownerEntity = _ownerEntity.lock(); - if (!ownerEntity) { - return false; - } - - glm::quat rotation; - glm::vec3 position; - glm::vec3 linearVelocity; - glm::vec3 angularVelocity; - - bool linearValid = false; - int linearSpringCount = 0; - bool angularValid = false; - int angularSpringCount = 0; - - QList springDerivedActions; - springDerivedActions.append(ownerEntity->getActionsOfType(DYNAMIC_TYPE_SPRING)); - springDerivedActions.append(ownerEntity->getActionsOfType(DYNAMIC_TYPE_FAR_GRAB)); - springDerivedActions.append(ownerEntity->getActionsOfType(DYNAMIC_TYPE_HOLD)); - - foreach (EntityDynamicPointer action, springDerivedActions) { - std::shared_ptr springAction = std::static_pointer_cast(action); - glm::quat rotationForAction; - glm::vec3 positionForAction; - glm::vec3 linearVelocityForAction; - glm::vec3 angularVelocityForAction; - float linearTimeScale; - float angularTimeScale; - bool success = springAction->getTarget(deltaTimeStep, - rotationForAction, positionForAction, - linearVelocityForAction, angularVelocityForAction, - linearTimeScale, angularTimeScale); - if (success) { - if (angularTimeScale < MAX_SPRING_TIMESCALE) { - angularValid = true; - angularSpringCount++; - angularVelocity += angularVelocityForAction; - if (springAction.get() == this) { - // only use the rotation for this action - rotation = rotationForAction; - } - } - - if (linearTimeScale < MAX_SPRING_TIMESCALE) { - linearValid = true; - linearSpringCount++; - position += positionForAction; - linearVelocity += linearVelocityForAction; - } - } - } - - if ((angularValid && angularSpringCount > 0) || (linearValid && linearSpringCount > 0)) { - withWriteLock([&]{ - if (linearValid && linearSpringCount > 0) { - position /= linearSpringCount; - linearVelocity /= linearSpringCount; - _positionalTarget = position; - _linearVelocityTarget = linearVelocity; - _positionalTargetSet = true; - _active = true; - } - if (angularValid && angularSpringCount > 0) { - angularVelocity /= angularSpringCount; - _rotationalTarget = rotation; - _angularVelocityTarget = angularVelocity; - _rotationalTargetSet = true; - _active = true; - } - }); - } - - return linearValid || angularValid; -} - - -void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { - if (!prepareForSpringUpdate(deltaTimeStep)) { - return; - } - - withReadLock([&]{ - auto ownerEntity = _ownerEntity.lock(); - if (!ownerEntity) { - return; - } - - void* physicsInfo = ownerEntity->getPhysicsInfo(); - if (!physicsInfo) { - return; - } - ObjectMotionState* motionState = static_cast(physicsInfo); - btRigidBody* rigidBody = motionState->getRigidBody(); - if (!rigidBody) { - qCDebug(physics) << "ObjectActionSpring::updateActionWorker no rigidBody"; - return; - } - - if (_linearTimeScale < MAX_SPRING_TIMESCALE) { - btVector3 targetVelocity(0.0f, 0.0f, 0.0f); - btVector3 offset = rigidBody->getCenterOfMassPosition() - glmToBullet(_positionalTarget); - float offsetLength = offset.length(); - if (offsetLength > FLT_EPSILON) { - float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); - targetVelocity = (-speed / offsetLength) * offset; - if (speed > rigidBody->getLinearSleepingThreshold()) { - forceBodyNonStatic(); - rigidBody->activate(); - } - } - // this action is aggresively critically damped and defeats the current velocity - rigidBody->setLinearVelocity(targetVelocity); - } - - if (_angularTimeScale < MAX_SPRING_TIMESCALE) { - btVector3 targetVelocity(0.0f, 0.0f, 0.0f); - - btQuaternion bodyRotation = rigidBody->getOrientation(); - auto alignmentDot = bodyRotation.dot(glmToBullet(_rotationalTarget)); - const float ALMOST_ONE = 0.99999f; - if (glm::abs(alignmentDot) < ALMOST_ONE) { - btQuaternion target = glmToBullet(_rotationalTarget); - if (alignmentDot < 0.0f) { - target = -target; - } - // if dQ is the incremental rotation that gets an object from Q0 to Q1 then: - // - // Q1 = dQ * Q0 - // - // solving for dQ gives: - // - // dQ = Q1 * Q0^ - btQuaternion deltaQ = target * bodyRotation.inverse(); - float speed = deltaQ.getAngle() / _angularTimeScale; - targetVelocity = speed * deltaQ.getAxis(); - if (speed > rigidBody->getAngularSleepingThreshold()) { - rigidBody->activate(); - } - } - // this action is aggresively critically damped and defeats the current velocity - rigidBody->setAngularVelocity(targetVelocity); - } - }); -} - -const float MIN_TIMESCALE = 0.1f; - - -bool ObjectActionSpring::updateArguments(QVariantMap arguments) { - glm::vec3 positionalTarget; - float linearTimeScale; - glm::quat rotationalTarget; - float angularTimeScale; - QUuid otherID; - - - bool needUpdate = false; - bool somethingChanged = ObjectDynamic::updateArguments(arguments); - withReadLock([&]{ - // targets are required, spring-constants are optional - bool ok = true; - positionalTarget = EntityDynamicInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false); - if (!ok) { - positionalTarget = _desiredPositionalTarget; - } - ok = true; - linearTimeScale = EntityDynamicInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false); - if (!ok || linearTimeScale <= 0.0f) { - linearTimeScale = _linearTimeScale; - } - - ok = true; - rotationalTarget = EntityDynamicInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false); - if (!ok) { - rotationalTarget = _desiredRotationalTarget; - } - - ok = true; - angularTimeScale = - EntityDynamicInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false); - if (!ok) { - angularTimeScale = _angularTimeScale; - } - - ok = true; - otherID = QUuid(EntityDynamicInterface::extractStringArgument("spring action", - arguments, "otherID", ok, false)); - if (!ok) { - otherID = _otherID; - } - - if (somethingChanged || - positionalTarget != _desiredPositionalTarget || - linearTimeScale != _linearTimeScale || - rotationalTarget != _desiredRotationalTarget || - angularTimeScale != _angularTimeScale || - otherID != _otherID) { - // something changed - needUpdate = true; - } - }); - - if (needUpdate) { - withWriteLock([&] { - _desiredPositionalTarget = positionalTarget; - _linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale)); - _desiredRotationalTarget = rotationalTarget; - _angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale)); - _otherID = otherID; - _active = true; - - auto ownerEntity = _ownerEntity.lock(); - if (ownerEntity) { - ownerEntity->setDynamicDataDirty(true); - ownerEntity->setDynamicDataNeedsTransmit(true); - } - }); - activateBody(); - } - - return true; -} - -QVariantMap ObjectActionSpring::getArguments() { - QVariantMap arguments = ObjectDynamic::getArguments(); - withReadLock([&] { - arguments["linearTimeScale"] = _linearTimeScale; - arguments["targetPosition"] = glmToQMap(_desiredPositionalTarget); - - arguments["targetRotation"] = glmToQMap(_desiredRotationalTarget); - arguments["angularTimeScale"] = _angularTimeScale; - - arguments["otherID"] = _otherID; - }); - return arguments; -} - -void ObjectActionSpring::serializeParameters(QDataStream& dataStream) const { - withReadLock([&] { - dataStream << _desiredPositionalTarget; - dataStream << _linearTimeScale; - dataStream << _positionalTargetSet; - dataStream << _desiredRotationalTarget; - dataStream << _angularTimeScale; - dataStream << _rotationalTargetSet; - dataStream << localTimeToServerTime(_expires); - dataStream << _tag; - dataStream << _otherID; - }); -} - -QByteArray ObjectActionSpring::serialize() const { - QByteArray serializedActionArguments; - QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly); - - dataStream << DYNAMIC_TYPE_SPRING; - dataStream << getID(); - dataStream << ObjectActionSpring::springVersion; - - serializeParameters(dataStream); - - return serializedActionArguments; -} - -void ObjectActionSpring::deserializeParameters(QByteArray serializedArguments, QDataStream& dataStream) { - withWriteLock([&] { - dataStream >> _desiredPositionalTarget; - dataStream >> _linearTimeScale; - dataStream >> _positionalTargetSet; - - dataStream >> _desiredRotationalTarget; - dataStream >> _angularTimeScale; - dataStream >> _rotationalTargetSet; - - quint64 serverExpires; - dataStream >> serverExpires; - _expires = serverTimeToLocalTime(serverExpires); - - dataStream >> _tag; - - dataStream >> _otherID; - - _active = true; - }); -} - -void ObjectActionSpring::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 != ObjectActionSpring::springVersion) { - assert(false); - return; - } - - deserializeParameters(serializedArguments, dataStream); -} diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h deleted file mode 100644 index 83a65b36b4..0000000000 --- a/libraries/physics/src/ObjectActionSpring.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// ObjectActionSpring.h -// libraries/physics/src -// -// Created by Seth Alves 2015-6-5 -// 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_ObjectActionSpring_h -#define hifi_ObjectActionSpring_h - -#include "ObjectAction.h" - -class ObjectActionSpring : public ObjectAction { -public: - ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity); - virtual ~ObjectActionSpring(); - - virtual bool updateArguments(QVariantMap arguments) override; - virtual QVariantMap getArguments() override; - - virtual void updateActionWorker(float deltaTimeStep) override; - - virtual QByteArray serialize() const override; - virtual void deserialize(QByteArray serializedArguments) override; - - virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, - glm::vec3& linearVelocity, glm::vec3& angularVelocity, - float& linearTimeScale, float& angularTimeScale); - -protected: - static const uint16_t springVersion; - - glm::vec3 _positionalTarget; - glm::vec3 _desiredPositionalTarget; - float _linearTimeScale; - bool _positionalTargetSet; - - glm::quat _rotationalTarget; - glm::quat _desiredRotationalTarget; - float _angularTimeScale; - bool _rotationalTargetSet; - - glm::vec3 _linearVelocityTarget; - glm::vec3 _angularVelocityTarget; - - virtual bool prepareForSpringUpdate(btScalar deltaTimeStep); - - void serializeParameters(QDataStream& dataStream) const; - void deserializeParameters(QByteArray serializedArguments, QDataStream& dataStream); -}; - -#endif // hifi_ObjectActionSpring_h diff --git a/libraries/physics/src/ObjectConstraintBallSocket.cpp b/libraries/physics/src/ObjectConstraintBallSocket.cpp index fb36a49e92..9dd85954a3 100644 --- a/libraries/physics/src/ObjectConstraintBallSocket.cpp +++ b/libraries/physics/src/ObjectConstraintBallSocket.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "QVariantGLM.h" #include "EntityTree.h" @@ -83,6 +85,9 @@ btTypedConstraint* ObjectConstraintBallSocket::getConstraint() { return constraint; } + static QString repeatedBallSocketNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex( + "ObjectConstraintBallSocket::getConstraint -- no rigidBody.*"); + btRigidBody* rigidBodyA = getRigidBody(); if (!rigidBodyA) { qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyA"; @@ -94,6 +99,7 @@ btTypedConstraint* ObjectConstraintBallSocket::getConstraint() { btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID); if (!rigidBodyB) { + qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyB"; return nullptr; } diff --git a/libraries/physics/src/ObjectConstraintConeTwist.cpp b/libraries/physics/src/ObjectConstraintConeTwist.cpp index 15d9378443..49f926af81 100644 --- a/libraries/physics/src/ObjectConstraintConeTwist.cpp +++ b/libraries/physics/src/ObjectConstraintConeTwist.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "QVariantGLM.h" #include "EntityTree.h" @@ -94,6 +96,9 @@ btTypedConstraint* ObjectConstraintConeTwist::getConstraint() { return constraint; } + static QString repeatedConeTwistNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex( + "ObjectConstraintConeTwist::getConstraint -- no rigidBody.*"); + btRigidBody* rigidBodyA = getRigidBody(); if (!rigidBodyA) { qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyA"; @@ -125,6 +130,7 @@ btTypedConstraint* ObjectConstraintConeTwist::getConstraint() { btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID); if (!rigidBodyB) { + qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyB"; return nullptr; } diff --git a/libraries/physics/src/ObjectConstraintHinge.cpp b/libraries/physics/src/ObjectConstraintHinge.cpp index dbadf433c3..52be64796a 100644 --- a/libraries/physics/src/ObjectConstraintHinge.cpp +++ b/libraries/physics/src/ObjectConstraintHinge.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "QVariantGLM.h" #include "EntityTree.h" @@ -93,6 +95,9 @@ btTypedConstraint* ObjectConstraintHinge::getConstraint() { return constraint; } + static QString repeatedHingeNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex( + "ObjectConstraintHinge::getConstraint -- no rigidBody.*"); + btRigidBody* rigidBodyA = getRigidBody(); if (!rigidBodyA) { qCDebug(physics) << "ObjectConstraintHinge::getConstraint -- no rigidBodyA"; @@ -110,6 +115,7 @@ btTypedConstraint* ObjectConstraintHinge::getConstraint() { // This hinge is between two entities... find the other rigid body. btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID); if (!rigidBodyB) { + qCDebug(physics) << "ObjectConstraintHinge::getConstraint -- no rigidBodyB"; return nullptr; } diff --git a/libraries/physics/src/ObjectConstraintSlider.cpp b/libraries/physics/src/ObjectConstraintSlider.cpp index 3716960a6e..ded9ad47e6 100644 --- a/libraries/physics/src/ObjectConstraintSlider.cpp +++ b/libraries/physics/src/ObjectConstraintSlider.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "QVariantGLM.h" #include "EntityTree.h" @@ -85,6 +87,9 @@ btTypedConstraint* ObjectConstraintSlider::getConstraint() { return constraint; } + static QString repeatedSliderNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex( + "ObjectConstraintSlider::getConstraint -- no rigidBody.*"); + btRigidBody* rigidBodyA = getRigidBody(); if (!rigidBodyA) { qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyA"; @@ -116,6 +121,7 @@ btTypedConstraint* ObjectConstraintSlider::getConstraint() { btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID); if (!rigidBodyB) { + qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyB"; return nullptr; } diff --git a/libraries/physics/src/ObjectDynamic.cpp b/libraries/physics/src/ObjectDynamic.cpp index 253739375a..3deadd6468 100644 --- a/libraries/physics/src/ObjectDynamic.cpp +++ b/libraries/physics/src/ObjectDynamic.cpp @@ -160,56 +160,6 @@ btRigidBody* ObjectDynamic::getRigidBody() { return nullptr; } -glm::vec3 ObjectDynamic::getPosition() { - auto rigidBody = getRigidBody(); - if (!rigidBody) { - return glm::vec3(0.0f); - } - return bulletToGLM(rigidBody->getCenterOfMassPosition()); -} - -glm::quat ObjectDynamic::getRotation() { - auto rigidBody = getRigidBody(); - if (!rigidBody) { - return glm::quat(0.0f, 0.0f, 0.0f, 1.0f); - } - return bulletToGLM(rigidBody->getOrientation()); -} - -glm::vec3 ObjectDynamic::getLinearVelocity() { - auto rigidBody = getRigidBody(); - if (!rigidBody) { - return glm::vec3(0.0f); - } - return bulletToGLM(rigidBody->getLinearVelocity()); -} - -void ObjectDynamic::setLinearVelocity(glm::vec3 linearVelocity) { - auto rigidBody = getRigidBody(); - if (!rigidBody) { - return; - } - rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f))); - rigidBody->activate(); -} - -glm::vec3 ObjectDynamic::getAngularVelocity() { - auto rigidBody = getRigidBody(); - if (!rigidBody) { - return glm::vec3(0.0f); - } - return bulletToGLM(rigidBody->getAngularVelocity()); -} - -void ObjectDynamic::setAngularVelocity(glm::vec3 angularVelocity) { - auto rigidBody = getRigidBody(); - if (!rigidBody) { - return; - } - rigidBody->setAngularVelocity(glmToBullet(angularVelocity)); - rigidBody->activate(); -} - void ObjectDynamic::activateBody(bool forceActivation) { auto rigidBody = getRigidBody(); if (rigidBody) { diff --git a/libraries/physics/src/ObjectDynamic.h b/libraries/physics/src/ObjectDynamic.h index 582f47db77..7fdf2e323a 100644 --- a/libraries/physics/src/ObjectDynamic.h +++ b/libraries/physics/src/ObjectDynamic.h @@ -56,12 +56,6 @@ protected: btRigidBody* getOtherRigidBody(EntityItemID otherEntityID); EntityItemPointer getEntityByID(EntityItemID entityID) const; virtual btRigidBody* getRigidBody(); - virtual glm::vec3 getPosition() override; - virtual glm::quat getRotation() override; - virtual glm::vec3 getLinearVelocity() override; - virtual void setLinearVelocity(glm::vec3 linearVelocity) override; - virtual glm::vec3 getAngularVelocity() override; - virtual void setAngularVelocity(glm::vec3 angularVelocity) override; virtual void activateBody(bool forceActivation = false); virtual void forceBodyNonStatic(); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 503b39dc1c..5a36d69035 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -63,10 +63,7 @@ ShapeManager* ObjectMotionState::getShapeManager() { } ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) : - _motionType(MOTION_TYPE_STATIC), _shape(shape), - _body(nullptr), - _mass(0.0f), _lastKinematicStep(worldSimulationStep) { } @@ -74,7 +71,43 @@ ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) : ObjectMotionState::~ObjectMotionState() { assert(!_body); setShape(nullptr); - _type = MOTIONSTATE_TYPE_INVALID; +} + +void ObjectMotionState::setMass(float mass) { + _density = 1.0f; + if (_shape) { + // we compute the density for the current shape's Aabb volume + // and save that instead of the total mass + btTransform transform; + transform.setIdentity(); + btVector3 minCorner, maxCorner; + _shape->getAabb(transform, minCorner, maxCorner); + btVector3 diagonal = maxCorner - minCorner; + float volume = diagonal.getX() * diagonal.getY() * diagonal.getZ(); + if (volume > EPSILON) { + _density = fabsf(mass) / volume; + } + } +} + +float ObjectMotionState::getMass() const { + if (_shape) { + // scale the density by the current Aabb volume to get mass + btTransform transform; + transform.setIdentity(); + btVector3 minCorner, maxCorner; + _shape->getAabb(transform, minCorner, maxCorner); + btVector3 diagonal = maxCorner - minCorner; + float volume = diagonal.getX() * diagonal.getY() * diagonal.getZ(); + + // cap the max mass for numerical stability + const float MIN_OBJECT_MASS = 0.0f; + const float MAX_OBJECT_DENSITY = 20000.0f; // kg/m^3 density of Tungsten + const float MAX_OBJECT_VOLUME = 1.0e6f; + const float MAX_OBJECT_MASS = MAX_OBJECT_DENSITY * MAX_OBJECT_VOLUME; + return glm::clamp(_density * volume, MIN_OBJECT_MASS, MAX_OBJECT_MASS); + } + return 0.0f; } void ObjectMotionState::setBodyLinearVelocity(const glm::vec3& velocity) const { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 645bd6fc14..1e582ea854 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -93,8 +93,8 @@ public: MotionStateType getType() const { return _type; } virtual PhysicsMotionType getMotionType() const { return _motionType; } - void setMass(float mass) { _mass = fabsf(mass); } - float getMass() { return _mass; } + void setMass(float mass); + float getMass() const; void setBodyLinearVelocity(const glm::vec3& velocity) const; void setBodyAngularVelocity(const glm::vec3& velocity) const; @@ -159,12 +159,12 @@ protected: void setRigidBody(btRigidBody* body); virtual void setShape(const btCollisionShape* shape); - MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState - PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC + MotionStateType _type { MOTIONSTATE_TYPE_INVALID }; // type of MotionState + PhysicsMotionType _motionType { MOTION_TYPE_STATIC }; // type of motion: KINEMATIC, DYNAMIC, or STATIC const btCollisionShape* _shape; - btRigidBody* _body; - float _mass; + btRigidBody* _body { nullptr }; + float _density { 1.0f }; uint32_t _lastKinematicStep; bool _hasInternalKinematicChanges { false }; diff --git a/libraries/shared/src/SettingHelpers.cpp b/libraries/shared/src/SettingHelpers.cpp index cbda4e4096..dd301aa5aa 100644 --- a/libraries/shared/src/SettingHelpers.cpp +++ b/libraries/shared/src/SettingHelpers.cpp @@ -126,19 +126,8 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { } switch (variantType) { - case QVariant::Map: { - auto varmap = variant.toMap(); - for (auto mapit = varmap.cbegin(); mapit != varmap.cend(); ++mapit) { - auto& mapkey = mapit.key(); - auto& mapvariant = mapit.value(); - object.insert(key + "/" + mapkey, QJsonValue::fromVariant(mapvariant)); - } - break; - } - - case QVariant::List: case QVariant::Hash: { - qCritical() << "Unsupported variant type" << variant.typeName(); + qCritical() << "Unsupported variant type" << variant.typeName() << ";" << key << variant; Q_ASSERT(false); break; } @@ -152,6 +141,8 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { case QVariant::UInt: case QVariant::Bool: case QVariant::Double: + case QVariant::Map: + case QVariant::List: object.insert(key, QJsonValue::fromVariant(variant)); break; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 81a0eed9f3..a68d27e620 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -768,9 +768,10 @@ bool similarStrings(const QString& stringA, const QString& stringB) { } void disableQtBearerPoll() { - // to work around the Qt constant wireless scanning, set the env for polling interval very high - const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT16_MAX).toLocal8Bit(); - qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT); + // to disable the Qt constant wireless scanning, set the env for polling interval + qDebug() << "Disabling Qt wireless polling by using a negative value for QTimer::setInterval"; + const QByteArray DISABLE_BEARER_POLL_TIMEOUT = QString::number(-1).toLocal8Bit(); + qputenv("QT_BEARER_POLL_TIMEOUT", DISABLE_BEARER_POLL_TIMEOUT); } void printSystemInformation() { diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index f6585e6ecb..e479559e6a 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -25,7 +25,9 @@ StoragePointer Storage::createView(size_t viewSize, size_t offset) const { viewSize = selfSize; } if ((viewSize + offset) > selfSize) { - throw std::runtime_error("Invalid mapping range"); + return StoragePointer(); + //TODO: Disable te exception for now and return an empty storage instead. + //throw std::runtime_error("Invalid mapping range"); } return std::make_shared(shared_from_this(), viewSize, data() + offset); } diff --git a/script-archive/vrShop/item/shopItemGrab.js b/script-archive/vrShop/item/shopItemGrab.js index 2b63ca1b53..f0488cb497 100644 --- a/script-archive/vrShop/item/shopItemGrab.js +++ b/script-archive/vrShop/item/shopItemGrab.js @@ -1,6 +1,6 @@ // shopItemGrab.js // -// Semplified and coarse version of handControllerGrab.js with the addition of the ownerID concept. +// Simplified and coarse version of handControllerGrab.js with the addition of the ownerID concept. // This grab is the only one which should run in the vrShop. It allows only near grab and add the feature of checking the ownerID. (See shopGrapSwapperEntityScript.js) // @@ -63,8 +63,8 @@ var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-g // equip // -var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; -var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position +var EQUIP_TRACTOR_SHUTOFF_DISTANCE = 0.05; +var EQUIP_TRACTOR_TIMEFRAME = 0.4; // how quickly objects move to their new position // // other constants @@ -121,7 +121,7 @@ var STATE_EQUIP_SEARCHING = 11; var STATE_EQUIP = 12 var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down var STATE_CONTINUE_EQUIP = 14; -var STATE_EQUIP_SPRING = 16; +var STATE_EQUIP_TRACTOR = 16; function stateToName(state) { @@ -152,8 +152,8 @@ function stateToName(state) { return "continue_equip_bd"; case STATE_CONTINUE_EQUIP: return "continue_equip"; - case STATE_EQUIP_SPRING: - return "state_equip_spring"; + case STATE_EQUIP_TRACTOR: + return "state_equip_tractor"; } return "unknown"; @@ -216,7 +216,7 @@ function MyController(hand) { case STATE_EQUIP: this.nearGrabbing(); break; - case STATE_EQUIP_SPRING: + case STATE_EQUIP_TRACTOR: this.pullTowardEquipPosition() break; case STATE_CONTINUE_NEAR_GRABBING: @@ -404,14 +404,14 @@ function MyController(hand) { return; } else if (!properties.locked) { var ownerObj = getEntityCustomData('ownerKey', intersection.entityID, null); - + if (ownerObj == null || ownerObj.ownerID === MyAvatar.sessionUUID) { //I can only grab new or already mine items this.grabbedEntity = intersection.entityID; if (this.state == STATE_SEARCHING) { this.setState(STATE_NEAR_GRABBING); } else { // equipping if (typeof grabbableData.spatialKey !== 'undefined') { - this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP_TRACTOR); } else { this.setState(STATE_EQUIP); } @@ -558,7 +558,7 @@ function MyController(hand) { var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - // use a spring to pull the object to where it will be when equipped + // use a tractor to pull the object to where it will be when equipped var relativeRotation = { x: 0.0, y: 0.0, @@ -582,34 +582,34 @@ function MyController(hand) { var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); var targetPosition = Vec3.sum(handPosition, offset); - if (typeof this.equipSpringID === 'undefined' || - this.equipSpringID === null || - this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + if (typeof this.equipTractorID === 'undefined' || + this.equipTractorID === null || + this.equipTractorID === NULL_ACTION_ID) { + this.equipTractorID = Entities.addAction("tractor", this.grabbedEntity, { targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, + linearTimeScale: EQUIP_TRACTOR_TIMEFRAME, targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, + angularTimeScale: EQUIP_TRACTOR_TIMEFRAME, ttl: ACTION_TTL }); - if (this.equipSpringID === NULL_ACTION_ID) { - this.equipSpringID = null; + if (this.equipTractorID === NULL_ACTION_ID) { + this.equipTractorID = null; this.setState(STATE_OFF); return; } } else { - Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + Entities.updateAction(this.grabbedEntity, this.equipTractorID, { targetPosition: targetPosition, - linearTimeScale: EQUIP_SPRING_TIMEFRAME, + linearTimeScale: EQUIP_TRACTOR_TIMEFRAME, targetRotation: targetRotation, - angularTimeScale: EQUIP_SPRING_TIMEFRAME, + angularTimeScale: EQUIP_TRACTOR_TIMEFRAME, ttl: ACTION_TTL }); } - if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { - Entities.deleteAction(this.grabbedEntity, this.equipSpringID); - this.equipSpringID = null; + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_TRACTOR_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipTractorID); + this.equipTractorID = null; this.setState(STATE_EQUIP); } }; @@ -862,4 +862,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); \ No newline at end of file +Script.update.connect(update); diff --git a/scripts/developer/tests/dynamics/dynamics-tests.html b/scripts/developer/tests/dynamics/dynamics-tests.html index 0f324e121c..6ef82c4b70 100644 --- a/scripts/developer/tests/dynamics/dynamics-tests.html +++ b/scripts/developer/tests/dynamics/dynamics-tests.html @@ -9,8 +9,8 @@ lifetime:
-
- A platform with a lever. The lever can be moved in a cone and rotated. A spring brings it back to its neutral position. +
+ A platform with a lever. The lever can be moved in a cone and rotated. A tractor brings it back to its neutral position.

A grabbable door with a hinge between it and world-space. @@ -31,7 +31,7 @@ A chain of spheres connected by ball-and-socket joints coincident-with the spheres.

- A self-righting ragdoll. The head is on a weak spring vs the body. + A self-righting ragdoll. The head is on a weak tractor vs the body. diff --git a/scripts/developer/tests/dynamics/dynamicsTests.js b/scripts/developer/tests/dynamics/dynamicsTests.js index 376eff182b..c0b001eab3 100644 --- a/scripts/developer/tests/dynamics/dynamicsTests.js +++ b/scripts/developer/tests/dynamics/dynamicsTests.js @@ -28,7 +28,7 @@ - function coneTwistAndSpringLeverTest(params) { + function coneTwistAndTractorLeverTest(params) { var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: -0.5, z: -2})); var lifetime = params.lifetime; @@ -84,10 +84,10 @@ tag: "cone-twist test" }); - Entities.addAction("spring", leverID, { + Entities.addAction("tractor", leverID, { targetRotation: { x: 0, y: 0, z: 0, w: 1 }, angularTimeScale: 0.2, - tag: "cone-twist test spring" + tag: "cone-twist test tractor" }); @@ -349,11 +349,11 @@ userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }" }); - Entities.addAction("spring", headID, { + Entities.addAction("tractor", headID, { targetRotation: { x: 0, y: 0, z: 0, w: 1 }, angularTimeScale: 2.0, otherID: bodyID, - tag: "cone-twist test spring" + tag: "cone-twist test tractor" }); @@ -705,7 +705,7 @@ if (event["dynamics-tests-command"]) { var commandToFunctionMap = { - "cone-twist-and-spring-lever-test": coneTwistAndSpringLeverTest, + "cone-twist-and-tractor-lever-test": coneTwistAndTractorLeverTest, "door-vs-world-test": doorVSWorldTest, "hinge-chain-test": hingeChainTest, "slider-vs-world-test": sliderVSWorldTest, diff --git a/scripts/tutorials/entity_scripts/springHold.js b/scripts/tutorials/entity_scripts/springHold.js index 12b34381a6..059ea2cc6f 100644 --- a/scripts/tutorials/entity_scripts/springHold.js +++ b/scripts/tutorials/entity_scripts/springHold.js @@ -113,4 +113,4 @@ }; return new SpringHold(); -}); \ No newline at end of file +}); diff --git a/scripts/tutorials/entity_scripts/touch.js b/scripts/tutorials/entity_scripts/touch.js index d6a59aa167..1d0586b350 100644 --- a/scripts/tutorials/entity_scripts/touch.js +++ b/scripts/tutorials/entity_scripts/touch.js @@ -2,7 +2,7 @@ // touch.js // - // Sample file using spring action, haptic vibration, and color change to demonstrate two spheres + // Sample file using tractor action, haptic vibration, and color change to demonstrate two spheres // That can give a sense of touch to the holders. // Create two standard spheres, make them grabbable, and attach this entity script. Grab them and touch them together. // @@ -53,7 +53,7 @@ _this = this; } - function updateSpringAction(timescale) { + function updateTractorAction(timescale) { var targetProps = Entities.getEntityProperties(_this.entityID); // // Look for nearby entities to touch @@ -113,7 +113,7 @@ var success = Entities.updateAction(_this.copy, _this.actionID, props); } - function createSpringAction(timescale) { + function createTractorAction(timescale) { var targetProps = Entities.getEntityProperties(_this.entityID); var props = { @@ -123,7 +123,7 @@ angularTimeScale: timescale, ttl: ACTION_TTL }; - _this.actionID = Entities.addAction("spring", _this.copy, props); + _this.actionID = Entities.addAction("tractor", _this.copy, props); return; } @@ -170,7 +170,7 @@ }); } - function deleteSpringAction() { + function deleteTractorAction() { Entities.deleteAction(_this.copy, _this.actionID); } @@ -188,19 +188,19 @@ }, startNearGrab: function(entityID, data) { createCopy(); - createSpringAction(TIMESCALE); + createTractorAction(TIMESCALE); makeOriginalInvisible(); setHand(Entities.getEntityProperties(_this.entityID).position); }, continueNearGrab: function() { - updateSpringAction(TIMESCALE); + updateTractorAction(TIMESCALE); }, releaseGrab: function() { - deleteSpringAction(); + deleteTractorAction(); deleteCopy(); makeOriginalVisible(); } }; return new TouchExample(); -}); \ No newline at end of file +}); diff --git a/unpublishedScripts/marketplace/boppo/lookAtEntity.js b/unpublishedScripts/marketplace/boppo/lookAtEntity.js index ba072814f2..a0e9274db3 100644 --- a/unpublishedScripts/marketplace/boppo/lookAtEntity.js +++ b/unpublishedScripts/marketplace/boppo/lookAtEntity.js @@ -89,7 +89,7 @@ LookAtTarget = function(sourceEntityID) { } }); if (!actionFound) { - Entities.addAction('spring', _sourceEntityID, getNewActionProperties()); + Entities.addAction('tractor', _sourceEntityID, getNewActionProperties()); } } };