From 41f73b5e9d4dfaa2a87bea47ba0df16207fa2199 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Oct 2013 15:16:29 -0700 Subject: [PATCH] Support for attaching models to joints. --- interface/src/renderer/FBXReader.cpp | 42 ++++++++++++++++++++++++++++ interface/src/renderer/FBXReader.h | 14 ++++++++++ interface/src/renderer/Model.cpp | 38 ++++++++++++++++++++++++- interface/src/renderer/Model.h | 4 ++- 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8a6abb4844..fb58b007e1 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -397,6 +398,19 @@ glm::vec3 getVec3(const QVariantList& properties, int index) { properties.at(index + 2).value()); } +glm::vec3 parseVec3(const QString& string) { + QStringList elements = string.split(','); + if (elements.isEmpty()) { + return glm::vec3(); + } + glm::vec3 value; + for (int i = 0; i < 3; i++) { + // duplicate last value if there aren't three elements + value[i] = elements.at(min(i, elements.size() - 1)).trimmed().toFloat(); + } + return value; +} + const char* FACESHIFT_BLENDSHAPES[] = { "EyeBlink_L", "EyeBlink_R", @@ -1129,6 +1143,34 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.meshes.append(mesh); } + // process attachments + QVariantHash attachments = mapping.value("attach").toHash(); + for (QVariantHash::const_iterator it = attachments.constBegin(); it != attachments.constEnd(); it++) { + FBXAttachment attachment; + attachment.jointIndex = modelIDs.indexOf(it.key()); + attachment.scale = glm::vec3(1.0f, 1.0f, 1.0f); + + QVariantList properties = it->toList(); + if (properties.isEmpty()) { + attachment.url = it->toUrl(); + } else { + attachment.url = properties.at(0).toString(); + + if (properties.size() >= 2) { + attachment.translation = parseVec3(properties.at(1).toString()); + + if (properties.size() >= 3) { + attachment.rotation = glm::quat(glm::radians(parseVec3(properties.at(2).toString()))); + + if (properties.size() >= 4) { + attachment.scale = parseVec3(properties.at(3).toString()); + } + } + } + } + geometry.attachments.append(attachment); + } + return geometry; } diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 17f743ec64..4a16ba19b9 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -9,6 +9,7 @@ #ifndef __interface__FBXReader__ #define __interface__FBXReader__ +#include #include #include #include @@ -98,6 +99,17 @@ public: QVector, 4> > vertexConnections; }; +/// An attachment to an FBX document. +class FBXAttachment { +public: + + int jointIndex; + QUrl url; + glm::vec3 translation; + glm::quat rotation; + glm::vec3 scale; +}; + /// A set of meshes extracted from an FBX document. class FBXGeometry { public: @@ -117,6 +129,8 @@ public: int headJointIndex; glm::vec3 neckPivot; + + QVector attachments; }; /// Reads FBX geometry from the supplied model and mapping data. diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 39f1df1654..ba43a0b214 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -13,7 +13,8 @@ using namespace std; -Model::Model() : +Model::Model(QObject* parent) : + QObject(parent), _pupilDilation(0.0f) { // we may have been created in the network thread, but we live in the main thread @@ -56,6 +57,10 @@ void Model::init() { void Model::reset() { _resetStates = true; + + foreach (Model* attachment, _attachments) { + attachment->reset(); + } } void Model::simulate(float deltaTime) { @@ -81,6 +86,13 @@ void Model::simulate(float deltaTime) { } _meshStates.append(state); } + foreach (const FBXAttachment& attachment, geometry.attachments) { + Model* model = new Model(this); + model->init(); + model->setURL(attachment.url); + model->setScale(attachment.scale); + _attachments.append(model); + } _resetStates = true; } @@ -89,6 +101,22 @@ void Model::simulate(float deltaTime) { updateJointState(i); } + // update the attachment transforms and simulate them + for (int i = 0; i < _attachments.size(); i++) { + const FBXAttachment& attachment = geometry.attachments.at(i); + Model* model = _attachments.at(i); + + glm::vec3 jointTranslation = _translation; + glm::quat jointRotation = _rotation; + getJointPosition(attachment.jointIndex, jointTranslation); + getJointRotation(attachment.jointIndex, jointRotation); + + model->setTranslation(jointTranslation + jointRotation * attachment.translation); + model->setRotation(jointRotation * attachment.rotation); + + model->simulate(deltaTime); + } + for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -175,6 +203,10 @@ void Model::simulate(float deltaTime) { } bool Model::render(float alpha) { + // render the attachments + foreach (Model* attachment, _attachments) { + attachment->render(alpha); + } if (_meshStates.isEmpty()) { return false; } @@ -443,6 +475,10 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation) const { } void Model::deleteGeometry() { + foreach (Model* attachment, _attachments) { + delete attachment; + } + _attachments.clear(); foreach (GLuint id, _blendedVertexBufferIDs) { glDeleteBuffers(1, &id); } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 19864c3b31..be1e49a8be 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -23,7 +23,7 @@ class Model : public QObject { public: - Model(); + Model(QObject* parent = NULL); virtual ~Model(); void setTranslation(const glm::vec3& translation) { _translation = translation; } @@ -126,6 +126,8 @@ private: QVector _blendedVertices; QVector _blendedNormals; + QVector _attachments; + static ProgramObject _program; static ProgramObject _skinProgram; static int _clusterMatricesLocation;