mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 15:13:41 +02:00
First cut at stretching the arms out and aligning forearms with wrists.
Closes #1423, #1504.
This commit is contained in:
parent
a8bbe41642
commit
5d88953f12
7 changed files with 80 additions and 32 deletions
|
@ -60,7 +60,7 @@ bool FaceModel::render(float alpha) {
|
|||
void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform *
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.rotation = glm::angleAxis(-_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(_owningHead->getYaw(), glm::normalize(inverse * axes[1])) *
|
||||
|
|
|
@ -154,7 +154,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
|||
return;
|
||||
}
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
setJointPosition(jointIndex, palm.getPosition());
|
||||
float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f;
|
||||
glm::quat palmRotation;
|
||||
getJointRotation(jointIndex, palmRotation, true);
|
||||
|
@ -186,6 +185,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
|||
|
||||
// no point in continuing if there are no fingers
|
||||
if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) {
|
||||
stretchArm(jointIndex, palm.getPosition());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -203,6 +203,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
|||
|
||||
setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true);
|
||||
}
|
||||
|
||||
stretchArm(jointIndex, palm.getPosition());
|
||||
}
|
||||
|
||||
void SkeletonModel::updateJointState(int index) {
|
||||
|
@ -219,9 +221,47 @@ void SkeletonModel::updateJointState(int index) {
|
|||
void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform *
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
|
||||
state.rotation = glm::angleAxis(-_owningAvatar->getHead().getLeanSideways(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(-_owningAvatar->getHead().getLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
}
|
||||
|
||||
void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) {
|
||||
// find out where the hand is pointing
|
||||
glm::quat handRotation;
|
||||
getJointRotation(jointIndex, handRotation, true);
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
glm::vec3 forwardVector(jointIndex == geometry.rightHandJointIndex ? -1.0f : 1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 handVector = handRotation * forwardVector;
|
||||
|
||||
// align elbow with hand
|
||||
const FBXJoint& joint = geometry.joints.at(jointIndex);
|
||||
if (joint.parentIndex == -1) {
|
||||
return;
|
||||
}
|
||||
glm::quat elbowRotation;
|
||||
getJointRotation(joint.parentIndex, elbowRotation, true);
|
||||
applyRotationDelta(joint.parentIndex, rotationBetween(elbowRotation * forwardVector, handVector), false);
|
||||
|
||||
// set position according to normal length
|
||||
float scale = extractUniformScale(_scale);
|
||||
glm::vec3 handPosition = position - _translation;
|
||||
glm::vec3 elbowPosition = handPosition - handVector * joint.distanceToParent * scale;
|
||||
|
||||
// set shoulder orientation to point to elbow
|
||||
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
|
||||
if (parentJoint.parentIndex == -1) {
|
||||
return;
|
||||
}
|
||||
glm::quat shoulderRotation;
|
||||
getJointRotation(parentJoint.parentIndex, shoulderRotation, true);
|
||||
applyRotationDelta(parentJoint.parentIndex, rotationBetween(shoulderRotation * forwardVector,
|
||||
elbowPosition - extractTranslation(_jointStates.at(parentJoint.parentIndex).transform)), false);
|
||||
|
||||
// update the shoulder state
|
||||
updateJointState(parentJoint.parentIndex);
|
||||
|
||||
// adjust the elbow's local translation
|
||||
setJointTranslation(joint.parentIndex, elbowPosition);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
/// Using the current position and rotation of the identified (hand) joint, computes a
|
||||
/// reasonable stretched configuration for the connected arm.
|
||||
void stretchArm(int jointIndex, const glm::vec3& position);
|
||||
|
||||
Avatar* _owningAvatar;
|
||||
};
|
||||
|
||||
|
|
|
@ -484,6 +484,7 @@ public:
|
|||
|
||||
int parentIndex;
|
||||
|
||||
glm::vec3 translation;
|
||||
glm::mat4 preTransform;
|
||||
glm::quat preRotation;
|
||||
glm::quat rotation;
|
||||
|
@ -499,8 +500,8 @@ glm::mat4 getGlobalTransform(const QMultiHash<QString, QString>& parentMap,
|
|||
glm::mat4 globalTransform;
|
||||
while (!nodeID.isNull()) {
|
||||
const FBXModel& model = models.value(nodeID);
|
||||
globalTransform = model.preTransform * glm::mat4_cast(model.preRotation * model.rotation * model.postRotation) *
|
||||
model.postTransform * globalTransform;
|
||||
globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation *
|
||||
model.rotation * model.postRotation) * model.postTransform * globalTransform;
|
||||
|
||||
QList<QString> parentIDs = parentMap.values(nodeID);
|
||||
nodeID = QString();
|
||||
|
@ -956,8 +957,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
}
|
||||
}
|
||||
// see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
|
||||
model.preTransform = glm::translate(translation) * glm::translate(rotationOffset) *
|
||||
glm::translate(rotationPivot);
|
||||
model.translation = translation;
|
||||
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
|
||||
model.preRotation = glm::quat(glm::radians(preRotation));
|
||||
model.rotation = glm::quat(glm::radians(rotation));
|
||||
model.postRotation = glm::quat(glm::radians(postRotation));
|
||||
|
@ -1142,6 +1143,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
}
|
||||
joint.freeLineage.remove(lastFreeIndex + 1, joint.freeLineage.size() - lastFreeIndex - 1);
|
||||
|
||||
joint.translation = model.translation;
|
||||
joint.preTransform = model.preTransform;
|
||||
joint.preRotation = model.preRotation;
|
||||
joint.rotation = model.rotation;
|
||||
|
@ -1151,13 +1153,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
joint.rotationMax = model.rotationMax;
|
||||
glm::quat combinedRotation = model.preRotation * model.rotation * model.postRotation;
|
||||
if (joint.parentIndex == -1) {
|
||||
joint.transform = geometry.offset * model.preTransform * glm::mat4_cast(combinedRotation) * model.postTransform;
|
||||
joint.transform = geometry.offset * glm::translate(model.translation) * model.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * model.postTransform;
|
||||
joint.inverseDefaultRotation = glm::inverse(combinedRotation);
|
||||
joint.distanceToParent = 0.0f;
|
||||
|
||||
} else {
|
||||
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
|
||||
joint.transform = parentJoint.transform *
|
||||
joint.transform = parentJoint.transform * glm::translate(model.translation) *
|
||||
model.preTransform * glm::mat4_cast(combinedRotation) * model.postTransform;
|
||||
joint.inverseDefaultRotation = glm::inverse(combinedRotation) * parentJoint.inverseDefaultRotation;
|
||||
joint.distanceToParent = glm::distance(extractTranslation(parentJoint.transform),
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
int parentIndex;
|
||||
float distanceToParent;
|
||||
float boneRadius;
|
||||
glm::vec3 translation;
|
||||
glm::mat4 preTransform;
|
||||
glm::quat preRotation;
|
||||
glm::quat rotation;
|
||||
|
|
|
@ -99,6 +99,7 @@ void Model::simulate(float deltaTime) {
|
|||
if (_jointStates.isEmpty()) {
|
||||
foreach (const FBXJoint& joint, geometry.joints) {
|
||||
JointState state;
|
||||
state.translation = joint.translation;
|
||||
state.rotation = joint.rotation;
|
||||
_jointStates.append(state);
|
||||
}
|
||||
|
@ -626,7 +627,7 @@ void Model::updateJointState(int index) {
|
|||
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset);
|
||||
|
||||
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
|
||||
state.transform = baseTransform * geometry.offset * joint.preTransform *
|
||||
state.transform = baseTransform * geometry.offset * glm::translate(state.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
state.combinedRotation = _rotation * combinedRotation;
|
||||
|
||||
|
@ -642,7 +643,7 @@ void Model::updateJointState(int index) {
|
|||
maybeUpdateEyeRotation(parentState, joint, state);
|
||||
}
|
||||
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
|
||||
state.transform = parentState.transform * joint.preTransform *
|
||||
state.transform = parentState.transform * glm::translate(state.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
state.combinedRotation = parentState.combinedRotation * combinedRotation;
|
||||
}
|
||||
|
@ -747,6 +748,23 @@ bool Model::setJointRotation(int jointIndex, const glm::quat& rotation, bool fro
|
|||
return true;
|
||||
}
|
||||
|
||||
void Model::setJointTranslation(int jointIndex, const glm::vec3& translation) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const FBXJoint& joint = geometry.joints.at(jointIndex);
|
||||
|
||||
glm::mat4 parentTransform;
|
||||
if (joint.parentIndex == -1) {
|
||||
parentTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||
|
||||
} else {
|
||||
parentTransform = _jointStates.at(joint.parentIndex).transform;
|
||||
}
|
||||
JointState& state = _jointStates[jointIndex];
|
||||
glm::vec3 preTranslation = extractTranslation(joint.preTransform * glm::mat4_cast(joint.preRotation *
|
||||
state.rotation * joint.postRotation) * joint.postTransform);
|
||||
state.translation = glm::vec3(glm::inverse(parentTransform) * glm::vec4(translation, 1.0f)) - preTranslation;
|
||||
}
|
||||
|
||||
bool Model::restoreJointPosition(int jointIndex, float percent) {
|
||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||
return false;
|
||||
|
@ -824,25 +842,6 @@ void Model::renderCollisionProxies(float alpha) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Model::setJointTranslation(int jointIndex, int parentIndex, int childIndex, const glm::vec3& translation) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
JointState& state = _jointStates[jointIndex];
|
||||
if (childIndex != -1 && geometry.joints.at(jointIndex).isFree) {
|
||||
// if there's a child, then I must adjust *my* rotation
|
||||
glm::vec3 childTranslation = extractTranslation(_jointStates.at(childIndex).transform);
|
||||
applyRotationDelta(jointIndex, rotationBetween(childTranslation - extractTranslation(state.transform),
|
||||
childTranslation - translation));
|
||||
}
|
||||
if (parentIndex != -1 && geometry.joints.at(parentIndex).isFree) {
|
||||
// if there's a parent, then I must adjust *its* rotation
|
||||
JointState& parent = _jointStates[parentIndex];
|
||||
glm::vec3 parentTranslation = extractTranslation(parent.transform);
|
||||
applyRotationDelta(parentIndex, rotationBetween(extractTranslation(state.transform) - parentTranslation,
|
||||
translation - parentTranslation));
|
||||
}
|
||||
::setTranslation(state.transform, translation);
|
||||
}
|
||||
|
||||
void Model::deleteGeometry() {
|
||||
foreach (Model* attachment, _attachments) {
|
||||
delete attachment;
|
||||
|
|
|
@ -141,6 +141,7 @@ protected:
|
|||
|
||||
class JointState {
|
||||
public:
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
glm::mat4 transform;
|
||||
glm::quat combinedRotation;
|
||||
|
@ -172,6 +173,8 @@ protected:
|
|||
bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f));
|
||||
bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false);
|
||||
|
||||
void setJointTranslation(int jointIndex, const glm::vec3& translation);
|
||||
|
||||
/// Restores the indexed joint to its default position.
|
||||
/// \param percent the percentage of the default position to apply (i.e., 0.25f to slerp one fourth of the way to
|
||||
/// the original position
|
||||
|
@ -188,8 +191,6 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
void setJointTranslation(int jointIndex, int parentIndex, int childIndex, const glm::vec3& translation);
|
||||
|
||||
void deleteGeometry();
|
||||
|
||||
float _pupilDilation;
|
||||
|
|
Loading…
Reference in a new issue