From d1f263ecc55f7dfa8bf497391914d4925a9bf544 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Oct 2014 14:05:35 -0700 Subject: [PATCH 1/2] group materials together when rendering models --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/renderer/Model.cpp | 217 ++++++++++++++++++------ interface/src/renderer/Model.h | 20 +++ interface/src/ui/Stats.cpp | 105 ++++++------ libraries/fbx/src/FBXReader.cpp | 5 +- libraries/fbx/src/FBXReader.h | 2 + libraries/octree/src/OctreeRenderer.cpp | 3 +- libraries/octree/src/OctreeRenderer.h | 3 + 9 files changed, 256 insertions(+), 101 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 35ee52f273..b54df88662 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -430,6 +430,7 @@ Menu::Menu() : QMenu* modelCullingMenu = modelDebugMenu->addMenu("Culling"); addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); + addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontReduceMaterialSwitches, 0, false); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3e2c095924..797f96fa2e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -374,6 +374,7 @@ namespace MenuOption { const QString ControlWithSpeech = "Control With Speech"; const QString DontCullOutOfViewMeshParts = "Don't Cull Out Of View Mesh Parts"; const QString DontCullTooSmallMeshParts = "Don't Cull Too Small Mesh Parts"; + const QString DontReduceMaterialSwitches = "Don't Attempt to Reduce Material Switches"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 40359c309d..1471f72b3a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1299,10 +1299,32 @@ void Model::segregateMeshGroups() { _meshesOpaqueSkinned.clear(); _meshesOpaqueTangentsSpecularSkinned.clear(); _meshesOpaqueSpecularSkinned.clear(); + + _unsortedMeshesTranslucentTangents.clear(); + _unsortedMeshesTranslucent.clear(); + _unsortedMeshesTranslucentTangentsSpecular.clear(); + _unsortedMeshesTranslucentSpecular.clear(); + + _unsortedMeshesTranslucentTangentsSkinned.clear(); + _unsortedMeshesTranslucentSkinned.clear(); + _unsortedMeshesTranslucentTangentsSpecularSkinned.clear(); + _unsortedMeshesTranslucentSpecularSkinned.clear(); + + _unsortedMeshesOpaqueTangents.clear(); + _unsortedMeshesOpaque.clear(); + _unsortedMeshesOpaqueTangentsSpecular.clear(); + _unsortedMeshesOpaqueSpecular.clear(); + + _unsortedMeshesOpaqueTangentsSkinned.clear(); + _unsortedMeshesOpaqueSkinned.clear(); + _unsortedMeshesOpaqueTangentsSpecularSkinned.clear(); + _unsortedMeshesOpaqueSpecularSkinned.clear(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); + + // Run through all of the meshes, and place them into their segregated, but unsorted buckets for (int i = 0; i < networkMeshes.size(); i++) { const NetworkMesh& networkMesh = networkMeshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i); @@ -1312,79 +1334,171 @@ void Model::segregateMeshGroups() { bool hasTangents = !mesh.tangents.isEmpty(); bool hasSpecular = mesh.hasSpecularTexture(); bool isSkinned = state.clusterMatrices.size() > 1; + QString materialID = mesh.parts.at(0).materialID; if (translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { - _meshesTranslucent.append(i); + _unsortedMeshesTranslucent.insertMulti(materialID, i); } else if (translucentMesh && hasTangents && !hasSpecular && !isSkinned) { - _meshesTranslucentTangents.append(i); + _unsortedMeshesTranslucentTangents.insertMulti(materialID, i); } else if (translucentMesh && hasTangents && hasSpecular && !isSkinned) { - _meshesTranslucentTangentsSpecular.append(i); + _unsortedMeshesTranslucentTangentsSpecular.insertMulti(materialID, i); } else if (translucentMesh && !hasTangents && hasSpecular && !isSkinned) { - _meshesTranslucentSpecular.append(i); + _unsortedMeshesTranslucentSpecular.insertMulti(materialID, i); } else if (translucentMesh && hasTangents && !hasSpecular && isSkinned) { - _meshesTranslucentTangentsSkinned.append(i); + _unsortedMeshesTranslucentTangentsSkinned.insertMulti(materialID, i); } else if (translucentMesh && !hasTangents && !hasSpecular && isSkinned) { - _meshesTranslucentSkinned.append(i); + _unsortedMeshesTranslucentSkinned.insertMulti(materialID, i); } else if (translucentMesh && hasTangents && hasSpecular && isSkinned) { - _meshesTranslucentTangentsSpecularSkinned.append(i); + _unsortedMeshesTranslucentTangentsSpecularSkinned.insertMulti(materialID, i); } else if (translucentMesh && !hasTangents && hasSpecular && isSkinned) { - _meshesTranslucentSpecularSkinned.append(i); + _unsortedMeshesTranslucentSpecularSkinned.insertMulti(materialID, i); } else if (!translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { - _meshesOpaque.append(i); + _unsortedMeshesOpaque.insertMulti(materialID, i); } else if (!translucentMesh && hasTangents && !hasSpecular && !isSkinned) { - _meshesOpaqueTangents.append(i); + _unsortedMeshesOpaqueTangents.insertMulti(materialID, i); } else if (!translucentMesh && hasTangents && hasSpecular && !isSkinned) { - _meshesOpaqueTangentsSpecular.append(i); + _unsortedMeshesOpaqueTangentsSpecular.insertMulti(materialID, i); } else if (!translucentMesh && !hasTangents && hasSpecular && !isSkinned) { - _meshesOpaqueSpecular.append(i); + _unsortedMeshesOpaqueSpecular.insertMulti(materialID, i); } else if (!translucentMesh && hasTangents && !hasSpecular && isSkinned) { - _meshesOpaqueTangentsSkinned.append(i); + _unsortedMeshesOpaqueTangentsSkinned.insertMulti(materialID, i); } else if (!translucentMesh && !hasTangents && !hasSpecular && isSkinned) { - _meshesOpaqueSkinned.append(i); + _unsortedMeshesOpaqueSkinned.insertMulti(materialID, i); } else if (!translucentMesh && hasTangents && hasSpecular && isSkinned) { - _meshesOpaqueTangentsSpecularSkinned.append(i); + _unsortedMeshesOpaqueTangentsSpecularSkinned.insertMulti(materialID, i); } else if (!translucentMesh && !hasTangents && hasSpecular && isSkinned) { - _meshesOpaqueSpecularSkinned.append(i); + _unsortedMeshesOpaqueSpecularSkinned.insertMulti(materialID, i); } else { qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???"; } } + + foreach(int i, _unsortedMeshesTranslucent) { + _meshesTranslucent.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentTangents) { + _meshesTranslucentTangents.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentTangentsSpecular) { + _meshesTranslucentTangentsSpecular.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentSpecular) { + _meshesTranslucentSpecular.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentSkinned) { + _meshesTranslucentSkinned.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentTangentsSkinned) { + _meshesTranslucentTangentsSkinned.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentTangentsSpecularSkinned) { + _meshesTranslucentTangentsSpecularSkinned.append(i); + } + + foreach(int i, _unsortedMeshesTranslucentSpecularSkinned) { + _meshesTranslucentSpecularSkinned.append(i); + } + + foreach(int i, _unsortedMeshesOpaque) { + _meshesOpaque.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueTangents) { + _meshesOpaqueTangents.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueTangentsSpecular) { + _meshesOpaqueTangentsSpecular.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueSpecular) { + _meshesOpaqueSpecular.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueSkinned) { + _meshesOpaqueSkinned.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueTangentsSkinned) { + _meshesOpaqueTangentsSkinned.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueTangentsSpecularSkinned) { + _meshesOpaqueTangentsSpecularSkinned.append(i); + } + + foreach(int i, _unsortedMeshesOpaqueSpecularSkinned) { + _meshesOpaqueSpecularSkinned.append(i); + } + + _unsortedMeshesTranslucentTangents.clear(); + _unsortedMeshesTranslucent.clear(); + _unsortedMeshesTranslucentTangentsSpecular.clear(); + _unsortedMeshesTranslucentSpecular.clear(); + + _unsortedMeshesTranslucentTangentsSkinned.clear(); + _unsortedMeshesTranslucentSkinned.clear(); + _unsortedMeshesTranslucentTangentsSpecularSkinned.clear(); + _unsortedMeshesTranslucentSpecularSkinned.clear(); + + _unsortedMeshesOpaqueTangents.clear(); + _unsortedMeshesOpaque.clear(); + _unsortedMeshesOpaqueTangentsSpecular.clear(); + _unsortedMeshesOpaqueSpecular.clear(); + + _unsortedMeshesOpaqueTangentsSkinned.clear(); + _unsortedMeshesOpaqueSkinned.clear(); + _unsortedMeshesOpaqueTangentsSpecularSkinned.clear(); + _unsortedMeshesOpaqueSpecularSkinned.clear(); + _meshGroupsKnown = true; } int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + + bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); + bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); + bool dontReduceMaterialSwitches = Menu::getInstance()->isOptionChecked(MenuOption::DontReduceMaterialSwitches); + + QString lastMaterialID; int meshPartsRendered = 0; updateVisibleJointStates(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); @@ -1507,9 +1621,6 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, // if we got here, then check to see if this mesh is in view if (args) { - bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); - bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); - bool shouldRender = true; args->_meshesConsidered++; @@ -1600,39 +1711,49 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, glBindTexture(GL_TEXTURE_2D, 0); } else { - glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity); - if (!(translucent && alphaThreshold == 0.0f)) { - glAlphaFunc(GL_EQUAL, diffuse.a = Application::getInstance()->getGlowEffect()->getIntensity()); - } - glm::vec4 specular = glm::vec4(part.specularColor, 1.0f); - 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, part.shininess); + if (dontReduceMaterialSwitches || lastMaterialID != part.materialID) { + //qDebug() << "Material Changed ---------------------------------------------"; + //qDebug() << "NEW part.materialID:" << part.materialID; + + glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity); + if (!(translucent && alphaThreshold == 0.0f)) { + glAlphaFunc(GL_EQUAL, diffuse.a = Application::getInstance()->getGlowEffect()->getIntensity()); + } + glm::vec4 specular = glm::vec4(part.specularColor, 1.0f); + 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, part.shininess); - Texture* diffuseMap = networkPart.diffuseTexture.data(); - if (mesh.isEye && diffuseMap) { - diffuseMap = (_dilatedTextures[i][j] = - static_cast(diffuseMap)->getDilatedTexture(_pupilDilation)).data(); - } - glBindTexture(GL_TEXTURE_2D, !diffuseMap ? - Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); + Texture* diffuseMap = networkPart.diffuseTexture.data(); + if (mesh.isEye && diffuseMap) { + diffuseMap = (_dilatedTextures[i][j] = + static_cast(diffuseMap)->getDilatedTexture(_pupilDilation)).data(); + } + glBindTexture(GL_TEXTURE_2D, !diffuseMap ? + Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); - if (!mesh.tangents.isEmpty()) { - glActiveTexture(GL_TEXTURE1); - Texture* normalMap = networkPart.normalTexture.data(); - glBindTexture(GL_TEXTURE_2D, !normalMap ? - Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); - glActiveTexture(GL_TEXTURE0); - } + if (!mesh.tangents.isEmpty()) { + glActiveTexture(GL_TEXTURE1); + Texture* normalMap = networkPart.normalTexture.data(); + glBindTexture(GL_TEXTURE_2D, !normalMap ? + Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); + glActiveTexture(GL_TEXTURE0); + } - if (specularTextureUnit) { - glActiveTexture(specularTextureUnit); - Texture* specularMap = networkPart.specularTexture.data(); - glBindTexture(GL_TEXTURE_2D, !specularMap ? - Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID()); - glActiveTexture(GL_TEXTURE0); + if (specularTextureUnit) { + glActiveTexture(specularTextureUnit); + Texture* specularMap = networkPart.specularTexture.data(); + glBindTexture(GL_TEXTURE_2D, !specularMap ? + Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID()); + glActiveTexture(GL_TEXTURE0); + } + if (args) { + args->_materialSwitches++; + } + } + lastMaterialID = part.materialID; } meshPartsRendered++; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index f03e3f5e38..86fa0c2b7a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -338,6 +338,26 @@ private: bool _meshGroupsKnown; + QMap _unsortedMeshesTranslucent; + QMap _unsortedMeshesTranslucentTangents; + QMap _unsortedMeshesTranslucentTangentsSpecular; + QMap _unsortedMeshesTranslucentSpecular; + + QMap _unsortedMeshesTranslucentSkinned; + QMap _unsortedMeshesTranslucentTangentsSkinned; + QMap _unsortedMeshesTranslucentTangentsSpecularSkinned; + QMap _unsortedMeshesTranslucentSpecularSkinned; + + QMap _unsortedMeshesOpaque; + QMap _unsortedMeshesOpaqueTangents; + QMap _unsortedMeshesOpaqueTangentsSpecular; + QMap _unsortedMeshesOpaqueSpecular; + + QMap _unsortedMeshesOpaqueSkinned; + QMap _unsortedMeshesOpaqueTangentsSkinned; + QMap _unsortedMeshesOpaqueTangentsSpecularSkinned; + QMap _unsortedMeshesOpaqueSpecularSkinned; + QVector _meshesTranslucent; QVector _meshesTranslucentTangents; QVector _meshesTranslucentTangentsSpecular; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 90e21e9caf..95263282b3 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -459,7 +459,7 @@ void Stats::display( VoxelSystem* voxels = Application::getInstance()->getVoxels(); - lines = _expanded ? 15 : 3; + lines = _expanded ? 14 : 3; if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { lines += 10; // spatial audio processing adds 1 spacing line and 8 extra lines of info } @@ -468,44 +468,54 @@ void Stats::display( lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; + // Model/Entity render details + EntityTreeRenderer* entities = Application::getInstance()->getEntities(); + voxelStats.str(""); + voxelStats << "Entity Items rendered: " << entities->getItemsRendered() + << " / Out of view:" << entities->getItemsOutOfView() + << " / Too small:" << entities->getItemsTooSmall(); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); + if (_expanded) { - // Model/Entity render details - EntityTreeRenderer* entities = Application::getInstance()->getEntities(); voxelStats.str(""); - voxelStats << "Entity Items rendered: " << entities->getItemsRendered() - << " Out of view:" << entities->getItemsOutOfView() - << " Too small:" << entities->getItemsTooSmall(); + voxelStats << " Meshes rendered: " << entities->getMeshesRendered() + << " / Out of view:" << entities->getMeshesOutOfView() + << " / Too small:" << entities->getMeshesTooSmall(); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); voxelStats.str(""); - voxelStats << "Meshes rendered: " << entities->getMeshesRendered() - << " Out of view:" << entities->getMeshesOutOfView() - << " Too small:" << entities->getMeshesTooSmall(); + voxelStats << " Triangles: " << entities->getTrianglesRendered() + << " / Quads:" << entities->getQuadsRendered() + << " / Material Switches:" << entities->getMaterialSwitches(); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); voxelStats.str(""); - voxelStats << "Triangles: " << entities->getTrianglesRendered() << " Quads:" << entities->getQuadsRendered(); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - - voxelStats.str(""); - voxelStats << "Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered() - << " Translucent:" << entities->getTranslucentMeshPartsRendered(); + voxelStats << " Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered() + << " / Translucent:" << entities->getTranslucentMeshPartsRendered(); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); + } + voxelStats.str(""); + voxelStats.precision(4); + voxelStats << "Voxels Drawn: " << voxels->getVoxelsWritten() / 1000.f << "K " << + "Abandoned: " << voxels->getAbandonedVoxels() / 1000.f << "K "; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); + if (_expanded) { // Local Voxel Memory Usage voxelStats.str(""); - voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB"; + voxelStats << " Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB"; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); voxelStats.str(""); voxelStats << - "Geometry RAM: " << voxels->getVoxelMemoryUsageRAM() / 1000000.f << "MB / " << + " Geometry RAM: " << voxels->getVoxelMemoryUsageRAM() / 1000000.f << "MB / " << "VBO: " << voxels->getVoxelMemoryUsageVBO() / 1000000.f << "MB"; if (voxels->hasVoxelMemoryUsageGPU()) { voxelStats << " / GPU: " << voxels->getVoxelMemoryUsageGPU() / 1000000.f << "MB"; @@ -516,18 +526,11 @@ void Stats::display( // Voxel Rendering voxelStats.str(""); voxelStats.precision(4); - voxelStats << "Voxel Rendering Slots Max: " << voxels->getMaxVoxels() / 1000.f << "K"; + voxelStats << " Voxel Rendering Slots Max: " << voxels->getMaxVoxels() / 1000.f << "K"; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } - voxelStats.str(""); - voxelStats.precision(4); - voxelStats << "Drawn: " << voxels->getVoxelsWritten() / 1000.f << "K " << - "Abandoned: " << voxels->getAbandonedVoxels() / 1000.f << "K "; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - // iterate all the current voxel stats, and list their sending modes, and total voxel counts std::stringstream sendingMode(""); sendingMode << "Octree Sending Mode: ["; @@ -598,44 +601,44 @@ void Stats::display( } QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); + unsigned long localTotal = VoxelTreeElement::getNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); - // Server Voxels - voxelStats.str(""); - voxelStats << "Server voxels: " << qPrintable(serversTotalString); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - - if (_expanded) { - QString serversInternalString = locale.toString((uint)totalInternal); - QString serversLeavesString = locale.toString((uint)totalLeaves); - + // Server Octree Elements + if (!_expanded) { voxelStats.str(""); - voxelStats << - "Internal: " << qPrintable(serversInternalString) << " " << - "Leaves: " << qPrintable(serversLeavesString) << ""; + voxelStats << "Octree Elements Server: " << qPrintable(serversTotalString) + << " Local:" << qPrintable(localTotalString); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } - unsigned long localTotal = VoxelTreeElement::getNodeCount(); - QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); - - // Local Voxels - voxelStats.str(""); - voxelStats << "Local voxels: " << qPrintable(localTotalString); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); - if (_expanded) { + voxelStats.str(""); + voxelStats << "Octree Elements -"; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); + + QString serversInternalString = locale.toString((uint)totalInternal); + QString serversLeavesString = locale.toString((uint)totalLeaves); + + voxelStats.str(""); + voxelStats << " Server: " << qPrintable(serversTotalString) << + " Internal: " << qPrintable(serversInternalString) << + " Leaves: " << qPrintable(serversLeavesString); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); + + // Local Voxels unsigned long localInternal = VoxelTreeElement::getInternalNodeCount(); unsigned long localLeaves = VoxelTreeElement::getLeafNodeCount(); QString localInternalString = locale.toString((uint)localInternal); QString localLeavesString = locale.toString((uint)localLeaves); voxelStats.str(""); - voxelStats << - "Internal: " << qPrintable(localInternalString) << " " << - "Leaves: " << qPrintable(localLeavesString) << ""; + voxelStats << " Local: " << qPrintable(serversTotalString) << + " Internal: " << qPrintable(localInternalString) << + " Leaves: " << qPrintable(localLeavesString) << ""; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 47120bda7a..43d23160f7 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -659,6 +659,7 @@ public: glm::vec3 emissive; float shininess; float opacity; + QString id; }; class Cluster { @@ -1319,7 +1320,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } } - materials.insert(getID(object.properties), material); + material.id = getID(object.properties); + materials.insert(material.id, material); } else if (object.name == "Deformer") { if (object.properties.last() == "Cluster") { @@ -1621,6 +1623,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) if (!specularTexture.filename.isNull()) { part.specularTexture = specularTexture; } + part.materialID = material.id; } } materialIndex++; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 423c810418..6a7a0904da 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -115,6 +115,8 @@ public: FBXTexture diffuseTexture; FBXTexture normalTexture; FBXTexture specularTexture; + + QString materialID; }; /// A single mesh (with optional blendshapes) extracted from an FBX document. diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 006255bfff..d6f3caef6c 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -163,7 +163,7 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { void OctreeRenderer::render(RenderMode renderMode) { RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); @@ -179,6 +179,7 @@ void OctreeRenderer::render(RenderMode renderMode) { _itemsOutOfView = args._itemsOutOfView; _itemsTooSmall = args._itemsTooSmall; + _materialSwitches = args._materialSwitches; _trianglesRendered = args._trianglesRendered; _quadsRendered = args._quadsRendered; diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 528235ed86..e37f20529f 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -74,6 +74,7 @@ public: int getMeshesOutOfView() const { return _meshesOutOfView; } int getMeshesTooSmall() const { return _meshesTooSmall; } + int getMaterialSwitches() const { return _materialSwitches; } int getTrianglesRendered() const { return _trianglesRendered; } int getQuadsRendered() const { return _quadsRendered; } @@ -95,6 +96,7 @@ protected: int _meshesOutOfView; int _meshesTooSmall; + int _materialSwitches; int _trianglesRendered; int _quadsRendered; @@ -120,6 +122,7 @@ public: int _meshesOutOfView; int _meshesTooSmall; + int _materialSwitches; int _trianglesRendered; int _quadsRendered; From 148b880bb1d7049e16cf0aafd7d9843fc707f63b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Oct 2014 14:32:07 -0700 Subject: [PATCH 2/2] handle case of meshes with multiple parts with different materials better, don't mix them in with single material meshes --- interface/src/renderer/Model.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1471f72b3a..1228a458b2 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1334,7 +1334,22 @@ void Model::segregateMeshGroups() { bool hasTangents = !mesh.tangents.isEmpty(); bool hasSpecular = mesh.hasSpecularTexture(); bool isSkinned = state.clusterMatrices.size() > 1; - QString materialID = mesh.parts.at(0).materialID; + QString materialID; + + // create a material name from all the parts. If there's one part, this will be a single material and its + // true name. If however the mesh has multiple parts the name will be all the part's materials mashed together + // which will result in those parts being sorted away from single material parts. + QString lastPartMaterialID; + foreach(FBXMeshPart part, mesh.parts) { + if (part.materialID != lastPartMaterialID) { + materialID += part.materialID; + } + lastPartMaterialID = part.materialID; + } + const bool wantDebug = false; + if (wantDebug) { + qDebug() << "materialID:" << materialID << "parts:" << mesh.parts.size(); + } if (translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { @@ -1712,8 +1727,12 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, } else { if (dontReduceMaterialSwitches || lastMaterialID != part.materialID) { - //qDebug() << "Material Changed ---------------------------------------------"; - //qDebug() << "NEW part.materialID:" << part.materialID; + const bool wantDebug = false; + if (wantDebug) { + qDebug() << "Material Changed ---------------------------------------------"; + qDebug() << "part INDEX:" << j; + qDebug() << "NEW part.materialID:" << part.materialID; + } glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity); if (!(translucent && alphaThreshold == 0.0f)) {