From dc9c774eb541439ea5064843abb39d8979987ab2 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 21 Sep 2015 13:09:43 -0700 Subject: [PATCH] merge model part quads and triangles together to reduce the number of draw calls --- interface/resources/qml/Stats.qml | 2 +- interface/src/ui/Stats.cpp | 1 - libraries/fbx/src/FBXReader.cpp | 53 ++++++++++++++++-------- libraries/fbx/src/FBXReader.h | 10 ++--- libraries/render-utils/src/Model.cpp | 61 ++-------------------------- libraries/render-utils/src/Model.h | 4 -- libraries/shared/src/RenderArgs.h | 1 - 7 files changed, 46 insertions(+), 86 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index c3829c7be2..eb39fbc70f 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -168,7 +168,7 @@ Item { color: root.fontColor; font.pixelSize: root.fontSize text: "Triangles: " + root.triangles + - " / Quads: " + root.quads + " / Material Switches: " + root.materialSwitches + " / Material Switches: " + root.materialSwitches } Text { color: root.fontColor; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 8ddb767537..4dd552210c 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -337,7 +337,6 @@ void Stats::updateStats() { void Stats::setRenderDetails(const RenderDetails& details) { STAT_UPDATE(triangles, details._trianglesRendered); - STAT_UPDATE(quads, details._quadsRendered); STAT_UPDATE(materialSwitches, details._materialSwitches); if (_expanded) { STAT_UPDATE(meshOpaque, details._opaque._rendered); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 6f69e8befc..2fbca10915 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -829,24 +829,30 @@ public: std::vector attributes; }; -gpu::BufferPointer FBXMeshPart::getTrianglesForQuads() const { +gpu::BufferPointer FBXMeshPart::getMergedTriangles() const { // if we've been asked for our triangulation of the original quads, but we don't yet have them // then create them now. - if (!trianglesForQuadsAvailable) { - trianglesForQuadsAvailable = true; + if (!mergedTrianglesAvailable) { + mergedTrianglesAvailable = true; - quadsAsTrianglesIndicesBuffer = std::make_shared(); + mergedTrianglesIndicesBuffer = std::make_shared(); // QVector quadIndices; // original indices from the FBX mesh - QVector quadsAsTrianglesIndices; // triangle versions of quads converted when first needed + QVector mergedTrianglesIndices; // triangle versions of quads converted when first needed + const int INDICES_PER_ORIGINAL_TRIANGLE = 3; const int INDICES_PER_ORIGINAL_QUAD = 4; const int INDICES_PER_TRIANGULATED_QUAD = 6; int numberOfQuads = quadIndices.size() / INDICES_PER_ORIGINAL_QUAD; - - quadsAsTrianglesIndices.resize(numberOfQuads * INDICES_PER_TRIANGULATED_QUAD); + int numberOfTriangles = triangleIndices.size() / INDICES_PER_ORIGINAL_TRIANGLE; + int mergedNumberOfIndices = (numberOfQuads * INDICES_PER_TRIANGULATED_QUAD) + triangleIndices.size(); + + // resized our merged indices to be enough room for our triangulated quads and our original triangles + mergedTrianglesIndices.resize(mergedNumberOfIndices); int originalIndex = 0; int triangulatedIndex = 0; + + // triangulate our quads for (int fromQuad = 0; fromQuad < numberOfQuads; fromQuad++) { int i0 = quadIndices[originalIndex + 0]; int i1 = quadIndices[originalIndex + 1]; @@ -860,23 +866,38 @@ gpu::BufferPointer FBXMeshPart::getTrianglesForQuads() const { // Triangle tri1 = { v0, v1, v2 }; // Triangle tri2 = { v2, v3, v0 }; - quadsAsTrianglesIndices[triangulatedIndex + 0] = i0; - quadsAsTrianglesIndices[triangulatedIndex + 1] = i1; - quadsAsTrianglesIndices[triangulatedIndex + 2] = i3; + mergedTrianglesIndices[triangulatedIndex + 0] = i0; + mergedTrianglesIndices[triangulatedIndex + 1] = i1; + mergedTrianglesIndices[triangulatedIndex + 2] = i3; - quadsAsTrianglesIndices[triangulatedIndex + 3] = i1; - quadsAsTrianglesIndices[triangulatedIndex + 4] = i2; - quadsAsTrianglesIndices[triangulatedIndex + 5] = i3; + mergedTrianglesIndices[triangulatedIndex + 3] = i1; + mergedTrianglesIndices[triangulatedIndex + 4] = i2; + mergedTrianglesIndices[triangulatedIndex + 5] = i3; originalIndex += INDICES_PER_ORIGINAL_QUAD; triangulatedIndex += INDICES_PER_TRIANGULATED_QUAD; } - trianglesForQuadsIndicesCount = INDICES_PER_TRIANGULATED_QUAD * numberOfQuads; - quadsAsTrianglesIndicesBuffer->append(quadsAsTrianglesIndices.size() * sizeof(quint32), (gpu::Byte*)quadsAsTrianglesIndices.data()); + // add our original triangs + originalIndex = 0; + for (int fromTriangle = 0; fromTriangle < numberOfTriangles; fromTriangle++) { + int i0 = triangleIndices[originalIndex + 0]; + int i1 = triangleIndices[originalIndex + 1]; + int i2 = triangleIndices[originalIndex + 2]; + + mergedTrianglesIndices[triangulatedIndex + 0] = i0; + mergedTrianglesIndices[triangulatedIndex + 1] = i1; + mergedTrianglesIndices[triangulatedIndex + 2] = i2; + + originalIndex += INDICES_PER_ORIGINAL_TRIANGLE; + triangulatedIndex += INDICES_PER_ORIGINAL_TRIANGLE; + } + + mergedTrianglesIndicesCount = mergedNumberOfIndices; + mergedTrianglesIndicesBuffer->append(mergedNumberOfIndices * sizeof(quint32), (gpu::Byte*)mergedTrianglesIndices.data()); } - return quadsAsTrianglesIndicesBuffer; + return mergedTrianglesIndicesBuffer; } void appendIndex(MeshData& data, QVector& indices, int index) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cff22676c8..f2fd9fdd15 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -117,10 +117,10 @@ public: /// A single part of a mesh (with the same material). class FBXMeshPart { public: - + QVector quadIndices; // original indices from the FBX mesh QVector triangleIndices; // original indices from the FBX mesh - mutable gpu::BufferPointer quadsAsTrianglesIndicesBuffer; + mutable gpu::BufferPointer mergedTrianglesIndicesBuffer; // both the quads and the triangles merged into a single set of triangles glm::vec3 diffuseColor; glm::vec3 specularColor; @@ -136,10 +136,10 @@ public: QString materialID; model::MaterialPointer _material; - mutable bool trianglesForQuadsAvailable = false; - mutable int trianglesForQuadsIndicesCount = 0; + mutable bool mergedTrianglesAvailable = false; + mutable int mergedTrianglesIndicesCount = 0; - gpu::BufferPointer getTrianglesForQuads() const; + gpu::BufferPointer getMergedTriangles() const; }; /// A single mesh (with optional blendshapes) extracted from an FBX document. diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a4dc1b1de3..a7910a7857 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -75,7 +75,6 @@ Model::Model(RigPointer rig, QObject* parent) : _isVisible(true), _blendNumber(0), _appliedBlendNumber(0), - _calculatedMeshPartOffsetValid(false), _calculatedMeshPartBoxesValid(false), _calculatedMeshBoxesValid(false), _calculatedMeshTrianglesValid(false), @@ -601,25 +600,6 @@ bool Model::convexHullContains(glm::vec3 point) { return false; } -void Model::recalculateMeshPartOffsets() { - if (!_calculatedMeshPartOffsetValid) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - int numberOfMeshes = geometry.meshes.size(); - _calculatedMeshPartOffset.clear(); - for (int i = 0; i < numberOfMeshes; i++) { - const FBXMesh& mesh = geometry.meshes.at(i); - qint64 partOffset = 0; - for (int j = 0; j < mesh.parts.size(); j++) { - const FBXMeshPart& part = mesh.parts.at(j); - _calculatedMeshPartOffset[QPair(i, j)] = partOffset; - partOffset += part.quadIndices.size() * sizeof(int); - partOffset += part.triangleIndices.size() * sizeof(int); - - } - } - _calculatedMeshPartOffsetValid = true; - } -} // TODO: we seem to call this too often when things haven't actually changed... look into optimizing this // Any script might trigger findRayIntersectionAgainstSubMeshes (and maybe convexHullContains), so these // can occur multiple times. In addition, rendering does it's own ray picking in order to decide which @@ -636,8 +616,6 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { _calculatedMeshTriangles.clear(); _calculatedMeshTriangles.resize(numberOfMeshes); _calculatedMeshPartBoxes.clear(); - _calculatedMeshPartOffset.clear(); - _calculatedMeshPartOffsetValid = false; for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents); @@ -646,7 +624,6 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { if (pickAgainstTriangles) { QVector thisMeshTriangles; - qint64 partOffset = 0; for (int j = 0; j < mesh.parts.size(); j++) { const FBXMeshPart& part = mesh.parts.at(j); @@ -732,15 +709,9 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { } } _calculatedMeshPartBoxes[QPair(i, j)] = thisPartBounds; - _calculatedMeshPartOffset[QPair(i, j)] = partOffset; - - partOffset += part.quadIndices.size() * sizeof(int); - partOffset += part.triangleIndices.size() * sizeof(int); - } _calculatedMeshTriangles[i] = thisMeshTriangles; _calculatedMeshPartBoxesValid = true; - _calculatedMeshPartOffsetValid = true; } } _calculatedMeshBoxesValid = true; @@ -1480,12 +1451,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran return; // bail asap } - // We need to make sure we have valid offsets calculated before we can render - if (!_calculatedMeshPartOffsetValid) { - _mutex.lock(); - recalculateMeshPartOffsets(); - _mutex.unlock(); - } auto textureCache = DependencyManager::get(); gpu::Batch& batch = *(args->_batch); @@ -1703,32 +1668,12 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } } - qint64 offset; - { - // FIXME_STUTTER: We should n't have any lock here - _mutex.lock(); - offset = _calculatedMeshPartOffset[QPair(meshIndex, partIndex)]; - _mutex.unlock(); - } - - if (part.quadIndices.size() > 0) { - batch.setIndexBuffer(gpu::UINT32, part.getTrianglesForQuads(), 0); - batch.drawIndexed(gpu::TRIANGLES, part.trianglesForQuadsIndicesCount, 0); - - offset += part.quadIndices.size() * sizeof(int); - batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); // restore this in case there are triangles too - } - - if (part.triangleIndices.size() > 0) { - batch.drawIndexed(gpu::TRIANGLES, part.triangleIndices.size(), offset); - offset += part.triangleIndices.size() * sizeof(int); - } + batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); + batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); if (args) { const int INDICES_PER_TRIANGLE = 3; - const int INDICES_PER_QUAD = 4; - args->_details._trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE; - args->_details._quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD; + args->_details._trianglesRendered += part.mergedTrianglesIndicesCount / INDICES_PER_TRIANGLE; } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 93b98da8b5..fd9a9e6353 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -352,9 +352,6 @@ private: }; QHash, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes - QHash, qint64> _calculatedMeshPartOffset; - bool _calculatedMeshPartOffsetValid; - bool _calculatedMeshPartBoxesValid; QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes @@ -365,7 +362,6 @@ private: QMutex _mutex; void recalculateMeshBoxes(bool pickAgainstTriangles = false); - void recalculateMeshPartOffsets(); void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 7a5daf7a17..25eed96490 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -43,7 +43,6 @@ public: int _materialSwitches = 0; int _trianglesRendered = 0; - int _quadsRendered = 0; Item _opaque; Item _translucent;