From 51c868fd28bff8a7673307a5b1e1ecd681c22b31 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 3 Oct 2013 18:12:58 -0700 Subject: [PATCH 01/26] Apply (some) FBX material properties to rendered meshes. --- interface/src/avatar/BlendFace.cpp | 16 +++++---- interface/src/renderer/FBXReader.cpp | 50 +++++++++++++++++++++++++++- interface/src/renderer/FBXReader.h | 5 +++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 321019b4a0..c88221c25b 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -88,8 +88,7 @@ bool BlendFace::render(float alpha) { // enable normalization under the expectation that the GPU can do it faster glEnable(GL_NORMALIZE); glEnable(GL_TEXTURE_2D); - - glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha); + glDisable(GL_COLOR_MATERIAL); for (int i = 0; i < networkMeshes.size(); i++) { const NetworkMesh& networkMesh = networkMeshes.at(i); @@ -118,12 +117,12 @@ bool BlendFace::render(float alpha) { } } - glMultMatrixf((const GLfloat*)&mesh.transform); + // apply material properties + glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&mesh.diffuseColor); + glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&mesh.specularColor); + glMaterialf(GL_FRONT, GL_SHININESS, mesh.shininess); - // all meshes after the first are white - if (i == 1) { - glColor4f(1.0f, 1.0f, 1.0f, alpha); - } + glMultMatrixf((const GLfloat*)&mesh.transform); glBindTexture(GL_TEXTURE_2D, texture == NULL ? 0 : texture->getID()); @@ -191,6 +190,9 @@ bool BlendFace::render(float alpha) { glPopMatrix(); + // restore all the default material settings + Application::getInstance()->setupWorldLight(*Application::getInstance()->getCamera()); + return true; } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 24644866cd..2a048b4d3b 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -346,6 +346,14 @@ void printNode(const FBXNode& node, int indent) { } } +class Material { +public: + glm::vec4 ambient; + glm::vec4 diffuse; + glm::vec4 specular; + float shininess; +}; + FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) { QHash meshes; QVector blendshapes; @@ -354,6 +362,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QHash localTransforms; QHash transformLinkMatrices; QHash textureFilenames; + QHash materials; QHash diffuseTextures; QHash bumpTextures; @@ -578,6 +587,37 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) textureFilenames.insert(object.properties.at(0).value(), filename); } } + } else if (object.name == "Material") { + Material material = { glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), + glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), 96.0f }; + 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) == "AmbientColor") { + material.ambient = glm::vec4(property.properties.at(4).value(), + property.properties.at(5).value(), + property.properties.at(6).value(), 1.0f); + + } else if (property.properties.at(0) == "DiffuseColor") { + material.diffuse = glm::vec4(property.properties.at(4).value(), + property.properties.at(5).value(), + property.properties.at(6).value(), 1.0f); + + } else if (property.properties.at(0) == "SpecularColor") { + material.specular = glm::vec4(property.properties.at(4).value(), + property.properties.at(5).value(), + property.properties.at(6).value(), 1.0f); + + } else if (property.properties.at(0) == "Shininess") { + material.shininess = property.properties.at(4).value(); + } + } + } + } + } + materials.insert(object.properties.at(0).value(), material); + } else if (object.name == "Deformer") { if (object.properties.at(2) == "Cluster") { foreach (const FBXNode& subobject, object.children) { @@ -641,8 +681,16 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) qint64 modelID = parentMap.value(it.key()); glm::mat4 modelTransform = getGlobalTransform(parentMap, localTransforms, modelID); - // look for textures + // look for textures, material properties foreach (qint64 childID, childMap.values(modelID)) { + if (!materials.contains(childID)) { + continue; + } + Material material = materials.value(childID); + mesh.ambientColor = material.ambient; + mesh.diffuseColor = material.diffuse; + mesh.specularColor = material.specular; + mesh.shininess = material.shininess; qint64 diffuseTextureID = diffuseTextures.value(childID); if (diffuseTextureID != 0) { mesh.diffuseFilename = textureFilenames.value(diffuseTextureID); diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index f84a06468e..77568072c4 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -51,6 +51,11 @@ public: bool isEye; + glm::vec4 ambientColor; + glm::vec4 diffuseColor; + glm::vec4 specularColor; + float shininess; + QByteArray diffuseFilename; QByteArray normalFilename; From b281facf45e48667e4a86920a1af26c3c13a16da Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Oct 2013 10:53:19 -0700 Subject: [PATCH 02/26] Remove references to ambient, use the requested alpha. --- interface/src/avatar/BlendFace.cpp | 6 ++++-- interface/src/renderer/FBXReader.cpp | 24 ++++++++---------------- interface/src/renderer/FBXReader.h | 5 ++--- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index c88221c25b..fb7ad46035 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -118,8 +118,10 @@ bool BlendFace::render(float alpha) { } // apply material properties - glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&mesh.diffuseColor); - glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&mesh.specularColor); + glm::vec4 diffuse = glm::vec4(mesh.diffuseColor, alpha); + glm::vec4 specular = glm::vec4(mesh.specularColor, alpha); + glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); glMaterialf(GL_FRONT, GL_SHININESS, mesh.shininess); glMultMatrixf((const GLfloat*)&mesh.transform); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 2a048b4d3b..1c24f8b6c6 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -348,9 +348,8 @@ void printNode(const FBXNode& node, int indent) { class Material { public: - glm::vec4 ambient; - glm::vec4 diffuse; - glm::vec4 specular; + glm::vec3 diffuse; + glm::vec3 specular; float shininess; }; @@ -588,26 +587,20 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } } else if (object.name == "Material") { - Material material = { glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), - glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), 96.0f }; + Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), 96.0f }; 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) == "AmbientColor") { - material.ambient = glm::vec4(property.properties.at(4).value(), + if (property.properties.at(0) == "DiffuseColor") { + material.diffuse = glm::vec3(property.properties.at(4).value(), property.properties.at(5).value(), - property.properties.at(6).value(), 1.0f); - - } else if (property.properties.at(0) == "DiffuseColor") { - material.diffuse = glm::vec4(property.properties.at(4).value(), - property.properties.at(5).value(), - property.properties.at(6).value(), 1.0f); + property.properties.at(6).value()); } else if (property.properties.at(0) == "SpecularColor") { - material.specular = glm::vec4(property.properties.at(4).value(), + material.specular = glm::vec3(property.properties.at(4).value(), property.properties.at(5).value(), - property.properties.at(6).value(), 1.0f); + property.properties.at(6).value()); } else if (property.properties.at(0) == "Shininess") { material.shininess = property.properties.at(4).value(); @@ -687,7 +680,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) continue; } Material material = materials.value(childID); - mesh.ambientColor = material.ambient; mesh.diffuseColor = material.diffuse; mesh.specularColor = material.specular; mesh.shininess = material.shininess; diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 77568072c4..310dea265f 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -51,9 +51,8 @@ public: bool isEye; - glm::vec4 ambientColor; - glm::vec4 diffuseColor; - glm::vec4 specularColor; + glm::vec3 diffuseColor; + glm::vec3 specularColor; float shininess; QByteArray diffuseFilename; From 5f2617756032b8ec2fd901d08b8bbb24052dd29e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Oct 2013 13:42:03 -0700 Subject: [PATCH 03/26] Fix for URLs' not being sent: setting the scale calls createMohawk, which reseeds the random number generator, breaking "shouldDo." --- interface/src/avatar/Head.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ae02790b94..e54d2fb18c 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -313,6 +313,9 @@ void Head::render(float alpha, bool isMine) { } void Head::setScale (float scale) { + if (_scale == scale) { + return; + } _scale = scale; createMohawk(); From 325ac73d0a420fcf2f9bf3fe5e76d5bee805ea39 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Oct 2013 17:04:50 -0700 Subject: [PATCH 04/26] Apply color to ambient material property, too. --- interface/src/avatar/BlendFace.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index fb7ad46035..d376c976eb 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -120,6 +120,7 @@ bool BlendFace::render(float alpha) { // apply material properties glm::vec4 diffuse = glm::vec4(mesh.diffuseColor, alpha); glm::vec4 specular = glm::vec4(mesh.specularColor, alpha); + glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); glMaterialf(GL_FRONT, GL_SHININESS, mesh.shininess); From 08426fbd9c862369cc73c28f5341659213c3e6f6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Oct 2013 17:49:18 -0700 Subject: [PATCH 05/26] Handle index-to-direct normals (exported by the Faceshift rig FBX). --- interface/src/renderer/FBXReader.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 1c24f8b6c6..e03b862f20 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -402,6 +402,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QVector polygonIndices; QVector normals; + QVector normalIndices; QVector texCoords; QVector texCoordIndices; foreach (const FBXNode& data, object.children) { @@ -417,6 +418,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) if (subdata.name == "Normals") { normals = createVec3Vector(subdata.properties.at(0).value >()); + } else if (subdata.name == "NormalsIndex") { + normalIndices = subdata.properties.at(0).value >(); + } else if (subdata.name == "MappingInformationType" && subdata.properties.at(0) == "ByVertice") { byVertex = true; @@ -440,10 +444,20 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) // convert normals from per-index to per-vertex if necessary if (mesh.normals.isEmpty()) { mesh.normals.resize(mesh.vertices.size()); - for (int i = 0, n = polygonIndices.size(); i < n; i++) { - int index = polygonIndices.at(i); - mesh.normals[index < 0 ? (-index - 1) : index] = normals.at(i); - } + if (normalIndices.isEmpty()) { + for (int i = 0, n = polygonIndices.size(); i < n; i++) { + int index = polygonIndices.at(i); + mesh.normals[index < 0 ? (-index - 1) : index] = normals.at(i); + } + } else { + for (int i = 0, n = polygonIndices.size(); i < n; i++) { + int index = polygonIndices.at(i); + int normalIndex = normalIndices.at(i); + if (normalIndex >= 0) { + mesh.normals[index < 0 ? (-index - 1) : index] = normals.at(normalIndex); + } + } + } } // same with the tex coords From a704a29864d18e79b4c30a6f4c2a889c1248f024 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Oct 2013 17:56:36 -0700 Subject: [PATCH 06/26] Include a mapping for the names generated by the FBX export. --- interface/src/renderer/FBXReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index e03b862f20..afacc86204 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -382,6 +382,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } QList mappings = blendshapeMappings.values(blendshapeName); if (mappings.isEmpty()) { + blendshapeIndices.insert(blendshapeName, QPair(i, 1.0f)); blendshapeIndices.insert("ExpressionBlendshapes." + blendshapeName, QPair(i, 1.0f)); } else { foreach (const QVariant& mapping, mappings) { From 0c70a05732caea290f59de248d6fe419d9f87878 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 4 Oct 2013 21:36:21 -0700 Subject: [PATCH 07/26] make view frustum oversend and don't remove oversend in client --- interface/src/VoxelSystem.cpp | 14 ++++++++++---- .../voxel-server-library/src/VoxelNodeData.cpp | 5 ++++- libraries/voxels/src/VoxelConstants.h | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0e2c37af81..753a97d738 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1416,7 +1416,7 @@ void VoxelSystem::falseColorizeDistanceFromView() { class removeOutOfViewArgs { public: VoxelSystem* thisVoxelSystem; - ViewFrustum* thisViewFrustum; + ViewFrustum thisViewFrustum; VoxelNodeBag dontRecurseBag; unsigned long nodesScanned; unsigned long nodesRemoved; @@ -1426,14 +1426,20 @@ public: removeOutOfViewArgs(VoxelSystem* voxelSystem) : thisVoxelSystem(voxelSystem), - thisViewFrustum(voxelSystem->getViewFrustum()), + thisViewFrustum(*voxelSystem->getViewFrustum()), dontRecurseBag(), nodesScanned(0), nodesRemoved(0), nodesInside(0), nodesIntersect(0), nodesOutside(0) - { } + { + // Widen the FOV for trimming + float originalFOV = thisViewFrustum.getFieldOfView(); + float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; + thisViewFrustum.setFieldOfView(wideFOV); // hack + thisViewFrustum.calculate(); + } }; void VoxelSystem::cancelImport() { @@ -1459,7 +1465,7 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { - ViewFrustum::location inFrustum = childNode->inFrustum(*args->thisViewFrustum); + ViewFrustum::location inFrustum = childNode->inFrustum(args->thisViewFrustum); switch (inFrustum) { case ViewFrustum::OUTSIDE: { args->nodesOutside++; diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 43d87c2f89..811e3bc63a 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -74,7 +74,10 @@ bool VoxelNodeData::updateCurrentViewFrustum() { newestViewFrustum.setOrientation(getCameraOrientation()); // Also make sure it's got the correct lens details from the camera - newestViewFrustum.setFieldOfView(getCameraFov()); + float originalFOV = getCameraFov(); + float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; + + newestViewFrustum.setFieldOfView(wideFOV); // hack newestViewFrustum.setAspectRatio(getCameraAspectRatio()); newestViewFrustum.setNearClip(getCameraNearClip()); newestViewFrustum.setFarClip(getCameraFarClip()); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 1871aa8e31..64a3f3cc44 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -52,4 +52,6 @@ const float VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0f; // once a second is fin const uint64_t CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS = 1000 * 5; // 1 packet every 50 milliseconds +const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f; + #endif \ No newline at end of file From 6fce838e2e16230ea69aa8d996c993bfa0991019 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 4 Oct 2013 21:38:47 -0700 Subject: [PATCH 08/26] remove comment --- interface/src/VoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 753a97d738..0b4dba1364 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1437,7 +1437,7 @@ public: // Widen the FOV for trimming float originalFOV = thisViewFrustum.getFieldOfView(); float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; - thisViewFrustum.setFieldOfView(wideFOV); // hack + thisViewFrustum.setFieldOfView(wideFOV); thisViewFrustum.calculate(); } }; From 3001917e10a03bb17503c6148274ba5b5d6257a9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 4 Oct 2013 22:49:05 -0700 Subject: [PATCH 09/26] added debugging --- interface/src/VoxelSystem.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0b4dba1364..a83914ed96 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -191,6 +191,8 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) { // This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". void VoxelSystem::clearFreeBufferIndexes() { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()"); + for (int i = 0; i < _freeIndexes.size(); i++) { glBufferIndex nodeIndex = _freeIndexes[i]; glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); @@ -606,7 +608,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawingSingleNode()"); // would like to include _voxelsInArrays, _voxelsUpdated + "setupNewVoxelsForDrawingSingleNode() xxxxx"); uint64_t start = usecTimestampNow(); uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; @@ -623,7 +625,11 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { checkForCulling(); // check for out of view and deleted voxels... // lock on the buffer write lock so we can't modify the data when the GPU is reading it - pthread_mutex_lock(&_bufferWriteLock); + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "setupNewVoxelsForDrawingSingleNode()... pthread_mutex_lock(&_bufferWriteLock);"); + pthread_mutex_lock(&_bufferWriteLock); + } _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty From 5f6fb3a3aeff6df71571a982dd00f7dfe25c7f2f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 5 Oct 2013 00:55:34 -0700 Subject: [PATCH 10/26] added some timing debugging --- interface/src/Application.cpp | 46 ++++++++++++++++++++++++-- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 2 ++ interface/src/VoxelPacketProcessor.cpp | 9 +++-- interface/src/VoxelSystem.cpp | 4 +++ libraries/shared/src/PerfStat.cpp | 13 ++++++-- libraries/shared/src/PerfStat.h | 3 ++ 7 files changed, 71 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 615fcfaa01..6d7686328f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -324,6 +324,8 @@ void Application::initializeGL() { } void Application::paintGL() { + PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::paintGL()"); PerfStat("display"); glEnable(GL_LINE_SMOOTH); @@ -1181,6 +1183,7 @@ void Application::idle() { double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check); if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { + const float BIGGEST_DELTA_TIME_SECS = 0.25f; update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); _glWidget->updateGL(); @@ -2379,6 +2382,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom } void Application::displaySide(Camera& whichCamera) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset // flip x if in mirror mode (also requires reversing winding order for backface culling) @@ -2410,6 +2414,8 @@ void Application::displaySide(Camera& whichCamera) { setupWorldLight(whichCamera); if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... stars..."); if (!_stars.getFileLoaded()) { _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); } @@ -2435,6 +2441,8 @@ void Application::displaySide(Camera& whichCamera) { // draw the sky dome if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... atmosphere..."); _environment.renderAtmospheres(whichCamera); } @@ -2457,6 +2465,9 @@ void Application::displaySide(Camera& whichCamera) { //draw a grid ground plane.... if (Menu::getInstance()->isOptionChecked(MenuOption::GroundPlane)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... ground plane..."); + // draw grass plane with fog glEnable(GL_FOG); glEnable(GL_NORMALIZE); @@ -2480,7 +2491,11 @@ void Application::displaySide(Camera& whichCamera) { } // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - _voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures)); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... voxels..."); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DontRenderVoxels)) { + _voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures)); + } } // restore default, white specular @@ -2488,6 +2503,9 @@ void Application::displaySide(Camera& whichCamera) { // indicate what we'll be adding/removing in mouse mode, if anything if (_mouseVoxel.s != 0) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... voxels TOOLS UX..."); + glDisable(GL_LIGHTING); glPushMatrix(); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); @@ -2533,6 +2551,9 @@ void Application::displaySide(Camera& whichCamera) { } if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... PASTE Preview..."); + glPushMatrix(); glTranslatef(_mouseVoxel.x * TREE_SCALE, _mouseVoxel.y * TREE_SCALE, @@ -2548,6 +2569,10 @@ void Application::displaySide(Camera& whichCamera) { _myAvatar.renderScreenTint(SCREEN_TINT_BEFORE_AVATARS, whichCamera); if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... Avatars..."); + + // Render avatars of other nodes NodeList* nodeList = NodeList::getInstance(); @@ -2592,16 +2617,22 @@ void Application::displaySide(Camera& whichCamera) { // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... AmbientOcclusion..."); _ambientOcclusionEffect.render(); } // brad's frustum for debugging if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... renderViewFrustum..."); renderViewFrustum(_viewFrustum); } // render voxel fades if they exist if (_voxelFades.size() > 0) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... voxel fades..."); for(std::vector::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) { fade->render(); if(fade->isDone()) { @@ -2611,11 +2642,18 @@ void Application::displaySide(Camera& whichCamera) { } } } - - renderFollowIndicator(); + + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... renderFollowIndicator..."); + renderFollowIndicator(); + } // render transmitter pick ray, if non-empty if (_transmitterPickStart != _transmitterPickEnd) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... transmitter pick ray..."); + Glower glower; const float TRANSMITTER_PICK_COLOR[] = { 1.0f, 1.0f, 0.0f }; glColor3fv(TRANSMITTER_PICK_COLOR); @@ -2637,6 +2675,8 @@ void Application::displaySide(Camera& whichCamera) { } void Application::displayOverlay() { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()"); + // Render 2D overlay: I/O level bar graphs and text glMatrixMode(GL_PROJECTION); glPushMatrix(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4ff97a39f1..ededcbccd0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -239,6 +239,7 @@ Menu::Menu() : true, appInstance, SLOT(setRenderVoxels(bool))); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRenderVoxels); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0, @@ -346,6 +347,7 @@ Menu::Menu() : QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools"); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings); + addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings); addActionToQMenuAndActionHash(renderDebugMenu, MenuOption::KillLocalVoxels, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d72a0397e8..5c21a35b35 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -138,6 +138,7 @@ namespace MenuOption { const QString DestructiveAddVoxel = "Create Voxel is Destructive"; const QString DeltaSending = "Delta Sending"; const QString DisplayFrustum = "Display Frustum"; + const QString DontRenderVoxels = "Don't Render Voxels"; const QString EchoAudio = "Echo Audio"; const QString ExportVoxels = "Export Voxels"; const QString HeadMouse = "Head Mouse"; @@ -193,6 +194,7 @@ namespace MenuOption { const QString ShowTrueColors = "Show TRUE Colors"; const QString SimulateLeapHand = "Simulate Leap Hand"; const QString SkeletonTracking = "Skeleton Tracking"; + const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString LEDTracking = "LED Tracking"; const QString Stars = "Stars"; const QString Stats = "Stats"; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 5d05253e36..8dc5092a64 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -47,15 +47,18 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { - voxelServer->lock(); + + voxelServer->lock(); // do we really need to lock this? just to get the ID? + int nodeID = voxelServer->getNodeID(); + voxelServer->unlock(); + if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { app->_environment.parseData(&senderAddress, packetData, messageLength); } else { - app->_voxels.setDataSourceID(voxelServer->getNodeID()); + app->_voxels.setDataSourceID(nodeID); app->_voxels.parseData(packetData, messageLength); app->_voxels.setDataSourceID(UNKNOWN_NODE_ID); } - voxelServer->unlock(); } } } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index a83914ed96..f0d6777053 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1077,6 +1077,8 @@ void VoxelSystem::render(bool texture) { updateVBOs(); if (_useVoxelShader) { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "render().. _useVoxelShader openGL.."); Application::getInstance()->getVoxelShader().begin(); @@ -1106,6 +1108,8 @@ void VoxelSystem::render(bool texture) { Application::getInstance()->getVoxelShader().end(); } else { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL..."); + // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 5199c09937..31f4b1a30b 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -103,6 +103,7 @@ int PerfStat::DumpStats(char** array) { return lineCount; } +bool PerformanceWarning::_suppressShortTimings = false; // Destructor handles recording all of our stats PerformanceWarning::~PerformanceWarning() { @@ -111,9 +112,17 @@ PerformanceWarning::~PerformanceWarning() { if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; - qDebug("%s%s took %lf seconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedsec); + qDebug("%s took %lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") ); } else { - qDebug("%s%s took %lf milliseconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedmsec); + if (_suppressShortTimings) { + if (elapsedmsec > 10) { + qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec, + (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); + } + } else { + qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec, + (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); + } } } else if (_alwaysDisplay) { qDebug("%s took %lf milliseconds\n", _message, elapsedmsec); diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 320da3d280..2c5924e5ce 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -89,6 +89,7 @@ private: const char* _message; bool _renderWarningsOn; bool _alwaysDisplay; + static bool _suppressShortTimings; public: PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) : _start(usecTimestampNow()), @@ -97,6 +98,8 @@ public: _alwaysDisplay(alwaysDisplay) { } ~PerformanceWarning(); + + static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; } }; From 3448ceccd212d0bd7d79bb7df164f2f70037074c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Oct 2013 17:25:46 -0700 Subject: [PATCH 11/26] Progress towards a spring-mass model. --- interface/src/avatar/BlendFace.cpp | 161 +++++++++++++++++++++------ interface/src/avatar/BlendFace.h | 10 ++ interface/src/avatar/Head.cpp | 2 + interface/src/renderer/FBXReader.cpp | 51 +++++++-- interface/src/renderer/FBXReader.h | 5 + 5 files changed, 190 insertions(+), 39 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index d376c976eb..b857a56b72 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -8,6 +8,8 @@ #include +#include + #include "Application.h" #include "BlendFace.h" #include "Head.h" @@ -41,21 +43,104 @@ void BlendFace::init() { } } +void BlendFace::reset() { + _resetStates = true; +} + const glm::vec3 MODEL_TRANSLATION(0.0f, -120.0f, 40.0f); // temporary fudge factor const float MODEL_SCALE = 0.0006f; -bool BlendFace::render(float alpha) { +void BlendFace::simulate(float deltaTime) { if (!isActive()) { + return; + } + + // set up world vertices on first simulate after load + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + bool first = false; + if (_meshStates.isEmpty()) { + QVector vertices; + foreach (const FBXMesh& mesh, geometry.meshes) { + MeshState state; + if (mesh.springiness > 0.0f) { + state.worldSpaceVertices.resize(mesh.vertices.size()); + state.worldSpaceNormals.resize(mesh.vertices.size()); + } + _meshStates.append(state); + } + _resetStates = true; + } + + glm::mat4 baseTransform = glm::translate(_owningHead->getPosition()) * glm::mat4_cast(_owningHead->getOrientation()) * + glm::scale(glm::vec3(-1.0f, 1.0f, -1.0f) * _owningHead->getScale() * MODEL_SCALE) * + glm::translate(MODEL_TRANSLATION - _geometry->getFBXGeometry().neckPivot); + + for (int i = 0; i < _meshStates.size(); i++) { + MeshState& state = _meshStates[i]; + int vertexCount = state.worldSpaceVertices.size(); + if (vertexCount == 0) { + continue; + } + glm::vec3* destVertices = state.worldSpaceVertices.data(); + glm::vec3* destNormals = state.worldSpaceNormals.data(); + const FBXMesh& mesh = geometry.meshes.at(i); + const glm::vec3* sourceVertices = mesh.vertices.constData(); + if (!mesh.blendshapes.isEmpty()) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + const vector& coefficients = _owningHead->getBlendshapeCoefficients(); + for (int j = 0; j < coefficients.size(); j++) { + float coefficient = coefficients[j]; + if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { + _blendedVertices[*index] += *vertex * coefficient; + } + } + + sourceVertices = _blendedVertices.constData(); + } + if (_resetStates) { + for (int j = 0; j < vertexCount; j++) { + destVertices[j] = glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)); + } + _resetStates = false; + + } else { + for (int j = 0; j < vertexCount; j++) { + destVertices[j] = glm::mix(destVertices[j], glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)), 0.25f); + } + } + for (int j = 0; j < vertexCount; j++) { + destNormals[j] = glm::vec3(0.0f, 0.0f, 0.0f); + + const glm::vec3& middle = destVertices[j]; + for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); + connection != mesh.vertexConnections.at(j).constEnd(); connection++) { + destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, + destVertices[connection->first] - middle)); + } + } + } +} + +bool BlendFace::render(float alpha) { + if (_meshStates.isEmpty()) { return false; } - // set up blended buffer ids on first render after load + // set up blended buffer ids on first render after load/simulate const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); if (_blendedVertexBufferIDs.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { GLuint id = 0; - if (!mesh.blendshapes.isEmpty()) { + if (!mesh.blendshapes.isEmpty() || mesh.springiness > 0.0f) { glGenBuffers(1, &id); glBindBuffer(GL_ARRAY_BUFFER, id); glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), @@ -69,6 +154,9 @@ bool BlendFace::render(float alpha) { _dilatedTextures.resize(geometry.meshes.size()); } + glm::mat4 viewMatrix; + glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&viewMatrix); + glPushMatrix(); glTranslatef(_owningHead->getPosition().x, _owningHead->getPosition().y, _owningHead->getPosition().z); glm::quat orientation = _owningHead->getOrientation(); @@ -130,39 +218,49 @@ bool BlendFace::render(float alpha) { glBindTexture(GL_TEXTURE_2D, texture == NULL ? 0 : texture->getID()); glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); - if (mesh.blendshapes.isEmpty()) { + if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3))); } else { glTexCoordPointer(2, GL_FLOAT, 0, 0); - - _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 j = 0; j < coefficients.size(); j++) { - float coefficient = coefficients[j]; - if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } - } - glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); - 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()); + + const MeshState& state = _meshStates.at(i); + if (!state.worldSpaceVertices.isEmpty()) { + glLoadMatrixf((const GLfloat*)&viewMatrix); + + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), + vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData()); + + } else { + _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 j = 0; j < coefficients.size(); j++) { + float coefficient = coefficients[j]; + if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { + _blendedVertices[*index] += *vertex * coefficient; + _blendedNormals[*index] += *normal * normalCoefficient; + } + } + + 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); glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); @@ -243,4 +341,5 @@ void BlendFace::deleteGeometry() { glDeleteBuffers(1, &id); } _blendedVertexBufferIDs.clear(); + _meshStates.clear(); } diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index 9307dc5c89..6851d63261 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -33,6 +33,8 @@ public: bool isActive() const { return _geometry && _geometry->isLoaded(); } void init(); + void reset(); + void simulate(float deltaTime); bool render(float alpha); Q_INVOKABLE void setModelURL(const QUrl& url); @@ -50,8 +52,16 @@ private: QSharedPointer _geometry; + class MeshState { + public: + QVector worldSpaceVertices; + QVector worldSpaceNormals; + }; + + QVector _meshStates; QVector _blendedVertexBufferIDs; QVector > _dilatedTextures; + bool _resetStates; QVector _blendedVertices; QVector _blendedNormals; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index e54d2fb18c..bd5847a44f 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -235,6 +235,8 @@ void Head::simulate(float deltaTime, bool isMine) { if (USING_PHYSICAL_MOHAWK) { updateHairPhysics(deltaTime); } + + _blendFace.simulate(deltaTime); } void Head::calculateGeometry() { diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index afacc86204..2390aa4991 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -300,6 +300,7 @@ const char* FACESHIFT_BLENDSHAPES[] = { class Transform { public: + QByteArray name; bool inheritScale; glm::mat4 withScale; glm::mat4 withoutScale; @@ -536,7 +537,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) glm::vec3 preRotation, rotation, postRotation; glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); glm::vec3 scalePivot, rotationPivot; - Transform transform = { true }; + Transform transform = { name, true }; foreach (const FBXNode& subobject, object.children) { if (subobject.name == "Properties70") { foreach (const FBXNode& property, subobject.children) { @@ -679,14 +680,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) mapping.value("ry").toFloat(), mapping.value("rz").toFloat())))) * glm::scale(offsetScale, offsetScale, offsetScale); - // as a temporary hack, put the mesh with the most blendshapes on top; assume it to be the face FBXGeometry geometry; - int mostBlendshapes = 0; + QVariantHash springs = mapping.value("spring").toHash(); for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { FBXMesh& mesh = it.value(); // accumulate local transforms qint64 modelID = parentMap.value(it.key()); + mesh.springiness = springs.value(localTransforms.value(modelID).name).toFloat(); glm::mat4 modelTransform = getGlobalTransform(parentMap, localTransforms, modelID); // look for textures, material properties @@ -731,13 +732,47 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } - if (mesh.blendshapes.size() > mostBlendshapes) { - geometry.meshes.prepend(mesh); - mostBlendshapes = mesh.blendshapes.size(); + // extract spring edges, connections if springy + if (mesh.springiness > 0.0f) { + QSet > edges; - } else { - geometry.meshes.append(mesh); + mesh.vertexConnections.resize(mesh.vertices.size()); + for (int i = 0; i < mesh.quadIndices.size(); i += 4) { + int index0 = mesh.quadIndices.at(i); + int index1 = mesh.quadIndices.at(i + 1); + int index2 = mesh.quadIndices.at(i + 2); + int index3 = mesh.quadIndices.at(i + 3); + + edges.insert(QPair(qMin(index0, index1), qMax(index0, index1))); + edges.insert(QPair(qMin(index1, index2), qMax(index1, index2))); + edges.insert(QPair(qMin(index2, index3), qMax(index2, index3))); + edges.insert(QPair(qMin(index3, index0), qMax(index3, index0))); + + mesh.vertexConnections[index0].append(QPair(index3, index1)); + mesh.vertexConnections[index1].append(QPair(index0, index2)); + mesh.vertexConnections[index2].append(QPair(index1, index3)); + mesh.vertexConnections[index3].append(QPair(index2, index0)); + } + for (int i = 0; i < mesh.triangleIndices.size(); i += 3) { + int index0 = mesh.triangleIndices.at(i); + int index1 = mesh.triangleIndices.at(i + 1); + int index2 = mesh.triangleIndices.at(i + 2); + + edges.insert(QPair(qMin(index0, index1), qMax(index0, index1))); + edges.insert(QPair(qMin(index1, index2), qMax(index1, index2))); + edges.insert(QPair(qMin(index2, index0), qMax(index2, index0))); + + mesh.vertexConnections[index0].append(QPair(index2, index1)); + mesh.vertexConnections[index1].append(QPair(index0, index2)); + mesh.vertexConnections[index2].append(QPair(index1, index0)); + } + + for (QSet >::const_iterator edge = edges.constBegin(); edge != edges.constEnd(); edge++) { + mesh.springEdges.append(*edge); + } } + + geometry.meshes.append(mesh); } // extract translation component for neck pivot diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 310dea265f..5c2ffd9ee0 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 @@ -59,6 +60,10 @@ public: QByteArray normalFilename; QVector blendshapes; + + float springiness; + QVector > springEdges; + QVector, 4> > vertexConnections; }; /// A set of meshes extracted from an FBX document. From c6981d1912e9b946a0be7856fdd403ad75eccabf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 7 Oct 2013 17:32:55 -0700 Subject: [PATCH 12/26] have animation server set an appropriate PPS based on it's voxel edit messages --- animation-server/src/main.cpp | 39 +++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 2ffc46ee2e..125a14f6b6 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -594,8 +594,12 @@ void* animateVoxels(void* args) { timeval lastSendTime; + bool firstTime = true; + while (true) { gettimeofday(&lastSendTime, NULL); + + int packetsStarting = ::voxelEditPacketSender->packetsToSendCount(); // some animations //sendVoxelBlinkMessage(); @@ -619,12 +623,22 @@ void* animateVoxels(void* args) { if (::buildStreet) { doBuildStreet(); } + + ::voxelEditPacketSender->releaseQueuedMessages(); + int packetsEnding = ::voxelEditPacketSender->packetsToSendCount(); - if (::voxelEditPacketSender) { - ::voxelEditPacketSender->releaseQueuedMessages(); - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->process(); - } + if (firstTime) { + int packetsPerSecond = (packetsEnding - packetsStarting) * (ACTUAL_FPS); + + std::cout << "Setting PPS to " << packetsPerSecond << "\n"; + + ::voxelEditPacketSender->setPacketsPerSecond(packetsPerSecond); + firstTime = false; + } + + + if (::nonThreadedPacketSender) { + ::voxelEditPacketSender->process(); } uint64_t end = usecTimestampNow(); @@ -715,14 +729,13 @@ int main(int argc, const char * argv[]) // Create out VoxelEditPacketSender ::voxelEditPacketSender = new VoxelEditPacketSender; - if (::voxelEditPacketSender) { - ::voxelEditPacketSender->initialize(!::nonThreadedPacketSender); - if (::jurisdictionListener) { - ::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions()); - } - if (::nonThreadedPacketSender) { - ::voxelEditPacketSender->setProcessCallIntervalHint(ANIMATE_VOXELS_INTERVAL_USECS); - } + ::voxelEditPacketSender->initialize(!::nonThreadedPacketSender); + + if (::jurisdictionListener) { + ::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions()); + } + if (::nonThreadedPacketSender) { + ::voxelEditPacketSender->setProcessCallIntervalHint(ANIMATE_VOXELS_INTERVAL_USECS); } srand((unsigned)time(0)); From 8baa863242ad0450089fcca4793a592d8bd49769 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 7 Oct 2013 17:34:41 -0700 Subject: [PATCH 13/26] fixed PPS bugs in threaded version of PacketSender class --- libraries/shared/src/PacketSender.cpp | 11 ++++++++--- libraries/shared/src/PacketSender.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/PacketSender.cpp b/libraries/shared/src/PacketSender.cpp index 41d5db87d1..5f6de128ba 100644 --- a/libraries/shared/src/PacketSender.cpp +++ b/libraries/shared/src/PacketSender.cpp @@ -85,7 +85,8 @@ bool PacketSender::process() { int packetsLeft = _packets.size(); bool keepGoing = packetsLeft > 0; while (keepGoing) { - + uint64_t SEND_INTERVAL_USECS = (_packetsPerSecond == 0) ? USECS_PER_SECOND : (USECS_PER_SECOND / _packetsPerSecond); + NetworkPacket& packet = _packets.front(); // send the packet through the NodeList... @@ -93,7 +94,7 @@ bool PacketSender::process() { nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength()); packetsThisCall++; - + if (_notify) { _notify->packetSentNotification(packet.getLength()); } @@ -110,11 +111,15 @@ bool PacketSender::process() { // dynamically sleep until we need to fire off the next set of voxels we only sleep in threaded mode if (keepGoing) { + now = usecTimestampNow(); uint64_t elapsed = now - _lastSendTime; - int usecToSleep = std::max(SEND_INTERVAL_USECS, SEND_INTERVAL_USECS - elapsed); + int usecToSleep = SEND_INTERVAL_USECS - elapsed; // we only sleep in non-threaded mode if (usecToSleep > 0) { + if (usecToSleep > SEND_INTERVAL_USECS) { + usecToSleep = SEND_INTERVAL_USECS; + } usleep(usecToSleep); } } diff --git a/libraries/shared/src/PacketSender.h b/libraries/shared/src/PacketSender.h index 84ae6ae9ca..9197c3c7d7 100644 --- a/libraries/shared/src/PacketSender.h +++ b/libraries/shared/src/PacketSender.h @@ -36,7 +36,7 @@ public: /// \thread any thread, typically the application thread void queuePacketForSending(sockaddr& address, unsigned char* packetData, ssize_t packetLength); - void setPacketsPerSecond(int packetsPerSecond) { _packetsPerSecond = std::min(MINIMUM_PACKETS_PER_SECOND, packetsPerSecond); } + void setPacketsPerSecond(int packetsPerSecond) { _packetsPerSecond = std::max(MINIMUM_PACKETS_PER_SECOND, packetsPerSecond); } int getPacketsPerSecond() const { return _packetsPerSecond; } void setPacketSenderNotify(PacketSenderNotify* notify) { _notify = notify; } From f6981feacf78e37c0728bd6735f9eb3121abfb51 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 7 Oct 2013 17:46:22 -0700 Subject: [PATCH 14/26] added various render mode options, including voxels as points --- interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 17 ++-- interface/src/Menu.h | 9 +- interface/src/VoxelSystem.cpp | 187 ++++++++++++++++++++++++---------- interface/src/VoxelSystem.h | 7 +- 5 files changed, 153 insertions(+), 68 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6d7686328f..46a2b9afde 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1589,6 +1589,7 @@ void Application::init() { // Set up VoxelSystem after loading preferences so we can get the desired max voxel count _voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels()); _voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader)); + _voxels.setVoxelsAsPoints(Menu::getInstance()->isOptionChecked(MenuOption::VoxelsAsPoints)); _voxels.setUseFastVoxelPipeline(Menu::getInstance()->isOptionChecked(MenuOption::FastVoxelPipeline)); _voxels.init(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ededcbccd0..8b92448e71 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -240,12 +240,18 @@ Menu::Menu() : appInstance, SLOT(setRenderVoxels(bool))); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRenderVoxels); - addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); - addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); - addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0, - false, this, SLOT(switchVoxelShader())); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontCallOpenGLForVoxels); + + _useVoxelShader = addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0, + false, appInstance->getVoxels(), SLOT(setUseVoxelShader(bool))); + + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelsAsPoints, 0, + false, appInstance->getVoxels(), SLOT(setVoxelsAsPoints(bool))); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0, false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool))); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); @@ -1005,7 +1011,4 @@ void Menu::updateFrustumRenderModeAction() { } } -void Menu::switchVoxelShader() { - Application::getInstance()->getVoxels()->setUseVoxelShader(isOptionChecked(MenuOption::UseVoxelShader)); -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5c21a35b35..f54d3767a1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -54,6 +54,7 @@ public: ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; } VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; } int getMaxVoxels() const { return _maxVoxels; } + QAction* getUseVoxelShader() const { return _useVoxelShader; } void handleViewFrustumOffsetKeyModifier(int key); @@ -78,7 +79,6 @@ private slots: void chooseVoxelPaintColor(); void runTests(); void resetSwatchColors(); - void switchVoxelShader(); private: static Menu* _instance; @@ -116,6 +116,7 @@ private: QActionGroup* _voxelModeActionsGroup; VoxelStatsDialog* _voxelStatsDialog; int _maxVoxels; + QAction* _useVoxelShader; }; namespace MenuOption { @@ -138,7 +139,8 @@ namespace MenuOption { const QString DestructiveAddVoxel = "Create Voxel is Destructive"; const QString DeltaSending = "Delta Sending"; const QString DisplayFrustum = "Display Frustum"; - const QString DontRenderVoxels = "Don't Render Voxels"; + const QString DontRenderVoxels = "Don't call _voxels.render()"; + const QString DontCallOpenGLForVoxels = "Don't call glDrawElements()/glDrawRangeElementsEXT() for Voxels"; const QString EchoAudio = "Echo Audio"; const QString ExportVoxels = "Export Voxels"; const QString HeadMouse = "Head Mouse"; @@ -205,8 +207,7 @@ namespace MenuOption { const QString UsePerlinFace = "Use Perlin's Face"; const QString Quit = "Quit"; const QString UseVoxelShader = "Use Voxel Shader"; - const QString UseByteNormals = "Use Byte Normals"; - const QString UseGlobalNormals = "Use Global Normals"; + const QString VoxelsAsPoints = "Draw Voxels as Points"; const QString Voxels = "Voxels"; const QString VoxelAddMode = "Add Voxel Mode"; const QString VoxelColorMode = "Color Voxel Mode"; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index f0d6777053..634486d8dc 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -90,6 +90,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); _useVoxelShader = false; + _voxelsAsPoints = false; + _voxelShaderModeWhenVoxelsAsPointsEnabled = false; _writeVoxelShaderData = NULL; _readVoxelShaderData = NULL; @@ -219,7 +221,6 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { if (maxVoxels == _maxVoxels) { return; } - pthread_mutex_lock(&_bufferWriteLock); bool wasInitialized = _initialized; if (wasInitialized) { clearAllNodesBufferIndex(); @@ -227,9 +228,8 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { } _maxVoxels = maxVoxels; if (wasInitialized) { - init(); + initVoxelMemory(); } - pthread_mutex_unlock(&_bufferWriteLock); if (wasInitialized) { forceRedrawEntireTree(); } @@ -240,7 +240,6 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { return; } - pthread_mutex_lock(&_bufferWriteLock); bool wasInitialized = _initialized; if (wasInitialized) { clearAllNodesBufferIndex(); @@ -248,17 +247,59 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { } _useVoxelShader = useVoxelShader; if (wasInitialized) { - init(); + initVoxelMemory(); } - pthread_mutex_unlock(&_bufferWriteLock); if (wasInitialized) { forceRedrawEntireTree(); } } +void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { + if (_voxelsAsPoints == voxelsAsPoints) { + return; + } + + bool wasInitialized = _initialized; + + // If we're "turning on" Voxels as points, we need to double check that we're in voxel shader mode. + // Voxels as points uses the VoxelShader memory model, so if we're not in voxel shader mode, + // then set it to voxel shader mode. + if (voxelsAsPoints) { + Menu::getInstance()->getUseVoxelShader()->setEnabled(false); + + // If enabling this... then do it before checking voxel shader status, that way, if voxel + // shader is already enabled, we just start drawing as points. + _voxelsAsPoints = true; + + if (!_useVoxelShader) { + setUseVoxelShader(true); + _voxelShaderModeWhenVoxelsAsPointsEnabled = false; + } else { + _voxelShaderModeWhenVoxelsAsPointsEnabled = true; + } + } else { + Menu::getInstance()->getUseVoxelShader()->setEnabled(true); + // if we're turning OFF voxels as point mode, then we check what the state of voxel shader was when we enabled + // voxels as points, if it was OFF, then we return it to that value. + if (_voxelShaderModeWhenVoxelsAsPointsEnabled == false) { + setUseVoxelShader(false); + } + // If disabling this... then do it AFTER checking previous voxel shader status, that way, if voxel + // shader is was not enabled, we switch back to normal mode before turning off points. + _voxelsAsPoints = false; + } + + // Set our voxels as points + if (wasInitialized) { + forceRedrawEntireTree(); + } +} + void VoxelSystem::cleanupVoxelMemory() { if (_initialized) { + pthread_mutex_lock(&_bufferWriteLock); + _initialized = false; // no longer initialized if (_useVoxelShader) { // these are used when in VoxelShader mode. glDeleteBuffers(1, &_vboVoxelsID); @@ -266,6 +307,9 @@ void VoxelSystem::cleanupVoxelMemory() { delete[] _writeVoxelShaderData; delete[] _readVoxelShaderData; + + _writeVoxelShaderData = _readVoxelShaderData = NULL; + } else { // Destroy glBuffers glDeleteBuffers(1, &_vboVerticesID); @@ -282,11 +326,18 @@ void VoxelSystem::cleanupVoxelMemory() { delete[] _writeVerticesArray; delete[] _readColorsArray; delete[] _writeColorsArray; + + _readVerticesArray = NULL; + _writeVerticesArray = NULL; + _readColorsArray = NULL; + _writeColorsArray = NULL; + } delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; + _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; + pthread_mutex_unlock(&_bufferWriteLock); } - _initialized = false; // no longer initialized } void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) { @@ -318,11 +369,11 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice } void VoxelSystem::initVoxelMemory() { - _initialMemoryUsageGPU = getFreeMemoryGPU(); + pthread_mutex_lock(&_bufferWriteLock); + _memoryUsageRAM = 0; _memoryUsageVBO = 0; // our VBO allocations as we know them if (_useVoxelShader) { - qDebug("Using Voxel Shader...\n"); GLuint* indicesArray = new GLuint[_maxVoxels]; // populate the indicesArray @@ -418,6 +469,10 @@ void VoxelSystem::initVoxelMemory() { _perlinModulateProgram.release(); } } + + _initialized = true; + + pthread_mutex_unlock(&_bufferWriteLock); } void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { @@ -544,7 +599,12 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { void VoxelSystem::setupNewVoxelsForDrawing() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated + "setupNewVoxelsForDrawing()"); + + if (!_initialized) { + return; // bail early if we're not initialized + } + uint64_t start = usecTimestampNow(); uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; @@ -587,7 +647,11 @@ void VoxelSystem::setupNewVoxelsForDrawing() { } // lock on the buffer write lock so we can't modify the data when the GPU is reading it - pthread_mutex_lock(&_bufferWriteLock); + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "setupNewVoxelsForDrawing()... pthread_mutex_lock(&_bufferWriteLock)"); + pthread_mutex_lock(&_bufferWriteLock); + } if (_voxelsUpdated) { _voxelsDirty=true; @@ -957,14 +1021,13 @@ void VoxelSystem::init() { _setupNewVoxelsForDrawingLastElapsed = 0; _lastViewCullingElapsed = _lastViewCulling = 0; - // When we change voxels representations in the arrays, we'll update this _voxelsDirty = false; _voxelsInWriteArrays = 0; _voxelsInReadArrays = 0; // VBO for the verticesArray + _initialMemoryUsageGPU = getFreeMemoryGPU(); initVoxelMemory(); - _initialized = true; // our own _removedVoxels doesn't need to be notified of voxel deletes VoxelNode::removeDeleteHook(&_removedVoxels); @@ -1071,16 +1134,14 @@ void VoxelSystem::render(bool texture) { return; } - // get the lock so that the update thread won't change anything - pthread_mutex_lock(&_bufferWriteLock); - updateVBOs(); - + + bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels); + // if not don't... then do... if (_useVoxelShader) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. _useVoxelShader openGL.."); - - Application::getInstance()->getVoxelShader().begin(); + //Define this somewhere in your header file #define BUFFER_OFFSET(i) ((void*)(i)) @@ -1088,14 +1149,29 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices - int loc = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); - glEnableVertexAttribArray(loc); - glVertexAttribPointer(loc, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); + + int attributeLocation; + + if (!_voxelsAsPoints) { + Application::getInstance()->getVoxelShader().begin(); + + attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); + glEnableVertexAttribArray(attributeLocation); + glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); + } else { + const float POINT_SIZE = 4.0; + glPointSize(POINT_SIZE); + } + + glEnableClientState(GL_COLOR_ARRAY); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID); - glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO + + if (!dontCallOpenGLDraw) { + glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO + } // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -1105,11 +1181,13 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - Application::getInstance()->getVoxelShader().end(); - + if (!_voxelsAsPoints) { + Application::getInstance()->getVoxelShader().end(); + glDisableVertexAttribArray(attributeLocation); + } } else { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL..."); - + // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); @@ -1121,47 +1199,48 @@ void VoxelSystem::render(bool texture) { glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); applyScaleAndBindProgram(texture); - + // for performance, enable backface culling glEnable(GL_CULL_FACE); // draw voxels in 6 passes - glNormal3f(0,1.0f,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + if (!dontCallOpenGLDraw) { + glNormal3f(0,1.0f,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(0,-1.0f,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(0,-1.0f,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(-1.0f,0,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(-1.0f,0,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(1.0f,0,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(1.0f,0,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - glNormal3f(0,0,-1.0f); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - - glNormal3f(0,0,1.0f); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, - INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(0,0,-1.0f); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + glNormal3f(0,0,1.0f); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + } glDisable(GL_CULL_FACE); removeScaleAndReleaseProgram(texture); - + // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); @@ -1170,8 +1249,6 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - - pthread_mutex_unlock(&_bufferWriteLock); } void VoxelSystem::applyScaleAndBindProgram(bool texture) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 4def28cfd2..456a9bc8c6 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -65,8 +65,6 @@ public: bool readFromSquareARGB32Pixels(const char* filename); bool readFromSchematicFile(const char* filename); - void setUseVoxelShader(bool useVoxelShader); - void setMaxVoxels(int maxVoxels); long int getMaxVoxels() const { return _maxVoxels; } unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; } @@ -137,6 +135,8 @@ public slots: void cancelImport(); void setUseFastVoxelPipeline(bool useFastVoxelPipeline); + void setUseVoxelShader(bool useVoxelShader); + void setVoxelsAsPoints(bool voxelsAsPoints); protected: float _treeScale; @@ -224,6 +224,9 @@ private: void cleanupVoxelMemory(); bool _useVoxelShader; + bool _voxelsAsPoints; + bool _voxelShaderModeWhenVoxelsAsPointsEnabled; + GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes VoxelShaderVBOData* _writeVoxelShaderData; From b0bc122a48617432e5a736f884ddc4fca60aa15f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Oct 2013 18:02:03 -0700 Subject: [PATCH 15/26] Got some actual damped oscillation going. --- interface/src/avatar/BlendFace.cpp | 11 +++++++++-- interface/src/avatar/BlendFace.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index b857a56b72..0857a2c24f 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -64,6 +64,7 @@ void BlendFace::simulate(float deltaTime) { MeshState state; if (mesh.springiness > 0.0f) { state.worldSpaceVertices.resize(mesh.vertices.size()); + state.vertexVelocities.resize(mesh.vertices.size()); state.worldSpaceNormals.resize(mesh.vertices.size()); } _meshStates.append(state); @@ -82,6 +83,7 @@ void BlendFace::simulate(float deltaTime) { continue; } glm::vec3* destVertices = state.worldSpaceVertices.data(); + glm::vec3* destVelocities = state.vertexVelocities.data(); glm::vec3* destNormals = state.worldSpaceNormals.data(); const FBXMesh& mesh = geometry.meshes.at(i); const glm::vec3* sourceVertices = mesh.vertices.constData(); @@ -108,16 +110,21 @@ void BlendFace::simulate(float deltaTime) { if (_resetStates) { for (int j = 0; j < vertexCount; j++) { destVertices[j] = glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)); + destVelocities[j] = glm::vec3(); } _resetStates = false; } else { + const float SPRINGINESS_MULTIPLIER = 20.0f; + const float DAMPING = 1.0f; for (int j = 0; j < vertexCount; j++) { - destVertices[j] = glm::mix(destVertices[j], glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)), 0.25f); + destVelocities[j] += ((glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * + mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; + destVertices[j] += destVelocities[j] * deltaTime; } } for (int j = 0; j < vertexCount; j++) { - destNormals[j] = glm::vec3(0.0f, 0.0f, 0.0f); + destNormals[j] = glm::vec3(); const glm::vec3& middle = destVertices[j]; for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index 6851d63261..bd8ad55541 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -55,6 +55,7 @@ private: class MeshState { public: QVector worldSpaceVertices; + QVector vertexVelocities; QVector worldSpaceNormals; }; From 54364a235dd2b8bb31e73da8d6d74160e3b479c0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 7 Oct 2013 19:43:45 -0700 Subject: [PATCH 16/26] tighten up mutex locks to keep at 60 fps --- interface/src/VoxelPacketProcessor.cpp | 4 ---- interface/src/VoxelSystem.cpp | 16 +++++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 8dc5092a64..e33f377edc 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -47,11 +47,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { - - voxelServer->lock(); // do we really need to lock this? just to get the ID? int nodeID = voxelServer->getNodeID(); - voxelServer->unlock(); - if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { app->_environment.parseData(&senderAddress, packetData, messageLength); } else { diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 634486d8dc..087662d92a 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -538,15 +538,15 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer); unsigned char* voxelData = sourceBuffer + numBytesPacketHeader; - pthread_mutex_lock(&_treeLock); - switch(command) { case PACKET_TYPE_VOXEL_DATA: { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID()); + pthread_mutex_lock(&_treeLock); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); + pthread_mutex_unlock(&_treeLock); } break; case PACKET_TYPE_VOXEL_DATA_MONOCHROME: { @@ -554,7 +554,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { "readBitstreamToTree()"); // ask the VoxelTree to read the MONOCHROME bitstream into the tree ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID()); + pthread_mutex_lock(&_treeLock); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); + pthread_mutex_unlock(&_treeLock); } break; case PACKET_TYPE_Z_COMMAND: @@ -572,7 +574,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { while (totalLength <= numBytes) { if (0==strcmp(command,(char*)"erase all")) { qDebug("got Z message == erase all\n"); + pthread_mutex_lock(&_treeLock); _tree->eraseAllVoxels(); + pthread_mutex_unlock(&_treeLock); _voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this?? } if (0==strcmp(command,(char*)"add scene")) { @@ -590,8 +594,6 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); } - pthread_mutex_unlock(&_treeLock); - Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes); return numBytes; @@ -1824,13 +1826,13 @@ VoxelNode* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { void VoxelSystem::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive) { - pthread_mutex_lock(&_treeLock); //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); + pthread_mutex_lock(&_treeLock); _tree->createVoxel(x, y, z, s, red, green, blue, destructive); - setupNewVoxelsForDrawing(); - pthread_mutex_unlock(&_treeLock); + + setupNewVoxelsForDrawing(); }; void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) { From aa80ec3497d58549df7a764846e78c319f3c2c73 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 7 Oct 2013 19:46:52 -0700 Subject: [PATCH 17/26] cleanup code for PR --- interface/src/VoxelSystem.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 087662d92a..24ca83b8a3 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -649,11 +649,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { } // lock on the buffer write lock so we can't modify the data when the GPU is reading it - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawing()... pthread_mutex_lock(&_bufferWriteLock)"); - pthread_mutex_lock(&_bufferWriteLock); - } + pthread_mutex_lock(&_bufferWriteLock); if (_voxelsUpdated) { _voxelsDirty=true; From 89a4ea6470a433d6ab7b2cf71888fca1cd0469ed Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 8 Oct 2013 09:56:47 -0700 Subject: [PATCH 18/26] two possible crash fixes --- interface/src/VoxelSystem.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 24ca83b8a3..c8791000c6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -908,6 +908,10 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // will forcibly remove it from the VBOs because we know better!!! int VoxelSystem::forceRemoveNodeFromArraysAsPartialVBO(VoxelNode* node) { + if (!_initialized) { + return 0; + } + // if the node is not in the VBOs then we have nothing to do! if (node->isKnownBufferIndex()) { @@ -937,6 +941,10 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } + + if (!_initialized) { + return 0; + } // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... if (node->isDirty()) { From b22334730db1e3f07a43e99e91da43c98bd1ea3d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 11:01:31 -0700 Subject: [PATCH 19/26] Fix for eyes rolling back in head. --- interface/src/avatar/BlendFace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 0857a2c24f..1d567d3e01 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -199,7 +199,7 @@ bool BlendFace::render(float alpha) { if (mesh.isEye) { 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()); + ((mesh.pivot + offset) * scale) + _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); From ce23b415e049d075557fe022fb83e9af9c58c705 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 11:11:01 -0700 Subject: [PATCH 20/26] Fix for macaw head without mapping file. --- interface/src/renderer/FBXReader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 2390aa4991..872020a952 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -384,7 +384,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QList mappings = blendshapeMappings.values(blendshapeName); if (mappings.isEmpty()) { blendshapeIndices.insert(blendshapeName, QPair(i, 1.0f)); - blendshapeIndices.insert("ExpressionBlendshapes." + blendshapeName, QPair(i, 1.0f)); + } else { foreach (const QVariant& mapping, mappings) { QVariantList blendshapeMapping = mapping.toList(); @@ -637,8 +637,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } else if (object.properties.at(2) == "BlendShapeChannel") { QByteArray name = object.properties.at(1).toByteArray(); + name = name.left(name.indexOf('\0')); + if (!blendshapeIndices.contains(name)) { + // try everything after the dot + name = name.mid(name.lastIndexOf('.') + 1); + } blendshapeChannelIndices.insert(object.properties.at(0).value(), - blendshapeIndices.value(name.left(name.indexOf('\0')))); + blendshapeIndices.value(name)); } } } From e3436eed91e451a8b045e9c874960d897687b91d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 11:18:12 -0700 Subject: [PATCH 21/26] Fixes for eyes rolling back in head, macaw head without mapping file. --- interface/src/avatar/BlendFace.cpp | 2 +- interface/src/renderer/FBXReader.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index d376c976eb..146e5062d5 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -104,7 +104,7 @@ bool BlendFace::render(float alpha) { if (mesh.isEye) { 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()); + ((mesh.pivot + offset) * scale) + _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); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index afacc86204..c8647459d7 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -383,7 +383,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QList mappings = blendshapeMappings.values(blendshapeName); if (mappings.isEmpty()) { blendshapeIndices.insert(blendshapeName, QPair(i, 1.0f)); - blendshapeIndices.insert("ExpressionBlendshapes." + blendshapeName, QPair(i, 1.0f)); } else { foreach (const QVariant& mapping, mappings) { QVariantList blendshapeMapping = mapping.toList(); @@ -636,8 +635,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } else if (object.properties.at(2) == "BlendShapeChannel") { QByteArray name = object.properties.at(1).toByteArray(); + name = name.left(name.indexOf('\0')); + if (!blendshapeIndices.contains(name)) { + // try everything after the dot + name = name.mid(name.lastIndexOf('.') + 1); + } blendshapeChannelIndices.insert(object.properties.at(0).value(), - blendshapeIndices.value(name.left(name.indexOf('\0')))); + blendshapeIndices.value(name)); } } } From 506f6670832f4582fde20525975b9e844931a9f0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 11:26:15 -0700 Subject: [PATCH 22/26] More springy, more damp. Removed unused variable. --- interface/src/avatar/BlendFace.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 1d567d3e01..c6b098235c 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -57,7 +57,6 @@ void BlendFace::simulate(float deltaTime) { // set up world vertices on first simulate after load const FBXGeometry& geometry = _geometry->getFBXGeometry(); - bool first = false; if (_meshStates.isEmpty()) { QVector vertices; foreach (const FBXMesh& mesh, geometry.meshes) { @@ -115,8 +114,8 @@ void BlendFace::simulate(float deltaTime) { _resetStates = false; } else { - const float SPRINGINESS_MULTIPLIER = 20.0f; - const float DAMPING = 1.0f; + const float SPRINGINESS_MULTIPLIER = 200.0f; + const float DAMPING = 5.0f; for (int j = 0; j < vertexCount; j++) { destVelocities[j] += ((glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; From 60306af3e9d2c6986c47d554dad79ac0cf04bed3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 13:35:02 -0700 Subject: [PATCH 23/26] Default springiness, allow springiness on non-blended meshes. --- interface/src/avatar/BlendFace.cpp | 14 +++++++++++--- interface/src/renderer/FBXReader.cpp | 3 ++- interface/src/renderer/GeometryCache.cpp | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index c6b098235c..f970a3eca8 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -71,9 +71,11 @@ void BlendFace::simulate(float deltaTime) { _resetStates = true; } - glm::mat4 baseTransform = glm::translate(_owningHead->getPosition()) * glm::mat4_cast(_owningHead->getOrientation()) * - glm::scale(glm::vec3(-1.0f, 1.0f, -1.0f) * _owningHead->getScale() * MODEL_SCALE) * - glm::translate(MODEL_TRANSLATION - _geometry->getFBXGeometry().neckPivot); + glm::quat orientation = _owningHead->getOrientation(); + glm::vec3 scale = glm::vec3(-1.0f, 1.0f, -1.0f) * _owningHead->getScale() * MODEL_SCALE; + glm::vec3 offset = MODEL_TRANSLATION - _geometry->getFBXGeometry().neckPivot; + glm::mat4 baseTransform = glm::translate(_owningHead->getPosition()) * glm::mat4_cast(orientation) * + glm::scale(scale) * glm::translate(offset); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; @@ -106,6 +108,12 @@ void BlendFace::simulate(float deltaTime) { sourceVertices = _blendedVertices.constData(); } + glm::mat4 transform = baseTransform; + if (mesh.isEye) { + transform = transform * glm::translate(mesh.pivot) * glm::mat4_cast(glm::inverse(orientation) * + _owningHead->getEyeRotation(orientation * ((mesh.pivot + offset) * scale) + _owningHead->getPosition())) * + glm::translate(-mesh.pivot); + } if (_resetStates) { for (int j = 0; j < vertexCount; j++) { destVertices[j] = glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index bc31dc3c7c..8091687488 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -686,12 +686,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) FBXGeometry geometry; QVariantHash springs = mapping.value("spring").toHash(); + QVariant defaultSpring = springs.value("default"); for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { FBXMesh& mesh = it.value(); // accumulate local transforms qint64 modelID = parentMap.value(it.key()); - mesh.springiness = springs.value(localTransforms.value(modelID).name).toFloat(); + mesh.springiness = springs.value(localTransforms.value(modelID).name, defaultSpring).toFloat(); glm::mat4 modelTransform = getGlobalTransform(parentMap, localTransforms, modelID); // look for textures, material properties diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index c63ec7eed4..aa717175a0 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -346,7 +346,7 @@ void NetworkGeometry::maybeReadModelWithMapping() { glGenBuffers(1, &networkMesh.vertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); - if (mesh.blendshapes.isEmpty()) { + if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) + mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData()); From 15f7b702690bf2d710993db6bef6eace240a7220 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 13:54:54 -0700 Subject: [PATCH 24/26] Let's actually use the transform we constructed. --- interface/src/avatar/BlendFace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index f970a3eca8..e4599ecaf4 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -116,7 +116,7 @@ void BlendFace::simulate(float deltaTime) { } if (_resetStates) { for (int j = 0; j < vertexCount; j++) { - destVertices[j] = glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)); + destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); destVelocities[j] = glm::vec3(); } _resetStates = false; @@ -125,7 +125,7 @@ void BlendFace::simulate(float deltaTime) { const float SPRINGINESS_MULTIPLIER = 200.0f; const float DAMPING = 5.0f; for (int j = 0; j < vertexCount; j++) { - destVelocities[j] += ((glm::vec3(baseTransform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * + destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; destVertices[j] += destVelocities[j] * deltaTime; } From 3cca3dc894e6864460234a2a6dae89662a9865af Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 14:06:04 -0700 Subject: [PATCH 25/26] Reset fix. --- interface/src/avatar/BlendFace.cpp | 5 ++--- interface/src/avatar/Head.cpp | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index e4599ecaf4..1dd643e0ab 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -118,9 +118,7 @@ void BlendFace::simulate(float deltaTime) { for (int j = 0; j < vertexCount; j++) { destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); destVelocities[j] = glm::vec3(); - } - _resetStates = false; - + } } else { const float SPRINGINESS_MULTIPLIER = 200.0f; const float DAMPING = 5.0f; @@ -141,6 +139,7 @@ void BlendFace::simulate(float deltaTime) { } } } + _resetStates = false; } bool BlendFace::render(float alpha) { diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index bd5847a44f..62c0f22348 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -117,6 +117,8 @@ void Head::reset() { if (USING_PHYSICAL_MOHAWK) { resetHairPhysics(); } + + _blendFace.reset(); } void Head::resetHairPhysics() { From 87bdd2fb1aa78964cdcbc3c298d4875979a74c52 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Oct 2013 15:09:56 -0700 Subject: [PATCH 26/26] When in mirror mode and using a blend face, try to position the camera so as to look directly into the face's eyes. --- interface/src/Application.cpp | 10 +++++++++- interface/src/avatar/BlendFace.cpp | 16 ++++++++++------ interface/src/avatar/BlendFace.h | 5 ++++- interface/src/avatar/Head.cpp | 13 ++++++------- interface/src/avatar/Head.h | 1 + 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 46a2b9afde..4299fcbf6a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -332,7 +332,15 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness (100.0f); - _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); + glm::vec3 targetPosition = _myAvatar.getUprightHeadPosition(); + if (_myAvatar.getHead().getBlendFace().isActive()) { + // make sure we're aligned to the blend face eyes + glm::vec3 leftEyePosition, rightEyePosition; + if (_myAvatar.getHead().getBlendFace().getEyePositions(leftEyePosition, rightEyePosition, true)) { + targetPosition = (leftEyePosition + rightEyePosition) * 0.5f; + } + } + _myCamera.setTargetPosition(targetPosition); _myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); } else if (OculusManager::isConnected()) { diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 1dd643e0ab..280dd6a5cc 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -310,12 +310,16 @@ bool BlendFace::render(float alpha) { return true; } -void BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { +bool BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition, bool upright) const { if (!isActive()) { - return; + return false; } - + glm::vec3 translation = _owningHead->getPosition(); glm::quat orientation = _owningHead->getOrientation(); + if (upright) { + translation = static_cast(_owningHead->_owningAvatar)->getUprightHeadPosition(); + orientation = static_cast(_owningHead->_owningAvatar)->getWorldAlignedOrientation(); + } glm::vec3 scale(-_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE, -_owningHead->getScale() * MODEL_SCALE); bool foundFirst = false; @@ -323,16 +327,16 @@ void BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEy const FBXGeometry& geometry = _geometry->getFBXGeometry(); foreach (const FBXMesh& mesh, geometry.meshes) { if (mesh.isEye) { - glm::vec3 position = orientation * ((mesh.pivot + MODEL_TRANSLATION - geometry.neckPivot) * scale) + - _owningHead->getPosition(); + glm::vec3 position = orientation * ((mesh.pivot + MODEL_TRANSLATION - geometry.neckPivot) * scale) + translation; if (foundFirst) { secondEyePosition = position; - return; + return true; } firstEyePosition = position; foundFirst = true; } } + return false; } void BlendFace::setModelURL(const QUrl& url) { diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index bd8ad55541..ea2d2eb597 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -40,7 +40,10 @@ public: Q_INVOKABLE void setModelURL(const QUrl& url); const QUrl& getModelURL() const { return _modelURL; } - void getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; + /// Retrieve the positions of up to two eye meshes. + /// \param upright if true, retrieve the locations of the eyes in the upright position + /// \return whether or not both eye meshes were found + bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition, bool upright = false) const; private: diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 62c0f22348..635edf29d4 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -304,15 +304,14 @@ void Head::render(float alpha, bool isMine) { renderEyeBrows(); } } + + if (_blendFace.isActive()) { + // the blend face may have custom eye meshes + _blendFace.getEyePositions(_leftEyePosition, _rightEyePosition); + } if (_renderLookatVectors) { - glm::vec3 firstEyePosition = _leftEyePosition; - glm::vec3 secondEyePosition = _rightEyePosition; - if (_blendFace.isActive()) { - // the blend face may have custom eye meshes - _blendFace.getEyePositions(firstEyePosition, secondEyePosition); - } - renderLookatVectors(firstEyePosition, secondEyePosition, _lookAtPosition); + renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 38574fa430..7c5491ae39 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -158,6 +158,7 @@ private: void resetHairPhysics(); void updateHairPhysics(float deltaTime); + friend class BlendFace; friend class PerlinFace; };