mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 01:00:44 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into smooth-faded-animations
This commit is contained in:
commit
2f2b59b6b6
18 changed files with 230 additions and 80 deletions
64
interface/resources/meshes/defaultAvatar_full.fst
Normal file
64
interface/resources/meshes/defaultAvatar_full.fst
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
name = defaultAvatar_full
|
||||||
|
type = body+head
|
||||||
|
scale = 1
|
||||||
|
filename = defaultAvatar_full/defaultAvatar_full.fbx
|
||||||
|
texdir = defaultAvatar_full/textures
|
||||||
|
joint = jointNeck = Head
|
||||||
|
joint = jointLeftHand = LeftHand
|
||||||
|
joint = jointRoot = Hips
|
||||||
|
joint = jointHead = HeadTop_End
|
||||||
|
joint = jointRightHand = RightHand
|
||||||
|
joint = jointLean = Spine
|
||||||
|
freeJoint = LeftArm
|
||||||
|
freeJoint = LeftForeArm
|
||||||
|
freeJoint = RightArm
|
||||||
|
freeJoint = RightForeArm
|
||||||
|
jointIndex = LeftHand = 35
|
||||||
|
jointIndex = Reye = 3
|
||||||
|
jointIndex = Hips = 10
|
||||||
|
jointIndex = LeftHandIndex1 = 36
|
||||||
|
jointIndex = LeftHandIndex2 = 37
|
||||||
|
jointIndex = LeftHandIndex3 = 38
|
||||||
|
jointIndex = LeftHandIndex4 = 39
|
||||||
|
jointIndex = LeftShoulder = 32
|
||||||
|
jointIndex = RightLeg = 12
|
||||||
|
jointIndex = Grp_blendshapes = 0
|
||||||
|
jointIndex = Leye = 4
|
||||||
|
jointIndex = headphone = 8
|
||||||
|
jointIndex = RightForeArm = 26
|
||||||
|
jointIndex = Spine = 21
|
||||||
|
jointIndex = LeftFoot = 18
|
||||||
|
jointIndex = RightToeBase = 14
|
||||||
|
jointIndex = face = 1
|
||||||
|
jointIndex = LeftToe_End = 20
|
||||||
|
jointIndex = Spine1 = 22
|
||||||
|
jointIndex = body = 9
|
||||||
|
jointIndex = Spine2 = 23
|
||||||
|
jointIndex = RightUpLeg = 11
|
||||||
|
jointIndex = top1 = 7
|
||||||
|
jointIndex = Neck = 40
|
||||||
|
jointIndex = HeadTop_End = 42
|
||||||
|
jointIndex = RightShoulder = 24
|
||||||
|
jointIndex = RightArm = 25
|
||||||
|
jointIndex = Head = 41
|
||||||
|
jointIndex = LeftLeg = 17
|
||||||
|
jointIndex = LeftForeArm = 34
|
||||||
|
jointIndex = hair = 6
|
||||||
|
jointIndex = RightHand = 27
|
||||||
|
jointIndex = LeftToeBase = 19
|
||||||
|
jointIndex = LeftUpLeg = 16
|
||||||
|
jointIndex = mouth = 2
|
||||||
|
jointIndex = RightFoot = 13
|
||||||
|
jointIndex = LeftArm = 33
|
||||||
|
jointIndex = shield = 5
|
||||||
|
jointIndex = RightHandIndex1 = 28
|
||||||
|
jointIndex = RightHandIndex2 = 29
|
||||||
|
jointIndex = RightToe_End = 15
|
||||||
|
jointIndex = RightHandIndex3 = 30
|
||||||
|
jointIndex = RightHandIndex4 = 31
|
||||||
|
ry = 0
|
||||||
|
rz = 0
|
||||||
|
tx = 0
|
||||||
|
ty = 0
|
||||||
|
tz = 0
|
||||||
|
rx = 0
|
Binary file not shown.
BIN
interface/resources/meshes/defaultAvatar_full/textures/visor.png
Normal file
BIN
interface/resources/meshes/defaultAvatar_full/textures/visor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -2013,6 +2013,7 @@ void Application::setActiveFaceTracker() {
|
||||||
#ifdef HAVE_DDE
|
#ifdef HAVE_DDE
|
||||||
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera);
|
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera);
|
||||||
Menu::getInstance()->getActionForOption(MenuOption::BinaryEyelidControl)->setVisible(isUsingDDE);
|
Menu::getInstance()->getActionForOption(MenuOption::BinaryEyelidControl)->setVisible(isUsingDDE);
|
||||||
|
Menu::getInstance()->getActionForOption(MenuOption::CoupleEyelids)->setVisible(isUsingDDE);
|
||||||
Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE);
|
Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE);
|
||||||
Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE);
|
Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE);
|
||||||
Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setVisible(isUsingDDE);
|
Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setVisible(isUsingDDE);
|
||||||
|
|
|
@ -421,6 +421,8 @@ Menu::Menu() {
|
||||||
faceTrackingMenu->addSeparator();
|
faceTrackingMenu->addSeparator();
|
||||||
QAction* binaryEyelidControl = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::BinaryEyelidControl, 0, true);
|
QAction* binaryEyelidControl = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::BinaryEyelidControl, 0, true);
|
||||||
binaryEyelidControl->setVisible(true); // DDE face tracking is on by default
|
binaryEyelidControl->setVisible(true); // DDE face tracking is on by default
|
||||||
|
QAction* coupleEyelids = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::CoupleEyelids, 0, true);
|
||||||
|
coupleEyelids->setVisible(true); // DDE face tracking is on by default
|
||||||
QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true);
|
QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true);
|
||||||
useAudioForMouth->setVisible(true); // DDE face tracking is on by default
|
useAudioForMouth->setVisible(true); // DDE face tracking is on by default
|
||||||
QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true);
|
QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true);
|
||||||
|
|
|
@ -165,6 +165,7 @@ namespace MenuOption {
|
||||||
const QString ControlWithSpeech = "Control With Speech";
|
const QString ControlWithSpeech = "Control With Speech";
|
||||||
const QString CopyAddress = "Copy Address to Clipboard";
|
const QString CopyAddress = "Copy Address to Clipboard";
|
||||||
const QString CopyPath = "Copy Path to Clipboard";
|
const QString CopyPath = "Copy Path to Clipboard";
|
||||||
|
const QString CoupleEyelids = "Couple Eyelids";
|
||||||
const QString DebugAmbientOcclusion = "Debug Ambient Occlusion";
|
const QString DebugAmbientOcclusion = "Debug Ambient Occlusion";
|
||||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||||
const QString DeleteBookmark = "Delete Bookmark...";
|
const QString DeleteBookmark = "Delete Bookmark...";
|
||||||
|
|
|
@ -936,8 +936,14 @@ void Avatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||||
|
|
||||||
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||||
|
const QUrl DEFAULT_FULL_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst");
|
||||||
const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst");
|
const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst");
|
||||||
_skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar());
|
if (isMyAvatar()) {
|
||||||
|
_skeletonModel.setURL(_skeletonModelURL,
|
||||||
|
getUseFullAvatar() ? DEFAULT_FULL_MODEL_URL : DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar());
|
||||||
|
} else {
|
||||||
|
_skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||||
|
|
|
@ -150,6 +150,7 @@ public:
|
||||||
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
||||||
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
||||||
|
|
||||||
|
virtual bool getUseFullAvatar() const { return false; }
|
||||||
|
|
||||||
/// Scales a world space position vector relative to the avatar position and scale
|
/// Scales a world space position vector relative to the avatar position and scale
|
||||||
/// \param vector position to be scaled. Will store the result
|
/// \param vector position to be scaled. Will store the result
|
||||||
|
|
|
@ -116,7 +116,7 @@ public:
|
||||||
Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL,
|
Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL,
|
||||||
const QString& headName = QString(), const QString& bodyName = QString());
|
const QString& headName = QString(), const QString& bodyName = QString());
|
||||||
|
|
||||||
Q_INVOKABLE bool getUseFullAvatar() const { return _useFullAvatar; }
|
Q_INVOKABLE virtual bool getUseFullAvatar() const { return _useFullAvatar; }
|
||||||
Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; }
|
Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; }
|
||||||
Q_INVOKABLE const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; }
|
Q_INVOKABLE const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; }
|
||||||
Q_INVOKABLE const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; }
|
Q_INVOKABLE const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; }
|
||||||
|
|
|
@ -42,7 +42,23 @@ SkeletonModel::~SkeletonModel() {
|
||||||
void SkeletonModel::initJointStates(QVector<JointState> states) {
|
void SkeletonModel::initJointStates(QVector<JointState> states) {
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||||
_boundingRadius = _rig->initJointStates(states, parentTransform);
|
|
||||||
|
int rootJointIndex = geometry.rootJointIndex;
|
||||||
|
int leftHandJointIndex = geometry.leftHandJointIndex;
|
||||||
|
int leftElbowJointIndex = leftHandJointIndex >= 0 ? geometry.joints.at(leftHandJointIndex).parentIndex : -1;
|
||||||
|
int leftShoulderJointIndex = leftElbowJointIndex >= 0 ? geometry.joints.at(leftElbowJointIndex).parentIndex : -1;
|
||||||
|
int rightHandJointIndex = geometry.rightHandJointIndex;
|
||||||
|
int rightElbowJointIndex = rightHandJointIndex >= 0 ? geometry.joints.at(rightHandJointIndex).parentIndex : -1;
|
||||||
|
int rightShoulderJointIndex = rightElbowJointIndex >= 0 ? geometry.joints.at(rightElbowJointIndex).parentIndex : -1;
|
||||||
|
|
||||||
|
_boundingRadius = _rig->initJointStates(states, parentTransform,
|
||||||
|
rootJointIndex,
|
||||||
|
leftHandJointIndex,
|
||||||
|
leftElbowJointIndex,
|
||||||
|
leftShoulderJointIndex,
|
||||||
|
rightHandJointIndex,
|
||||||
|
rightElbowJointIndex,
|
||||||
|
rightShoulderJointIndex);
|
||||||
|
|
||||||
// Determine the default eye position for avatar scale = 1.0
|
// Determine the default eye position for avatar scale = 1.0
|
||||||
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
|
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
|
||||||
|
@ -227,7 +243,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
||||||
palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation;
|
palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation;
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) {
|
||||||
setHandPosition(jointIndex, palmPosition, palmRotation);
|
_rig->setHandPosition(jointIndex, palmPosition, palmRotation, extractUniformScale(_scale), PALM_PRIORITY);
|
||||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
} else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
||||||
float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale);
|
float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale);
|
||||||
glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f);
|
glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f);
|
||||||
|
@ -332,69 +348,6 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde
|
||||||
geometryCache->renderLine(batch, position, pFront, blue, jointLineIDs._front);
|
geometryCache->renderLine(batch, position, pFront, blue, jointLineIDs._front);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation) {
|
|
||||||
// this algorithm is from sample code from sixense
|
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
|
||||||
int elbowJointIndex = geometry.joints.at(jointIndex).parentIndex;
|
|
||||||
if (elbowJointIndex == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int shoulderJointIndex = geometry.joints.at(elbowJointIndex).parentIndex;
|
|
||||||
glm::vec3 shoulderPosition;
|
|
||||||
if (!getJointPosition(shoulderJointIndex, shoulderPosition)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// precomputed lengths
|
|
||||||
float scale = extractUniformScale(_scale);
|
|
||||||
float upperArmLength = geometry.joints.at(elbowJointIndex).distanceToParent * scale;
|
|
||||||
float lowerArmLength = geometry.joints.at(jointIndex).distanceToParent * scale;
|
|
||||||
|
|
||||||
// first set wrist position
|
|
||||||
glm::vec3 wristPosition = position;
|
|
||||||
|
|
||||||
glm::vec3 shoulderToWrist = wristPosition - shoulderPosition;
|
|
||||||
float distanceToWrist = glm::length(shoulderToWrist);
|
|
||||||
|
|
||||||
// prevent gimbal lock
|
|
||||||
if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) {
|
|
||||||
distanceToWrist = upperArmLength + lowerArmLength - EPSILON;
|
|
||||||
shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist;
|
|
||||||
wristPosition = shoulderPosition + shoulderToWrist;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cosine of angle from upper arm to hand vector
|
|
||||||
float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) /
|
|
||||||
(2 * upperArmLength * distanceToWrist);
|
|
||||||
float mid = upperArmLength * cosA;
|
|
||||||
float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA);
|
|
||||||
|
|
||||||
// direction of the elbow
|
|
||||||
glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist
|
|
||||||
glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down
|
|
||||||
const float NORMAL_WEIGHT = 0.5f;
|
|
||||||
glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT);
|
|
||||||
|
|
||||||
bool rightHand = (jointIndex == geometry.rightHandJointIndex);
|
|
||||||
if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) {
|
|
||||||
finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis)
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal));
|
|
||||||
|
|
||||||
// ik solution
|
|
||||||
glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height;
|
|
||||||
glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
|
|
||||||
glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition);
|
|
||||||
|
|
||||||
_rig->setJointRotationInBindFrame(shoulderJointIndex, shoulderRotation, PALM_PRIORITY);
|
|
||||||
_rig->setJointRotationInBindFrame(elbowJointIndex,
|
|
||||||
rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) *
|
|
||||||
shoulderRotation, PALM_PRIORITY);
|
|
||||||
_rig->setJointRotationInBindFrame(jointIndex, rotation, PALM_PRIORITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const {
|
bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const {
|
||||||
return getJointPositionInWorldFrame(getLeftHandJointIndex(), position);
|
return getJointPositionInWorldFrame(getLeftHandJointIndex(), position);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,6 @@ private:
|
||||||
QHash<int, OrientationLineIDs> _jointOrientationLines;
|
QHash<int, OrientationLineIDs> _jointOrientationLines;
|
||||||
int _triangleFanID;
|
int _triangleFanID;
|
||||||
|
|
||||||
/// \param jointIndex index of joint in model
|
|
||||||
/// \param position position of joint in model-frame
|
|
||||||
/// \param rotation rotation of joint in model-frame
|
|
||||||
void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation);
|
|
||||||
|
|
||||||
bool getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
bool getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||||
|
|
||||||
Avatar* _owningAvatar;
|
Avatar* _owningAvatar;
|
||||||
|
|
|
@ -564,6 +564,13 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||||
eyeCoefficients[1] = _filteredEyeBlinks[1];
|
eyeCoefficients[1] = _filteredEyeBlinks[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Couple eyelid values if configured - use the most "open" value for both
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::CoupleEyelids)) {
|
||||||
|
float eyeCoefficient = std::min(eyeCoefficients[0], eyeCoefficients[1]);
|
||||||
|
eyeCoefficients[0] = eyeCoefficient;
|
||||||
|
eyeCoefficients[1] = eyeCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
// Use EyeBlink values to control both EyeBlink and EyeOpen
|
// Use EyeBlink values to control both EyeBlink and EyeOpen
|
||||||
if (eyeCoefficients[0] > 0) {
|
if (eyeCoefficients[0] > 0) {
|
||||||
_coefficients[_leftBlinkIndex] = eyeCoefficients[0];
|
_coefficients[_leftBlinkIndex] = eyeCoefficients[0];
|
||||||
|
|
|
@ -20,15 +20,81 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) {
|
||||||
const FBXJoint& joint = state.getFBXJoint();
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
|
|
||||||
// compute model transforms
|
// compute model transforms
|
||||||
int parentIndex = joint.parentIndex;
|
if (index == _rootJointIndex) {
|
||||||
if (parentIndex == -1) {
|
// we always zero-out the translation part of an avatar's root join-transform.
|
||||||
state.computeTransform(parentTransform);
|
state.computeTransform(parentTransform);
|
||||||
clearJointTransformTranslation(index);
|
clearJointTransformTranslation(index);
|
||||||
} else {
|
} else {
|
||||||
// guard against out-of-bounds access to _jointStates
|
// guard against out-of-bounds access to _jointStates
|
||||||
if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) {
|
int parentIndex = joint.parentIndex;
|
||||||
|
if (parentIndex >= 0 && parentIndex < _jointStates.size()) {
|
||||||
const JointState& parentState = _jointStates.at(parentIndex);
|
const JointState& parentState = _jointStates.at(parentIndex);
|
||||||
state.computeTransform(parentState.getTransform(), parentState.getTransformChanged());
|
state.computeTransform(parentState.getTransform(), parentState.getTransformChanged());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarRig::setHandPosition(int jointIndex,
|
||||||
|
const glm::vec3& position, const glm::quat& rotation,
|
||||||
|
float scale, float priority) {
|
||||||
|
bool rightHand = (jointIndex == _rightHandJointIndex);
|
||||||
|
|
||||||
|
int elbowJointIndex = rightHand ? _rightElbowJointIndex : _leftElbowJointIndex;
|
||||||
|
int shoulderJointIndex = rightHand ? _rightShoulderJointIndex : _leftShoulderJointIndex;
|
||||||
|
|
||||||
|
// this algorithm is from sample code from sixense
|
||||||
|
if (elbowJointIndex == -1 || shoulderJointIndex == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 shoulderPosition;
|
||||||
|
if (!getJointPosition(shoulderJointIndex, shoulderPosition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// precomputed lengths
|
||||||
|
float upperArmLength = _jointStates[elbowJointIndex].getFBXJoint().distanceToParent * scale;
|
||||||
|
float lowerArmLength = _jointStates[jointIndex].getFBXJoint().distanceToParent * scale;
|
||||||
|
|
||||||
|
// first set wrist position
|
||||||
|
glm::vec3 wristPosition = position;
|
||||||
|
|
||||||
|
glm::vec3 shoulderToWrist = wristPosition - shoulderPosition;
|
||||||
|
float distanceToWrist = glm::length(shoulderToWrist);
|
||||||
|
|
||||||
|
// prevent gimbal lock
|
||||||
|
if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) {
|
||||||
|
distanceToWrist = upperArmLength + lowerArmLength - EPSILON;
|
||||||
|
shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist;
|
||||||
|
wristPosition = shoulderPosition + shoulderToWrist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cosine of angle from upper arm to hand vector
|
||||||
|
float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) /
|
||||||
|
(2 * upperArmLength * distanceToWrist);
|
||||||
|
float mid = upperArmLength * cosA;
|
||||||
|
float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA);
|
||||||
|
|
||||||
|
// direction of the elbow
|
||||||
|
glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist
|
||||||
|
glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down
|
||||||
|
const float NORMAL_WEIGHT = 0.5f;
|
||||||
|
glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT);
|
||||||
|
|
||||||
|
if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) {
|
||||||
|
finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal));
|
||||||
|
|
||||||
|
// ik solution
|
||||||
|
glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height;
|
||||||
|
glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
|
||||||
|
glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition);
|
||||||
|
|
||||||
|
setJointRotationInBindFrame(shoulderJointIndex, shoulderRotation, priority);
|
||||||
|
setJointRotationInBindFrame(elbowJointIndex,
|
||||||
|
rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) *
|
||||||
|
shoulderRotation, priority);
|
||||||
|
setJointRotationInBindFrame(jointIndex, rotation, priority);
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ class AvatarRig : public Rig {
|
||||||
public:
|
public:
|
||||||
~AvatarRig() {}
|
~AvatarRig() {}
|
||||||
virtual void updateJointState(int index, glm::mat4 parentTransform);
|
virtual void updateJointState(int index, glm::mat4 parentTransform);
|
||||||
|
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||||
|
float scale, float priority);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AvatarRig_h
|
#endif // hifi_AvatarRig_h
|
||||||
|
|
|
@ -22,6 +22,8 @@ class EntityRig : public Rig {
|
||||||
public:
|
public:
|
||||||
~EntityRig() {}
|
~EntityRig() {}
|
||||||
virtual void updateJointState(int index, glm::mat4 parentTransform);
|
virtual void updateJointState(int index, glm::mat4 parentTransform);
|
||||||
|
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||||
|
float scale, float priority) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityRig_h
|
#endif // hifi_EntityRig_h
|
||||||
|
|
|
@ -182,8 +182,24 @@ void Rig::deleteAnimations() {
|
||||||
_animationHandles.clear();
|
_animationHandles.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Rig::initJointStates(QVector<JointState> states, glm::mat4 parentTransform) {
|
float Rig::initJointStates(QVector<JointState> states, glm::mat4 parentTransform,
|
||||||
|
int rootJointIndex,
|
||||||
|
int leftHandJointIndex,
|
||||||
|
int leftElbowJointIndex,
|
||||||
|
int leftShoulderJointIndex,
|
||||||
|
int rightHandJointIndex,
|
||||||
|
int rightElbowJointIndex,
|
||||||
|
int rightShoulderJointIndex) {
|
||||||
_jointStates = states;
|
_jointStates = states;
|
||||||
|
|
||||||
|
_rootJointIndex = rootJointIndex;
|
||||||
|
_leftHandJointIndex = leftHandJointIndex;
|
||||||
|
_leftElbowJointIndex = leftElbowJointIndex;
|
||||||
|
_leftShoulderJointIndex = leftShoulderJointIndex;
|
||||||
|
_rightHandJointIndex = rightHandJointIndex;
|
||||||
|
_rightElbowJointIndex = rightElbowJointIndex;
|
||||||
|
_rightShoulderJointIndex = rightShoulderJointIndex;
|
||||||
|
|
||||||
initJointTransforms(parentTransform);
|
initJointTransforms(parentTransform);
|
||||||
|
|
||||||
int numStates = _jointStates.size();
|
int numStates = _jointStates.size();
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
|
|
||||||
class AnimationHandle;
|
class AnimationHandle;
|
||||||
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
|
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
|
||||||
// typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
|
||||||
|
|
||||||
class Rig;
|
class Rig;
|
||||||
typedef std::shared_ptr<Rig> RigPointer;
|
typedef std::shared_ptr<Rig> RigPointer;
|
||||||
|
@ -91,7 +90,14 @@ public:
|
||||||
float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f,
|
float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f,
|
||||||
float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList(), bool startAutomatically = false);
|
float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList(), bool startAutomatically = false);
|
||||||
|
|
||||||
float initJointStates(QVector<JointState> states, glm::mat4 parentTransform);
|
float initJointStates(QVector<JointState> states, glm::mat4 parentTransform,
|
||||||
|
int rootJointIndex,
|
||||||
|
int leftHandJointIndex,
|
||||||
|
int leftElbowJointIndex,
|
||||||
|
int leftShoulderJointIndex,
|
||||||
|
int rightHandJointIndex,
|
||||||
|
int rightElbowJointIndex,
|
||||||
|
int rightShoulderJointIndex);
|
||||||
bool jointStatesEmpty() { return _jointStates.isEmpty(); };
|
bool jointStatesEmpty() { return _jointStates.isEmpty(); };
|
||||||
int getJointStateCount() const { return _jointStates.size(); }
|
int getJointStateCount() const { return _jointStates.size(); }
|
||||||
int indexOfJoint(const QString& jointName) ;
|
int indexOfJoint(const QString& jointName) ;
|
||||||
|
@ -150,6 +156,9 @@ public:
|
||||||
|
|
||||||
void updateFromHeadParameters(const HeadParameters& params);
|
void updateFromHeadParameters(const HeadParameters& params);
|
||||||
|
|
||||||
|
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||||
|
float scale, float priority) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
|
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
|
||||||
|
@ -157,6 +166,15 @@ public:
|
||||||
void updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
|
void updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
|
||||||
|
|
||||||
QVector<JointState> _jointStates;
|
QVector<JointState> _jointStates;
|
||||||
|
int _rootJointIndex = -1;
|
||||||
|
|
||||||
|
int _leftHandJointIndex = -1;
|
||||||
|
int _leftElbowJointIndex = -1;
|
||||||
|
int _leftShoulderJointIndex = -1;
|
||||||
|
|
||||||
|
int _rightHandJointIndex = -1;
|
||||||
|
int _rightElbowJointIndex = -1;
|
||||||
|
int _rightShoulderJointIndex = -1;
|
||||||
|
|
||||||
QList<AnimationHandlePointer> _animationHandles;
|
QList<AnimationHandlePointer> _animationHandles;
|
||||||
QList<AnimationHandlePointer> _runningAnimations;
|
QList<AnimationHandlePointer> _runningAnimations;
|
||||||
|
@ -164,6 +182,6 @@ public:
|
||||||
bool _enableRig;
|
bool _enableRig;
|
||||||
glm::vec3 _lastFront;
|
glm::vec3 _lastFront;
|
||||||
glm::vec3 _lastPosition;
|
glm::vec3 _lastPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__Rig__) */
|
#endif /* defined(__hifi__Rig__) */
|
||||||
|
|
|
@ -473,7 +473,23 @@ bool Model::updateGeometry() {
|
||||||
void Model::initJointStates(QVector<JointState> states) {
|
void Model::initJointStates(QVector<JointState> states) {
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||||
_boundingRadius = _rig->initJointStates(states, parentTransform);
|
|
||||||
|
int rootJointIndex = geometry.rootJointIndex;
|
||||||
|
int leftHandJointIndex = geometry.leftHandJointIndex;
|
||||||
|
int leftElbowJointIndex = leftHandJointIndex >= 0 ? geometry.joints.at(leftHandJointIndex).parentIndex : -1;
|
||||||
|
int leftShoulderJointIndex = leftElbowJointIndex >= 0 ? geometry.joints.at(leftElbowJointIndex).parentIndex : -1;
|
||||||
|
int rightHandJointIndex = geometry.rightHandJointIndex;
|
||||||
|
int rightElbowJointIndex = rightHandJointIndex >= 0 ? geometry.joints.at(rightHandJointIndex).parentIndex : -1;
|
||||||
|
int rightShoulderJointIndex = rightElbowJointIndex >= 0 ? geometry.joints.at(rightElbowJointIndex).parentIndex : -1;
|
||||||
|
|
||||||
|
_boundingRadius = _rig->initJointStates(states, parentTransform,
|
||||||
|
rootJointIndex,
|
||||||
|
leftHandJointIndex,
|
||||||
|
leftElbowJointIndex,
|
||||||
|
leftShoulderJointIndex,
|
||||||
|
rightHandJointIndex,
|
||||||
|
rightElbowJointIndex,
|
||||||
|
rightShoulderJointIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
|
|
Loading…
Reference in a new issue