mirror of
https://github.com/overte-org/overte.git
synced 2025-08-18 07:36:38 +02:00
More work on custom skeletons.
This commit is contained in:
parent
49acca3587
commit
349f7b363a
8 changed files with 149 additions and 57 deletions
|
@ -6,6 +6,8 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "FaceModel.h"
|
||||
#include "Head.h"
|
||||
|
@ -34,22 +36,37 @@ void FaceModel::simulate(float deltaTime) {
|
|||
Model::simulate(deltaTime);
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateNeckRotation(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(getRotation());
|
||||
glm::mat3 inverse = glm::inverse(glm::mat3(_jointStates[joint.parentIndex].transform *
|
||||
joint.preRotation * glm::mat4_cast(joint.rotation)));
|
||||
state.rotation = glm::angleAxis(_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(_owningHead->getYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(_owningHead->getPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateEyeRotation(const FBXJoint& joint, JointState& state) {
|
||||
// get the lookat position in joint space and use it to adjust the rotation
|
||||
glm::mat4 inverse = glm::inverse(_jointStates[joint.parentIndex].transform *
|
||||
joint.preRotation * glm::mat4_cast(joint.rotation));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||
_owningHead->getSaccade(), 1.0f));
|
||||
state.rotation = rotationBetween(front, lookAt) * joint.rotation;
|
||||
void FaceModel::updateJointState(int index) {
|
||||
JointState& state = _jointStates[index];
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const FBXJoint& joint = geometry.joints.at(index);
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
glm::mat4 baseTransform = glm::translate(_translation) * glm::mat4_cast(_rotation) *
|
||||
glm::scale(_scale) * glm::translate(_offset);
|
||||
state.transform = baseTransform * geometry.offset * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
|
||||
} else {
|
||||
if (index == geometry.neckJointIndex) {
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 axes = glm::mat3_cast(getRotation());
|
||||
glm::mat3 inverse = glm::inverse(glm::mat3(_jointStates[joint.parentIndex].transform *
|
||||
joint.preRotation * glm::mat4_cast(joint.rotation)));
|
||||
state.rotation = glm::angleAxis(_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(_owningHead->getYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(_owningHead->getPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
|
||||
} else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) {
|
||||
// likewise with the eye joints
|
||||
glm::mat4 inverse = glm::inverse(_jointStates[joint.parentIndex].transform *
|
||||
joint.preRotation * glm::mat4_cast(joint.rotation));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||
_owningHead->getSaccade(), 1.0f));
|
||||
state.rotation = rotationBetween(front, lookAt) * joint.rotation;
|
||||
}
|
||||
state.transform = _jointStates[joint.parentIndex].transform * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,8 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
/// Applies neck rotation based on head orientation.
|
||||
virtual void maybeUpdateNeckRotation(const FBXJoint& joint, JointState& state);
|
||||
|
||||
/// Applies eye rotation based on lookat position.
|
||||
virtual void maybeUpdateEyeRotation(const FBXJoint& joint, JointState& state);
|
||||
/// Updates the state of the joint at the specified index.
|
||||
virtual void updateJointState(int index);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "SkeletonModel.h"
|
||||
|
||||
|
@ -26,3 +28,62 @@ void SkeletonModel::simulate(float deltaTime) {
|
|||
|
||||
Model::simulate(deltaTime);
|
||||
}
|
||||
|
||||
bool SkeletonModel::render(float alpha) {
|
||||
if (_jointStates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
const JointState& joint = _jointStates.at(i);
|
||||
|
||||
glPushMatrix();
|
||||
glMultMatrixf((const GLfloat*)&joint.transform);
|
||||
|
||||
if (i == geometry.rootJointIndex) {
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
} else {
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
glutSolidSphere(0.05f, 10, 10);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
Model::render(alpha);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkeletonModel::updateJointState(int index) {
|
||||
JointState& state = _jointStates[index];
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const FBXJoint& joint = geometry.joints.at(index);
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
glm::mat4 baseTransform = glm::translate(_translation) * glm::mat4_cast(_rotation) *
|
||||
glm::scale(_scale) * glm::translate(_offset);
|
||||
state.transform = baseTransform * geometry.offset * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
|
||||
} else {
|
||||
if (index == geometry.leanJointIndex) {
|
||||
// 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::inverse(glm::mat3(_jointStates[joint.parentIndex].transform *
|
||||
joint.preRotation * glm::mat4_cast(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;
|
||||
}
|
||||
state.transform = _jointStates[joint.parentIndex].transform * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
}
|
||||
|
||||
if (index == geometry.rootJointIndex) {
|
||||
state.transform[3][0] = _translation.x;
|
||||
state.transform[3][1] = _translation.y;
|
||||
state.transform[3][2] = _translation.z;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,12 @@ public:
|
|||
SkeletonModel(Avatar* owningAvatar);
|
||||
|
||||
void simulate(float deltaTime);
|
||||
bool render(float alpha);
|
||||
|
||||
protected:
|
||||
|
||||
/// Updates the state of the joint at the specified index.
|
||||
virtual void updateJointState(int index);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -660,9 +660,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
QByteArray jointEyeLeftName = joints.value("jointEyeLeft", "jointEyeLeft").toByteArray();
|
||||
QByteArray jointEyeRightName = joints.value("jointEyeRight", "jointEyeRight").toByteArray();
|
||||
QByteArray jointNeckName = joints.value("jointNeck", "jointNeck").toByteArray();
|
||||
QByteArray jointRootName = joints.value("jointRoot", "jointRoot").toByteArray();
|
||||
QByteArray jointLeanName = joints.value("jointLean", "jointLean").toByteArray();
|
||||
QString jointEyeLeftID;
|
||||
QString jointEyeRightID;
|
||||
QString jointNeckID;
|
||||
QString jointRootID;
|
||||
QString jointLeanID;
|
||||
|
||||
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
|
||||
QHash<QByteArray, QPair<int, float> > blendshapeIndices;
|
||||
|
@ -711,8 +715,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
blendshapes.append(extracted);
|
||||
}
|
||||
} else if (object.name == "Model") {
|
||||
QByteArray name = object.properties.at(1).toByteArray();
|
||||
name = name.left(name.indexOf('\0'));
|
||||
QByteArray name;
|
||||
if (object.properties.size() == 3) {
|
||||
name = object.properties.at(1).toByteArray();
|
||||
name = name.left(name.indexOf('\0'));
|
||||
|
||||
} else {
|
||||
name = object.properties.at(0).toByteArray();
|
||||
}
|
||||
if (name == jointEyeLeftName || name == "EyeL" || name == "joint_Leye") {
|
||||
jointEyeLeftID = object.properties.at(0).toString();
|
||||
|
||||
|
@ -721,6 +731,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
|
||||
} else if (name == jointNeckName || name == "NeckRot" || name == "joint_neck") {
|
||||
jointNeckID = object.properties.at(0).toString();
|
||||
|
||||
} else if (name == jointRootName) {
|
||||
jointRootID = object.properties.at(0).toString();
|
||||
|
||||
} else if (name == jointLeanName) {
|
||||
jointLeanID = object.properties.at(0).toString();
|
||||
}
|
||||
glm::vec3 translation;
|
||||
glm::vec3 rotationOffset;
|
||||
|
@ -947,6 +963,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
geometry.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID);
|
||||
geometry.rightEyeJointIndex = modelIDs.indexOf(jointEyeRightID);
|
||||
geometry.neckJointIndex = modelIDs.indexOf(jointNeckID);
|
||||
geometry.rootJointIndex = modelIDs.indexOf(jointRootID);
|
||||
geometry.leanJointIndex = modelIDs.indexOf(jointLeanID);
|
||||
|
||||
// extract the translation component of the neck transform
|
||||
if (geometry.neckJointIndex != -1) {
|
||||
|
@ -973,7 +991,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
FBXMeshPart& part = mesh.parts[partIndex];
|
||||
if (textureFilenames.contains(childID)) {
|
||||
part.diffuseFilename = textureFilenames.value(childID);
|
||||
qDebug() << "hello " << part.diffuseFilename << "\n";
|
||||
continue;
|
||||
}
|
||||
if (!materials.contains(childID)) {
|
||||
|
|
|
@ -109,6 +109,8 @@ public:
|
|||
int leftEyeJointIndex;
|
||||
int rightEyeJointIndex;
|
||||
int neckJointIndex;
|
||||
int rootJointIndex;
|
||||
int leanJointIndex;
|
||||
|
||||
glm::vec3 neckPivot;
|
||||
};
|
||||
|
|
|
@ -91,22 +91,7 @@ void Model::simulate(float deltaTime) {
|
|||
|
||||
// update the world space transforms for all joints
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
JointState& state = _jointStates[i];
|
||||
const FBXJoint& joint = geometry.joints.at(i);
|
||||
if (joint.parentIndex == -1) {
|
||||
state.transform = baseTransform * geometry.offset * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
|
||||
} else {
|
||||
if (i == geometry.neckJointIndex) {
|
||||
maybeUpdateNeckRotation(joint, state);
|
||||
|
||||
} else if (i == geometry.leftEyeJointIndex || i == geometry.rightEyeJointIndex) {
|
||||
maybeUpdateEyeRotation(joint, state);
|
||||
}
|
||||
state.transform = _jointStates[joint.parentIndex].transform * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
}
|
||||
updateJointState(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _meshStates.size(); i++) {
|
||||
|
@ -396,12 +381,21 @@ glm::vec4 Model::computeAverageColor() const {
|
|||
return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void Model::maybeUpdateNeckRotation(const FBXJoint& joint, JointState& state) {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
void Model::maybeUpdateEyeRotation(const FBXJoint& joint, JointState& state) {
|
||||
// nothing by default
|
||||
void Model::updateJointState(int index) {
|
||||
JointState& state = _jointStates[index];
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const FBXJoint& joint = geometry.joints.at(index);
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
glm::mat4 baseTransform = glm::translate(_translation) * glm::mat4_cast(_rotation) *
|
||||
glm::scale(_scale) * glm::translate(_offset);
|
||||
state.transform = baseTransform * geometry.offset * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
|
||||
} else {
|
||||
state.transform = _jointStates[joint.parentIndex].transform * joint.preRotation *
|
||||
glm::mat4_cast(state.rotation) * joint.postRotation;
|
||||
}
|
||||
}
|
||||
|
||||
void Model::deleteGeometry() {
|
||||
|
|
|
@ -65,6 +65,11 @@ protected:
|
|||
|
||||
QSharedPointer<NetworkGeometry> _geometry;
|
||||
|
||||
glm::vec3 _translation;
|
||||
glm::quat _rotation;
|
||||
glm::vec3 _scale;
|
||||
glm::vec3 _offset;
|
||||
|
||||
class JointState {
|
||||
public:
|
||||
glm::quat rotation;
|
||||
|
@ -72,21 +77,14 @@ protected:
|
|||
};
|
||||
|
||||
QVector<JointState> _jointStates;
|
||||
|
||||
/// Gives subclasses a chance to update the neck joint rotation after its parents and before its children.
|
||||
virtual void maybeUpdateNeckRotation(const FBXJoint& joint, JointState& state);
|
||||
|
||||
/// Gives subclasses a chance to update an eye joint rotation after its parents and before its children.
|
||||
virtual void maybeUpdateEyeRotation(const FBXJoint& joint, JointState& state);
|
||||
/// Updates the state of the joint at the specified index.
|
||||
virtual void updateJointState(int index);
|
||||
|
||||
private:
|
||||
|
||||
void deleteGeometry();
|
||||
|
||||
glm::vec3 _translation;
|
||||
glm::quat _rotation;
|
||||
glm::vec3 _scale;
|
||||
glm::vec3 _offset;
|
||||
float _pupilDilation;
|
||||
std::vector<float> _blendshapeCoefficients;
|
||||
|
||||
|
|
Loading…
Reference in a new issue