mirror of
https://github.com/overte-org/overte.git
synced 2025-08-16 06:11:15 +02:00
Working on wiring up the fingers.
This commit is contained in:
parent
be09d319b7
commit
e6cd9a7368
8 changed files with 92 additions and 15 deletions
|
@ -660,7 +660,7 @@ void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJ
|
|||
float distance = glm::length(armVector);
|
||||
|
||||
// don't let right hand get dragged beyond maximum arm length...
|
||||
float armLength = _maxArmLength * 0.5f;
|
||||
float armLength = _maxArmLength * 0.75f;
|
||||
if (distance > armLength) {
|
||||
// reset right hand to be constrained to maximum arm length
|
||||
fingerJoint.position = shoulderJoint.position;
|
||||
|
|
|
@ -45,6 +45,7 @@ void SkeletonModel::simulate(float deltaTime) {
|
|||
|
||||
const float HAND_RESTORATION_RATE = 0.25f;
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
if (firstActivePalmIndex == -1) {
|
||||
// no Leap data; set hands from mouse
|
||||
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
|
||||
|
@ -56,7 +57,8 @@ void SkeletonModel::simulate(float deltaTime) {
|
|||
|
||||
} else if (secondActivePalmIndex == -1) {
|
||||
// right hand only
|
||||
applyPalmData(_geometry->getFBXGeometry().rightHandJointIndex, hand.getPalms()[firstActivePalmIndex]);
|
||||
applyPalmData(geometry.rightHandJointIndex, geometry.rightFingertipJointIndices,
|
||||
hand.getPalms()[firstActivePalmIndex]);
|
||||
restoreLeftHandPosition(HAND_RESTORATION_RATE);
|
||||
|
||||
} else {
|
||||
|
@ -65,8 +67,10 @@ void SkeletonModel::simulate(float deltaTime) {
|
|||
hand.getPalms()[secondActivePalmIndex].getRawPosition().x) {
|
||||
qSwap(firstActivePalmIndex, secondActivePalmIndex);
|
||||
}
|
||||
applyPalmData(_geometry->getFBXGeometry().leftHandJointIndex, hand.getPalms()[firstActivePalmIndex]);
|
||||
applyPalmData(_geometry->getFBXGeometry().rightHandJointIndex, hand.getPalms()[secondActivePalmIndex]);
|
||||
applyPalmData(geometry.leftHandJointIndex, geometry.leftFingertipJointIndices,
|
||||
hand.getPalms()[firstActivePalmIndex]);
|
||||
applyPalmData(geometry.rightHandJointIndex, geometry.rightFingertipJointIndices,
|
||||
hand.getPalms()[secondActivePalmIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,9 +124,48 @@ bool SkeletonModel::render(float alpha) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) {
|
||||
class IndexValue {
|
||||
public:
|
||||
int index;
|
||||
float value;
|
||||
};
|
||||
|
||||
bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) {
|
||||
return firstIndex.value < secondIndex.value;
|
||||
}
|
||||
|
||||
void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingertipJointIndices, PalmData& palm) {
|
||||
setJointPosition(jointIndex, palm.getPosition());
|
||||
setJointRotation(jointIndex, rotationBetween(_rotation * IDENTITY_UP, -palm.getNormal()));
|
||||
setJointRotation(jointIndex, rotationBetween(_rotation * IDENTITY_UP, palm.getNormal()) * _rotation);
|
||||
|
||||
// no point in continuing if there are no fingers
|
||||
if (palm.getNumFingers() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sort the finger indices by raw x
|
||||
QVector<IndexValue> fingerIndices;
|
||||
for (int i = 0; i < palm.getNumFingers(); i++) {
|
||||
IndexValue indexValue = { i, palm.getFingers()[i].getTipRawPosition().x };
|
||||
fingerIndices.append(indexValue);
|
||||
}
|
||||
qSort(fingerIndices.begin(), fingerIndices.end());
|
||||
|
||||
// likewise with the joint indices and relative x
|
||||
QVector<IndexValue> jointIndices;
|
||||
foreach (int index, fingertipJointIndices) {
|
||||
glm::vec3 position = glm::inverse(_rotation) * extractTranslation(_jointStates[index].transform);
|
||||
IndexValue indexValue = { index, position.x };
|
||||
jointIndices.append(indexValue);
|
||||
}
|
||||
//qSort(jointIndices.begin(), jointIndices.end());
|
||||
|
||||
// match them up as best we can
|
||||
float proportion = fingerIndices.size() / (float)jointIndices.size();
|
||||
for (int i = 0; i < jointIndices.size(); i++) {
|
||||
int fingerIndex = fingerIndices.at(roundf(i * proportion)).index;
|
||||
setJointPosition(jointIndices.at(i).index, palm.getFingers()[fingerIndex].getTipPosition(), jointIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::updateJointState(int index) {
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
void applyPalmData(int jointIndex, const PalmData& palm);
|
||||
void applyPalmData(int jointIndex, const QVector<int>& fingertipJointIndices, PalmData& palm);
|
||||
|
||||
/// Updates the state of the joint at the specified index.
|
||||
virtual void updateJointState(int index);
|
||||
|
|
|
@ -198,8 +198,8 @@ void LeapManager::nextFrame(Avatar& avatar) {
|
|||
// There's no real Leap data and we need to fake it.
|
||||
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
||||
static const glm::vec3 fakeHandOffsets[] = {
|
||||
glm::vec3( -500.0f, 50.0f, 50.0f),
|
||||
glm::vec3( 0.0f, 50.0f, 50.0f)
|
||||
glm::vec3( -250.0f, 50.0f, 50.0f),
|
||||
glm::vec3( 250.0f, 50.0f, 50.0f)
|
||||
};
|
||||
static const glm::vec3 fakeHandFingerMirrors[] = {
|
||||
glm::vec3( -1.0f, 1.0f, 1.0f),
|
||||
|
|
|
@ -747,6 +747,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
QString jointHeadName = processID(joints.value("jointHead", "jointHead").toString());
|
||||
QString jointLeftHandName = processID(joints.value("jointLeftHand", "jointLeftHand").toString());
|
||||
QString jointRightHandName = processID(joints.value("jointRightHand", "jointRightHand").toString());
|
||||
QVariantList jointLeftFingertipNames = joints.values("jointLeftFingertip");
|
||||
QVariantList jointRightFingertipNames = joints.values("jointRightFingertip");
|
||||
QString jointEyeLeftID;
|
||||
QString jointEyeRightID;
|
||||
QString jointNeckID;
|
||||
|
@ -755,6 +757,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
QString jointHeadID;
|
||||
QString jointLeftHandID;
|
||||
QString jointRightHandID;
|
||||
QStringList jointLeftFingertipIDs;
|
||||
QStringList jointRightFingertipIDs;
|
||||
|
||||
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
|
||||
QHash<QByteArray, QPair<int, float> > blendshapeIndices;
|
||||
|
@ -834,6 +838,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
|
||||
} else if (name == jointRightHandName) {
|
||||
jointRightHandID = getID(object.properties);
|
||||
|
||||
} else if (jointLeftFingertipNames.contains(name)) {
|
||||
jointLeftFingertipIDs.append(getID(object.properties));
|
||||
|
||||
} else if (jointRightFingertipNames.contains(name)) {
|
||||
jointRightFingertipIDs.append(getID(object.properties));
|
||||
}
|
||||
glm::vec3 translation;
|
||||
glm::vec3 rotationOffset;
|
||||
|
@ -1088,6 +1098,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
geometry.leftHandJointIndex = modelIDs.indexOf(jointLeftHandID);
|
||||
geometry.rightHandJointIndex = modelIDs.indexOf(jointRightHandID);
|
||||
|
||||
foreach (const QString& id, jointLeftFingertipIDs) {
|
||||
geometry.leftFingertipJointIndices.append(modelIDs.indexOf(id));
|
||||
}
|
||||
foreach (const QString& id, jointRightFingertipIDs) {
|
||||
geometry.rightFingertipJointIndices.append(modelIDs.indexOf(id));
|
||||
}
|
||||
|
||||
// extract the translation component of the neck transform
|
||||
if (geometry.neckJointIndex != -1) {
|
||||
const glm::mat4& transform = geometry.joints.at(geometry.neckJointIndex).transform;
|
||||
|
@ -1096,9 +1113,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
|
||||
QVariantHash springs = mapping.value("spring").toHash();
|
||||
QVariant defaultSpring = springs.value("default");
|
||||
int vertices = 0;
|
||||
int quads = 0;
|
||||
int tris = 0;
|
||||
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
ExtractedMesh& extracted = it.value();
|
||||
|
||||
vertices += extracted.mesh.vertices.size();
|
||||
|
||||
// accumulate local transforms
|
||||
QString modelID = models.contains(it.key()) ? it.key() : parentMap.value(it.key());
|
||||
extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat();
|
||||
|
@ -1112,6 +1134,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
break;
|
||||
}
|
||||
FBXMeshPart& part = extracted.mesh.parts[partIndex];
|
||||
quads += part.quadIndices.size() / 4;
|
||||
tris += part.triangleIndices.size() / 3;
|
||||
if (textureFilenames.contains(childID)) {
|
||||
part.diffuseFilename = textureFilenames.value(childID);
|
||||
continue;
|
||||
|
@ -1272,6 +1296,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
geometry.meshes.append(extracted.mesh);
|
||||
}
|
||||
|
||||
qDebug("%d %d %d\n", vertices, quads, tris);
|
||||
|
||||
// process attachments
|
||||
QVariantHash attachments = mapping.value("attach").toHash();
|
||||
for (QVariantHash::const_iterator it = attachments.constBegin(); it != attachments.constEnd(); it++) {
|
||||
|
|
|
@ -135,6 +135,9 @@ public:
|
|||
int leftHandJointIndex;
|
||||
int rightHandJointIndex;
|
||||
|
||||
QVector<int> leftFingertipJointIndices;
|
||||
QVector<int> rightFingertipJointIndices;
|
||||
|
||||
glm::vec3 neckPivot;
|
||||
|
||||
QVector<FBXAttachment> attachments;
|
||||
|
|
|
@ -584,8 +584,9 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation) const {
|
|||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
glm::quat delta = rotationBetween(childTranslation - extractTranslation(state.transform),
|
||||
|
@ -593,7 +594,7 @@ void Model::setJointTranslation(int jointIndex, int parentIndex, int childIndex,
|
|||
state.rotation = state.rotation * glm::inverse(state.combinedRotation) * delta * state.combinedRotation;
|
||||
state.combinedRotation = delta * state.combinedRotation;
|
||||
}
|
||||
if (parentIndex != -1) {
|
||||
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);
|
||||
|
@ -605,13 +606,16 @@ void Model::setJointTranslation(int jointIndex, int parentIndex, int childIndex,
|
|||
::setTranslation(state.transform, translation);
|
||||
}
|
||||
|
||||
bool Model::setJointPosition(int jointIndex, const glm::vec3& position) {
|
||||
bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex) {
|
||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
glm::vec3 relativePosition = position - _translation;
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
|
||||
if (lastFreeIndex == -1) {
|
||||
lastFreeIndex = freeLineage.last();
|
||||
}
|
||||
|
||||
// this is a constraint relaxation algorithm: see
|
||||
// http://www.ryanjuckett.com/programming/animation/22-constraint-relaxation-ik-in-2d
|
||||
|
@ -626,9 +630,10 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position) {
|
|||
// start by optimistically setting the position of the end joint to our target
|
||||
setJointTranslation(jointIndex, freeLineage.at(1), -1, relativePosition);
|
||||
|
||||
for (int j = 1; j < freeLineage.size(); j++) {
|
||||
for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) {
|
||||
int sourceIndex = freeLineage.at(j);
|
||||
int destIndex = freeLineage.at(j - 1);
|
||||
bool last = (sourceIndex == lastFreeIndex);
|
||||
JointState& sourceState = _jointStates[sourceIndex];
|
||||
JointState& destState = _jointStates[destIndex];
|
||||
glm::vec3 sourceTranslation = extractTranslation(sourceState.transform);
|
||||
|
@ -646,7 +651,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position) {
|
|||
setJointTranslation(sourceIndex, freeLineage.at(j + 1), -1,
|
||||
sourceTranslation - boneVector * extension + gravity);
|
||||
|
||||
} else if (j == freeLineage.size() - 1) {
|
||||
} else if (sourceIndex == lastFreeIndex) {
|
||||
setJointTranslation(destIndex, -1, freeLineage.at(j - 2),
|
||||
destTranslation + boneVector * extension + gravity);
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ protected:
|
|||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
||||
|
||||
bool setJointPosition(int jointIndex, const glm::vec3& position);
|
||||
bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1);
|
||||
bool setJointRotation(int jointIndex, const glm::quat& rotation);
|
||||
|
||||
/// Restores the indexed joint to its default position.
|
||||
|
|
Loading…
Reference in a new issue