From 3a6715c0bcff26ae38ab1efe325713190184008e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 14:00:56 -0700 Subject: [PATCH 1/5] improve timing stats display --- interface/src/ui/Stats.cpp | 114 +++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ec5433c4c4..3002fbc435 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -221,8 +221,30 @@ void Stats::display( int totalServers = NodeList::getInstance()->size(); lines = _expanded ? 5 : 3; - drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10); + int columnOneWidth = _generalStatsWidth; + + if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + + PerformanceTimer::tallyAllTimerRecords(); + + columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // make it 3 columns wide... + // we will also include room for 1 line per timing record and a header of 4 lines + lines += 4; + + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator i(allRecords); + while (i.hasNext()) { + i.next(); + if (includeTimingRecord(i.key())) { + lines++; + } + } + } + + drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; + + int columnOneHorizontalOffset = horizontalOffset; char serverNodes[30]; sprintf(serverNodes, "Servers: %d", totalServers); @@ -249,6 +271,46 @@ void Stats::display( verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond, color); } + + // TODO: the display of these timing details should all be moved to JavaScript + if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + // Timing details... + const int TIMER_OUTPUT_LINE_LENGTH = 1000; + char perfLine[TIMER_OUTPUT_LINE_LENGTH]; + verticalOffset += STATS_PELS_PER_LINE * 4; // skip 4 lines to be under the other columns + drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, + "-------------------------------------------------------- Function " + "------------------------------------------------------- --msecs- -calls--", color); + + // First iterate all the records, and for the ones that should be included, insert them into + // a new Map sorted by average time... + QMap sortedRecords; + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator i(allRecords); + + while (i.hasNext()) { + i.next(); + if (includeTimingRecord(i.key())) { + float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; + sortedRecords.insertMulti(averageTime, i.key()); + } + } + + QMapIterator j(sortedRecords); + j.toBack(); + while (j.hasPrevious()) { + j.previous(); + QString functionName = j.value(); + const PerformanceTimerRecord& record = allRecords.value(functionName); + + sprintf(perfLine, "%120s: %8.4f [%6llu]", qPrintable(functionName), + (float)record.getMovingAverage() / (float)USECS_PER_MSEC, + record.getCount()); + + verticalOffset += STATS_PELS_PER_LINE; + drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine, color); + } + } verticalOffset = 0; horizontalOffset = _lastHorizontalOffset + _generalStatsWidth +1; @@ -283,7 +345,11 @@ void Stats::display( } lines = _expanded ? 4 : 3; - drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10); + + // only draw our background if column one didn't draw a wide background + if (columnOneWidth == _generalStatsWidth) { + drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10); + } horizontalOffset += 5; @@ -319,7 +385,9 @@ void Stats::display( lines = _expanded ? 8 : 3; - drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10); + if (columnOneWidth == _generalStatsWidth) { + drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10); + } horizontalOffset += 5; char avatarPosition[200]; @@ -396,20 +464,6 @@ void Stats::display( lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info } - if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { - // we will also include room for 1 line per timing record and a header - lines += 1; - - const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); - QMapIterator i(allRecords); - while (i.hasNext()) { - i.next(); - if (includeTimingRecord(i.key())) { - lines++; - } - } - } - drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -585,32 +639,6 @@ void Stats::display( drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } - PerformanceTimer::tallyAllTimerRecords(); - - // TODO: the display of these timing details should all be moved to JavaScript - if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { - // Timing details... - const int TIMER_OUTPUT_LINE_LENGTH = 300; - char perfLine[TIMER_OUTPUT_LINE_LENGTH]; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, - "--------------------- Function -------------------- --msecs- -calls--", color); - - const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); - QMapIterator i(allRecords); - while (i.hasNext()) { - i.next(); - if (includeTimingRecord(i.key())) { - sprintf(perfLine, "%50s: %8.4f [%6llu]", qPrintable(i.key()), - (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC, - i.value().getCount()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, perfLine, color); - } - } - } - if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { verticalOffset += STATS_PELS_PER_LINE; // space one line... From c8db8855ccf097d8dccb9caa7948e8efec971fa3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 14:23:29 -0700 Subject: [PATCH 2/5] move tallyAllTimerRecords out of conditional so they don't pile up --- interface/src/ui/Stats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 3002fbc435..524a306bc0 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -222,11 +222,11 @@ void Stats::display( lines = _expanded ? 5 : 3; int columnOneWidth = _generalStatsWidth; + + PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { - PerformanceTimer::tallyAllTimerRecords(); - columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // make it 3 columns wide... // we will also include room for 1 line per timing record and a header of 4 lines lines += 4; From 8a835119424e14a7f85a953c60248fbcf15b4fe0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 14:40:42 -0700 Subject: [PATCH 3/5] first cut at separating opaque from transparent meshes --- interface/src/renderer/Model.cpp | 76 +++++++++++++++++++++++++------- interface/src/renderer/Model.h | 9 +++- interface/src/ui/Stats.cpp | 8 +++- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3a6d88e307..9587d34dc1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -46,7 +46,8 @@ Model::Model(QObject* parent) : _url("http://invalid.com"), _blendNumber(0), _appliedBlendNumber(0), - _calculatedMeshBoxesValid(false) { + _calculatedMeshBoxesValid(false), + _translucentMeshesKnown(false) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -271,6 +272,8 @@ void Model::reset() { for (int i = 0; i < _jointStates.size(); i++) { _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f); } + + _translucentMeshesKnown = false; } bool Model::updateGeometry() { @@ -421,6 +424,10 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _dilatedTextures.append(dilated); } } + + if (!_translucentMeshesKnown) { + calculateTranslucentMeshes(); + } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -451,11 +458,11 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { mode == DEFAULT_RENDER_MODE); const float DEFAULT_ALPHA_THRESHOLD = 0.5f; - renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, args); + int opaqueMeshPartsRendered = renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, args); // render translucent meshes afterwards Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); - renderMeshes(mode, true, 0.75f, args); + int translucentMeshPartsRendered = renderMeshes(mode, true, 0.75f, args); glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND); @@ -465,7 +472,7 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { - renderMeshes(mode, true, 0.0f, args); + translucentMeshPartsRendered += renderMeshes(mode, true, 0.0f, args); } glDepthMask(true); @@ -488,6 +495,11 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { // restore all the default material settings Application::getInstance()->setupWorldLight(); + + if (args) { + args->_translucentMeshPartsRendered = translucentMeshPartsRendered; + args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; + } return true; } @@ -1238,21 +1250,45 @@ void Model::deleteGeometry() { _blendedBlendshapeCoefficients.clear(); } -void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) { +void Model::calculateTranslucentMeshes() { + _translucentMeshes.clear(); + _opaqueMeshes.clear(); + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const QVector& networkMeshes = _geometry->getMeshes(); + + for (int i = 0; i < networkMeshes.size(); i++) { + const NetworkMesh& networkMesh = networkMeshes.at(i); + const FBXMesh& mesh = geometry.meshes.at(i); + + bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); + if (translucentMesh) { + _translucentMeshes.append(i); + } else { + _opaqueMeshes.append(i); + } + } + _translucentMeshesKnown = true; +} + +int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) { + int meshPartsRendered = 0; updateVisibleJointStates(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts); - for (int i = 0; i < networkMeshes.size(); i++) { + // if we're called in translucent mode, then use our translucent list vs opaque list + QList& list = translucent ? _translucentMeshes : _opaqueMeshes; + + + // i is the "index" from the original networkMeshes QVector... + foreach (int i, list) { + // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i); - if (translucent ? (networkMesh.getTranslucentPartCount(mesh) == 0) : - (networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size())) { - continue; - } + const_cast(networkMesh.indexBuffer).bind(); int vertexCount = mesh.vertices.size(); @@ -1424,11 +1460,19 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold glActiveTexture(GL_TEXTURE0); } } - glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); - offset += part.quadIndices.size() * sizeof(int); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(), - GL_UNSIGNED_INT, (void*)offset); - offset += part.triangleIndices.size() * sizeof(int); + + meshPartsRendered++; + + if (part.quadIndices.size() > 0) { + glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); + offset += part.quadIndices.size() * sizeof(int); + } + + if (part.triangleIndices.size() > 0) { + glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(), + GL_UNSIGNED_INT, (void*)offset); + offset += part.triangleIndices.size() * sizeof(int); + } if (args) { const int INDICES_PER_TRIANGLE = 3; @@ -1467,6 +1511,8 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold activeProgram->release(); } + + return meshPartsRendered; } void AnimationHandle::setURL(const QUrl& url) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 2e11d2b75e..d0e59305ad 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -251,7 +251,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - void renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f, RenderArgs* args = NULL); + int renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f, RenderArgs* args = NULL); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); @@ -332,6 +332,13 @@ private: QVector _calculatedMeshBoxes; bool _calculatedMeshBoxesValid; + + void calculateTranslucentMeshes(); // used to calculate our list of translucent vs opaque meshes + + bool _translucentMeshesKnown; + QList _translucentMeshes; // indices of the meshes that are translucent + QList _opaqueMeshes; // indices of the meshes that are opaque + }; Q_DECLARE_METATYPE(QPointer) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 524a306bc0..e78297323a 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -461,7 +461,7 @@ void Stats::display( lines = _expanded ? 14 : 3; if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { - lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info + lines += 10; // spatial audio processing adds 1 spacing line and 8 extra lines of info } drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, @@ -486,6 +486,12 @@ void Stats::display( 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(); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); + // Local Voxel Memory Usage voxelStats.str(""); From 952a604d771b492a1ab453312a71f63c538d0049 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 16:49:09 -0700 Subject: [PATCH 4/5] added some more rendering stats --- libraries/octree/src/OctreeRenderer.cpp | 3 +++ libraries/octree/src/OctreeRenderer.h | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 9ea31077a5..21c085c5df 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -179,6 +179,9 @@ void OctreeRenderer::render(RenderMode renderMode) { _trianglesRendered = args._trianglesRendered; _quadsRendered = args._quadsRendered; + _translucentMeshPartsRendered = args._translucentMeshPartsRendered; + _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; + } void OctreeRenderer::clear() { diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index fbb02344af..6d734d113e 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -74,7 +74,10 @@ public: int getTrianglesRendered() const { return _trianglesRendered; } int getQuadsRendered() const { return _quadsRendered; } - + + int getTranslucentMeshPartsRendered() const { return _translucentMeshPartsRendered; } + int getOpaqueMeshPartsRendered() const { return _opaqueMeshPartsRendered; } + protected: Octree* _tree; bool _managedTree; @@ -90,6 +93,9 @@ protected: int _trianglesRendered; int _quadsRendered; + + int _translucentMeshPartsRendered; + int _opaqueMeshPartsRendered; }; class RenderArgs { @@ -110,6 +116,9 @@ public: int _trianglesRendered; int _quadsRendered; + + int _translucentMeshPartsRendered; + int _opaqueMeshPartsRendered; }; From 56b4d58f181d54a8f430df5fc63070082de5e0ec Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 17:08:47 -0700 Subject: [PATCH 5/5] implement mesh groups and pull out shader programs in renderMeshes() to outside the loop based on group --- interface/src/renderer/Model.cpp | 289 ++++++++++++++++++++++++------- interface/src/renderer/Model.h | 28 ++- 2 files changed, 245 insertions(+), 72 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9587d34dc1..72a6ab7afe 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -47,7 +47,7 @@ Model::Model(QObject* parent) : _blendNumber(0), _appliedBlendNumber(0), _calculatedMeshBoxesValid(false), - _translucentMeshesKnown(false) { + _meshesGroupsKnown(false) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -273,7 +273,7 @@ void Model::reset() { _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f); } - _translucentMeshesKnown = false; + _meshesGroupsKnown = false; } bool Model::updateGeometry() { @@ -323,6 +323,7 @@ bool Model::updateGeometry() { deleteGeometry(); _dilatedTextures.clear(); _geometry = geometry; + _meshesGroupsKnown = false; setJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { @@ -425,8 +426,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { } } - if (!_translucentMeshesKnown) { - calculateTranslucentMeshes(); + if (!_meshesGroupsKnown) { + segregateMeshGroups(); } glEnableClientState(GL_VERTEX_ARRAY); @@ -458,11 +459,30 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { mode == DEFAULT_RENDER_MODE); const float DEFAULT_ALPHA_THRESHOLD = 0.5f; - int opaqueMeshPartsRendered = renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, args); + + //renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args); + int opaqueMeshPartsRendered = 0; + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); + opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); // render translucent meshes afterwards Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); - int translucentMeshPartsRendered = renderMeshes(mode, true, 0.75f, args); + int translucentMeshPartsRendered = 0; + const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND); @@ -472,7 +492,15 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { - translucentMeshPartsRendered += renderMeshes(mode, true, 0.0f, args); + const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); } glDepthMask(true); @@ -1219,6 +1247,7 @@ void Model::applyNextGeometry() { // we retain a reference to the base geometry so that its reference count doesn't fall to zero _baseGeometry = _nextBaseGeometry; _geometry = _nextGeometry; + _meshesGroupsKnown = false; _nextBaseGeometry.reset(); _nextGeometry.reset(); } @@ -1250,37 +1279,210 @@ void Model::deleteGeometry() { _blendedBlendshapeCoefficients.clear(); } -void Model::calculateTranslucentMeshes() { - _translucentMeshes.clear(); - _opaqueMeshes.clear(); +void Model::segregateMeshGroups() { + _meshesTranslucentTangents.clear(); + _meshesTranslucent.clear(); + _meshesTranslucentTangentsSpecular.clear(); + _meshesTranslucentSpecular.clear(); + + _meshesTranslucentTangentsSkinned.clear(); + _meshesTranslucentSkinned.clear(); + _meshesTranslucentTangentsSpecularSkinned.clear(); + _meshesTranslucentSpecularSkinned.clear(); + + _meshesOpaqueTangents.clear(); + _meshesOpaque.clear(); + _meshesOpaqueTangentsSpecular.clear(); + _meshesOpaqueSpecular.clear(); + + _meshesOpaqueTangentsSkinned.clear(); + _meshesOpaqueSkinned.clear(); + _meshesOpaqueTangentsSpecularSkinned.clear(); + _meshesOpaqueSpecularSkinned.clear(); + const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); for (int i = 0; i < networkMeshes.size(); i++) { const NetworkMesh& networkMesh = networkMeshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i); + const MeshState& state = _meshStates.at(i); bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); - if (translucentMesh) { - _translucentMeshes.append(i); + bool hasTangents = !mesh.tangents.isEmpty(); + bool hasSpecular = mesh.hasSpecularTexture(); + bool isSkinned = state.clusterMatrices.size() > 1; + + if (translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { + + _meshesTranslucent.append(i); + + } else if (translucentMesh && hasTangents && !hasSpecular && !isSkinned) { + + _meshesTranslucentTangents.append(i); + + } else if (translucentMesh && hasTangents && hasSpecular && !isSkinned) { + + _meshesTranslucentTangentsSpecular.append(i); + + } else if (translucentMesh && !hasTangents && hasSpecular && !isSkinned) { + + _meshesTranslucentSpecular.append(i); + + } else if (translucentMesh && hasTangents && !hasSpecular && isSkinned) { + + _meshesTranslucentTangentsSkinned.append(i); + + } else if (translucentMesh && !hasTangents && !hasSpecular && isSkinned) { + + _meshesTranslucentSkinned.append(i); + + } else if (translucentMesh && hasTangents && hasSpecular && isSkinned) { + + _meshesTranslucentTangentsSpecularSkinned.append(i); + + } else if (translucentMesh && !hasTangents && hasSpecular && isSkinned) { + + _meshesTranslucentSpecularSkinned.append(i); + + } else if (!translucentMesh && !hasTangents && !hasSpecular && !isSkinned) { + + _meshesOpaque.append(i); + + } else if (!translucentMesh && hasTangents && !hasSpecular && !isSkinned) { + + _meshesOpaqueTangents.append(i); + + } else if (!translucentMesh && hasTangents && hasSpecular && !isSkinned) { + + _meshesOpaqueTangentsSpecular.append(i); + + } else if (!translucentMesh && !hasTangents && hasSpecular && !isSkinned) { + + _meshesOpaqueSpecular.append(i); + + } else if (!translucentMesh && hasTangents && !hasSpecular && isSkinned) { + + _meshesOpaqueTangentsSkinned.append(i); + + } else if (!translucentMesh && !hasTangents && !hasSpecular && isSkinned) { + + _meshesOpaqueSkinned.append(i); + + } else if (!translucentMesh && hasTangents && hasSpecular && isSkinned) { + + _meshesOpaqueTangentsSpecularSkinned.append(i); + + } else if (!translucentMesh && !hasTangents && hasSpecular && isSkinned) { + + _meshesOpaqueSpecularSkinned.append(i); } else { - _opaqueMeshes.append(i); + qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???"; } } - _translucentMeshesKnown = true; + _meshesGroupsKnown = true; } -int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) { +int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { int meshPartsRendered = 0; updateVisibleJointStates(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts); + + // depending on which parameters we were called with, pick the correct mesh group to render + QList* whichList = NULL; + if (translucent && !hasTangents && !hasSpecular && !isSkinned) { + whichList = &_meshesTranslucent; + } else if (translucent && hasTangents && !hasSpecular && !isSkinned) { + whichList = &_meshesTranslucentTangents; + } else if (translucent && hasTangents && hasSpecular && !isSkinned) { + whichList = &_meshesTranslucentTangentsSpecular; + } else if (translucent && !hasTangents && hasSpecular && !isSkinned) { + whichList = &_meshesTranslucentSpecular; + } else if (translucent && hasTangents && !hasSpecular && isSkinned) { + whichList = &_meshesTranslucentTangentsSkinned; + } else if (translucent && !hasTangents && !hasSpecular && isSkinned) { + whichList = &_meshesTranslucentSkinned; + } else if (translucent && hasTangents && hasSpecular && isSkinned) { + whichList = &_meshesTranslucentTangentsSpecularSkinned; + } else if (translucent && !hasTangents && hasSpecular && isSkinned) { + whichList = &_meshesTranslucentSpecularSkinned; + } else if (!translucent && !hasTangents && !hasSpecular && !isSkinned) { + whichList = &_meshesOpaque; + } else if (!translucent && hasTangents && !hasSpecular && !isSkinned) { + whichList = &_meshesOpaqueTangents; + } else if (!translucent && hasTangents && hasSpecular && !isSkinned) { + whichList = &_meshesOpaqueTangentsSpecular; + } else if (!translucent && !hasTangents && hasSpecular && !isSkinned) { + whichList = &_meshesOpaqueSpecular; + } else if (!translucent && hasTangents && !hasSpecular && isSkinned) { + whichList = &_meshesOpaqueTangentsSkinned; + } else if (!translucent && !hasTangents && !hasSpecular && isSkinned) { + whichList = &_meshesOpaqueSkinned; + } else if (!translucent && hasTangents && hasSpecular && isSkinned) { + whichList = &_meshesOpaqueTangentsSpecularSkinned; + } else if (!translucent && !hasTangents && hasSpecular && isSkinned) { + whichList = &_meshesOpaqueSpecularSkinned; + } else { + qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???"; + } - // if we're called in translucent mode, then use our translucent list vs opaque list - QList& list = translucent ? _translucentMeshes : _opaqueMeshes; + if (!whichList) { + qDebug() << "unexpected!!! we don't know which list of meshes to render..."; + return 0; + } + QList& list = *whichList; + + ProgramObject* program = &_program; + Locations* locations = &_locations; + ProgramObject* skinProgram = &_skinProgram; + SkinLocations* skinLocations = &_skinLocations; + GLenum specularTextureUnit = 0; + if (mode == SHADOW_RENDER_MODE) { + program = &_shadowProgram; + skinProgram = &_skinShadowProgram; + skinLocations = &_skinShadowLocations; + } else if (translucent && alphaThreshold == 0.0f) { + program = &_translucentProgram; + locations = &_translucentLocations; + skinProgram = &_skinTranslucentProgram; + skinLocations = &_skinTranslucentLocations; + + } else if (hasTangents) { + if (hasSpecular) { + program = &_normalSpecularMapProgram; + locations = &_normalSpecularMapLocations; + skinProgram = &_skinNormalSpecularMapProgram; + skinLocations = &_skinNormalSpecularMapLocations; + specularTextureUnit = GL_TEXTURE2; + } else { + program = &_normalMapProgram; + locations = &_normalMapLocations; + skinProgram = &_skinNormalMapProgram; + skinLocations = &_skinNormalMapLocations; + } + } else if (hasSpecular) { + program = &_specularMapProgram; + locations = &_specularMapLocations; + skinProgram = &_skinSpecularMapProgram; + skinLocations = &_skinSpecularMapLocations; + specularTextureUnit = GL_TEXTURE1; + } + ProgramObject* activeProgram = program; + Locations* activeLocations = locations; + + if (isSkinned) { + skinProgram->bind(); + activeProgram = skinProgram; + activeLocations = skinLocations; + } else { + program->bind(); + } + activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold); // i is the "index" from the original networkMeshes QVector... foreach (int i, list) { @@ -1316,52 +1518,11 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, const_cast(networkMesh.vertexBuffer).bind(); - ProgramObject* program = &_program; - Locations* locations = &_locations; - ProgramObject* skinProgram = &_skinProgram; - SkinLocations* skinLocations = &_skinLocations; - GLenum specularTextureUnit = 0; - if (mode == SHADOW_RENDER_MODE) { - program = &_shadowProgram; - skinProgram = &_skinShadowProgram; - skinLocations = &_skinShadowLocations; - - } else if (translucent && alphaThreshold == 0.0f) { - program = &_translucentProgram; - locations = &_translucentLocations; - skinProgram = &_skinTranslucentProgram; - skinLocations = &_skinTranslucentLocations; - - } else if (!mesh.tangents.isEmpty()) { - if (mesh.hasSpecularTexture()) { - program = &_normalSpecularMapProgram; - locations = &_normalSpecularMapLocations; - skinProgram = &_skinNormalSpecularMapProgram; - skinLocations = &_skinNormalSpecularMapLocations; - specularTextureUnit = GL_TEXTURE2; - - } else { - program = &_normalMapProgram; - locations = &_normalMapLocations; - skinProgram = &_skinNormalMapProgram; - skinLocations = &_skinNormalMapLocations; - } - } else if (mesh.hasSpecularTexture()) { - program = &_specularMapProgram; - locations = &_specularMapLocations; - skinProgram = &_skinSpecularMapProgram; - skinLocations = &_skinSpecularMapLocations; - specularTextureUnit = GL_TEXTURE1; - } - - const MeshState& state = _meshStates.at(i); - ProgramObject* activeProgram = program; - Locations* activeLocations = locations; glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); - + + const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { - skinProgram->bind(); glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) + @@ -1372,16 +1533,10 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, offset + vertexCount * sizeof(glm::vec4), 4); skinProgram->enableAttributeArray(skinLocations->clusterIndices); skinProgram->enableAttributeArray(skinLocations->clusterWeights); - activeProgram = skinProgram; - activeLocations = skinLocations; - } else { glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); - program->bind(); } - activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold); - if (mesh.blendshapes.isEmpty()) { if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); @@ -1509,8 +1664,8 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, } glPopMatrix(); - activeProgram->release(); } + activeProgram->release(); return meshPartsRendered; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index d0e59305ad..55a2eed9d1 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -251,7 +251,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - int renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f, RenderArgs* args = NULL); + int renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); @@ -333,11 +333,29 @@ private: QVector _calculatedMeshBoxes; bool _calculatedMeshBoxesValid; - void calculateTranslucentMeshes(); // used to calculate our list of translucent vs opaque meshes + void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes - bool _translucentMeshesKnown; - QList _translucentMeshes; // indices of the meshes that are translucent - QList _opaqueMeshes; // indices of the meshes that are opaque + bool _meshesGroupsKnown; + + QList _meshesTranslucent; + QList _meshesTranslucentTangents; + QList _meshesTranslucentTangentsSpecular; + QList _meshesTranslucentSpecular; + + QList _meshesTranslucentSkinned; + QList _meshesTranslucentTangentsSkinned; + QList _meshesTranslucentTangentsSpecularSkinned; + QList _meshesTranslucentSpecularSkinned; + + QList _meshesOpaque; + QList _meshesOpaqueTangents; + QList _meshesOpaqueTangentsSpecular; + QList _meshesOpaqueSpecular; + + QList _meshesOpaqueSkinned; + QList _meshesOpaqueTangentsSkinned; + QList _meshesOpaqueTangentsSpecularSkinned; + QList _meshesOpaqueSpecularSkinned; };