From 9034eb1e72ba7d5cce6fb7f2f173e4ad0ced0c52 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 23 Sep 2013 14:37:48 -0700 Subject: [PATCH 1/8] Experimenting with the simplest method of including the other meshes. --- interface/src/renderer/FBXReader.cpp | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index b23f7fee35..7fa183b45e 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -264,6 +264,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { QHash meshMap; qint64 blendshapeId = 0; QHash parentMap; + QHash > poseMatrices; foreach (const FBXNode& child, node.children) { if (child.name == "Objects") { @@ -346,6 +347,22 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { blendshapes.resize(qMax(blendshapes.size(), index + 1)); blendshapes[index] = blendshape; } + } else if (object.name == "Pose") { + foreach (const FBXNode& subobject, object.children) { + if (subobject.name == "PoseNode") { + qint64 nodeId; + QVector matrix; + foreach (const FBXNode& data, subobject.children) { + if (data.name == "Node") { + nodeId = data.properties.at(0).value(); + + } else if (data.name == "Matrix") { + matrix = data.properties.at(0).value >(); + } + } + poseMatrices.insert(nodeId, matrix); + } + } } else if (object.name == "Deformer" && object.properties.at(2) == "BlendShape") { blendshapeId = object.properties.at(0).value(); } @@ -365,6 +382,19 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { geometry = *meshMap.begin(); } else { geometry = meshMap.take(parentMap.value(blendshapeId)); + + foreach (const FBXGeometry& mesh, meshMap) { + int offset = geometry.vertices.size(); + geometry.vertices += mesh.vertices; + geometry.normals += mesh.normals; + + foreach (int index, mesh.quadIndices) { + geometry.quadIndices.append(index + offset); + } + foreach (int index, mesh.triangleIndices) { + geometry.triangleIndices.append(index + offset); + } + } } geometry.blendshapes = blendshapes; From aa6eb7b3d862a51437f7162c0dd35388f3840212 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 23 Sep 2013 16:34:28 -0700 Subject: [PATCH 2/8] Render the "other" meshes as separate, static, white. --- interface/src/avatar/BlendFace.cpp | 113 ++++++++++++++++++--------- interface/src/avatar/BlendFace.h | 9 ++- interface/src/renderer/FBXReader.cpp | 27 ++----- interface/src/renderer/FBXReader.h | 18 +++-- 4 files changed, 103 insertions(+), 64 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index d1a61b3fa3..11882ca000 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -17,22 +17,18 @@ using namespace std; BlendFace::BlendFace(Head* owningHead) : _owningHead(owningHead), - _modelReply(NULL), - _iboID(0) + _modelReply(NULL) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); } BlendFace::~BlendFace() { - if (_iboID != 0) { - glDeleteBuffers(1, &_iboID); - glDeleteBuffers(1, &_vboID); - } + deleteGeometry(); } bool BlendFace::render(float alpha) { - if (_iboID == 0) { + if (_baseMeshIDs.first == 0) { return false; } @@ -47,12 +43,12 @@ bool BlendFace::render(float alpha) { -_owningHead->getScale() * MODEL_SCALE); // start with the base - int vertexCount = _geometry.vertices.size(); - int normalCount = _geometry.normals.size(); + int vertexCount = _geometry.blendMesh.vertices.size(); + int normalCount = _geometry.blendMesh.normals.size(); _blendedVertices.resize(vertexCount); _blendedNormals.resize(normalCount); - memcpy(_blendedVertices.data(), _geometry.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), _geometry.normals.constData(), normalCount * sizeof(glm::vec3)); + memcpy(_blendedVertices.data(), _geometry.blendMesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + memcpy(_blendedNormals.data(), _geometry.blendMesh.normals.constData(), normalCount * sizeof(glm::vec3)); // blend in each coefficient const vector& coefficients = _owningHead->getBlendshapeCoefficients(); @@ -76,7 +72,7 @@ bool BlendFace::render(float alpha) { glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha); // update the blended vertices - glBindBuffer(GL_ARRAY_BUFFER, _vboID); + glBindBuffer(GL_ARRAY_BUFFER, _baseMeshIDs.second); glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), normalCount * sizeof(glm::vec3), _blendedNormals.constData()); @@ -90,12 +86,29 @@ bool BlendFace::render(float alpha) { // enable normalization under the expectation that the GPU can do it faster glEnable(GL_NORMALIZE); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iboID); - glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, _geometry.quadIndices.size(), GL_UNSIGNED_INT, 0); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, _geometry.triangleIndices.size(), GL_UNSIGNED_INT, - (void*)(_geometry.quadIndices.size() * sizeof(int))); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _baseMeshIDs.first); + glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, _geometry.blendMesh.quadIndices.size(), GL_UNSIGNED_INT, 0); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, _geometry.blendMesh.triangleIndices.size(), GL_UNSIGNED_INT, + (void*)(_geometry.blendMesh.quadIndices.size() * sizeof(int))); glDisable(GL_NORMALIZE); + + // back to white for the other meshes + glColor4f(1.0f, 1.0f, 1.0f, alpha); + + for (int i = 0; i < _geometry.otherMeshes.size(); i++) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _otherMeshIDs.at(i).first); + glBindBuffer(GL_ARRAY_BUFFER, _otherMeshIDs.at(i).second); + + glVertexPointer(3, GL_FLOAT, 0, 0); + int vertexCount = _geometry.otherMeshes.at(i).vertices.size(); + glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); + + glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, _geometry.otherMeshes.at(i).quadIndices.size(), + GL_UNSIGNED_INT, 0); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, _geometry.otherMeshes.at(i).triangleIndices.size(), + GL_UNSIGNED_INT, (void*)(_geometry.otherMeshes.at(i).quadIndices.size() * sizeof(int))); + } // deactivate vertex arrays after drawing glDisableClientState(GL_NORMAL_ARRAY); @@ -170,32 +183,60 @@ void BlendFace::handleModelReplyError() { _modelReply = 0; } +void createIndexBuffer(const FBXMesh& mesh, GLuint& iboID) { + glGenBuffers(1, &iboID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (mesh.quadIndices.size() + mesh.triangleIndices.size()) * sizeof(int), + NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh.quadIndices.size() * sizeof(int), mesh.quadIndices.constData()); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, mesh.quadIndices.size() * sizeof(int), + mesh.triangleIndices.size() * sizeof(int), mesh.triangleIndices.constData()); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + void BlendFace::setGeometry(const FBXGeometry& geometry) { - if (geometry.vertices.isEmpty()) { - // clear any existing geometry - if (_iboID != 0) { - glDeleteBuffers(1, &_iboID); - glDeleteBuffers(1, &_vboID); - _iboID = 0; - } + // clear any existing geometry + deleteGeometry(); + + if (geometry.blendMesh.vertices.isEmpty()) { return; } - if (_iboID == 0) { - glGenBuffers(1, &_iboID); - glGenBuffers(1, &_vboID); - } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iboID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (geometry.quadIndices.size() + geometry.triangleIndices.size()) * sizeof(int), - NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, geometry.quadIndices.size() * sizeof(int), geometry.quadIndices.constData()); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, geometry.quadIndices.size() * sizeof(int), - geometry.triangleIndices.size() * sizeof(int), geometry.triangleIndices.constData()); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + createIndexBuffer(geometry.blendMesh, _baseMeshIDs.first); - glBindBuffer(GL_ARRAY_BUFFER, _vboID); - glBufferData(GL_ARRAY_BUFFER, (geometry.vertices.size() + geometry.normals.size()) * sizeof(glm::vec3), + glGenBuffers(1, &_baseMeshIDs.second); + glBindBuffer(GL_ARRAY_BUFFER, _baseMeshIDs.second); + glBufferData(GL_ARRAY_BUFFER, (geometry.blendMesh.vertices.size() + geometry.blendMesh.normals.size()) * sizeof(glm::vec3), NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); + foreach (const FBXMesh& mesh, geometry.otherMeshes) { + VerticesIndices ids; + createIndexBuffer(mesh, ids.first); + + glGenBuffers(1, &ids.second); + glBindBuffer(GL_ARRAY_BUFFER, ids.second); + glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), + NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(glm::vec3), + mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData()); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + _otherMeshIDs.append(ids); + } + _geometry = geometry; } + +void BlendFace::deleteGeometry() { + if (_baseMeshIDs.first != 0) { + glDeleteBuffers(1, &_baseMeshIDs.first); + glDeleteBuffers(1, &_baseMeshIDs.second); + _baseMeshIDs = VerticesIndices(); + } + foreach (const VerticesIndices& meshIDs, _otherMeshIDs) { + glDeleteBuffers(1, &meshIDs.first); + glDeleteBuffers(1, &meshIDs.second); + } + _otherMeshIDs.clear(); +} diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index 336d6cc5f0..821cda93ef 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -28,7 +28,7 @@ public: BlendFace(Head* owningHead); ~BlendFace(); - bool isActive() const { return _iboID != 0; } + bool isActive() const { return _baseMeshIDs.first != 0; } bool render(float alpha); @@ -43,6 +43,7 @@ private slots: private: void setGeometry(const FBXGeometry& geometry); + void deleteGeometry(); Head* _owningHead; @@ -50,8 +51,10 @@ private: QNetworkReply* _modelReply; - GLuint _iboID; - GLuint _vboID; + typedef QPair VerticesIndices; + + VerticesIndices _baseMeshIDs; + QVector _otherMeshIDs; FBXGeometry _geometry; QVector _blendedVertices; diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 7fa183b45e..fb7a8e2cb9 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -261,7 +261,7 @@ QHash createBlendshapeMap() { FBXGeometry extractFBXGeometry(const FBXNode& node) { QVector blendshapes; - QHash meshMap; + QHash meshMap; qint64 blendshapeId = 0; QHash parentMap; QHash > poseMatrices; @@ -271,7 +271,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { foreach (const FBXNode& object, child.children) { if (object.name == "Geometry") { if (object.properties.at(2) == "Mesh") { - FBXGeometry mesh; + FBXMesh mesh; QVector normals; QVector polygonIndices; @@ -378,26 +378,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { // get the mesh that owns the blendshape FBXGeometry geometry; - if (meshMap.size() == 1) { - geometry = *meshMap.begin(); - } else { - geometry = meshMap.take(parentMap.value(blendshapeId)); - - foreach (const FBXGeometry& mesh, meshMap) { - int offset = geometry.vertices.size(); - geometry.vertices += mesh.vertices; - geometry.normals += mesh.normals; - - foreach (int index, mesh.quadIndices) { - geometry.quadIndices.append(index + offset); - } - foreach (int index, mesh.triangleIndices) { - geometry.triangleIndices.append(index + offset); - } - } - } + geometry.blendMesh = meshMap.take(parentMap.value(blendshapeId)); geometry.blendshapes = blendshapes; + foreach (const FBXMesh& mesh, meshMap) { + geometry.otherMeshes.append(mesh); + } + return geometry; } diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 52447d20b4..dfa972697f 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -29,6 +29,16 @@ public: FBXNodeList children; }; +/// A single mesh extracted from an FBX document. +class FBXMesh { +public: + + QVector quadIndices; + QVector triangleIndices; + QVector vertices; + QVector normals; +}; + /// A single blendshape extracted from an FBX document. class FBXBlendshape { public: @@ -42,12 +52,10 @@ public: class FBXGeometry { public: - QVector quadIndices; - QVector triangleIndices; - QVector vertices; - QVector normals; - + FBXMesh blendMesh; QVector blendshapes; + + QVector otherMeshes; }; /// Parses the input from the supplied data as an FBX file. From ad69a9547f0ab47d41d5bfa869d2279aa7a983bf Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Sep 2013 11:12:59 -0700 Subject: [PATCH 3/8] Remove the pose bits, at least for now. --- interface/src/renderer/FBXReader.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index fb7a8e2cb9..e370fae4b2 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -264,7 +264,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { QHash meshMap; qint64 blendshapeId = 0; QHash parentMap; - QHash > poseMatrices; foreach (const FBXNode& child, node.children) { if (child.name == "Objects") { @@ -347,22 +346,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { blendshapes.resize(qMax(blendshapes.size(), index + 1)); blendshapes[index] = blendshape; } - } else if (object.name == "Pose") { - foreach (const FBXNode& subobject, object.children) { - if (subobject.name == "PoseNode") { - qint64 nodeId; - QVector matrix; - foreach (const FBXNode& data, subobject.children) { - if (data.name == "Node") { - nodeId = data.properties.at(0).value(); - - } else if (data.name == "Matrix") { - matrix = data.properties.at(0).value >(); - } - } - poseMatrices.insert(nodeId, matrix); - } - } } else if (object.name == "Deformer" && object.properties.at(2) == "BlendShape") { blendshapeId = object.properties.at(0).value(); } From fd41a075edb4857e7e9d4d98a1804010b4ffdca8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Sep 2013 13:53:19 -0700 Subject: [PATCH 4/8] Added support for multiple blended meshes. --- interface/src/avatar/BlendFace.cpp | 164 ++++++++++++--------------- interface/src/avatar/BlendFace.h | 6 +- interface/src/renderer/FBXReader.cpp | 51 +++++---- interface/src/renderer/FBXReader.h | 29 +++-- 4 files changed, 120 insertions(+), 130 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 11882ca000..886184aafc 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -28,7 +28,7 @@ BlendFace::~BlendFace() { } bool BlendFace::render(float alpha) { - if (_baseMeshIDs.first == 0) { + if (_meshIDs.isEmpty()) { return false; } @@ -42,74 +42,63 @@ bool BlendFace::render(float alpha) { glScalef(_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE, -_owningHead->getScale() * MODEL_SCALE); - // start with the base - int vertexCount = _geometry.blendMesh.vertices.size(); - int normalCount = _geometry.blendMesh.normals.size(); - _blendedVertices.resize(vertexCount); - _blendedNormals.resize(normalCount); - memcpy(_blendedVertices.data(), _geometry.blendMesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), _geometry.blendMesh.normals.constData(), normalCount * sizeof(glm::vec3)); - - // blend in each coefficient - const vector& coefficients = _owningHead->getBlendshapeCoefficients(); - for (int i = 0; i < coefficients.size(); i++) { - float coefficient = coefficients[i]; - if (coefficient == 0.0f || i >= _geometry.blendshapes.size() || _geometry.blendshapes[i].vertices.isEmpty()) { - continue; - } - const float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = _geometry.blendshapes[i].vertices.constData(); - const glm::vec3* normal = _geometry.blendshapes[i].normals.constData(); - for (const int* index = _geometry.blendshapes[i].indices.constData(), - *end = index + _geometry.blendshapes[i].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } - } - - // use the head skin color - glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha); - - // update the blended vertices - glBindBuffer(GL_ARRAY_BUFFER, _baseMeshIDs.second); - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - normalCount * sizeof(glm::vec3), _blendedNormals.constData()); - - // tell OpenGL where to find vertex information glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, 0); glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); // enable normalization under the expectation that the GPU can do it faster glEnable(GL_NORMALIZE); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _baseMeshIDs.first); - glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, _geometry.blendMesh.quadIndices.size(), GL_UNSIGNED_INT, 0); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, _geometry.blendMesh.triangleIndices.size(), GL_UNSIGNED_INT, - (void*)(_geometry.blendMesh.quadIndices.size() * sizeof(int))); - - glDisable(GL_NORMALIZE); - - // back to white for the other meshes - glColor4f(1.0f, 1.0f, 1.0f, alpha); + for (int i = 0; i < _meshIDs.size(); i++) { + const VerticesIndices& ids = _meshIDs.at(i); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ids.first); + glBindBuffer(GL_ARRAY_BUFFER, ids.second); + + const FBXMesh& mesh = _geometry.meshes.at(i); + int vertexCount = mesh.vertices.size(); + + if (mesh.blendshapes.isEmpty()) { + glColor4f(1.0f, 1.0f, 1.0f, alpha); + + } else { + glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha); + + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + _blendedNormals.resize(_blendedVertices.size()); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + const vector& coefficients = _owningHead->getBlendshapeCoefficients(); + for (int i = 0; i < coefficients.size(); i++) { + float coefficient = coefficients[i]; + if (coefficient == 0.0f || i >= mesh.blendshapes.size() || mesh.blendshapes[i].vertices.isEmpty()) { + continue; + } + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; + const glm::vec3* vertex = mesh.blendshapes[i].vertices.constData(); + const glm::vec3* normal = mesh.blendshapes[i].normals.constData(); + for (const int* index = mesh.blendshapes[i].indices.constData(), + *end = index + mesh.blendshapes[i].indices.size(); index != end; index++, vertex++, normal++) { + _blendedVertices[*index] += *vertex * coefficient; + _blendedNormals[*index] += *normal * normalCoefficient; + } + } - for (int i = 0; i < _geometry.otherMeshes.size(); i++) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _otherMeshIDs.at(i).first); - glBindBuffer(GL_ARRAY_BUFFER, _otherMeshIDs.at(i).second); + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), + vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); + } glVertexPointer(3, GL_FLOAT, 0, 0); - int vertexCount = _geometry.otherMeshes.at(i).vertices.size(); glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); - - glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, _geometry.otherMeshes.at(i).quadIndices.size(), - GL_UNSIGNED_INT, 0); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, _geometry.otherMeshes.at(i).triangleIndices.size(), - GL_UNSIGNED_INT, (void*)(_geometry.otherMeshes.at(i).quadIndices.size() * sizeof(int))); + glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, mesh.quadIndices.size(), GL_UNSIGNED_INT, 0); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, mesh.triangleIndices.size(), + GL_UNSIGNED_INT, (void*)(mesh.quadIndices.size() * sizeof(int))); } + glDisable(GL_NORMALIZE); + // deactivate vertex arrays after drawing glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -183,60 +172,51 @@ void BlendFace::handleModelReplyError() { _modelReply = 0; } -void createIndexBuffer(const FBXMesh& mesh, GLuint& iboID) { - glGenBuffers(1, &iboID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (mesh.quadIndices.size() + mesh.triangleIndices.size()) * sizeof(int), - NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh.quadIndices.size() * sizeof(int), mesh.quadIndices.constData()); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, mesh.quadIndices.size() * sizeof(int), - mesh.triangleIndices.size() * sizeof(int), mesh.triangleIndices.constData()); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - void BlendFace::setGeometry(const FBXGeometry& geometry) { // clear any existing geometry deleteGeometry(); - if (geometry.blendMesh.vertices.isEmpty()) { + if (geometry.meshes.isEmpty()) { return; } - createIndexBuffer(geometry.blendMesh, _baseMeshIDs.first); - - glGenBuffers(1, &_baseMeshIDs.second); - glBindBuffer(GL_ARRAY_BUFFER, _baseMeshIDs.second); - glBufferData(GL_ARRAY_BUFFER, (geometry.blendMesh.vertices.size() + geometry.blendMesh.normals.size()) * sizeof(glm::vec3), - NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - foreach (const FBXMesh& mesh, geometry.otherMeshes) { + foreach (const FBXMesh& mesh, geometry.meshes) { VerticesIndices ids; - createIndexBuffer(mesh, ids.first); + glGenBuffers(1, &ids.first); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ids.first); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (mesh.quadIndices.size() + mesh.triangleIndices.size()) * sizeof(int), + NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh.quadIndices.size() * sizeof(int), mesh.quadIndices.constData()); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, mesh.quadIndices.size() * sizeof(int), + mesh.triangleIndices.size() * sizeof(int), mesh.triangleIndices.constData()); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glGenBuffers(1, &ids.second); glBindBuffer(GL_ARRAY_BUFFER, ids.second); - glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), - NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(glm::vec3), - mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData()); + + if (mesh.blendshapes.isEmpty()) { + glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), + NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(glm::vec3), + mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData()); + + } else { + glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), + NULL, GL_DYNAMIC_DRAW); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); - _otherMeshIDs.append(ids); + _meshIDs.append(ids); } _geometry = geometry; } void BlendFace::deleteGeometry() { - if (_baseMeshIDs.first != 0) { - glDeleteBuffers(1, &_baseMeshIDs.first); - glDeleteBuffers(1, &_baseMeshIDs.second); - _baseMeshIDs = VerticesIndices(); - } - foreach (const VerticesIndices& meshIDs, _otherMeshIDs) { + foreach (const VerticesIndices& meshIDs, _meshIDs) { glDeleteBuffers(1, &meshIDs.first); glDeleteBuffers(1, &meshIDs.second); } - _otherMeshIDs.clear(); + _meshIDs.clear(); } diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index 821cda93ef..e9ce58e3c4 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -28,7 +28,7 @@ public: BlendFace(Head* owningHead); ~BlendFace(); - bool isActive() const { return _baseMeshIDs.first != 0; } + bool isActive() const { return !_meshIDs.isEmpty(); } bool render(float alpha); @@ -52,9 +52,7 @@ private: QNetworkReply* _modelReply; typedef QPair VerticesIndices; - - VerticesIndices _baseMeshIDs; - QVector _otherMeshIDs; + QVector _meshIDs; FBXGeometry _geometry; QVector _blendedVertices; diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index e370fae4b2..5219669193 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -259,10 +259,16 @@ QHash createBlendshapeMap() { } } +class ExtractedBlendshape { +public: + qint64 id; + int index; + FBXBlendshape blendshape; +}; + FBXGeometry extractFBXGeometry(const FBXNode& node) { - QVector blendshapes; - QHash meshMap; - qint64 blendshapeId = 0; + QHash meshes; + QVector blendshapes; QHash parentMap; foreach (const FBXNode& child, node.children) { @@ -323,31 +329,32 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { beginIndex = endIndex; } } - meshMap.insert(object.properties.at(0).value(), mesh); + meshes.insert(object.properties.at(0).value(), mesh); } else { // object.properties.at(2) == "Shape" - FBXBlendshape blendshape; + ExtractedBlendshape extracted = { object.properties.at(0).value() }; + foreach (const FBXNode& data, object.children) { if (data.name == "Indexes") { - blendshape.indices = data.properties.at(0).value >(); + extracted.blendshape.indices = data.properties.at(0).value >(); } else if (data.name == "Vertices") { - blendshape.vertices = createVec3Vector(data.properties.at(0).value >()); + extracted.blendshape.vertices = createVec3Vector( + data.properties.at(0).value >()); } else if (data.name == "Normals") { - blendshape.normals = createVec3Vector(data.properties.at(0).value >()); + extracted.blendshape.normals = createVec3Vector( + data.properties.at(0).value >()); } } // the name is followed by a null and some type info QByteArray name = object.properties.at(1).toByteArray(); static QHash blendshapeMap = createBlendshapeMap(); - int index = blendshapeMap.value(name.left(name.indexOf('\0'))); - blendshapes.resize(qMax(blendshapes.size(), index + 1)); - blendshapes[index] = blendshape; + extracted.index = blendshapeMap.value(name.left(name.indexOf('\0'))); + + blendshapes.append(extracted); } - } else if (object.name == "Deformer" && object.properties.at(2) == "BlendShape") { - blendshapeId = object.properties.at(0).value(); } } } else if (child.name == "Connections") { @@ -359,13 +366,19 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { } } - // get the mesh that owns the blendshape - FBXGeometry geometry; - geometry.blendMesh = meshMap.take(parentMap.value(blendshapeId)); - geometry.blendshapes = blendshapes; + // assign the blendshapes to their corresponding meshes + foreach (const ExtractedBlendshape& extracted, blendshapes) { + qint64 blendshapeChannelID = parentMap.value(extracted.id); + qint64 blendshapeID = parentMap.value(blendshapeChannelID); + qint64 meshID = parentMap.value(blendshapeID); + FBXMesh& mesh = meshes[meshID]; + mesh.blendshapes.resize(max(mesh.blendshapes.size(), extracted.index + 1)); + mesh.blendshapes[extracted.index] = extracted.blendshape; + } - foreach (const FBXMesh& mesh, meshMap) { - geometry.otherMeshes.append(mesh); + FBXGeometry geometry; + foreach (const FBXMesh& mesh, meshes) { + geometry.meshes.append(mesh); } return geometry; diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index dfa972697f..db67c6b54a 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -29,16 +29,6 @@ public: FBXNodeList children; }; -/// A single mesh extracted from an FBX document. -class FBXMesh { -public: - - QVector quadIndices; - QVector triangleIndices; - QVector vertices; - QVector normals; -}; - /// A single blendshape extracted from an FBX document. class FBXBlendshape { public: @@ -48,14 +38,23 @@ public: QVector normals; }; -/// Base geometry with blendshapes mapped by name. -class FBXGeometry { +/// A single mesh (with optional blendshapes) extracted from an FBX document. +class FBXMesh { public: - FBXMesh blendMesh; - QVector blendshapes; + QVector quadIndices; + QVector triangleIndices; + QVector vertices; + QVector normals; - QVector otherMeshes; + QVector blendshapes; +}; + +/// A set of meshes extracted from an FBX document. +class FBXGeometry { +public: + + QVector meshes; }; /// Parses the input from the supplied data as an FBX file. From 1b9444cb39062c69da3f617ee122d81e9d67843f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Sep 2013 14:22:01 -0700 Subject: [PATCH 5/8] As a temporary hack, render the mesh with the most blendshapes with the head color (other meshes white). --- interface/src/avatar/BlendFace.cpp | 12 +++++++----- interface/src/renderer/FBXReader.cpp | 11 ++++++++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 886184aafc..14818ff22f 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -48,6 +48,8 @@ bool BlendFace::render(float alpha) { // enable normalization under the expectation that the GPU can do it faster glEnable(GL_NORMALIZE); + glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha); + for (int i = 0; i < _meshIDs.size(); i++) { const VerticesIndices& ids = _meshIDs.at(i); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ids.first); @@ -56,12 +58,12 @@ bool BlendFace::render(float alpha) { const FBXMesh& mesh = _geometry.meshes.at(i); int vertexCount = mesh.vertices.size(); - if (mesh.blendshapes.isEmpty()) { + // all meshes after the first are white + if (i == 1) { glColor4f(1.0f, 1.0f, 1.0f, alpha); - - } else { - glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha); - + } + + if (!mesh.blendshapes.isEmpty()) { _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); _blendedNormals.resize(_blendedVertices.size()); memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 5219669193..a5fd85673f 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -376,9 +376,18 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { mesh.blendshapes[extracted.index] = extracted.blendshape; } + // as a temporary hack, put the mesh with the most blendshapes on top; assume it to be the face FBXGeometry geometry; + int mostBlendshapes = 0; + int mostBlendshapesIndex = 0; foreach (const FBXMesh& mesh, meshes) { - geometry.meshes.append(mesh); + if (mesh.blendshapes.size() > mostBlendshapes) { + geometry.meshes.prepend(mesh); + mostBlendshapes = mesh.blendshapes.size(); + + } else { + geometry.meshes.append(mesh); + } } return geometry; From 4666c736d8533bedc170162b35dd821860e4e806 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Sep 2013 14:24:57 -0700 Subject: [PATCH 6/8] Remove unused variable. --- interface/src/renderer/FBXReader.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index a5fd85673f..67ead61d0c 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -379,7 +379,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { // as a temporary hack, put the mesh with the most blendshapes on top; assume it to be the face FBXGeometry geometry; int mostBlendshapes = 0; - int mostBlendshapesIndex = 0; foreach (const FBXMesh& mesh, meshes) { if (mesh.blendshapes.size() > mostBlendshapes) { geometry.meshes.prepend(mesh); From 452eb9be47f0ceacd2d117530ba734e53f53eb58 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Sep 2013 16:50:38 -0700 Subject: [PATCH 7/8] Extract the pivot points from the limb nodes, make sure we extract the vector elements in the right order. --- interface/src/renderer/FBXReader.cpp | 28 ++++++++++++++++++++++++++-- interface/src/renderer/FBXReader.h | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 67ead61d0c..0c74e14527 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -189,7 +189,10 @@ FBXNode parseFBX(QIODevice* device) { QVector createVec3Vector(const QVector& doubleVector) { QVector values; for (const double* it = doubleVector.constData(), *end = it + doubleVector.size(); it != end; ) { - values.append(glm::vec3(*it++, *it++, *it++)); + float x = *it++; + float y = *it++; + float z = *it++; + values.append(glm::vec3(x, y, z)); } return values; } @@ -270,6 +273,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { QHash meshes; QVector blendshapes; QHash parentMap; + QMultiHash childMap; + QHash pivots; foreach (const FBXNode& child, node.children) { if (child.name == "Objects") { @@ -355,12 +360,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { blendshapes.append(extracted); } + } else if (object.name == "Deformer" && object.properties.at(2) == "Cluster") { + foreach (const FBXNode& subobject, object.children) { + if (subobject.name == "TransformLink") { + QVector values = subobject.properties.at(0).value >(); + pivots.insert(object.properties.at(0).value(), + glm::vec3(values.at(12), values.at(13), values.at(14))); // matrix translation component + } + } } } } else if (child.name == "Connections") { foreach (const FBXNode& connection, child.children) { if (connection.name == "C") { parentMap.insert(connection.properties.at(1).value(), connection.properties.at(2).value()); + childMap.insert(connection.properties.at(2).value(), connection.properties.at(1).value()); } } } @@ -379,7 +393,17 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { // as a temporary hack, put the mesh with the most blendshapes on top; assume it to be the face FBXGeometry geometry; int mostBlendshapes = 0; - foreach (const FBXMesh& mesh, meshes) { + for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { + FBXMesh& mesh = it.value(); + + // look for a limb pivot + foreach (qint64 childID, childMap.values(it.key())) { + qint64 clusterID = childMap.value(childID); + if (pivots.contains(clusterID)) { + mesh.pivot = pivots.value(clusterID); + } + } + if (mesh.blendshapes.size() > mostBlendshapes) { geometry.meshes.prepend(mesh); mostBlendshapes = mesh.blendshapes.size(); diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index db67c6b54a..fbaad6868e 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -47,6 +47,8 @@ public: QVector vertices; QVector normals; + glm::vec3 pivot; + QVector blendshapes; }; From 71ec6f75e58cca0a37e420765ae86ed469cf6de1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Sep 2013 18:57:37 -0700 Subject: [PATCH 8/8] Move the eyeball meshes according to the lookat direction (not really visible yet since the eyeballs have no textures). --- interface/src/avatar/BlendFace.cpp | 21 +++++++++++++++++++-- interface/src/avatar/Head.cpp | 14 +++++++------- interface/src/avatar/Head.h | 2 ++ interface/src/renderer/FBXReader.cpp | 13 +++++++++++++ interface/src/renderer/FBXReader.h | 2 ++ 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 14818ff22f..d25009f40f 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -37,10 +37,12 @@ bool BlendFace::render(float alpha) { glm::quat orientation = _owningHead->getOrientation(); glm::vec3 axis = glm::axis(orientation); glRotatef(glm::angle(orientation), axis.x, axis.y, axis.z); - glTranslatef(0.0f, -0.025f, -0.025f); // temporary fudge factor until we have a better method of per-model positioning + const glm::vec3 MODEL_TRANSLATION(0.0f, -0.025f, -0.025f); // temporary fudge factor + glTranslatef(MODEL_TRANSLATION.x, MODEL_TRANSLATION.y, MODEL_TRANSLATION.z); const float MODEL_SCALE = 0.0006f; - glScalef(_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE, + glm::vec3 scale(_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE, -_owningHead->getScale() * MODEL_SCALE); + glScalef(scale.x, scale.y, scale.z); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -58,6 +60,17 @@ bool BlendFace::render(float alpha) { const FBXMesh& mesh = _geometry.meshes.at(i); int vertexCount = mesh.vertices.size(); + // 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()); + glm::vec3 rotationAxis = glm::axis(rotation); + glRotatef(glm::angle(rotation), rotationAxis.x, rotationAxis.y, rotationAxis.z); + glTranslatef(-mesh.pivot.x, -mesh.pivot.y, -mesh.pivot.z); + } + // all meshes after the first are white if (i == 1) { glColor4f(1.0f, 1.0f, 1.0f, alpha); @@ -97,6 +110,10 @@ bool BlendFace::render(float alpha) { glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, mesh.quadIndices.size(), GL_UNSIGNED_INT, 0); glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, mesh.triangleIndices.size(), GL_UNSIGNED_INT, (void*)(mesh.quadIndices.size() * sizeof(int))); + + if (mesh.isEye) { + glPopMatrix(); + } } glDisable(GL_NORMALIZE); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 7b54fb0c8f..52e6278c8e 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -459,6 +459,11 @@ glm::quat Head::getCameraOrientation () const { * glm::quat(glm::radians(glm::vec3(_cameraPitch + _mousePitch, _cameraYaw, 0.0f))); } +glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const { + glm::quat orientation = getOrientation(); + return rotationBetween(orientation * IDENTITY_FRONT, _lookAtPosition + _saccade - eyePosition) * orientation; +} + void Head::renderHeadSphere() { glPushMatrix(); glTranslatef(_position.x, _position.y, _position.z); //translate to head position @@ -663,17 +668,13 @@ void Head::renderEyeBalls() { glBindTexture(GL_TEXTURE_2D, _irisTextureID); glEnable(GL_TEXTURE_2D); - glm::quat orientation = getOrientation(); - glm::vec3 front = orientation * IDENTITY_FRONT; - // render left iris glm::quat leftIrisRotation; glPushMatrix(); { glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatVector = _lookAtPosition + _saccade - _leftEyePosition; - leftIrisRotation = rotationBetween(front, targetLookatVector) * orientation; + leftIrisRotation = getEyeRotation(_leftEyePosition); glm::vec3 rotationAxis = glm::axis(leftIrisRotation); glRotatef(glm::angle(leftIrisRotation), rotationAxis.x, rotationAxis.y, rotationAxis.z); glTranslatef(0.0f, 0.0f, -_scale * IRIS_PROTRUSION); @@ -697,8 +698,7 @@ void Head::renderEyeBalls() { glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatVector = _lookAtPosition + _saccade - _rightEyePosition; - rightIrisRotation = rotationBetween(front, targetLookatVector) * orientation; + rightIrisRotation = getEyeRotation(_rightEyePosition); glm::vec3 rotationAxis = glm::axis(rightIrisRotation); glRotatef(glm::angle(rightIrisRotation), rotationAxis.x, rotationAxis.y, rotationAxis.z); glTranslatef(0.0f, 0.0f, -_scale * IRIS_PROTRUSION); diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 04fc26c7f9..4c535edcba 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -72,6 +72,8 @@ public: glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } + glm::quat getEyeRotation(const glm::vec3& eyePosition) const; + Face& getFace() { return _face; } BlendFace& getBlendFace() { return _blendFace; } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 0c74e14527..054a1cf3a9 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -275,6 +275,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { QHash parentMap; QMultiHash childMap; QHash pivots; + qint64 jointEyeLeftID = 0; + qint64 jointEyeRightID = 0; foreach (const FBXNode& child, node.children) { if (child.name == "Objects") { @@ -360,6 +362,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { blendshapes.append(extracted); } + } else if (object.name == "Model" && object.properties.at(2) == "LimbNode") { + if (object.properties.at(1).toByteArray().startsWith("jointEyeLeft")) { + jointEyeLeftID = object.properties.at(0).value(); + + } else if (object.properties.at(1).toByteArray().startsWith("jointEyeRight")) { + jointEyeRightID = object.properties.at(0).value(); + } } else if (object.name == "Deformer" && object.properties.at(2) == "Cluster") { foreach (const FBXNode& subobject, object.children) { if (subobject.name == "TransformLink") { @@ -401,6 +410,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { 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; + } } } diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index fbaad6868e..09866c82c9 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -49,6 +49,8 @@ public: glm::vec3 pivot; + bool isEye; + QVector blendshapes; };