mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge pull request #996 from ey6es/master
Transformation rejiggery to support Ryan's alien model.
This commit is contained in:
commit
617b905385
3 changed files with 135 additions and 18 deletions
|
@ -43,7 +43,7 @@ void BlendFace::init() {
|
|||
}
|
||||
}
|
||||
|
||||
const glm::vec3 MODEL_TRANSLATION(0.0f, -0.025f, -0.025f); // temporary fudge factor
|
||||
const glm::vec3 MODEL_TRANSLATION(0.0f, -0.07f, -0.025f); // temporary fudge factor
|
||||
const float MODEL_SCALE = 0.0006f;
|
||||
|
||||
bool BlendFace::render(float alpha) {
|
||||
|
@ -61,6 +61,8 @@ bool BlendFace::render(float alpha) {
|
|||
-_owningHead->getScale() * MODEL_SCALE);
|
||||
glScalef(scale.x, scale.y, scale.z);
|
||||
|
||||
glTranslatef(-_geometry.neckPivot.x, -_geometry.neckPivot.y, -_geometry.neckPivot.z);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
|
@ -77,9 +79,10 @@ bool BlendFace::render(float alpha) {
|
|||
const FBXMesh& mesh = _geometry.meshes.at(i);
|
||||
int vertexCount = mesh.vertices.size();
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
// apply eye rotation if appropriate
|
||||
if (mesh.isEye) {
|
||||
glPushMatrix();
|
||||
glTranslatef(mesh.pivot.x, mesh.pivot.y, mesh.pivot.z);
|
||||
glm::quat rotation = glm::inverse(orientation) * _owningHead->getEyeRotation(orientation *
|
||||
(mesh.pivot * scale + MODEL_TRANSLATION) + _owningHead->getPosition());
|
||||
|
@ -98,6 +101,8 @@ bool BlendFace::render(float alpha) {
|
|||
_eyeProgram.bind();
|
||||
}
|
||||
|
||||
glMultMatrixf((const GLfloat*)&mesh.transform);
|
||||
|
||||
// all meshes after the first are white
|
||||
if (i == 1) {
|
||||
glColor4f(1.0f, 1.0f, 1.0f, alpha);
|
||||
|
@ -144,8 +149,9 @@ bool BlendFace::render(float alpha) {
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glDisable(GL_NORMALIZE);
|
||||
|
@ -171,7 +177,8 @@ void BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEy
|
|||
|
||||
foreach (const FBXMesh& mesh, _geometry.meshes) {
|
||||
if (mesh.isEye) {
|
||||
glm::vec3 position = orientation * (mesh.pivot * scale + MODEL_TRANSLATION) + _owningHead->getPosition();
|
||||
glm::vec3 position = orientation * ((mesh.pivot - _geometry.neckPivot) * scale + MODEL_TRANSLATION) +
|
||||
_owningHead->getPosition();
|
||||
if (foundFirst) {
|
||||
secondEyePosition = position;
|
||||
return;
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <QtDebug>
|
||||
#include <QtEndian>
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include "FBXReader.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -207,6 +210,13 @@ QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) {
|
|||
return values;
|
||||
}
|
||||
|
||||
glm::mat4 createMat4(const QVector<double>& doubleVector) {
|
||||
return glm::mat4(doubleVector.at(0), doubleVector.at(1), doubleVector.at(2), doubleVector.at(3),
|
||||
doubleVector.at(4), doubleVector.at(5), doubleVector.at(6), doubleVector.at(7),
|
||||
doubleVector.at(8), doubleVector.at(9), doubleVector.at(10), doubleVector.at(11),
|
||||
doubleVector.at(12), doubleVector.at(13), doubleVector.at(14), doubleVector.at(15));
|
||||
}
|
||||
|
||||
const char* FACESHIFT_BLENDSHAPES[] = {
|
||||
"EyeBlink_L",
|
||||
"EyeBlink_R",
|
||||
|
@ -272,6 +282,26 @@ QHash<QByteArray, int> createBlendshapeMap() {
|
|||
}
|
||||
}
|
||||
|
||||
glm::mat4 getGlobalTransform(
|
||||
const QMultiHash<qint64, qint64>& parentMap, const QHash<qint64, glm::mat4>& localTransforms, qint64 nodeID) {
|
||||
|
||||
glm::mat4 globalTransform;
|
||||
while (nodeID != 0) {
|
||||
globalTransform = localTransforms.value(nodeID) * globalTransform;
|
||||
|
||||
QList<qint64> parentIDs = parentMap.values(nodeID);
|
||||
nodeID = 0;
|
||||
foreach (qint64 parentID, parentIDs) {
|
||||
if (localTransforms.contains(parentID)) {
|
||||
nodeID = parentID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return globalTransform;
|
||||
}
|
||||
|
||||
class ExtractedBlendshape {
|
||||
public:
|
||||
qint64 id;
|
||||
|
@ -282,11 +312,13 @@ public:
|
|||
FBXGeometry extractFBXGeometry(const FBXNode& node) {
|
||||
QHash<qint64, FBXMesh> meshes;
|
||||
QVector<ExtractedBlendshape> blendshapes;
|
||||
QHash<qint64, qint64> parentMap;
|
||||
QMultiHash<qint64, qint64> parentMap;
|
||||
QMultiHash<qint64, qint64> childMap;
|
||||
QHash<qint64, glm::vec3> pivots;
|
||||
QHash<qint64, glm::mat4> localTransforms;
|
||||
QHash<qint64, glm::mat4> transformLinkMatrices;
|
||||
qint64 jointEyeLeftID = 0;
|
||||
qint64 jointEyeRightID = 0;
|
||||
qint64 jointNeckID = 0;
|
||||
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
if (child.name == "Objects") {
|
||||
|
@ -400,22 +432,80 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
|
|||
QByteArray name = object.properties.at(1).toByteArray();
|
||||
static QHash<QByteArray, int> blendshapeMap = createBlendshapeMap();
|
||||
extracted.index = blendshapeMap.value(name.left(name.indexOf('\0')));
|
||||
|
||||
|
||||
blendshapes.append(extracted);
|
||||
}
|
||||
} else if (object.name == "Model" && object.properties.at(2) == "LimbNode") {
|
||||
if (object.properties.at(1).toByteArray().startsWith("jointEyeLeft")) {
|
||||
} else if (object.name == "Model") {
|
||||
QByteArray name = object.properties.at(1).toByteArray();
|
||||
if (name.startsWith("jointEyeLeft") || name.startsWith("EyeL")) {
|
||||
jointEyeLeftID = object.properties.at(0).value<qint64>();
|
||||
|
||||
} else if (object.properties.at(1).toByteArray().startsWith("jointEyeRight")) {
|
||||
} else if (name.startsWith("jointEyeRight") || name.startsWith("EyeR")) {
|
||||
jointEyeRightID = object.properties.at(0).value<qint64>();
|
||||
|
||||
} else if (name.startsWith("jointNeck") || name.startsWith("NeckRot")) {
|
||||
jointNeckID = object.properties.at(0).value<qint64>();
|
||||
}
|
||||
glm::vec3 translation;
|
||||
glm::vec3 preRotation, rotation, postRotation;
|
||||
glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
glm::vec3 scalePivot, rotationPivot;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
if (subobject.name == "Properties70") {
|
||||
foreach (const FBXNode& property, subobject.children) {
|
||||
if (property.name == "P") {
|
||||
if (property.properties.at(0) == "Lcl Translation") {
|
||||
translation = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
|
||||
} else if (property.properties.at(0) == "RotationPivot") {
|
||||
rotationPivot = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
|
||||
} else if (property.properties.at(0) == "PreRotation") {
|
||||
preRotation = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
|
||||
} else if (property.properties.at(0) == "Lcl Rotation") {
|
||||
rotation = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
|
||||
} else if (property.properties.at(0) == "PostRotation") {
|
||||
postRotation = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
|
||||
} else if (property.properties.at(0) == "ScalingPivot") {
|
||||
scalePivot = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
|
||||
} else if (property.properties.at(0) == "Lcl Scaling") {
|
||||
scale = glm::vec3(property.properties.at(4).value<double>(),
|
||||
property.properties.at(5).value<double>(),
|
||||
property.properties.at(6).value<double>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
|
||||
localTransforms.insert(object.properties.at(0).value<qint64>(),
|
||||
glm::translate(translation) * glm::translate(rotationPivot) *
|
||||
glm::mat4_cast(glm::quat(glm::radians(preRotation))) *
|
||||
glm::mat4_cast(glm::quat(glm::radians(rotation))) *
|
||||
glm::mat4_cast(glm::quat(glm::radians(postRotation))) * glm::translate(-rotationPivot) *
|
||||
glm::translate(scalePivot) * glm::scale(scale) * glm::translate(-scalePivot));
|
||||
|
||||
} else if (object.name == "Deformer" && object.properties.at(2) == "Cluster") {
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
if (subobject.name == "TransformLink") {
|
||||
QVector<double> values = subobject.properties.at(0).value<QVector<double> >();
|
||||
pivots.insert(object.properties.at(0).value<qint64>(),
|
||||
glm::vec3(values.at(12), values.at(13), values.at(14))); // matrix translation component
|
||||
transformLinkMatrices.insert(object.properties.at(0).value<qint64>(), createMat4(values));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,17 +536,30 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
|
|||
for (QHash<qint64, FBXMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
FBXMesh& mesh = it.value();
|
||||
|
||||
// accumulate local transforms
|
||||
for (qint64 parentID = parentMap.value(it.key()); parentID != 0; parentID = parentMap.value(parentID)) {
|
||||
mesh.transform = localTransforms.value(parentID) * mesh.transform;
|
||||
}
|
||||
|
||||
// look for a limb pivot
|
||||
mesh.isEye = false;
|
||||
foreach (qint64 childID, childMap.values(it.key())) {
|
||||
qint64 clusterID = childMap.value(childID);
|
||||
if (pivots.contains(clusterID)) {
|
||||
mesh.pivot = pivots.value(clusterID);
|
||||
qint64 jointID = childMap.value(clusterID);
|
||||
if (jointID == jointEyeLeftID || jointID == jointEyeRightID) {
|
||||
mesh.isEye = true;
|
||||
}
|
||||
if (!transformLinkMatrices.contains(clusterID)) {
|
||||
continue;
|
||||
}
|
||||
qint64 jointID = childMap.value(clusterID);
|
||||
if (jointID == jointEyeLeftID || jointID == jointEyeRightID) {
|
||||
mesh.isEye = true;
|
||||
}
|
||||
|
||||
// see http://stackoverflow.com/questions/13566608/loading-skinning-information-from-fbx for a discussion
|
||||
// of skinning information in FBX
|
||||
glm::mat4 jointTransform = getGlobalTransform(parentMap, localTransforms, jointID);
|
||||
mesh.transform = jointTransform * glm::inverse(transformLinkMatrices.value(clusterID)) * mesh.transform;
|
||||
|
||||
// extract translation component for pivot
|
||||
mesh.pivot = glm::vec3(jointTransform[3][0], jointTransform[3][1], jointTransform[3][2]);
|
||||
}
|
||||
|
||||
if (mesh.blendshapes.size() > mostBlendshapes) {
|
||||
|
@ -468,6 +571,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
|
|||
}
|
||||
}
|
||||
|
||||
// extract translation component for neck pivot
|
||||
glm::mat4 neckTransform = getGlobalTransform(parentMap, localTransforms, jointNeckID);
|
||||
geometry.neckPivot = glm::vec3(neckTransform[3][0], neckTransform[3][1], neckTransform[3][2]);
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
QVector<glm::vec2> texCoords;
|
||||
|
||||
glm::vec3 pivot;
|
||||
glm::mat4 transform;
|
||||
|
||||
bool isEye;
|
||||
|
||||
|
@ -60,6 +61,8 @@ class FBXGeometry {
|
|||
public:
|
||||
|
||||
QVector<FBXMesh> meshes;
|
||||
|
||||
glm::vec3 neckPivot;
|
||||
};
|
||||
|
||||
/// Parses the input from the supplied data as an FBX file.
|
||||
|
|
Loading…
Reference in a new issue