mirror of
https://github.com/JulianGro/overte.git
synced 2025-06-05 14:50:33 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into ambient
This commit is contained in:
commit
2c6e10fbe1
33 changed files with 331 additions and 106 deletions
|
@ -145,7 +145,7 @@ private:
|
||||||
std::unordered_map<QUuid, QVector<JointData>> _lastOtherAvatarSentJoints;
|
std::unordered_map<QUuid, QVector<JointData>> _lastOtherAvatarSentJoints;
|
||||||
|
|
||||||
uint64_t _identityChangeTimestamp;
|
uint64_t _identityChangeTimestamp;
|
||||||
bool _avatarSessionDisplayNameMustChange{ false };
|
bool _avatarSessionDisplayNameMustChange{ true };
|
||||||
|
|
||||||
int _numAvatarsSentLastFrame = 0;
|
int _numAvatarsSentLastFrame = 0;
|
||||||
int _numFramesSinceAdjustment = 0;
|
int _numFramesSinceAdjustment = 0;
|
||||||
|
|
|
@ -56,43 +56,64 @@
|
||||||
"jointName": "Hips",
|
"jointName": "Hips",
|
||||||
"positionVar": "hipsPosition",
|
"positionVar": "hipsPosition",
|
||||||
"rotationVar": "hipsRotation",
|
"rotationVar": "hipsRotation",
|
||||||
"typeVar": "hipsType"
|
"typeVar": "hipsType",
|
||||||
|
"weightVar": "hipsWeight",
|
||||||
|
"weight": 1.0,
|
||||||
|
"flexCoefficients": [1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"jointName": "RightHand",
|
"jointName": "RightHand",
|
||||||
"positionVar": "rightHandPosition",
|
"positionVar": "rightHandPosition",
|
||||||
"rotationVar": "rightHandRotation",
|
"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",
|
"jointName": "LeftHand",
|
||||||
"positionVar": "leftHandPosition",
|
"positionVar": "leftHandPosition",
|
||||||
"rotationVar": "leftHandRotation",
|
"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",
|
"jointName": "RightFoot",
|
||||||
"positionVar": "rightFootPosition",
|
"positionVar": "rightFootPosition",
|
||||||
"rotationVar": "rightFootRotation",
|
"rotationVar": "rightFootRotation",
|
||||||
"typeVar": "rightFootType"
|
"typeVar": "rightFootType",
|
||||||
|
"weightVar": "rightFootWeight",
|
||||||
|
"weight": 1.0,
|
||||||
|
"flexCoefficients": [1, 0.45, 0.45]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"jointName": "LeftFoot",
|
"jointName": "LeftFoot",
|
||||||
"positionVar": "leftFootPosition",
|
"positionVar": "leftFootPosition",
|
||||||
"rotationVar": "leftFootRotation",
|
"rotationVar": "leftFootRotation",
|
||||||
"typeVar": "leftFootType"
|
"typeVar": "leftFootType",
|
||||||
|
"weightVar": "leftFootWeight",
|
||||||
|
"weight": 1.0,
|
||||||
|
"flexCoefficients": [1, 0.45, 0.45]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"jointName": "Spine2",
|
"jointName": "Spine2",
|
||||||
"positionVar": "spine2Position",
|
"positionVar": "spine2Position",
|
||||||
"rotationVar": "spine2Rotation",
|
"rotationVar": "spine2Rotation",
|
||||||
"typeVar": "spine2Type"
|
"typeVar": "spine2Type",
|
||||||
|
"weightVar": "spine2Weight",
|
||||||
|
"weight": 1.0,
|
||||||
|
"flexCoefficients": [0.45, 0.45]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"jointName": "Head",
|
"jointName": "Head",
|
||||||
"positionVar": "headPosition",
|
"positionVar": "headPosition",
|
||||||
"rotationVar": "headRotation",
|
"rotationVar": "headRotation",
|
||||||
"typeVar": "headType"
|
"typeVar": "headType",
|
||||||
|
"weightVar": "headWeight",
|
||||||
|
"weight": 4.0,
|
||||||
|
"flexCoefficients": [1, 0.5, 0.5, 0.5, 0.5]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -5258,9 +5258,8 @@ void Application::nodeActivated(SharedNodePointer node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->getType() == NodeType::AvatarMixer) {
|
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()->markIdentityDataChanged();
|
||||||
getMyAvatar()->sendIdentityPacket();
|
|
||||||
getMyAvatar()->resetLastSent();
|
getMyAvatar()->resetLastSent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||||
if (shape) {
|
if (shape) {
|
||||||
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
|
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
|
||||||
|
motionState->setMass(avatar->computeMass());
|
||||||
avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); });
|
avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); });
|
||||||
_motionStates.insert(avatar.get(), motionState);
|
_motionStates.insert(avatar.get(), motionState);
|
||||||
_motionStatesToAddToPhysics.insert(motionState);
|
_motionStatesToAddToPhysics.insert(motionState);
|
||||||
|
|
|
@ -19,9 +19,6 @@
|
||||||
AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||||
assert(_avatar);
|
assert(_avatar);
|
||||||
_type = MOTIONSTATE_TYPE_AVATAR;
|
_type = MOTIONSTATE_TYPE_AVATAR;
|
||||||
if (_shape) {
|
|
||||||
_mass = 100.0f; // HACK
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarMotionState::~AvatarMotionState() {
|
AvatarMotionState::~AvatarMotionState() {
|
||||||
|
|
|
@ -239,6 +239,7 @@ MyAvatar::MyAvatar(QThread* thread, RigPointer rig) :
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(rig.get(), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete()));
|
connect(rig.get(), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete()));
|
||||||
|
_characterController.setDensity(_density);
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar::~MyAvatar() {
|
MyAvatar::~MyAvatar() {
|
||||||
|
|
|
@ -125,7 +125,7 @@ class MyAvatar : public Avatar {
|
||||||
Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
|
Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
|
||||||
|
|
||||||
Q_PROPERTY(float energy READ getEnergy WRITE setEnergy)
|
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 hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled)
|
||||||
Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled)
|
Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled)
|
||||||
|
|
|
@ -49,12 +49,9 @@ void MyCharacterController::updateShapeIfNecessary() {
|
||||||
// create RigidBody if it doesn't exist
|
// create RigidBody if it doesn't exist
|
||||||
if (!_rigidBody) {
|
if (!_rigidBody) {
|
||||||
btCollisionShape* shape = computeShape();
|
btCollisionShape* shape = computeShape();
|
||||||
|
btScalar mass = 1.0f;
|
||||||
// HACK: use some simple mass property defaults for now
|
btVector3 inertia(1.0f, 1.0f, 1.0f);
|
||||||
const btScalar DEFAULT_AVATAR_MASS = 100.0f;
|
_rigidBody = new btRigidBody(mass, nullptr, shape, inertia);
|
||||||
const btVector3 DEFAULT_AVATAR_INERTIA_TENSOR(30.0f, 8.0f, 30.0f);
|
|
||||||
|
|
||||||
_rigidBody = new btRigidBody(DEFAULT_AVATAR_MASS, nullptr, shape, DEFAULT_AVATAR_INERTIA_TENSOR);
|
|
||||||
} else {
|
} else {
|
||||||
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||||
if (shape) {
|
if (shape) {
|
||||||
|
@ -63,6 +60,7 @@ void MyCharacterController::updateShapeIfNecessary() {
|
||||||
shape = computeShape();
|
shape = computeShape();
|
||||||
_rigidBody->setCollisionShape(shape);
|
_rigidBody->setCollisionShape(shape);
|
||||||
}
|
}
|
||||||
|
updateMassProperties();
|
||||||
|
|
||||||
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
|
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
|
||||||
_rigidBody->setAngularFactor(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);
|
||||||
|
}
|
||||||
|
|
|
@ -40,8 +40,11 @@ public:
|
||||||
/// return true if RayShotgun hits anything
|
/// return true if RayShotgun hits anything
|
||||||
bool testRayShotgun(const glm::vec3& position, const glm::vec3& step, RayShotgunResult& result);
|
bool testRayShotgun(const glm::vec3& position, const glm::vec3& step, RayShotgunResult& result);
|
||||||
|
|
||||||
|
void setDensity(btScalar density) { _density = density; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initRayShotgun(const btCollisionWorld* world);
|
void initRayShotgun(const btCollisionWorld* world);
|
||||||
|
void updateMassProperties() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
btConvexHullShape* computeShape() const;
|
btConvexHullShape* computeShape() const;
|
||||||
|
@ -52,6 +55,7 @@ protected:
|
||||||
// shotgun scan data
|
// shotgun scan data
|
||||||
btAlignedObjectArray<btVector3> _topPoints;
|
btAlignedObjectArray<btVector3> _topPoints;
|
||||||
btAlignedObjectArray<btVector3> _bottomPoints;
|
btAlignedObjectArray<btVector3> _bottomPoints;
|
||||||
|
btScalar _density { 1.0f };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MyCharacterController_h
|
#endif // hifi_MyCharacterController_h
|
||||||
|
|
|
@ -21,6 +21,39 @@
|
||||||
#include "SwingTwistConstraint.h"
|
#include "SwingTwistConstraint.h"
|
||||||
#include "AnimationLogging.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<float>& 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) {
|
AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimNode::Type::InverseKinematics, id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,26 +93,22 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::setTargetVars(
|
void AnimInverseKinematics::setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar,
|
||||||
const QString& jointName,
|
const QString& typeVar, const QString& weightVar, float weight, const std::vector<float>& flexCoefficients) {
|
||||||
const QString& positionVar,
|
IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients);
|
||||||
const QString& rotationVar,
|
|
||||||
const QString& typeVar) {
|
|
||||||
// if there are dups, last one wins.
|
// if there are dups, last one wins.
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto& targetVar: _targetVarVec) {
|
for (auto& targetVarIter: _targetVarVec) {
|
||||||
if (targetVar.jointName == jointName) {
|
if (targetVarIter.jointName == jointName) {
|
||||||
// update existing targetVar
|
targetVarIter = targetVar;
|
||||||
targetVar.positionVar = positionVar;
|
|
||||||
targetVar.rotationVar = rotationVar;
|
|
||||||
targetVar.typeVar = typeVar;
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// create a new entry
|
// 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);
|
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
||||||
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot());
|
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot());
|
||||||
glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans());
|
glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans());
|
||||||
|
float weight = animVars.lookup(targetVar.weightVar, targetVar.weight);
|
||||||
|
|
||||||
target.setPose(rotation, translation);
|
target.setPose(rotation, translation);
|
||||||
target.setIndex(targetVar.jointIndex);
|
target.setIndex(targetVar.jointIndex);
|
||||||
|
target.setWeight(weight);
|
||||||
|
target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients);
|
||||||
|
|
||||||
targets.push_back(target);
|
targets.push_back(target);
|
||||||
|
|
||||||
if (targetVar.jointIndex > _maxTargetIndex) {
|
if (targetVar.jointIndex > _maxTargetIndex) {
|
||||||
_maxTargetIndex = targetVar.jointIndex;
|
_maxTargetIndex = targetVar.jointIndex;
|
||||||
}
|
}
|
||||||
|
@ -271,6 +305,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe
|
||||||
// cache tip absolute position
|
// cache tip absolute position
|
||||||
glm::vec3 tipPosition = absolutePoses[tipIndex].trans();
|
glm::vec3 tipPosition = absolutePoses[tipIndex].trans();
|
||||||
|
|
||||||
|
size_t chainDepth = 1;
|
||||||
|
|
||||||
// descend toward root, pivoting each joint to get tip closer to target position
|
// descend toward root, pivoting each joint to get tip closer to target position
|
||||||
while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
|
while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
|
||||||
// compute the two lines that should be aligned
|
// compute the two lines that should be aligned
|
||||||
|
@ -312,9 +348,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe
|
||||||
float angle = acosf(cosAngle);
|
float angle = acosf(cosAngle);
|
||||||
const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f;
|
const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f;
|
||||||
if (angle > MIN_ADJUSTMENT_ANGLE) {
|
if (angle > MIN_ADJUSTMENT_ANGLE) {
|
||||||
// reduce angle by a fraction (for stability)
|
// reduce angle by a flexCoefficient
|
||||||
const float STABILITY_FRACTION = 0.5f;
|
angle *= target.getFlexCoefficient(chainDepth);
|
||||||
angle *= STABILITY_FRACTION;
|
|
||||||
deltaRotation = glm::angleAxis(angle, axis);
|
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
|
// 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;
|
pivotIndex = pivotsParentIndex;
|
||||||
pivotsParentIndex = _skeleton->getParentIndex(pivotIndex);
|
pivotsParentIndex = _skeleton->getParentIndex(pivotIndex);
|
||||||
|
|
||||||
|
chainDepth++;
|
||||||
}
|
}
|
||||||
return lowestMovedIndex;
|
return lowestMovedIndex;
|
||||||
}
|
}
|
||||||
|
@ -806,7 +843,7 @@ void AnimInverseKinematics::initConstraints() {
|
||||||
stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST);
|
stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST);
|
||||||
|
|
||||||
std::vector<float> minDots;
|
std::vector<float> minDots;
|
||||||
const float MAX_SHOULDER_SWING = PI / 20.0f;
|
const float MAX_SHOULDER_SWING = PI / 16.0f;
|
||||||
minDots.push_back(cosf(MAX_SHOULDER_SWING));
|
minDots.push_back(cosf(MAX_SHOULDER_SWING));
|
||||||
stConstraint->setSwingLimits(minDots);
|
stConstraint->setSwingLimits(minDots);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ public:
|
||||||
void loadPoses(const AnimPoseVec& poses);
|
void loadPoses(const AnimPoseVec& poses);
|
||||||
void computeAbsolutePoses(AnimPoseVec& absolutePoses) const;
|
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<float>& flexCoefficients);
|
||||||
|
|
||||||
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimNode::Triggers& triggersOut) override;
|
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;
|
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(const AnimInverseKinematics&) = delete;
|
||||||
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
|
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
|
||||||
|
|
||||||
|
enum FlexCoefficients { MAX_FLEX_COEFFICIENTS = 10 };
|
||||||
struct IKTargetVar {
|
struct IKTargetVar {
|
||||||
IKTargetVar(const QString& jointNameIn,
|
IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn,
|
||||||
const QString& positionVarIn,
|
const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector<float>& flexCoefficientsIn);
|
||||||
const QString& rotationVarIn,
|
IKTargetVar(const IKTargetVar& orig);
|
||||||
const QString& typeVarIn) :
|
|
||||||
positionVar(positionVarIn),
|
|
||||||
rotationVar(rotationVarIn),
|
|
||||||
typeVar(typeVarIn),
|
|
||||||
jointName(jointNameIn),
|
|
||||||
jointIndex(-1)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
QString jointName;
|
||||||
QString positionVar;
|
QString positionVar;
|
||||||
QString rotationVar;
|
QString rotationVar;
|
||||||
QString typeVar;
|
QString typeVar;
|
||||||
QString jointName;
|
QString weightVar;
|
||||||
|
float weight;
|
||||||
|
float flexCoefficients[MAX_FLEX_COEFFICIENTS];
|
||||||
|
size_t numFlexCoefficients;
|
||||||
int jointIndex; // cached joint index
|
int jointIndex; // cached joint index
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,13 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) {
|
||||||
} \
|
} \
|
||||||
float NAME = (float)NAME##_VAL.toDouble()
|
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) {
|
static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUrl) {
|
||||||
auto idVal = jsonObj.value("id");
|
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(positionVar, targetObj, id, jsonUrl, nullptr);
|
||||||
READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr);
|
READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr);
|
||||||
READ_OPTIONAL_STRING(typeVar, targetObj);
|
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<float> 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);
|
READ_OPTIONAL_STRING(solutionSource, jsonObj);
|
||||||
|
|
|
@ -14,6 +14,23 @@ void IKTarget::setPose(const glm::quat& rotation, const glm::vec3& translation)
|
||||||
_pose.trans() = 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) {
|
void IKTarget::setType(int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case (int)Type::RotationAndPosition:
|
case (int)Type::RotationAndPosition:
|
||||||
|
|
|
@ -35,15 +35,21 @@ public:
|
||||||
void setPose(const glm::quat& rotation, const glm::vec3& translation);
|
void setPose(const glm::quat& rotation, const glm::vec3& translation);
|
||||||
void setIndex(int index) { _index = index; }
|
void setIndex(int index) { _index = index; }
|
||||||
void setType(int);
|
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
|
void setWeight(float weight) { _weight = weight; }
|
||||||
float getWeight() const { return _type == Type::HmdHead ? HACK_HMD_TARGET_WEIGHT : 1.0f; }
|
float getWeight() const { return _weight; }
|
||||||
|
|
||||||
|
enum FlexCoefficients { MAX_FLEX_COEFFICIENTS = 10 };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AnimPose _pose;
|
AnimPose _pose;
|
||||||
int _index{-1};
|
int _index{-1};
|
||||||
Type _type{Type::RotationAndPosition};
|
Type _type{Type::RotationAndPosition};
|
||||||
|
float _weight;
|
||||||
|
float _flexCoefficients[MAX_FLEX_COEFFICIENTS];
|
||||||
|
size_t _numFlexCoefficients;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_IKTarget_h
|
#endif // hifi_IKTarget_h
|
||||||
|
|
|
@ -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.
|
// 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.
|
// 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.set("headType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
|
_animVars.unset("headWeight"); // use the default weight for this target.
|
||||||
} else {
|
} else {
|
||||||
// When there is no hips IK target, use the HmdHead IK chain type. This will make the spine very stiff,
|
// 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.
|
// but because the IK _hipsOffset is enabled, the hips will naturally follow underneath the head.
|
||||||
_animVars.set("headType", (int)IKTarget::Type::HmdHead);
|
_animVars.set("headType", (int)IKTarget::Type::HmdHead);
|
||||||
|
_animVars.set("headWeight", 8.0f);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_animVars.unset("headPosition");
|
_animVars.unset("headPosition");
|
||||||
|
@ -1400,22 +1402,24 @@ void Rig::computeAvatarBoundingCapsule(
|
||||||
|
|
||||||
AnimInverseKinematics ikNode("boundingShape");
|
AnimInverseKinematics ikNode("boundingShape");
|
||||||
ikNode.setSkeleton(_animSkeleton);
|
ikNode.setSkeleton(_animSkeleton);
|
||||||
|
|
||||||
|
// AJT: FIX ME!!!!! ensure that empty weights vector does something reasonable....
|
||||||
ikNode.setTargetVars("LeftHand",
|
ikNode.setTargetVars("LeftHand",
|
||||||
"leftHandPosition",
|
"leftHandPosition",
|
||||||
"leftHandRotation",
|
"leftHandRotation",
|
||||||
"leftHandType");
|
"leftHandType", "leftHandWeight", 1.0f, {});
|
||||||
ikNode.setTargetVars("RightHand",
|
ikNode.setTargetVars("RightHand",
|
||||||
"rightHandPosition",
|
"rightHandPosition",
|
||||||
"rightHandRotation",
|
"rightHandRotation",
|
||||||
"rightHandType");
|
"rightHandType", "rightHandWeight", 1.0f, {});
|
||||||
ikNode.setTargetVars("LeftFoot",
|
ikNode.setTargetVars("LeftFoot",
|
||||||
"leftFootPosition",
|
"leftFootPosition",
|
||||||
"leftFootRotation",
|
"leftFootRotation",
|
||||||
"leftFootType");
|
"leftFootType", "leftFootWeight", 1.0f, {});
|
||||||
ikNode.setTargetVars("RightFoot",
|
ikNode.setTargetVars("RightFoot",
|
||||||
"rightFootPosition",
|
"rightFootPosition",
|
||||||
"rightFootRotation",
|
"rightFootRotation",
|
||||||
"rightFootType");
|
"rightFootType", "rightFootWeight", 1.0f, {});
|
||||||
|
|
||||||
AnimPose geometryToRig = _modelOffset * _geometryOffset;
|
AnimPose geometryToRig = _modelOffset * _geometryOffset;
|
||||||
|
|
||||||
|
|
|
@ -1265,6 +1265,17 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) {
|
||||||
radius = halfExtents.x;
|
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
|
// virtual
|
||||||
void Avatar::rebuildCollisionShape() {
|
void Avatar::rebuildCollisionShape() {
|
||||||
addPhysicsFlags(Simulation::DIRTY_SHAPE);
|
addPhysicsFlags(Simulation::DIRTY_SHAPE);
|
||||||
|
|
|
@ -195,6 +195,7 @@ public:
|
||||||
|
|
||||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||||
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
|
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
|
||||||
|
float computeMass();
|
||||||
|
|
||||||
using SpatiallyNestable::setPosition;
|
using SpatiallyNestable::setPosition;
|
||||||
virtual void setPosition(const glm::vec3& position) override;
|
virtual void setPosition(const glm::vec3& position) override;
|
||||||
|
|
|
@ -52,6 +52,7 @@ const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData";
|
||||||
static const int TRANSLATION_COMPRESSION_RADIX = 12;
|
static const int TRANSLATION_COMPRESSION_RADIX = 12;
|
||||||
static const int SENSOR_TO_WORLD_SCALE_RADIX = 10;
|
static const int SENSOR_TO_WORLD_SCALE_RADIX = 10;
|
||||||
static const float AUDIO_LOUDNESS_SCALE = 1024.0f;
|
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)
|
#define ASSERT(COND) do { if (!(COND)) { abort(); } } while(0)
|
||||||
|
|
||||||
|
@ -65,7 +66,8 @@ AvatarData::AvatarData() :
|
||||||
_headData(NULL),
|
_headData(NULL),
|
||||||
_errorLogExpiry(0),
|
_errorLogExpiry(0),
|
||||||
_owningAvatarMixer(),
|
_owningAvatarMixer(),
|
||||||
_targetVelocity(0.0f)
|
_targetVelocity(0.0f),
|
||||||
|
_density(DEFAULT_AVATAR_DENSITY)
|
||||||
{
|
{
|
||||||
setBodyPitch(0.0f);
|
setBodyPitch(0.0f);
|
||||||
setBodyYaw(-90.0f);
|
setBodyYaw(-90.0f);
|
||||||
|
@ -1588,8 +1590,6 @@ void AvatarData::setDisplayName(const QString& displayName) {
|
||||||
_displayName = displayName;
|
_displayName = displayName;
|
||||||
_sessionDisplayName = "";
|
_sessionDisplayName = "";
|
||||||
|
|
||||||
sendIdentityPacket();
|
|
||||||
|
|
||||||
qCDebug(avatars) << "Changing display name for avatar to" << displayName;
|
qCDebug(avatars) << "Changing display name for avatar to" << displayName;
|
||||||
markIdentityDataChanged();
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -629,6 +629,8 @@ public:
|
||||||
_identityUpdatedAt = usecTimestampNow();
|
_identityUpdatedAt = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getDensity() const { return _density; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void displayNameChanged();
|
void displayNameChanged();
|
||||||
|
|
||||||
|
@ -785,6 +787,7 @@ protected:
|
||||||
|
|
||||||
bool _identityDataChanged { false };
|
bool _identityDataChanged { false };
|
||||||
quint64 _identityUpdatedAt { 0 };
|
quint64 _identityUpdatedAt { 0 };
|
||||||
|
float _density;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||||
|
|
|
@ -1691,14 +1691,20 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
|
||||||
setLocalVelocity(Vectors::ZERO);
|
setLocalVelocity(Vectors::ZERO);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const float MIN_LINEAR_SPEED = 0.001f;
|
float speed = glm::length(value);
|
||||||
if (glm::length(value) < MIN_LINEAR_SPEED) {
|
if (!glm::isnan(speed)) {
|
||||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
const float MIN_LINEAR_SPEED = 0.001f;
|
||||||
} else {
|
const float MAX_LINEAR_SPEED = 270.0f; // 3m per step at 90Hz
|
||||||
velocity = value;
|
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) {
|
if (getShapeType() == SHAPE_TYPE_STATIC_MESH) {
|
||||||
_gravity = Vectors::ZERO;
|
_gravity = Vectors::ZERO;
|
||||||
} else {
|
} else {
|
||||||
_gravity = value;
|
float magnitude = glm::length(value);
|
||||||
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
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) {
|
if (getShapeType() == SHAPE_TYPE_STATIC_MESH) {
|
||||||
setLocalAngularVelocity(Vectors::ZERO);
|
setLocalAngularVelocity(Vectors::ZERO);
|
||||||
} else {
|
} else {
|
||||||
const float MIN_ANGULAR_SPEED = 0.0002f;
|
float speed = glm::length(value);
|
||||||
if (glm::length(value) < MIN_ANGULAR_SPEED) {
|
if (!glm::isnan(speed)) {
|
||||||
angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
const float MIN_ANGULAR_SPEED = 0.0002f;
|
||||||
} else {
|
const float MAX_ANGULAR_SPEED = 9.0f * TWO_PI; // 1/10 rotation per step at 90Hz
|
||||||
angularVelocity = value;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,16 @@ PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
|
||||||
auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face);
|
auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face);
|
||||||
if (faceSize != 0 && faceOffset != 0) {
|
if (faceSize != 0 && faceOffset != 0) {
|
||||||
auto file = maybeOpenFile();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,9 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
_dynamicsWorld = nullptr;
|
_dynamicsWorld = nullptr;
|
||||||
}
|
}
|
||||||
int16_t collisionGroup = computeCollisionGroup();
|
int16_t collisionGroup = computeCollisionGroup();
|
||||||
|
if (_rigidBody) {
|
||||||
|
updateMassProperties();
|
||||||
|
}
|
||||||
if (world && _rigidBody) {
|
if (world && _rigidBody) {
|
||||||
// add to new world
|
// add to new world
|
||||||
_dynamicsWorld = world;
|
_dynamicsWorld = world;
|
||||||
|
@ -127,7 +130,9 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
_ghost.setCollisionGroupAndMask(collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ collisionGroup));
|
_ghost.setCollisionGroupAndMask(collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ collisionGroup));
|
||||||
_ghost.setCollisionWorld(_dynamicsWorld);
|
_ghost.setCollisionWorld(_dynamicsWorld);
|
||||||
_ghost.setRadiusAndHalfHeight(_radius, _halfHeight);
|
_ghost.setRadiusAndHalfHeight(_radius, _halfHeight);
|
||||||
_ghost.setWorldTransform(_rigidBody->getWorldTransform());
|
if (_rigidBody) {
|
||||||
|
_ghost.setWorldTransform(_rigidBody->getWorldTransform());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (_dynamicsWorld) {
|
if (_dynamicsWorld) {
|
||||||
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
||||||
|
|
|
@ -128,6 +128,7 @@ protected:
|
||||||
void setState(State state);
|
void setState(State state);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
virtual void updateMassProperties() = 0;
|
||||||
void updateGravity();
|
void updateGravity();
|
||||||
void updateUpAxis(const glm::quat& rotation);
|
void updateUpAxis(const glm::quat& rotation);
|
||||||
bool checkForSupport(btCollisionWorld* collisionWorld);
|
bool checkForSupport(btCollisionWorld* collisionWorld);
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "QVariantGLM.h"
|
#include "QVariantGLM.h"
|
||||||
|
|
||||||
#include "EntityTree.h"
|
#include "EntityTree.h"
|
||||||
|
@ -83,6 +85,9 @@ btTypedConstraint* ObjectConstraintBallSocket::getConstraint() {
|
||||||
return constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString repeatedBallSocketNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||||
|
"ObjectConstraintBallSocket::getConstraint -- no rigidBody.*");
|
||||||
|
|
||||||
btRigidBody* rigidBodyA = getRigidBody();
|
btRigidBody* rigidBodyA = getRigidBody();
|
||||||
if (!rigidBodyA) {
|
if (!rigidBodyA) {
|
||||||
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyA";
|
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyA";
|
||||||
|
@ -94,6 +99,7 @@ btTypedConstraint* ObjectConstraintBallSocket::getConstraint() {
|
||||||
|
|
||||||
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
||||||
if (!rigidBodyB) {
|
if (!rigidBodyB) {
|
||||||
|
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyB";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "QVariantGLM.h"
|
#include "QVariantGLM.h"
|
||||||
|
|
||||||
#include "EntityTree.h"
|
#include "EntityTree.h"
|
||||||
|
@ -94,6 +96,9 @@ btTypedConstraint* ObjectConstraintConeTwist::getConstraint() {
|
||||||
return constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString repeatedConeTwistNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||||
|
"ObjectConstraintConeTwist::getConstraint -- no rigidBody.*");
|
||||||
|
|
||||||
btRigidBody* rigidBodyA = getRigidBody();
|
btRigidBody* rigidBodyA = getRigidBody();
|
||||||
if (!rigidBodyA) {
|
if (!rigidBodyA) {
|
||||||
qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyA";
|
qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyA";
|
||||||
|
@ -125,6 +130,7 @@ btTypedConstraint* ObjectConstraintConeTwist::getConstraint() {
|
||||||
|
|
||||||
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
||||||
if (!rigidBodyB) {
|
if (!rigidBodyB) {
|
||||||
|
qCDebug(physics) << "ObjectConstraintConeTwist::getConstraint -- no rigidBodyB";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "QVariantGLM.h"
|
#include "QVariantGLM.h"
|
||||||
|
|
||||||
#include "EntityTree.h"
|
#include "EntityTree.h"
|
||||||
|
@ -93,6 +95,9 @@ btTypedConstraint* ObjectConstraintHinge::getConstraint() {
|
||||||
return constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString repeatedHingeNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||||
|
"ObjectConstraintHinge::getConstraint -- no rigidBody.*");
|
||||||
|
|
||||||
btRigidBody* rigidBodyA = getRigidBody();
|
btRigidBody* rigidBodyA = getRigidBody();
|
||||||
if (!rigidBodyA) {
|
if (!rigidBodyA) {
|
||||||
qCDebug(physics) << "ObjectConstraintHinge::getConstraint -- no 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.
|
// This hinge is between two entities... find the other rigid body.
|
||||||
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
||||||
if (!rigidBodyB) {
|
if (!rigidBodyB) {
|
||||||
|
qCDebug(physics) << "ObjectConstraintHinge::getConstraint -- no rigidBodyB";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "QVariantGLM.h"
|
#include "QVariantGLM.h"
|
||||||
|
|
||||||
#include "EntityTree.h"
|
#include "EntityTree.h"
|
||||||
|
@ -85,6 +87,9 @@ btTypedConstraint* ObjectConstraintSlider::getConstraint() {
|
||||||
return constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString repeatedSliderNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||||
|
"ObjectConstraintSlider::getConstraint -- no rigidBody.*");
|
||||||
|
|
||||||
btRigidBody* rigidBodyA = getRigidBody();
|
btRigidBody* rigidBodyA = getRigidBody();
|
||||||
if (!rigidBodyA) {
|
if (!rigidBodyA) {
|
||||||
qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyA";
|
qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyA";
|
||||||
|
@ -116,6 +121,7 @@ btTypedConstraint* ObjectConstraintSlider::getConstraint() {
|
||||||
|
|
||||||
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
|
||||||
if (!rigidBodyB) {
|
if (!rigidBodyB) {
|
||||||
|
qCDebug(physics) << "ObjectConstraintSlider::getConstraint -- no rigidBodyB";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,7 @@ ShapeManager* ObjectMotionState::getShapeManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) :
|
ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) :
|
||||||
_motionType(MOTION_TYPE_STATIC),
|
|
||||||
_shape(shape),
|
_shape(shape),
|
||||||
_body(nullptr),
|
|
||||||
_mass(0.0f),
|
|
||||||
_lastKinematicStep(worldSimulationStep)
|
_lastKinematicStep(worldSimulationStep)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -74,7 +71,43 @@ ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) :
|
||||||
ObjectMotionState::~ObjectMotionState() {
|
ObjectMotionState::~ObjectMotionState() {
|
||||||
assert(!_body);
|
assert(!_body);
|
||||||
setShape(nullptr);
|
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 {
|
void ObjectMotionState::setBodyLinearVelocity(const glm::vec3& velocity) const {
|
||||||
|
|
|
@ -93,8 +93,8 @@ public:
|
||||||
MotionStateType getType() const { return _type; }
|
MotionStateType getType() const { return _type; }
|
||||||
virtual PhysicsMotionType getMotionType() const { return _motionType; }
|
virtual PhysicsMotionType getMotionType() const { return _motionType; }
|
||||||
|
|
||||||
void setMass(float mass) { _mass = fabsf(mass); }
|
void setMass(float mass);
|
||||||
float getMass() { return _mass; }
|
float getMass() const;
|
||||||
|
|
||||||
void setBodyLinearVelocity(const glm::vec3& velocity) const;
|
void setBodyLinearVelocity(const glm::vec3& velocity) const;
|
||||||
void setBodyAngularVelocity(const glm::vec3& velocity) const;
|
void setBodyAngularVelocity(const glm::vec3& velocity) const;
|
||||||
|
@ -159,12 +159,12 @@ protected:
|
||||||
void setRigidBody(btRigidBody* body);
|
void setRigidBody(btRigidBody* body);
|
||||||
virtual void setShape(const btCollisionShape* shape);
|
virtual void setShape(const btCollisionShape* shape);
|
||||||
|
|
||||||
MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState
|
MotionStateType _type { MOTIONSTATE_TYPE_INVALID }; // type of MotionState
|
||||||
PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC
|
PhysicsMotionType _motionType { MOTION_TYPE_STATIC }; // type of motion: KINEMATIC, DYNAMIC, or STATIC
|
||||||
|
|
||||||
const btCollisionShape* _shape;
|
const btCollisionShape* _shape;
|
||||||
btRigidBody* _body;
|
btRigidBody* _body { nullptr };
|
||||||
float _mass;
|
float _density { 1.0f };
|
||||||
|
|
||||||
uint32_t _lastKinematicStep;
|
uint32_t _lastKinematicStep;
|
||||||
bool _hasInternalKinematicChanges { false };
|
bool _hasInternalKinematicChanges { false };
|
||||||
|
|
|
@ -126,19 +126,8 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (variantType) {
|
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: {
|
case QVariant::Hash: {
|
||||||
qCritical() << "Unsupported variant type" << variant.typeName();
|
qCritical() << "Unsupported variant type" << variant.typeName() << ";" << key << variant;
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +141,8 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) {
|
||||||
case QVariant::UInt:
|
case QVariant::UInt:
|
||||||
case QVariant::Bool:
|
case QVariant::Bool:
|
||||||
case QVariant::Double:
|
case QVariant::Double:
|
||||||
|
case QVariant::Map:
|
||||||
|
case QVariant::List:
|
||||||
object.insert(key, QJsonValue::fromVariant(variant));
|
object.insert(key, QJsonValue::fromVariant(variant));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -768,9 +768,10 @@ bool similarStrings(const QString& stringA, const QString& stringB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disableQtBearerPoll() {
|
void disableQtBearerPoll() {
|
||||||
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
// to disable the Qt constant wireless scanning, set the env for polling interval
|
||||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT16_MAX).toLocal8Bit();
|
qDebug() << "Disabling Qt wireless polling by using a negative value for QTimer::setInterval";
|
||||||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
const QByteArray DISABLE_BEARER_POLL_TIMEOUT = QString::number(-1).toLocal8Bit();
|
||||||
|
qputenv("QT_BEARER_POLL_TIMEOUT", DISABLE_BEARER_POLL_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printSystemInformation() {
|
void printSystemInformation() {
|
||||||
|
|
|
@ -25,7 +25,9 @@ StoragePointer Storage::createView(size_t viewSize, size_t offset) const {
|
||||||
viewSize = selfSize;
|
viewSize = selfSize;
|
||||||
}
|
}
|
||||||
if ((viewSize + offset) > 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<ViewStorage>(shared_from_this(), viewSize, data() + offset);
|
return std::make_shared<ViewStorage>(shared_from_this(), viewSize, data() + offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
lifetime: <input id="lifetime" type="text" size=6>
|
lifetime: <input id="lifetime" type="text" size=6>
|
||||||
<hr>
|
<hr>
|
||||||
<input type="button" id="cone-twist-and-spring-lever-test" value="Cone-Twist and Spring-Action Lever"><br>
|
<input type="button" id="cone-twist-and-tractor-lever-test" value="Cone-Twist and Tractor-Action Lever"><br>
|
||||||
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.
|
||||||
<hr>
|
<hr>
|
||||||
<input type="button" id="door-vs-world-test" value="Hinge Between Swinging Door and World"><br>
|
<input type="button" id="door-vs-world-test" value="Hinge Between Swinging Door and World"><br>
|
||||||
A grabbable door with a hinge between it and world-space.
|
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 chain of spheres connected by ball-and-socket joints coincident-with the spheres.
|
||||||
<hr>
|
<hr>
|
||||||
<input type="button" id="ragdoll-test" value="Ragdoll"><br>
|
<input type="button" id="ragdoll-test" value="Ragdoll"><br>
|
||||||
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.
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue