From 518f5fe17c3fa6fa46eecf29bec522ea7647a6f4 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Sep 2015 18:21:36 -0700 Subject: [PATCH 01/19] Starting to clean the mesh part of the RenderItem.... --- libraries/fbx/src/FBXReader.h | 2 +- libraries/fbx/src/FBXReader_Mesh.cpp | 28 ++++++------- .../src/model-networking/ModelCache.cpp | 1 + .../src/model-networking/ModelCache.h | 5 +-- libraries/render-utils/src/Model.cpp | 41 ++++++++++++++++--- .../render-utils/src/RenderDeferredTask.cpp | 8 +++- 6 files changed, 58 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 3027eb52cc..01c3785086 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -181,7 +181,7 @@ public: unsigned int meshIndex; // the order the meshes appeared in the object file # if USE_MODEL_MESH - model::Mesh _mesh; + model::MeshPointer _mesh; # endif }; diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index c0cf57df58..f3bf3f433d 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -370,19 +370,19 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*"); if (extracted.mesh.vertices.size() == 0) { - extracted.mesh._mesh = model::Mesh(); + extracted.mesh._mesh; qCDebug(modelformat) << "buildModelMesh failed -- no vertices, url = " << url; return; } FBXMesh& fbxMesh = extracted.mesh; - model::Mesh mesh; + model::MeshPointer mesh(new model::Mesh()); // Grab the vertices in a buffer auto vb = std::make_shared(); vb->setData(extracted.mesh.vertices.size() * sizeof(glm::vec3), (const gpu::Byte*) extracted.mesh.vertices.data()); gpu::BufferView vbv(vb, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - mesh.setVertexBuffer(vbv); + mesh->setVertexBuffer(vbv); // evaluate all attribute channels sizes int normalsSize = fbxMesh.normals.size() * sizeof(glm::vec3); @@ -414,37 +414,37 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (gpu::Byte*) fbxMesh.clusterWeights.constData()); if (normalsSize) { - mesh.addAttribute(gpu::Stream::NORMAL, + mesh->addAttribute(gpu::Stream::NORMAL, model::BufferView(attribBuffer, normalsOffset, normalsSize, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); } if (tangentsSize) { - mesh.addAttribute(gpu::Stream::TANGENT, + mesh->addAttribute(gpu::Stream::TANGENT, model::BufferView(attribBuffer, tangentsOffset, tangentsSize, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); } if (colorsSize) { - mesh.addAttribute(gpu::Stream::COLOR, + mesh->addAttribute(gpu::Stream::COLOR, model::BufferView(attribBuffer, colorsOffset, colorsSize, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB))); } if (texCoordsSize) { - mesh.addAttribute(gpu::Stream::TEXCOORD, + mesh->addAttribute(gpu::Stream::TEXCOORD, model::BufferView( attribBuffer, texCoordsOffset, texCoordsSize, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); } if (texCoords1Size) { - mesh.addAttribute(gpu::Stream::TEXCOORD1, + mesh->addAttribute(gpu::Stream::TEXCOORD1, model::BufferView(attribBuffer, texCoords1Offset, texCoords1Size, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); } if (clusterIndicesSize) { - mesh.addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, + mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); } if (clusterWeightsSize) { - mesh.addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, + mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); } @@ -457,7 +457,6 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { } if (! totalIndices) { - extracted.mesh._mesh = model::Mesh(); qCDebug(modelformat) << "buildModelMesh failed -- no indices, url = " << url; return; } @@ -489,21 +488,20 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { } gpu::BufferView ibv(ib, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::XYZ)); - mesh.setIndexBuffer(ibv); + mesh->setIndexBuffer(ibv); if (parts.size()) { auto pb = std::make_shared(); pb->setData(parts.size() * sizeof(model::Mesh::Part), (const gpu::Byte*) parts.data()); gpu::BufferView pbv(pb, gpu::Element(gpu::VEC4, gpu::UINT32, gpu::XYZW)); - mesh.setPartBuffer(pbv); + mesh->setPartBuffer(pbv); } else { - extracted.mesh._mesh = model::Mesh(); qCDebug(modelformat) << "buildModelMesh failed -- no parts, url = " << url; return; } // model::Box box = - mesh.evalPartBound(0); + mesh->evalPartBound(0); extracted.mesh._mesh = mesh; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index a66fda624d..71d225a43a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -269,6 +269,7 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas auto textureCache = DependencyManager::get(); NetworkMesh* networkMesh = new NetworkMesh(); + networkMesh->_mesh = mesh._mesh; int totalIndices = 0; bool checkForTexcoordLightmap = false; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 1110d36e3e..4067bed122 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -191,15 +191,14 @@ public: /// The state associated with a single mesh. class NetworkMesh { public: + model::MeshPointer _mesh; + gpu::BufferPointer _indexBuffer; gpu::BufferPointer _vertexBuffer; gpu::BufferStreamPointer _vertexStream; gpu::Stream::FormatPointer _vertexFormat; - - int getTranslucentPartCount(const FBXMesh& fbxMesh) const; - bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const; }; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7cf965951b..a374f9acb8 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -754,6 +754,16 @@ public: int meshIndex; int partIndex; int _shapeID; + + render::Item::Bound getBound() const { + if (_isBoundInvalid) { + model->getPartBounds(meshIndex, partIndex); + _isBoundInvalid = false; + } + return _bound; + } + mutable render::Item::Bound _bound; + mutable bool _isBoundInvalid = true; }; namespace render { @@ -780,7 +790,7 @@ namespace render { template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { if (payload) { - return payload->model->getPartBounds(payload->meshIndex, payload->partIndex); + return payload->getBound(); // model->getPartBounds(payload->meshIndex, payload->partIndex); } return render::Item::Bound(); } @@ -1486,6 +1496,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape const FBXMesh& mesh = geometry.meshes.at(meshIndex); const MeshState& state = _meshStates.at(meshIndex); + auto drawMesh = networkMesh._mesh; + + auto drawMaterialKey = material->getKey(); bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); @@ -1541,7 +1554,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape return; // FIXME! } - batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); + // Assign index buffer: + batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); + // batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); int vertexCount = mesh.vertices.size(); if (vertexCount == 0) { // sanity check @@ -1574,10 +1589,21 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape batch.setModelTransform(_transforms[0]); if (mesh.blendshapes.isEmpty()) { - batch.setInputFormat(networkMesh._vertexFormat); - batch.setInputStream(0, *networkMesh._vertexStream); + batch.setInputFormat((drawMesh->getVertexFormat())); + auto inputStream = drawMesh->makeBufferStream(); + + batch.setInputStream(0, inputStream); + + // batch.setInputFormat(networkMesh._vertexFormat); + // batch.setInputStream(0, *networkMesh._vertexStream); } else { + /* batch.setInputFormat((drawMesh->getVertexFormat())); + auto inputStream = drawMesh->makeBufferStream(); + + batch.setInputStream(0, inputStream); + */ batch.setInputFormat(networkMesh._vertexFormat); + batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); batch.setInputStream(2, *networkMesh._vertexStream); @@ -1702,9 +1728,12 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape } } - batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); - batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); + auto& drawPart = drawMesh->getPartBuffer().get(); + batch.drawIndexed(model::Mesh::topologyToPrimitive(drawPart._topology), drawPart._numIndices, drawPart._startIndex); +/* batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); + batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); + */ if (args) { const int INDICES_PER_TRIANGLE = 3; args->_details._trianglesRendered += part.mergedTrianglesIndicesCount / INDICES_PER_TRIANGLE; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 137294c5b6..0094a3c3a1 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -189,8 +189,12 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems); - args->_context->render((*args->_batch)); - args->_batch = nullptr; + { + PerformanceTimer perfTimer("DrawOpaqueDeferred::run::renderBatch"); + + args->_context->render((*args->_batch)); + args->_batch = nullptr; + } } void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { From b8ea83099afa841ce0140ba898167545fe496c1d Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 1 Oct 2015 21:13:22 -0700 Subject: [PATCH 02/19] Debuggging --- libraries/fbx/src/FBXReader_Mesh.cpp | 1 + libraries/render-utils/src/Model.cpp | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index f3bf3f433d..21b51245cb 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -480,6 +480,7 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { } model::Mesh::Part triPart(indexNum, part.triangleIndices.size(), 0, model::Mesh::TRIANGLES); if (triPart._numIndices) { + parts.push_back(triPart); ib->setSubData(offset, part.triangleIndices.size() * sizeof(int), (gpu::Byte*) part.triangleIndices.constData()); offset += part.triangleIndices.size() * sizeof(int); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3a4d83f68d..c7649d27ed 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1527,7 +1527,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape } // Assign index buffer: - batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); + // batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); // batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); int vertexCount = mesh.vertices.size(); if (vertexCount == 0) { @@ -1561,6 +1561,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape batch.setModelTransform(_transforms[0]); if (mesh.blendshapes.isEmpty()) { + // Assign index buffer: + batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); + // batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); + batch.setInputFormat((drawMesh->getVertexFormat())); auto inputStream = drawMesh->makeBufferStream(); @@ -1569,16 +1573,18 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape // batch.setInputFormat(networkMesh._vertexFormat); // batch.setInputStream(0, *networkMesh._vertexStream); } else { - /* batch.setInputFormat((drawMesh->getVertexFormat())); + return; + batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); + batch.setInputFormat((drawMesh->getVertexFormat())); auto inputStream = drawMesh->makeBufferStream(); batch.setInputStream(0, inputStream); - */ - batch.setInputFormat(networkMesh._vertexFormat); + + /* batch.setInputFormat(networkMesh._vertexFormat); batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); - batch.setInputStream(2, *networkMesh._vertexStream); + batch.setInputStream(2, *networkMesh._vertexStream);*/ } if (mesh.colors.isEmpty()) { From edb485cb0f2ccac6c5f6533bc398611639b48a50 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 2 Oct 2015 12:24:41 -0700 Subject: [PATCH 03/19] working on getting the Model payload to use model::Mesh --- libraries/fbx/src/FBXReader_Mesh.cpp | 25 +++++++++++++++---------- libraries/gpu/src/gpu/Stream.cpp | 13 +++++++++++++ libraries/gpu/src/gpu/Stream.h | 4 +++- libraries/render-utils/src/Model.cpp | 15 +++++++++------ 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 21b51245cb..299968d663 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -415,29 +415,34 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { if (normalsSize) { mesh->addAttribute(gpu::Stream::NORMAL, - model::BufferView(attribBuffer, normalsOffset, normalsSize, - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); + model::BufferView(attribBuffer, normalsOffset, normalsSize, + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); } if (tangentsSize) { mesh->addAttribute(gpu::Stream::TANGENT, - model::BufferView(attribBuffer, tangentsOffset, tangentsSize, - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); + model::BufferView(attribBuffer, tangentsOffset, tangentsSize, + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); } if (colorsSize) { mesh->addAttribute(gpu::Stream::COLOR, - model::BufferView(attribBuffer, colorsOffset, colorsSize, - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB))); + model::BufferView(attribBuffer, colorsOffset, colorsSize, + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB))); } if (texCoordsSize) { mesh->addAttribute(gpu::Stream::TEXCOORD, - model::BufferView( attribBuffer, texCoordsOffset, texCoordsSize, - gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); + model::BufferView( attribBuffer, texCoordsOffset, texCoordsSize, + gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); } if (texCoords1Size) { + mesh->addAttribute( gpu::Stream::TEXCOORD1, + model::BufferView(attribBuffer, texCoords1Offset, texCoords1Size, + gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); + } else if (texCoordsSize) { mesh->addAttribute(gpu::Stream::TEXCOORD1, - model::BufferView(attribBuffer, texCoords1Offset, texCoords1Size, - gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); + model::BufferView(attribBuffer, texCoordsOffset, texCoordsSize, + gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); } + if (clusterIndicesSize) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, diff --git a/libraries/gpu/src/gpu/Stream.cpp b/libraries/gpu/src/gpu/Stream.cpp index 61150ab90e..183f2137fb 100644 --- a/libraries/gpu/src/gpu/Stream.cpp +++ b/libraries/gpu/src/gpu/Stream.cpp @@ -92,3 +92,16 @@ void BufferStream::addBuffer(const BufferPointer& buffer, Offset offset, Offset _offsets.push_back(offset); _strides.push_back(stride); } + +BufferStream BufferStream::makeRangedStream(uint32 offset, uint32 count) const { + if ((offset < _buffers.size())) { + auto rangeSize = std::min(count, (uint32)(_buffers.size() - offset)); + BufferStream newStream; + newStream._buffers.insert(newStream._buffers.begin(), _buffers.begin() + offset, _buffers.begin() + offset + rangeSize); + newStream._offsets.insert(newStream._offsets.begin(), _offsets.begin() + offset, _offsets.begin() + offset + rangeSize); + newStream._strides.insert(newStream._strides.begin(), _strides.begin() + offset, _strides.begin() + offset + rangeSize); + return newStream; + } + + return BufferStream(); +} diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 420aa50f72..53509c1033 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -139,7 +139,9 @@ public: const Buffers& getBuffers() const { return _buffers; } const Offsets& getOffsets() const { return _offsets; } const Strides& getStrides() const { return _strides; } - uint8 getNumBuffers() const { return _buffers.size(); } + uint32 getNumBuffers() const { return _buffers.size(); } + + BufferStream makeRangedStream(uint32 offset, uint32 count = -1) const; protected: Buffers _buffers; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c7649d27ed..872592a9a4 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1573,14 +1573,17 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape // batch.setInputFormat(networkMesh._vertexFormat); // batch.setInputStream(0, *networkMesh._vertexStream); } else { - return; - batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); - batch.setInputFormat((drawMesh->getVertexFormat())); - auto inputStream = drawMesh->makeBufferStream(); + batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); + batch.setInputFormat((drawMesh->getVertexFormat())); - batch.setInputStream(0, inputStream); + batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); + + auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2); - /* batch.setInputFormat(networkMesh._vertexFormat); + batch.setInputStream(2, inputStream); + + /* batch.setInputFormat(networkMesh._vertexFormat); batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); From edaa8f998a340384ca3319d21f0d29520e41f87a Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 2 Oct 2015 18:12:16 -0700 Subject: [PATCH 04/19] Migrating to the new mesh for rendering and having problems with multi part mesh --- libraries/fbx/src/FBXReader.h | 1 + libraries/fbx/src/FBXReader_Mesh.cpp | 72 ++++++++--- libraries/gpu/src/gpu/GLBackendInput.cpp | 2 +- .../src/model-networking/ModelCache.cpp | 119 ------------------ .../src/model-networking/ModelCache.h | 4 +- libraries/render-utils/src/Model.cpp | 52 ++++---- 6 files changed, 87 insertions(+), 163 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index ab0bfeacf1..3bb0545e78 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -123,6 +123,7 @@ class FBXMeshPart { public: QVector quadIndices; // original indices from the FBX mesh + QVector quadTrianglesIndices; // original indices from the FBX mesh of the quad converted has triangles QVector triangleIndices; // original indices from the FBX mesh mutable gpu::BufferPointer mergedTrianglesIndicesBuffer; // both the quads and the triangles merged into a single set of triangles diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 299968d663..2754fc5d67 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -348,6 +348,28 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn appendIndex(data, part.quadIndices, beginIndex++); appendIndex(data, part.quadIndices, beginIndex++); appendIndex(data, part.quadIndices, beginIndex++); + + int quadStartIndex = part.quadIndices.size() - 4; + int i0 = part.quadIndices[quadStartIndex + 0]; + int i1 = part.quadIndices[quadStartIndex + 1]; + int i2 = part.quadIndices[quadStartIndex + 2]; + int i3 = part.quadIndices[quadStartIndex + 3]; + + // Sam's recommended triangle slices + // Triangle tri1 = { v0, v1, v3 }; + // Triangle tri2 = { v1, v2, v3 }; + // NOTE: Random guy on the internet's recommended triangle slices + // Triangle tri1 = { v0, v1, v2 }; + // Triangle tri2 = { v2, v3, v0 }; + + part.quadTrianglesIndices.append(i0); + part.quadTrianglesIndices.append(i1); + part.quadTrianglesIndices.append(i3); + + part.quadTrianglesIndices.append(i1); + part.quadTrianglesIndices.append(i2); + part.quadTrianglesIndices.append(i3); + } else { for (int nextIndex = beginIndex + 1;; ) { appendIndex(data, part.triangleIndices, beginIndex); @@ -369,11 +391,22 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*"); + unsigned int totalSourceIndices = 0; + foreach(const FBXMeshPart& part, extracted.mesh.parts) { + totalSourceIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size()); + } + + if (!totalSourceIndices) { + qCDebug(modelformat) << "buildModelMesh failed -- no indices, url = " << url; + return; + } + if (extracted.mesh.vertices.size() == 0) { extracted.mesh._mesh; qCDebug(modelformat) << "buildModelMesh failed -- no vertices, url = " << url; return; } + FBXMesh& fbxMesh = extracted.mesh; model::MeshPointer mesh(new model::Mesh()); @@ -456,9 +489,8 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { unsigned int totalIndices = 0; - foreach(const FBXMeshPart& part, extracted.mesh.parts) { - totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); + totalIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size()); } if (! totalIndices) { @@ -473,24 +505,34 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { int offset = 0; std::vector< model::Mesh::Part > parts; - + if (extracted.mesh.parts.size() > 1) { + indexNum = 0; + } foreach(const FBXMeshPart& part, extracted.mesh.parts) { - model::Mesh::Part quadPart(indexNum, part.quadIndices.size(), 0, model::Mesh::QUADS); - if (quadPart._numIndices) { - parts.push_back(quadPart); - ib->setSubData(offset, part.quadIndices.size() * sizeof(int), - (gpu::Byte*) part.quadIndices.constData()); - offset += part.quadIndices.size() * sizeof(int); - indexNum += part.quadIndices.size(); + model::Mesh::Part modelPart(indexNum, 0, 0, model::Mesh::TRIANGLES); + if (part.quadTrianglesIndices.size()) { + + + ib->setSubData( offset, + part.quadTrianglesIndices.size() * sizeof(int), + (gpu::Byte*) part.quadTrianglesIndices.constData()); + offset += part.quadTrianglesIndices.size() * sizeof(int); + indexNum += part.quadTrianglesIndices.size(); + modelPart._numIndices += part.quadTrianglesIndices.size(); } - model::Mesh::Part triPart(indexNum, part.triangleIndices.size(), 0, model::Mesh::TRIANGLES); - if (triPart._numIndices) { - parts.push_back(triPart); - ib->setSubData(offset, part.triangleIndices.size() * sizeof(int), - (gpu::Byte*) part.triangleIndices.constData()); + // model::Mesh::Part triPart(indexNum, part.triangleIndices.size(), 0, model::Mesh::TRIANGLES); + + if (part.triangleIndices.size()) { + // parts.push_back(triPart); + ib->setSubData( offset, + part.triangleIndices.size() * sizeof(int), + (gpu::Byte*) part.triangleIndices.constData()); offset += part.triangleIndices.size() * sizeof(int); indexNum += part.triangleIndices.size(); + modelPart._numIndices += part.triangleIndices.size(); } + + parts.push_back(modelPart); } gpu::BufferView ibv(ib, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::XYZ)); diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp index a70e91d7fa..5cdcf0adc6 100755 --- a/libraries/gpu/src/gpu/GLBackendInput.cpp +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -315,7 +315,7 @@ void GLBackend::do_setIndirectBuffer(Batch& batch, uint32 paramOffset) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferID(*buffer)); } else { // FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null? - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index d8b53420a4..c7d3523496 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -266,126 +266,9 @@ void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) { } static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) { - auto textureCache = DependencyManager::get(); NetworkMesh* networkMesh = new NetworkMesh(); networkMesh->_mesh = mesh._mesh; - int totalIndices = 0; - //bool checkForTexcoordLightmap = false; - - - - // process network parts - foreach (const FBXMeshPart& part, mesh.parts) { - totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); - } - - // initialize index buffer - { - networkMesh->_indexBuffer = std::make_shared(); - networkMesh->_indexBuffer->resize(totalIndices * sizeof(int)); - int offset = 0; - foreach(const FBXMeshPart& part, mesh.parts) { - networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int), - (gpu::Byte*) part.quadIndices.constData()); - offset += part.quadIndices.size() * sizeof(int); - networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int), - (gpu::Byte*) part.triangleIndices.constData()); - offset += part.triangleIndices.size() * sizeof(int); - } - } - - // initialize vertex buffer - { - networkMesh->_vertexBuffer = std::make_shared(); - // if we don't need to do any blending, the positions/normals can be static - if (mesh.blendshapes.isEmpty()) { - int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); - int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); - int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); - int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2); - int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); - - networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); - - networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData()); - networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData()); - networkMesh->_vertexBuffer->setSubData(tangentsOffset, - mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData()); - networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData()); - networkMesh->_vertexBuffer->setSubData(texCoordsOffset, - mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData()); - networkMesh->_vertexBuffer->setSubData(texCoords1Offset, - mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData()); - networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset, - mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData()); - networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset, - mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData()); - - // otherwise, at least the cluster indices/weights can be static - networkMesh->_vertexStream = std::make_shared(); - networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3)); - if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3)); - if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3)); - if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3)); - if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2)); - if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2)); - if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4)); - if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4)); - - int channelNum = 0; - networkMesh->_vertexFormat = std::make_shared(); - networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); - if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - if (mesh.texCoords1.size()) { - networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - // } else if (checkForTexcoordLightmap && mesh.texCoords.size()) { - } else if (mesh.texCoords.size()) { - // need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel - networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - } - if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); - if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); - } - else { - int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); - int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); - - networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); - networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData()); - networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData()); - networkMesh->_vertexBuffer->setSubData(texCoordsOffset, - mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData()); - networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset, - mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData()); - networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset, - mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData()); - - networkMesh->_vertexStream = std::make_shared(); - if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3)); - if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3)); - if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2)); - if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4)); - if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4)); - - int channelNum = 0; - networkMesh->_vertexFormat = std::make_shared(); - networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); - if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); - if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); - } - } return networkMesh; } @@ -394,8 +277,6 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const auto textureCache = DependencyManager::get(); NetworkMaterial* networkMaterial = new NetworkMaterial(); - //bool checkForTexcoordLightmap = false; - networkMaterial->_material = material._material; if (!material.diffuseTexture.filename.isEmpty()) { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 4067bed122..b53ea18874 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -193,12 +193,12 @@ class NetworkMesh { public: model::MeshPointer _mesh; - gpu::BufferPointer _indexBuffer; +/* gpu::BufferPointer _indexBuffer; gpu::BufferPointer _vertexBuffer; gpu::BufferStreamPointer _vertexStream; gpu::Stream::FormatPointer _vertexFormat; -}; +*/}; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 872592a9a4..44484131d9 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -759,17 +759,27 @@ public: int partIndex; int _shapeID; - render::Item::Bound getBound() const { - if (_isBoundInvalid) { - model->getPartBounds(meshIndex, partIndex); - _isBoundInvalid = false; - } - return _bound; - } + // Render Item interface + render::Item::Bound getBound() const; + void render(RenderArgs* args) const; + + mutable render::Item::Bound _bound; mutable bool _isBoundInvalid = true; }; + +render::Item::Bound MeshPartPayload::getBound() const { + if (_isBoundInvalid) { + model->getPartBounds(meshIndex, partIndex); + _isBoundInvalid = false; + } + return _bound; +} +void MeshPartPayload::render(RenderArgs* args) const { + return model->renderPart(args, meshIndex, partIndex, _shapeID); +} + namespace render { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { if (!payload->model->isVisible()) { @@ -794,14 +804,12 @@ namespace render { template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { if (payload) { - return payload->getBound(); // model->getPartBounds(payload->meshIndex, payload->partIndex); + return payload->getBound(); } return render::Item::Bound(); } template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { - if (args) { - return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, payload->_shapeID); - } + return payload->render(args); } /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) { @@ -1560,20 +1568,17 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape } batch.setModelTransform(_transforms[0]); + auto drawPart = drawMesh->getPartBuffer().get(partIndex); + if (mesh.blendshapes.isEmpty()) { - // Assign index buffer: batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); - // batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); - + batch.setInputFormat((drawMesh->getVertexFormat())); auto inputStream = drawMesh->makeBufferStream(); batch.setInputStream(0, inputStream); - - // batch.setInputFormat(networkMesh._vertexFormat); - // batch.setInputStream(0, *networkMesh._vertexStream); } else { - batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); + batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); batch.setInputFormat((drawMesh->getVertexFormat())); batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); @@ -1582,12 +1587,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2); batch.setInputStream(2, inputStream); - - /* batch.setInputFormat(networkMesh._vertexFormat); - - batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); - batch.setInputStream(2, *networkMesh._vertexStream);*/ } if (mesh.colors.isEmpty()) { @@ -1712,8 +1711,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape { PerformanceTimer perfTimer("batch.drawIndexed()"); - batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); - batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); + // part.getMergedTriangles(); + // part.mergedTrianglesIndicesCount; + batch.drawIndexed(gpu::TRIANGLES, drawPart._numIndices, drawPart._startIndex); } /* batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); From 48416262a1fcaaeeb4ea70a357423cba6b6c71b6 Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 4 Oct 2015 18:31:19 -0700 Subject: [PATCH 05/19] Migrated the FBXReader mesh code to use excusively the Model::mesh and use them directly for rendering in the ModelPartPayload, fixed a bug in the indexBUffer offset value used in drawIndexed and drawIndexedInstanced --- libraries/fbx/src/FBXReader.cpp | 72 ---------------------------- libraries/fbx/src/FBXReader.h | 22 ++++----- libraries/fbx/src/FBXReader_Mesh.cpp | 22 +++------ libraries/gpu/src/gpu/GLBackend.cpp | 14 ++++-- libraries/gpu/src/gpu/GLBackend.h | 2 +- libraries/render-utils/src/Model.cpp | 9 +--- 6 files changed, 28 insertions(+), 113 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index d6ec59499d..9dd5030244 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -264,78 +264,6 @@ void appendModelIDs(const QString& parentID, const QMultiHash& } } - -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 (!mergedTrianglesAvailable) { - mergedTrianglesAvailable = true; - - mergedTrianglesIndicesBuffer = std::make_shared(); - - // QVector quadIndices; // original indices from the FBX mesh - 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; - 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]; - int i2 = quadIndices[originalIndex + 2]; - int i3 = quadIndices[originalIndex + 3]; - - // Sam's recommended triangle slices - // Triangle tri1 = { v0, v1, v3 }; - // Triangle tri2 = { v1, v2, v3 }; - // NOTE: Random guy on the internet's recommended triangle slices - // Triangle tri1 = { v0, v1, v2 }; - // Triangle tri2 = { v2, v3, v0 }; - - mergedTrianglesIndices[triangulatedIndex + 0] = i0; - mergedTrianglesIndices[triangulatedIndex + 1] = i1; - mergedTrianglesIndices[triangulatedIndex + 2] = i3; - - mergedTrianglesIndices[triangulatedIndex + 3] = i1; - mergedTrianglesIndices[triangulatedIndex + 4] = i2; - mergedTrianglesIndices[triangulatedIndex + 5] = i3; - - originalIndex += INDICES_PER_ORIGINAL_QUAD; - triangulatedIndex += INDICES_PER_TRIANGULATED_QUAD; - } - - // 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 mergedTrianglesIndicesBuffer; -} - FBXBlendshape extractBlendshape(const FBXNode& object) { FBXBlendshape blendshape; foreach (const FBXNode& data, object.children) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 3bb0545e78..d317205909 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -123,28 +123,22 @@ class FBXMeshPart { public: QVector quadIndices; // original indices from the FBX mesh - QVector quadTrianglesIndices; // original indices from the FBX mesh of the quad converted has triangles + QVector quadTrianglesIndices; // original indices from the FBX mesh of the quad converted as triangles QVector triangleIndices; // original indices from the FBX mesh - mutable gpu::BufferPointer mergedTrianglesIndicesBuffer; // both the quads and the triangles merged into a single set of triangles QString materialID; - - mutable bool mergedTrianglesAvailable = false; - mutable int mergedTrianglesIndicesCount = 0; - - gpu::BufferPointer getMergedTriangles() const; }; class FBXMaterial { public: FBXMaterial() {}; - FBXMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor, - const glm::vec2& emissiveParams, float shininess, float opacity) : - diffuseColor(diffuseColor), - specularColor(specularColor), - emissiveColor(emissiveColor), - emissiveParams(emissiveParams), - shininess(shininess), + FBXMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor, + const glm::vec2& emissiveParams, float shininess, float opacity) : + diffuseColor(diffuseColor), + specularColor(specularColor), + emissiveColor(emissiveColor), + emissiveParams(emissiveParams), + shininess(shininess), opacity(opacity) {} glm::vec3 diffuseColor{ 1.0f }; diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 2754fc5d67..411f477a84 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -362,12 +362,12 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn // Triangle tri1 = { v0, v1, v2 }; // Triangle tri2 = { v2, v3, v0 }; - part.quadTrianglesIndices.append(i0); - part.quadTrianglesIndices.append(i1); - part.quadTrianglesIndices.append(i3); - - part.quadTrianglesIndices.append(i1); - part.quadTrianglesIndices.append(i2); + part.quadTrianglesIndices.append(i0); + part.quadTrianglesIndices.append(i1); + part.quadTrianglesIndices.append(i2); + + part.quadTrianglesIndices.append(i1); + part.quadTrianglesIndices.append(i2); part.quadTrianglesIndices.append(i3); } else { @@ -386,8 +386,6 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn return data.extracted; } - -#if USE_MODEL_MESH void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*"); @@ -402,7 +400,6 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { } if (extracted.mesh.vertices.size() == 0) { - extracted.mesh._mesh; qCDebug(modelformat) << "buildModelMesh failed -- no vertices, url = " << url; return; } @@ -510,9 +507,8 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { } foreach(const FBXMeshPart& part, extracted.mesh.parts) { model::Mesh::Part modelPart(indexNum, 0, 0, model::Mesh::TRIANGLES); + if (part.quadTrianglesIndices.size()) { - - ib->setSubData( offset, part.quadTrianglesIndices.size() * sizeof(int), (gpu::Byte*) part.quadTrianglesIndices.constData()); @@ -520,10 +516,8 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { indexNum += part.quadTrianglesIndices.size(); modelPart._numIndices += part.quadTrianglesIndices.size(); } - // model::Mesh::Part triPart(indexNum, part.triangleIndices.size(), 0, model::Mesh::TRIANGLES); if (part.triangleIndices.size()) { - // parts.push_back(triPart); ib->setSubData( offset, part.triangleIndices.size() * sizeof(int), (gpu::Byte*) part.triangleIndices.constData()); @@ -553,5 +547,3 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { extracted.mesh._mesh = mesh; } -#endif // USE_MODEL_MESH - diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index b1e63a18bd..37135ccd98 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -319,8 +319,11 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { uint32 startIndex = batch._params[paramOffset + 0]._uint; GLenum glType = _elementTypeToGLType[_input._indexBufferType]; + + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); - glDrawElements(mode, numIndices, glType, reinterpret_cast(startIndex + _input._indexBufferOffset)); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); (void) CHECK_GL_ERROR(); } @@ -353,10 +356,13 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { uint32 startInstance = batch._params[paramOffset + 0]._uint; GLenum glType = _elementTypeToGLType[_input._indexBufferType]; + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + #if (GPU_INPUT_PROFILE == GPU_CORE_43) - glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, reinterpret_cast(startIndex + _input._indexBufferOffset), numInstances, 0, startInstance); + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); #else - glDrawElementsInstanced(mode, numIndices, glType, reinterpret_cast(startIndex + _input._indexBufferOffset), numInstances); + glDrawElementsInstanced(mode, numIndices, glType, indexBufferByteOffset, numInstances); Q_UNUSED(startInstance); #endif (void)CHECK_GL_ERROR(); @@ -389,7 +395,7 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { uint commandCount = batch._params[paramOffset + 0]._uint; GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint]; GLenum indexType = _elementTypeToGLType[_input._indexBufferType]; - + glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, _input._indirectBufferStride); #else // FIXME implement the slow path diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index f12cda827a..e01dbcd0dc 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -286,7 +286,7 @@ protected: BufferPointer _indexBuffer; Offset _indexBufferOffset; Type _indexBufferType; - + BufferPointer _indirectBuffer; Offset _indirectBufferOffset{ 0 }; Offset _indirectBufferStride{ 0 }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 44484131d9..a1ded35ba0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1711,17 +1711,12 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape { PerformanceTimer perfTimer("batch.drawIndexed()"); - // part.getMergedTriangles(); - // part.mergedTrianglesIndicesCount; - batch.drawIndexed(gpu::TRIANGLES, drawPart._numIndices, drawPart._startIndex); + batch.drawIndexed(gpu::TRIANGLES, drawPart._numIndices, drawPart._startIndex); } -/* batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); - batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); - */ if (args) { const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += part.mergedTrianglesIndicesCount / INDICES_PER_TRIANGLE; + args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE; } } From 1799322c672faf946e2bab3e9d25e213fbd9bc5e Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 4 Oct 2015 18:46:35 -0700 Subject: [PATCH 06/19] Fix typos introduce in previous commit about the Quad to triangle indexing and remove dead code in model.cpp --- libraries/fbx/src/FBXReader_Mesh.cpp | 2 +- libraries/render-utils/src/Model.cpp | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 411f477a84..c88eaf4137 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -364,7 +364,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn part.quadTrianglesIndices.append(i0); part.quadTrianglesIndices.append(i1); - part.quadTrianglesIndices.append(i2); + part.quadTrianglesIndices.append(i3); part.quadTrianglesIndices.append(i1); part.quadTrianglesIndices.append(i2); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 276ad7a17a..d2fbbc1e43 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1546,9 +1546,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape return; // FIXME! } - // Assign index buffer: - // batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); - // batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); int vertexCount = mesh.vertices.size(); if (vertexCount == 0) { // sanity check @@ -1610,8 +1607,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape return; } - const FBXMeshPart& part = mesh.parts.at(partIndex); - #ifdef WANT_DEBUG if (material == nullptr) { From fd232b7d3269e7c40a35d1b9011e01e63803c0ec Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 4 Oct 2015 22:27:48 -0700 Subject: [PATCH 07/19] ONe more file to deal with the Model rendering --- libraries/render-utils/src/Model.cpp | 76 +------------------ .../render-utils/src/ModelRenderPayload.cpp | 55 ++++++++++++++ .../render-utils/src/ModelRenderPayload.h | 68 +++++++++++++++++ 3 files changed, 124 insertions(+), 75 deletions(-) create mode 100644 libraries/render-utils/src/ModelRenderPayload.cpp create mode 100644 libraries/render-utils/src/ModelRenderPayload.h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d2fbbc1e43..cb7b2b4b0c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -20,13 +20,12 @@ #include #include #include -#include -#include #include "AbstractViewStateInterface.h" #include "AnimationHandle.h" #include "DeferredLightingEffect.h" #include "Model.h" +#include "ModelRenderPayload.h" #include "model_vert.h" #include "model_shadow_vert.h" @@ -744,79 +743,6 @@ void Model::renderSetup(RenderArgs* args) { } } - -class MeshPartPayload { -public: - MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : - model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) { } - - typedef render::Payload Payload; - typedef Payload::DataPointer Pointer; - - Model* model; - QUrl url; - int meshIndex; - int partIndex; - int _shapeID; - - // Render Item interface - render::Item::Bound getBound() const; - void render(RenderArgs* args) const; - - - mutable render::Item::Bound _bound; - mutable bool _isBoundInvalid = true; -}; - - -render::Item::Bound MeshPartPayload::getBound() const { - if (_isBoundInvalid) { - model->getPartBounds(meshIndex, partIndex); - _isBoundInvalid = false; - } - return _bound; -} -void MeshPartPayload::render(RenderArgs* args) const { - return model->renderPart(args, meshIndex, partIndex, _shapeID); -} - -namespace render { - template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { - if (!payload->model->isVisible()) { - return ItemKey::Builder().withInvisible().build(); - } - auto geometry = payload->model->getGeometry(); - if (!geometry.isNull()) { - auto drawMaterial = geometry->getShapeMaterial(payload->_shapeID); - if (drawMaterial) { - auto matKey = drawMaterial->_material->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { - return ItemKey::Builder::transparentShape(); - } else { - return ItemKey::Builder::opaqueShape(); - } - } - } - - // Return opaque for lack of a better idea - return ItemKey::Builder::opaqueShape(); - } - - template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getBound(); - } - return render::Item::Bound(); - } - template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { - return payload->render(args); - } - - /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) { - return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); - }*/ -} - void Model::setVisibleInScene(bool newValue, std::shared_ptr scene) { if (_isVisible != newValue) { _isVisible = newValue; diff --git a/libraries/render-utils/src/ModelRenderPayload.cpp b/libraries/render-utils/src/ModelRenderPayload.cpp new file mode 100644 index 0000000000..c8961c0c4f --- /dev/null +++ b/libraries/render-utils/src/ModelRenderPayload.cpp @@ -0,0 +1,55 @@ +// +// ModelRenderPayload.cpp +// interface/src/renderer +// +// Created by Sam Gateau on 10/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ModelRenderPayload.h" + +#include "Model.h" + +using namespace render; + +MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : + model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) +{ +} + +render::ItemKey MeshPartPayload::getKey() const { + if (!model->isVisible()) { + return ItemKey::Builder().withInvisible().build(); + } + auto geometry = model->getGeometry(); + if (!geometry.isNull()) { + auto drawMaterial = geometry->getShapeMaterial(_shapeID); + if (drawMaterial) { + auto matKey = drawMaterial->_material->getKey(); + if (matKey.isTransparent() || matKey.isTransparentMap()) { + return ItemKey::Builder::transparentShape(); + } else { + return ItemKey::Builder::opaqueShape(); + } + } + } + + // Return opaque for lack of a better idea + return ItemKey::Builder::opaqueShape(); +} + +render::Item::Bound MeshPartPayload::getBound() const { + if (_isBoundInvalid) { + model->getPartBounds(meshIndex, partIndex); + _isBoundInvalid = false; + } + return _bound; +} + +void MeshPartPayload::render(RenderArgs* args) const { + return model->renderPart(args, meshIndex, partIndex, _shapeID); +} + diff --git a/libraries/render-utils/src/ModelRenderPayload.h b/libraries/render-utils/src/ModelRenderPayload.h new file mode 100644 index 0000000000..fe38415edc --- /dev/null +++ b/libraries/render-utils/src/ModelRenderPayload.h @@ -0,0 +1,68 @@ +// +// ModelRenderPayload.h +// interface/src/renderer +// +// Created by Sam Gateau on 10/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ModelRenderPayload_h +#define hifi_ModelRenderPayload_h + +#include +#include + +class Model; + +class MeshPartPayload { +public: + MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex); + + typedef render::Payload Payload; + typedef Payload::DataPointer Pointer; + + Model* model; + QUrl url; + int meshIndex; + int partIndex; + int _shapeID; + + // Render Item interface + render::ItemKey getKey() const; + render::Item::Bound getBound() const; + void render(RenderArgs* args) const; + + + mutable render::Item::Bound _bound; + mutable bool _isBoundInvalid = true; +}; + +namespace render { + template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); + } + // Return opaque for lack of a better idea + return ItemKey::Builder::opaqueShape(); + } + + template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return render::Item::Bound(); + } + template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); + } + + /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) { + return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); + }*/ +} + + +#endif // hifi_ModelRenderPayload_h \ No newline at end of file From 9e393ced46f3b9a3d9fa530e8457e3c0618d7675 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 5 Oct 2015 09:17:16 -0700 Subject: [PATCH 08/19] MOving rednering code of Model into ModelRenderPayload.h/cpp --- libraries/render-utils/src/Model.cpp | 11 +- libraries/render-utils/src/Model.h | 3 +- .../render-utils/src/ModelRenderPayload.cpp | 343 +++++++++++++++++- .../render-utils/src/ModelRenderPayload.h | 39 +- 4 files changed, 364 insertions(+), 32 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index cb7b2b4b0c..c02cd99b1f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1373,7 +1373,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { return AABox(); } -void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) { +void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID, const MeshPartPayload* payload) { // PROFILE_RANGE(__FUNCTION__); PerformanceTimer perfTimer("Model::renderPart"); if (!_readyWhenAdded) { @@ -1505,6 +1505,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape auto drawPart = drawMesh->getPartBuffer().get(partIndex); + /* if (mesh.blendshapes.isEmpty()) { batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); @@ -1527,7 +1528,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape if (mesh.colors.isEmpty()) { batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } - +*/ + payload->bindMesh(batch); + // guard against partially loaded meshes if (partIndex >= mesh.parts.size()) { return; @@ -1644,9 +1647,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape { PerformanceTimer perfTimer("batch.drawIndexed()"); - batch.drawIndexed(gpu::TRIANGLES, drawPart._numIndices, drawPart._startIndex); + payload->drawCall(batch); } - + if (args) { const int INDICES_PER_TRIANGLE = 3; args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 093c22938e..a36b773ed7 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -88,7 +88,7 @@ public: bool isVisible() const { return _isVisible; } AABox getPartBounds(int meshIndex, int partIndex); - void renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID); + void renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID, const MeshPartPayload* payload); bool maybeStartBlender(); @@ -494,6 +494,7 @@ private: bool _needsReload = true; bool _needsUpdateClusterMatrices = true; + friend class MeshPartPayload; protected: RigPointer _rig; }; diff --git a/libraries/render-utils/src/ModelRenderPayload.cpp b/libraries/render-utils/src/ModelRenderPayload.cpp index c8961c0c4f..a6c62ee9e1 100644 --- a/libraries/render-utils/src/ModelRenderPayload.cpp +++ b/libraries/render-utils/src/ModelRenderPayload.cpp @@ -13,13 +13,44 @@ #include "Model.h" +namespace render { + template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); + } + // Return opaque for lack of a better idea + return ItemKey::Builder::opaqueShape(); + } + + template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return render::Item::Bound(); + } + template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); + } + + /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) { + return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); + }*/ +} + using namespace render; MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) { + const std::vector>& networkMeshes = model->_geometry->getMeshes(); + const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); + _drawMesh = networkMesh._mesh; + + _drawPart = _drawMesh->getPartBuffer().get(partIndex); + } + render::ItemKey MeshPartPayload::getKey() const { if (!model->isVisible()) { return ItemKey::Builder().withInvisible().build(); @@ -50,6 +81,316 @@ render::Item::Bound MeshPartPayload::getBound() const { } void MeshPartPayload::render(RenderArgs* args) const { - return model->renderPart(args, meshIndex, partIndex, _shapeID); + return model->renderPart(args, meshIndex, partIndex, _shapeID, this); } +void MeshPartPayload::bindMesh(gpu::Batch& batch) const { + const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); + const std::vector>& networkMeshes = model->_geometry->getMeshes(); + const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); + const FBXMesh& mesh = geometry.meshes.at(meshIndex); + // auto drawMesh = networkMesh._mesh; + + if (mesh.blendshapes.isEmpty()) { + batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); + + batch.setInputFormat((_drawMesh->getVertexFormat())); + auto inputStream = _drawMesh->makeBufferStream(); + + batch.setInputStream(0, inputStream); + } else { + batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); + batch.setInputFormat((_drawMesh->getVertexFormat())); + + batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); + + auto inputStream = _drawMesh->makeBufferStream().makeRangedStream(2); + + batch.setInputStream(2, inputStream); + } + + if (mesh.colors.isEmpty()) { + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } +} + +void MeshPartPayload::drawCall(gpu::Batch& batch) const { + batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); +} +/* +void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) { + // PROFILE_RANGE(__FUNCTION__); + PerformanceTimer perfTimer("Model::renderPart"); + if (!_readyWhenAdded) { + return; // bail asap + } + + auto textureCache = DependencyManager::get(); + + gpu::Batch& batch = *(args->_batch); + auto mode = args->_renderMode; + + + // Capture the view matrix once for the rendering of this model + if (_transforms.empty()) { + _transforms.push_back(Transform()); + } + + auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME + + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const std::vector>& networkMeshes = _geometry->getMeshes(); + + auto networkMaterial = _geometry->getShapeMaterial(shapeID); + if (!networkMaterial) { + return; + }; + auto material = networkMaterial->_material; + if (!material) { + return; + } + + // TODO: Not yet + // auto drawMesh = _geometry->getShapeMesh(shapeID); + // auto drawPart = _geometry->getShapePart(shapeID); + + // guard against partially loaded meshes + if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) { + return; + } + + updateClusterMatrices(); + + const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); + const FBXMesh& mesh = geometry.meshes.at(meshIndex); + const MeshState& state = _meshStates.at(meshIndex); + + auto drawMesh = networkMesh._mesh; + + + auto drawMaterialKey = material->getKey(); + bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + + bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); + bool hasSpecular = drawMaterialKey.isGlossMap(); // !drawMaterial->specularTextureName.isEmpty(); //mesh.hasSpecularTexture(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); // !drawMaterial->emissiveTextureName.isEmpty(); //mesh.hasEmissiveTexture(); + bool isSkinned = state.clusterMatrices.size() > 1; + bool wireframe = isWireframe(); + + // render the part bounding box +#ifdef DEBUG_BOUNDING_PARTS + { + AABox partBounds = getPartBounds(meshIndex, partIndex); + bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE; + + glm::vec4 cubeColor; + if (isSkinned) { + cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f); + } else if (inView) { + cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f); + } else { + cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); + } + + Transform transform; + transform.setTranslation(partBounds.calcCenter()); + transform.setScale(partBounds.getDimensions()); + batch.setModelTransform(transform); + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + } +#endif //def DEBUG_BOUNDING_PARTS + + if (wireframe) { + translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + } + + Locations* locations = nullptr; + pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + args, locations); + + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { + _meshGroupsKnown = false; // regenerate these lists next time around. + _readyWhenAdded = false; // in case any of our users are using scenes + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return; // FIXME! + } + + int vertexCount = mesh.vertices.size(); + if (vertexCount == 0) { + // sanity check + return; // FIXME! + } + + // Transform stage + if (_transforms.empty()) { + _transforms.push_back(Transform()); + } + + if (isSkinned) { + const float* bones; + if (_cauterizeBones) { + bones = (const float*)state.cauterizedClusterMatrices.constData(); + } else { + bones = (const float*)state.clusterMatrices.constData(); + } + batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones); + _transforms[0] = Transform(); + _transforms[0].preTranslate(_translation); + } else { + if (_cauterizeBones) { + _transforms[0] = Transform(state.cauterizedClusterMatrices[0]); + } else { + _transforms[0] = Transform(state.clusterMatrices[0]); + } + _transforms[0].preTranslate(_translation); + } + batch.setModelTransform(_transforms[0]); + + auto drawPart = drawMesh->getPartBuffer().get(partIndex); + + if (mesh.blendshapes.isEmpty()) { + batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); + + batch.setInputFormat((drawMesh->getVertexFormat())); + auto inputStream = drawMesh->makeBufferStream(); + + batch.setInputStream(0, inputStream); + } else { + batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); + batch.setInputFormat((drawMesh->getVertexFormat())); + + batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); + + auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2); + + batch.setInputStream(2, inputStream); + } + + if (mesh.colors.isEmpty()) { + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + + // guard against partially loaded meshes + if (partIndex >= mesh.parts.size()) { + return; + } + + +#ifdef WANT_DEBUG + if (material == nullptr) { + qCDebug(renderutils) << "WARNING: material == nullptr!!!"; + } +#endif + + { + + // apply material properties + if (mode != RenderArgs::SHADOW_RENDER_MODE) { +#ifdef WANT_DEBUG + qCDebug(renderutils) << "Material Changed ---------------------------------------------"; + qCDebug(renderutils) << "part INDEX:" << partIndex; + qCDebug(renderutils) << "NEW part.materialID:" << part.materialID; +#endif //def WANT_DEBUG + + if (locations->materialBufferUnit >= 0) { + batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); + } + + auto materialKey = material->getKey(); + auto textureMaps = material->getTextureMaps(); + glm::mat4 texcoordTransform[2]; + + // Diffuse + if (materialKey.isDiffuseMap()) { + auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; + if (diffuseMap && diffuseMap->isDefined()) { + batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); + + if (!diffuseMap->getTextureTransform().isIdentity()) { + diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); + } + } else { + batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); + } + } else { + batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); + } + + // Normal map + if ((locations->normalTextureUnit >= 0) && hasTangents) { + auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; + if (normalMap && normalMap->isDefined()) { + batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView()); + + // texcoord are assumed to be the same has diffuse + } else { + batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture()); + } + } else { + batch.setResourceTexture(NORMAL_MAP_SLOT, nullptr); + } + + // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that + if ((locations->specularTextureUnit >= 0) && materialKey.isGlossMap()) { + auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; + if (specularMap && specularMap->isDefined()) { + batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView()); + + // texcoord are assumed to be the same has diffuse + } else { + batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); + } + } else { + batch.setResourceTexture(SPECULAR_MAP_SLOT, nullptr); + } + + // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too + if ((locations->emissiveTextureUnit >= 0) && materialKey.isLightmapMap()) { + auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; + + if (lightmapMap && lightmapMap->isDefined()) { + batch.setResourceTexture(LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); + + auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); + batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); + + if (!lightmapMap->getTextureTransform().isIdentity()) { + lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); + } + } + else { + batch.setResourceTexture(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); + } + } else { + batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr); + } + + // Texcoord transforms ? + if (locations->texcoordMatrices >= 0) { + batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); + } + + // TODO: We should be able to do that just in the renderTransparentJob + if (translucentMesh && locations->lightBufferUnit >= 0) { + PerformanceTimer perfTimer("DLE->setupTransparent()"); + + DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); + } + + + if (args) { + args->_details._materialSwitches++; + } + } + } + + if (args) { + const int INDICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE; + } +} +*/ \ No newline at end of file diff --git a/libraries/render-utils/src/ModelRenderPayload.h b/libraries/render-utils/src/ModelRenderPayload.h index fe38415edc..bee7c186b9 100644 --- a/libraries/render-utils/src/ModelRenderPayload.h +++ b/libraries/render-utils/src/ModelRenderPayload.h @@ -12,9 +12,14 @@ #ifndef hifi_ModelRenderPayload_h #define hifi_ModelRenderPayload_h -#include +#include + #include +#include + +#include + class Model; class MeshPartPayload { @@ -35,34 +40,16 @@ public: render::Item::Bound getBound() const; void render(RenderArgs* args) const; + // MeshPartPayload functions to perform render + void bindMesh(gpu::Batch& batch) const; + void drawCall(gpu::Batch& batch) const; + + model::MeshPointer _drawMesh; + model::Mesh::Part _drawPart; + model::MaterialPointer _drawMaterial; mutable render::Item::Bound _bound; mutable bool _isBoundInvalid = true; }; -namespace render { - template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getKey(); - } - // Return opaque for lack of a better idea - return ItemKey::Builder::opaqueShape(); - } - - template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getBound(); - } - return render::Item::Bound(); - } - template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { - return payload->render(args); - } - - /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) { - return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); - }*/ -} - - #endif // hifi_ModelRenderPayload_h \ No newline at end of file From 12fedb6ff0bb146300043eb997ce81f8c2d95a67 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 5 Oct 2015 18:31:05 -0700 Subject: [PATCH 09/19] Move skinning shader features in its own slh and get ready for moving cluster matrices to uniform buffer --- libraries/gpu/src/gpu/Stream.h | 1 + libraries/model/src/model/Geometry.cpp | 35 +- libraries/model/src/model/Geometry.h | 9 +- .../src/DeferredLightingEffect.cpp | 2 +- libraries/render-utils/src/Model.cpp | 499 +----------- libraries/render-utils/src/Model.h | 132 +--- .../render-utils/src/ModelRenderPayload.cpp | 717 +++++++++++------- .../render-utils/src/ModelRenderPayload.h | 163 +++- libraries/render-utils/src/Skinning.slh | 68 ++ libraries/render-utils/src/skin_model.slv | 15 +- .../src/skin_model_normal_map.slv | 14 +- .../render-utils/src/skin_model_shadow.slv | 11 +- 12 files changed, 731 insertions(+), 935 deletions(-) create mode 100644 libraries/render-utils/src/Skinning.slh diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 53509c1033..492af5f62a 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -134,6 +134,7 @@ public: BufferStream(); ~BufferStream(); + void clear() { _buffers.clear(); _offsets.clear(); _strides.clear(); } void addBuffer(const BufferPointer& buffer, Offset offset, Offset stride); const Buffers& getBuffers() const { return _buffers; } diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 6723293dc1..63adeec0f1 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -64,6 +64,24 @@ void Mesh::evalVertexFormat() { } _vertexFormat.reset(vf); + + evalVertexStream(); +} + + +void Mesh::evalVertexStream() { + _vertexStream.clear(); + + int channelNum = 0; + if (hasVertexData()) { + _vertexStream.addBuffer(_vertexBuffer._buffer, _vertexBuffer._offset, _vertexFormat->getChannelStride(channelNum)); + channelNum++; + } + for (auto attrib : _attributeBuffers) { + BufferView& view = attrib.second; + _vertexStream.addBuffer(view._buffer, view._offset, _vertexFormat->getChannelStride(channelNum)); + channelNum++; + } } void Mesh::setIndexBuffer(const BufferView& buffer) { @@ -116,23 +134,6 @@ const Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const return totalBound; } -const gpu::BufferStream Mesh::makeBufferStream() const { - gpu::BufferStream stream; - - int channelNum = 0; - if (hasVertexData()) { - stream.addBuffer(_vertexBuffer._buffer, _vertexBuffer._offset, _vertexFormat->getChannelStride(channelNum)); - channelNum++; - } - for (auto attrib : _attributeBuffers) { - BufferView& view = attrib.second; - stream.addBuffer(view._buffer, view._offset, _vertexFormat->getChannelStride(channelNum)); - channelNum++; - } - - return stream; -} - Geometry::Geometry() { } diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index 5ef414a2d1..8b5f448a64 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -57,6 +57,9 @@ public: // Stream format const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; } + // BufferStream on the mesh vertices and attributes matching the vertex format + const gpu::BufferStream getVertexStream() const { return _vertexStream; } + // Index Buffer void setIndexBuffer(const BufferView& buffer); const BufferView& getIndexBuffer() const { return _indexBuffer; } @@ -109,15 +112,12 @@ public: // the returned box is the bounding box of ALL the evaluated part bounds. const Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const; - - // Generate a BufferStream on the mesh vertices and attributes - const gpu::BufferStream makeBufferStream() const; - static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast(topo); } protected: gpu::Stream::FormatPointer _vertexFormat; + gpu::BufferStream _vertexStream; BufferView _vertexBuffer; BufferViewMap _attributeBuffers; @@ -127,6 +127,7 @@ protected: BufferView _partBuffer; void evalVertexFormat(); + void evalVertexStream(); }; typedef std::shared_ptr< Mesh > MeshPointer; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index dbcbe3c05e..e9d2cf4061 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -887,7 +887,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL)); - _spotLightMesh->makeBufferStream(); + _spotLightMesh->getVertexStream(); } return _spotLightMesh; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c02cd99b1f..a86cd305dc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -27,26 +27,6 @@ #include "Model.h" #include "ModelRenderPayload.h" -#include "model_vert.h" -#include "model_shadow_vert.h" -#include "model_normal_map_vert.h" -#include "model_lightmap_vert.h" -#include "model_lightmap_normal_map_vert.h" -#include "skin_model_vert.h" -#include "skin_model_shadow_vert.h" -#include "skin_model_normal_map_vert.h" - -#include "model_frag.h" -#include "model_shadow_frag.h" -#include "model_normal_map_frag.h" -#include "model_normal_specular_map_frag.h" -#include "model_specular_map_frag.h" -#include "model_lightmap_frag.h" -#include "model_lightmap_normal_map_frag.h" -#include "model_lightmap_normal_specular_map_frag.h" -#include "model_lightmap_specular_map_frag.h" -#include "model_translucent_frag.h" - #include "RenderUtilsLogging.h" using namespace std; @@ -92,112 +72,6 @@ Model::~Model() { deleteGeometry(); } -Model::RenderPipelineLib Model::_renderPipelineLib; -const int MATERIAL_GPU_SLOT = 3; -const int DIFFUSE_MAP_SLOT = 0; -const int NORMAL_MAP_SLOT = 1; -const int SPECULAR_MAP_SLOT = 2; -const int LIGHTMAP_MAP_SLOT = 3; -const int LIGHT_BUFFER_SLOT = 4; - -void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, - gpu::ShaderPointer& vertexShader, - gpu::ShaderPointer& pixelShader ) { - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), DIFFUSE_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), NORMAL_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), SPECULAR_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), LIGHTMAP_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_BUFFER_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); - gpu::Shader::makeProgram(*program, slotBindings); - - - auto locations = std::make_shared(); - initLocations(program, *locations); - - - auto state = std::make_shared(); - - // Backface on shadow - if (key.isShadow()) { - state->setCullMode(gpu::State::CULL_FRONT); - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(4.0f); - } else { - state->setCullMode(gpu::State::CULL_BACK); - } - - // Z test depends if transparent or not - state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - - // Blend on transparent - state->setBlendFunction(key.isTranslucent(), - gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - // Good to go add the brand new pipeline - auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); - - - if (!key.isWireFrame()) { - - RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME); - auto wireframeState = std::make_shared(state->getValues()); - - wireframeState->setFillMode(gpu::State::FILL_LINE); - - // create a new RenderPipeline with the same shader side and the mirrorState - auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); - insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); - } - - // If not a shadow pass, create the mirror version from the same state, just change the FrontFace - if (!key.isShadow()) { - - RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR); - auto mirrorState = std::make_shared(state->getValues()); - - // create a new RenderPipeline with the same shader side and the mirrorState - auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); - insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); - - if (!key.isWireFrame()) { - RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME); - auto wireframeState = std::make_shared(state->getValues()); - - wireframeState->setFillMode(gpu::State::FILL_LINE); - - // create a new RenderPipeline with the same shader side and the mirrorState - auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); - insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); - } - } -} - - -void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model::Locations& locations) { - locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold"); - locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); - locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); - locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); - locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); - locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap"); - locations.normalTextureUnit = program->getTextures().findLocation("normalMap"); - locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); - locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); - locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); - locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); - locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex"); - locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight"); -} - AbstractViewStateInterface* Model::_viewState = NULL; void Model::setTranslation(const glm::vec3& translation) { @@ -255,128 +129,6 @@ void Model::initJointTransforms() { } void Model::init() { - if (_renderPipelineLib.empty()) { - // Vertex shaders - auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); - auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); - auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert))); - auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert))); - auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert))); - auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert))); - auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert))); - auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert))); - - // Pixel shaders - auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))); - auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag))); - auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag))); - auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag))); - auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag))); - auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag))); - auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag))); - auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag))); - auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); - auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); - - // Fill the renderPipelineLib - - _renderPipelineLib.addRenderPipeline( - RenderKey(0), - modelVertex, modelPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS), - modelNormalMapVertex, modelNormalMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_SPECULAR), - modelVertex, modelSpecularMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), - modelNormalMapVertex, modelNormalSpecularMapPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT), - modelVertex, modelTranslucentPixel); - // FIXME Ignore lightmap for translucents meshpart - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), - modelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), - modelNormalMapVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - modelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - modelNormalMapVertex, modelTranslucentPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP), - modelLightmapVertex, modelLightmapPixel); - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS), - modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR), - modelLightmapVertex, modelLightmapSpecularMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), - modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED), - skinModelVertex, modelPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS), - skinModelNormalMapVertex, modelNormalMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR), - skinModelVertex, modelSpecularMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), - skinModelNormalMapVertex, modelNormalSpecularMapPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), - skinModelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), - skinModelNormalMapVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - skinModelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - skinModelNormalMapVertex, modelTranslucentPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), - modelShadowVertex, modelShadowPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), - skinModelShadowVertex, modelShadowPixel); - } } void Model::reset() { @@ -416,6 +168,9 @@ bool Model::updateGeometry() { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); state.cauterizedClusterMatrices.resize(mesh.clusters.size()); + if (mesh.clusters.size() > 1) { + state.clusterBuffer = std::make_shared(mesh.clusters.size() * sizeof(glm::mat4), nullptr); + } _meshStates.append(state); auto buffer = std::make_shared(); @@ -1237,6 +992,7 @@ void Model::updateClusterMatrices() { for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); + for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); @@ -1250,6 +1006,17 @@ void Model::updateClusterMatrices() { state.cauterizedClusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; } } + + // Once computed the cluster matrices, update the buffer + if (state.clusterBuffer) { + const float* bones; + if (_cauterizeBones) { + bones = (const float*)state.cauterizedClusterMatrices.constData(); + } else { + bones = (const float*)state.clusterMatrices.constData(); + } + state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) bones); + } } // post the blender if we're not currently waiting for one to finish @@ -1385,12 +1152,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape gpu::Batch& batch = *(args->_batch); auto mode = args->_renderMode; - - // Capture the view matrix once for the rendering of this model - if (_transforms.empty()) { - _transforms.push_back(Transform()); - } - auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME const FBXGeometry& geometry = _geometry->getFBXGeometry(); @@ -1420,9 +1181,22 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape const FBXMesh& mesh = geometry.meshes.at(meshIndex); const MeshState& state = _meshStates.at(meshIndex); - auto drawMesh = networkMesh._mesh; + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { + _meshGroupsKnown = false; // regenerate these lists next time around. + _readyWhenAdded = false; // in case any of our users are using scenes + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return; // FIXME! + } + int vertexCount = mesh.vertices.size(); + if (vertexCount == 0) { + // sanity check + return; // FIXME! + } + auto drawMaterialKey = material->getKey(); bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); @@ -1459,76 +1233,13 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; } - Locations* locations = nullptr; - pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + ModelRender::Locations* locations = nullptr; + ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, args, locations); - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { - _meshGroupsKnown = false; // regenerate these lists next time around. - _readyWhenAdded = false; // in case any of our users are using scenes - invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return; // FIXME! - } - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return; // FIXME! - } + payload->bindTransform(batch, locations); - // Transform stage - if (_transforms.empty()) { - _transforms.push_back(Transform()); - } - - if (isSkinned) { - const float* bones; - if (_cauterizeBones) { - bones = (const float*)state.cauterizedClusterMatrices.constData(); - } else { - bones = (const float*)state.clusterMatrices.constData(); - } - batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones); - _transforms[0] = Transform(); - _transforms[0].preTranslate(_translation); - } else { - if (_cauterizeBones) { - _transforms[0] = Transform(state.cauterizedClusterMatrices[0]); - } else { - _transforms[0] = Transform(state.clusterMatrices[0]); - } - _transforms[0].preTranslate(_translation); - } - batch.setModelTransform(_transforms[0]); - - auto drawPart = drawMesh->getPartBuffer().get(partIndex); - - /* - if (mesh.blendshapes.isEmpty()) { - batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); - - batch.setInputFormat((drawMesh->getVertexFormat())); - auto inputStream = drawMesh->makeBufferStream(); - - batch.setInputStream(0, inputStream); - } else { - batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); - batch.setInputFormat((drawMesh->getVertexFormat())); - - batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); - - auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2); - - batch.setInputStream(2, inputStream); - } - - if (mesh.colors.isEmpty()) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } -*/ payload->bindMesh(batch); // guard against partially loaded meshes @@ -1544,104 +1255,18 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape #endif { - // apply material properties - if (mode != RenderArgs::SHADOW_RENDER_MODE) { - #ifdef WANT_DEBUG - qCDebug(renderutils) << "Material Changed ---------------------------------------------"; - qCDebug(renderutils) << "part INDEX:" << partIndex; - qCDebug(renderutils) << "NEW part.materialID:" << part.materialID; - #endif //def WANT_DEBUG - - if (locations->materialBufferUnit >= 0) { - batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); - } - - auto materialKey = material->getKey(); - auto textureMaps = material->getTextureMaps(); - glm::mat4 texcoordTransform[2]; - - // Diffuse - if (materialKey.isDiffuseMap()) { - auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; - if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); - - if (!diffuseMap->getTextureTransform().isIdentity()) { - diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); - } - } else { - batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); - } - } else { - batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); - } - - // Normal map - if ((locations->normalTextureUnit >= 0) && hasTangents) { - auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; - if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView()); - - // texcoord are assumed to be the same has diffuse - } else { - batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture()); - } - } else { - batch.setResourceTexture(NORMAL_MAP_SLOT, nullptr); - } - - // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that - if ((locations->specularTextureUnit >= 0) && materialKey.isGlossMap()) { - auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; - if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView()); - - // texcoord are assumed to be the same has diffuse - } else { - batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); - } - } else { - batch.setResourceTexture(SPECULAR_MAP_SLOT, nullptr); - } - - // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too - if ((locations->emissiveTextureUnit >= 0) && materialKey.isLightmapMap()) { - auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; - - if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); - - auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); - batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); - - if (!lightmapMap->getTextureTransform().isIdentity()) { - lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); - } - } - else { - batch.setResourceTexture(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); - } - } else { - batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr); - } - - // Texcoord transforms ? - if (locations->texcoordMatrices >= 0) { - batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); - } - - // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { - PerformanceTimer perfTimer("DLE->setupTransparent()"); - - DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); - } + payload->bindMaterial(batch, locations); - if (args) { - args->_details._materialSwitches++; - } + // TODO: We should be able to do that just in the renderTransparentJob + if (translucentMesh && locations->lightBufferUnit >= 0) { + PerformanceTimer perfTimer("DLE->setupTransparent()"); + + DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); + } + if (args) { + args->_details._materialSwitches++; } } @@ -1652,7 +1277,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape if (args) { const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE; + args->_details._trianglesRendered += payload->_drawPart._numIndices / INDICES_PER_TRIANGLE; } } @@ -1684,46 +1309,6 @@ void Model::segregateMeshGroups() { _meshGroupsKnown = true; } -void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, - Locations*& locations) { - - PerformanceTimer perfTimer("Model::pickPrograms"); - - - RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); - if (mode == RenderArgs::MIRROR_RENDER_MODE) { - key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR); - } - auto pipeline = _renderPipelineLib.find(key.getRaw()); - if (pipeline == _renderPipelineLib.end()) { - qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); - locations = 0; - return; - } - - gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram(); - locations = (*pipeline).second._locations.get(); - - - // Setup the One pipeline - batch.setPipeline((*pipeline).second._pipeline); - - if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { - batch._glUniform1f(locations->alphaThreshold, alphaThreshold); - } - - if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { - const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed - batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY); - } - - if ((locations->normalFittingMapUnit > -1)) { - batch.setResourceTexture(locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); - } -} - bool Model::initWhenReady(render::ScenePointer scene) { if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) { segregateMeshGroups(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index a36b773ed7..108480e4ef 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -47,6 +47,7 @@ namespace render { typedef unsigned int ItemID; } class MeshPartPayload; +class ModelRenderLocations; inline uint qHash(const std::shared_ptr& a, uint seed) { return qHash(a.get(), seed); @@ -257,6 +258,7 @@ protected: public: QVector clusterMatrices; QVector cauterizedClusterMatrices; + gpu::BufferPointer clusterBuffer; }; QVector _meshStates; @@ -323,8 +325,6 @@ private: bool _isVisible; gpu::Buffers _blendedVertexBuffers; - std::vector _transforms; - gpu::Batch _renderBatch; QVector > > _dilatedTextures; @@ -332,25 +332,6 @@ private: int _blendNumber; int _appliedBlendNumber; - class Locations { - public: - int tangent; - int alphaThreshold; - int texcoordMatrices; - int diffuseTextureUnit; - int normalTextureUnit; - int specularTextureUnit; - int emissiveTextureUnit; - int emissiveParams; - int glowIntensity; - int normalFittingMapUnit; - int materialBufferUnit; - int clusterMatrices; - int clusterIndices; - int clusterWeights; - int lightBufferUnit; - }; - QHash, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes bool _calculatedMeshPartBoxesValid; @@ -373,118 +354,9 @@ private: void renderDebugMeshBoxes(gpu::Batch& batch); int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID; - // helper functions used by render() or renderInScene() - - static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, - Locations*& locations); static AbstractViewStateInterface* _viewState; - class RenderKey { - public: - enum FlagBit { - IS_TRANSLUCENT_FLAG = 0, - HAS_LIGHTMAP_FLAG, - HAS_TANGENTS_FLAG, - HAS_SPECULAR_FLAG, - HAS_EMISSIVE_FLAG, - IS_SKINNED_FLAG, - IS_STEREO_FLAG, - IS_DEPTH_ONLY_FLAG, - IS_SHADOW_FLAG, - IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" - IS_WIREFRAME_FLAG, - - NUM_FLAGS, - }; - - enum Flag { - IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG), - HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG), - HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG), - HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG), - HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG), - IS_SKINNED = (1 << IS_SKINNED_FLAG), - IS_STEREO = (1 << IS_STEREO_FLAG), - IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG), - IS_SHADOW = (1 << IS_SHADOW_FLAG), - IS_MIRROR = (1 << IS_MIRROR_FLAG), - IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG), - }; - typedef unsigned short Flags; - - - - bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } - - bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); } - bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); } - bool hasTangents() const { return isFlag(HAS_TANGENTS); } - bool hasSpecular() const { return isFlag(HAS_SPECULAR); } - bool hasEmissive() const { return isFlag(HAS_EMISSIVE); } - bool isSkinned() const { return isFlag(IS_SKINNED); } - bool isStereo() const { return isFlag(IS_STEREO); } - bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); } - bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing - bool isMirror() const { return isFlag(IS_MIRROR); } - bool isWireFrame() const { return isFlag(IS_WIREFRAME); } - - Flags _flags = 0; - short _spare = 0; - - int getRaw() { return *reinterpret_cast(this); } - - - RenderKey( - bool translucent, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : - RenderKey( (translucent ? IS_TRANSLUCENT : 0) - | (hasLightmap ? HAS_LIGHTMAP : 0) - | (hasTangents ? HAS_TANGENTS : 0) - | (hasSpecular ? HAS_SPECULAR : 0) - | (isSkinned ? IS_SKINNED : 0) - | (isWireframe ? IS_WIREFRAME : 0) - ) {} - - RenderKey(RenderArgs::RenderMode mode, - bool translucent, float alphaThreshold, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : - RenderKey( ((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) - | (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly - | (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0) - | (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0) - | (isSkinned ? IS_SKINNED : 0) - | (isWireframe ? IS_WIREFRAME : 0) - | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0) - | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0) - | ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR :0) - ) {} - - RenderKey(int bitmask) : _flags(bitmask) {} - }; - - - class RenderPipeline { - public: - gpu::PipelinePointer _pipeline; - std::shared_ptr _locations; - RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : - _pipeline(pipeline), _locations(locations) {} - }; - - typedef std::unordered_map BaseRenderPipelineMap; - class RenderPipelineLib : public BaseRenderPipelineMap { - public: - typedef RenderKey Key; - - - void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); - - void initLocations(gpu::ShaderPointer& program, Locations& locations); - }; - static RenderPipelineLib _renderPipelineLib; - bool _renderCollisionHull; diff --git a/libraries/render-utils/src/ModelRenderPayload.cpp b/libraries/render-utils/src/ModelRenderPayload.cpp index a6c62ee9e1..e4998e445a 100644 --- a/libraries/render-utils/src/ModelRenderPayload.cpp +++ b/libraries/render-utils/src/ModelRenderPayload.cpp @@ -11,8 +11,299 @@ #include "ModelRenderPayload.h" +#include "DeferredLightingEffect.h" + #include "Model.h" +#include "model_vert.h" +#include "model_shadow_vert.h" +#include "model_normal_map_vert.h" +#include "model_lightmap_vert.h" +#include "model_lightmap_normal_map_vert.h" +#include "skin_model_vert.h" +#include "skin_model_shadow_vert.h" +#include "skin_model_normal_map_vert.h" + +#include "model_frag.h" +#include "model_shadow_frag.h" +#include "model_normal_map_frag.h" +#include "model_normal_specular_map_frag.h" +#include "model_specular_map_frag.h" +#include "model_lightmap_frag.h" +#include "model_lightmap_normal_map_frag.h" +#include "model_lightmap_normal_specular_map_frag.h" +#include "model_lightmap_specular_map_frag.h" +#include "model_translucent_frag.h" + +ModelRender::RenderPipelineLib ModelRender::_renderPipelineLib; + +const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib() { + if (_renderPipelineLib.empty()) { + // Vertex shaders + auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); + auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); + auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert))); + auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert))); + auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert))); + auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert))); + auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert))); + auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert))); + + // Pixel shaders + auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))); + auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag))); + auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag))); + auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag))); + auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag))); + auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag))); + auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag))); + auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag))); + auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); + auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); + + // Fill the renderPipelineLib + + _renderPipelineLib.addRenderPipeline( + RenderKey(0), + modelVertex, modelPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS), + modelNormalMapVertex, modelNormalMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_SPECULAR), + modelVertex, modelSpecularMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + modelNormalMapVertex, modelNormalSpecularMapPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + // FIXME Ignore lightmap for translucents meshpart + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), + modelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + modelNormalMapVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + modelNormalMapVertex, modelTranslucentPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP), + modelLightmapVertex, modelLightmapPixel); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS), + modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR), + modelLightmapVertex, modelLightmapSpecularMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED), + skinModelVertex, modelPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS), + skinModelNormalMapVertex, modelNormalMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR), + skinModelVertex, modelSpecularMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), + skinModelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + skinModelNormalMapVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + skinModelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + skinModelNormalMapVertex, modelTranslucentPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + modelShadowVertex, modelShadowPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + skinModelShadowVertex, modelShadowPixel); + } + + return _renderPipelineLib; +} + + +void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey key, + gpu::ShaderPointer& vertexShader, + gpu::ShaderPointer& pixelShader) { + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), ModelRender::SPECULAR_MAP_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), ModelRender::LIGHTMAP_MAP_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ModelRender::LIGHT_BUFFER_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); + + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + gpu::Shader::makeProgram(*program, slotBindings); + + + auto locations = std::make_shared(); + initLocations(program, *locations); + + + auto state = std::make_shared(); + + // Backface on shadow + if (key.isShadow()) { + state->setCullMode(gpu::State::CULL_FRONT); + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(4.0f); + } else { + state->setCullMode(gpu::State::CULL_BACK); + } + + // Z test depends if transparent or not + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(key.isTranslucent(), + gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + // Good to go add the brand new pipeline + auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); + + + if (!key.isWireFrame()) { + + RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME); + auto wireframeState = std::make_shared(state->getValues()); + + wireframeState->setFillMode(gpu::State::FILL_LINE); + + // create a new RenderPipeline with the same shader side and the mirrorState + auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); + insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); + } + + // If not a shadow pass, create the mirror version from the same state, just change the FrontFace + if (!key.isShadow()) { + + RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR); + auto mirrorState = std::make_shared(state->getValues()); + + // create a new RenderPipeline with the same shader side and the mirrorState + auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); + insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); + + if (!key.isWireFrame()) { + RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME); + auto wireframeState = std::make_shared(state->getValues()); + + wireframeState->setFillMode(gpu::State::FILL_LINE); + + // create a new RenderPipeline with the same shader side and the mirrorState + auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); + insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); + } + } +} + + +void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) { + locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold"); + locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); + locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); + locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); + locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); + locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap"); + locations.normalTextureUnit = program->getTextures().findLocation("normalMap"); + locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); + locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); + locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); + locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); + locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex"); + locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight"); +} + + +void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, + Locations*& locations) { + + // PerformanceTimer perfTimer("Model::pickPrograms"); + getRenderPipelineLib(); + + RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); + if (mode == RenderArgs::MIRROR_RENDER_MODE) { + key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR); + } + auto pipeline = _renderPipelineLib.find(key.getRaw()); + if (pipeline == _renderPipelineLib.end()) { + qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); + locations = 0; + return; + } + + gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram(); + locations = (*pipeline).second._locations.get(); + + + // Setup the One pipeline + batch.setPipeline((*pipeline).second._pipeline); + + if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { + batch._glUniform1f(locations->alphaThreshold, alphaThreshold); + } + + if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { + const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed + batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY); + } + + if ((locations->normalFittingMapUnit > -1)) { + batch.setResourceTexture(locations->normalFittingMapUnit, + DependencyManager::get()->getNormalFittingTexture()); + } +} + namespace render { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { if (payload) { @@ -42,34 +333,50 @@ using namespace render; MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) { + initCache(); +} + +void MeshPartPayload::initCache() { const std::vector>& networkMeshes = model->_geometry->getMeshes(); const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); _drawMesh = networkMesh._mesh; - + + const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); + const FBXMesh& mesh = geometry.meshes.at(meshIndex); + _hasColorAttrib = !mesh.colors.isEmpty(); + _isBlendShaped = !mesh.blendshapes.isEmpty(); + _isSkinned = !mesh.clusterIndices.isEmpty(); + + _drawPart = _drawMesh->getPartBuffer().get(partIndex); + auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID); + if (networkMaterial) { + _drawMaterial = networkMaterial->_material; + }; + } - render::ItemKey MeshPartPayload::getKey() const { + ItemKey::Builder builder; + builder.withTypeShape(); + if (!model->isVisible()) { - return ItemKey::Builder().withInvisible().build(); + builder.withInvisible(); } - auto geometry = model->getGeometry(); - if (!geometry.isNull()) { - auto drawMaterial = geometry->getShapeMaterial(_shapeID); - if (drawMaterial) { - auto matKey = drawMaterial->_material->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { - return ItemKey::Builder::transparentShape(); - } else { - return ItemKey::Builder::opaqueShape(); - } + + if (_isBlendShaped || _isSkinned) { + builder.withDeformed(); + } + + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTransparent() || matKey.isTransparentMap()) { + builder.withTransparent(); } } - - // Return opaque for lack of a better idea - return ItemKey::Builder::opaqueShape(); + + return builder.build(); } render::Item::Bound MeshPartPayload::getBound() const { @@ -84,313 +391,139 @@ void MeshPartPayload::render(RenderArgs* args) const { return model->renderPart(args, meshIndex, partIndex, _shapeID, this); } +void MeshPartPayload::drawCall(gpu::Batch& batch) const { + batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); +} + void MeshPartPayload::bindMesh(gpu::Batch& batch) const { - const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); - const std::vector>& networkMeshes = model->_geometry->getMeshes(); - const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); - const FBXMesh& mesh = geometry.meshes.at(meshIndex); - // auto drawMesh = networkMesh._mesh; - - if (mesh.blendshapes.isEmpty()) { + if (!_isBlendShaped) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); batch.setInputFormat((_drawMesh->getVertexFormat())); - auto inputStream = _drawMesh->makeBufferStream(); - batch.setInputStream(0, inputStream); + batch.setInputStream(0, _drawMesh->getVertexStream()); } else { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); + batch.setInputFormat((_drawMesh->getVertexFormat())); - + batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); - - auto inputStream = _drawMesh->makeBufferStream().makeRangedStream(2); - - batch.setInputStream(2, inputStream); + batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); } - if (mesh.colors.isEmpty()) { + // TODO: Get rid of that extra call + if (!_hasColorAttrib) { batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } } -void MeshPartPayload::drawCall(gpu::Batch& batch) const { - batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); -} -/* -void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) { - // PROFILE_RANGE(__FUNCTION__); - PerformanceTimer perfTimer("Model::renderPart"); - if (!_readyWhenAdded) { - return; // bail asap +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const { + if (!_drawMaterial) { + return; } - + auto textureCache = DependencyManager::get(); - - gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; - - - // Capture the view matrix once for the rendering of this model - if (_transforms.empty()) { - _transforms.push_back(Transform()); - } - - auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME - - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const std::vector>& networkMeshes = _geometry->getMeshes(); - - auto networkMaterial = _geometry->getShapeMaterial(shapeID); - if (!networkMaterial) { - return; - }; - auto material = networkMaterial->_material; - if (!material) { - return; - } - - // TODO: Not yet - // auto drawMesh = _geometry->getShapeMesh(shapeID); - // auto drawPart = _geometry->getShapePart(shapeID); - - // guard against partially loaded meshes - if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) { - return; - } - - updateClusterMatrices(); - - const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); - const FBXMesh& mesh = geometry.meshes.at(meshIndex); - const MeshState& state = _meshStates.at(meshIndex); - - auto drawMesh = networkMesh._mesh; - - - auto drawMaterialKey = material->getKey(); - bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - - bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); - bool hasSpecular = drawMaterialKey.isGlossMap(); // !drawMaterial->specularTextureName.isEmpty(); //mesh.hasSpecularTexture(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); // !drawMaterial->emissiveTextureName.isEmpty(); //mesh.hasEmissiveTexture(); - bool isSkinned = state.clusterMatrices.size() > 1; - bool wireframe = isWireframe(); - - // render the part bounding box -#ifdef DEBUG_BOUNDING_PARTS - { - AABox partBounds = getPartBounds(meshIndex, partIndex); - bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE; - - glm::vec4 cubeColor; - if (isSkinned) { - cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f); - } else if (inView) { - cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f); + + batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer()); + + auto materialKey = _drawMaterial->getKey(); + auto textureMaps = _drawMaterial->getTextureMaps(); + glm::mat4 texcoordTransform[2]; + + // Diffuse + if (materialKey.isDiffuseMap()) { + auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; + if (diffuseMap && diffuseMap->isDefined()) { + batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); + + if (!diffuseMap->getTextureTransform().isIdentity()) { + diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); + } } else { - cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); + batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); } - - Transform transform; - transform.setTranslation(partBounds.calcCenter()); - transform.setScale(partBounds.getDimensions()); - batch.setModelTransform(transform); - DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + } else { + batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); } -#endif //def DEBUG_BOUNDING_PARTS - - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + + // Normal map + if (materialKey.isNormalMap()) { + auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; + if (normalMap && normalMap->isDefined()) { + batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView()); + + // texcoord are assumed to be the same has diffuse + } else { + batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture()); + } + } else { + batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr); } - - Locations* locations = nullptr; - pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, - args, locations); - - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { - _meshGroupsKnown = false; // regenerate these lists next time around. - _readyWhenAdded = false; // in case any of our users are using scenes - invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return; // FIXME! + + // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that + if (materialKey.isGlossMap()) { + auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; + if (specularMap && specularMap->isDefined()) { + batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView()); + + // texcoord are assumed to be the same has diffuse + } else { + batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); + } + } else { + batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr); } - - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return; // FIXME! + + // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too + if (materialKey.isLightmapMap()) { + auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; + + if (lightmapMap && lightmapMap->isDefined()) { + batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); + + auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); + batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); + + if (!lightmapMap->getTextureTransform().isIdentity()) { + lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); + } + } else { + batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); + } + } else { + batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr); } - - // Transform stage - if (_transforms.empty()) { - _transforms.push_back(Transform()); + + // Texcoord transforms ? + if (locations->texcoordMatrices >= 0) { + batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); } - - if (isSkinned) { +} + +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { + Transform transform; + // Still relying on the raw data from the + const Model::MeshState& state = model->_meshStates.at(meshIndex); + + if (_isSkinned) { const float* bones; - if (_cauterizeBones) { + if (model->_cauterizeBones) { bones = (const float*)state.cauterizedClusterMatrices.constData(); } else { bones = (const float*)state.clusterMatrices.constData(); } batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones); - _transforms[0] = Transform(); - _transforms[0].preTranslate(_translation); - } else { - if (_cauterizeBones) { - _transforms[0] = Transform(state.cauterizedClusterMatrices[0]); - } else { - _transforms[0] = Transform(state.clusterMatrices[0]); - } - _transforms[0].preTranslate(_translation); - } - batch.setModelTransform(_transforms[0]); - - auto drawPart = drawMesh->getPartBuffer().get(partIndex); - - if (mesh.blendshapes.isEmpty()) { - batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); - - batch.setInputFormat((drawMesh->getVertexFormat())); - auto inputStream = drawMesh->makeBufferStream(); - - batch.setInputStream(0, inputStream); - } else { - batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0); - batch.setInputFormat((drawMesh->getVertexFormat())); - - batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3)); - - auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2); - - batch.setInputStream(2, inputStream); - } - - if (mesh.colors.isEmpty()) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } - - // guard against partially loaded meshes - if (partIndex >= mesh.parts.size()) { - return; - } - - -#ifdef WANT_DEBUG - if (material == nullptr) { - qCDebug(renderutils) << "WARNING: material == nullptr!!!"; - } -#endif - - { - - // apply material properties - if (mode != RenderArgs::SHADOW_RENDER_MODE) { -#ifdef WANT_DEBUG - qCDebug(renderutils) << "Material Changed ---------------------------------------------"; - qCDebug(renderutils) << "part INDEX:" << partIndex; - qCDebug(renderutils) << "NEW part.materialID:" << part.materialID; -#endif //def WANT_DEBUG - - if (locations->materialBufferUnit >= 0) { - batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); - } - - auto materialKey = material->getKey(); - auto textureMaps = material->getTextureMaps(); - glm::mat4 texcoordTransform[2]; - - // Diffuse - if (materialKey.isDiffuseMap()) { - auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; - if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); - - if (!diffuseMap->getTextureTransform().isIdentity()) { - diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); - } - } else { - batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); - } - } else { - batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); - } - - // Normal map - if ((locations->normalTextureUnit >= 0) && hasTangents) { - auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; - if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView()); - - // texcoord are assumed to be the same has diffuse - } else { - batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture()); - } - } else { - batch.setResourceTexture(NORMAL_MAP_SLOT, nullptr); - } - - // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that - if ((locations->specularTextureUnit >= 0) && materialKey.isGlossMap()) { - auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; - if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView()); - - // texcoord are assumed to be the same has diffuse - } else { - batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); - } - } else { - batch.setResourceTexture(SPECULAR_MAP_SLOT, nullptr); - } - - // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too - if ((locations->emissiveTextureUnit >= 0) && materialKey.isLightmapMap()) { - auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; - - if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); - - auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); - batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); - - if (!lightmapMap->getTextureTransform().isIdentity()) { - lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); - } - } - else { - batch.setResourceTexture(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); - } - } else { - batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr); - } - - // Texcoord transforms ? - if (locations->texcoordMatrices >= 0) { - batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); - } - - // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { - PerformanceTimer perfTimer("DLE->setupTransparent()"); - - DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); - } - - - if (args) { - args->_details._materialSwitches++; - } - } - } - if (args) { - const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE; + transform.preTranslate(model->_translation); + } else { + if (model->_cauterizeBones) { + transform = Transform(state.cauterizedClusterMatrices[0]); + } else { + transform = Transform(state.clusterMatrices[0]); + } + transform.preTranslate(model->_translation); } + batch.setModelTransform(transform); } -*/ \ No newline at end of file + diff --git a/libraries/render-utils/src/ModelRenderPayload.h b/libraries/render-utils/src/ModelRenderPayload.h index bee7c186b9..53285f5780 100644 --- a/libraries/render-utils/src/ModelRenderPayload.h +++ b/libraries/render-utils/src/ModelRenderPayload.h @@ -22,6 +22,148 @@ class Model; +class ModelRender { +public: + + static const int MATERIAL_GPU_SLOT = 3; + static const int DIFFUSE_MAP_SLOT = 0; + static const int NORMAL_MAP_SLOT = 1; + static const int SPECULAR_MAP_SLOT = 2; + static const int LIGHTMAP_MAP_SLOT = 3; + static const int LIGHT_BUFFER_SLOT = 4; + + class Locations { + public: + int tangent; + int alphaThreshold; + int texcoordMatrices; + int diffuseTextureUnit; + int normalTextureUnit; + int specularTextureUnit; + int emissiveTextureUnit; + int emissiveParams; + int glowIntensity; + int normalFittingMapUnit; + int materialBufferUnit; + int clusterMatrices; + int clusterIndices; + int clusterWeights; + int lightBufferUnit; + }; + + static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, + Locations*& locations); + + class RenderKey { + public: + enum FlagBit { + IS_TRANSLUCENT_FLAG = 0, + HAS_LIGHTMAP_FLAG, + HAS_TANGENTS_FLAG, + HAS_SPECULAR_FLAG, + HAS_EMISSIVE_FLAG, + IS_SKINNED_FLAG, + IS_STEREO_FLAG, + IS_DEPTH_ONLY_FLAG, + IS_SHADOW_FLAG, + IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" + IS_WIREFRAME_FLAG, + + NUM_FLAGS, + }; + + enum Flag { + IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG), + HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG), + HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG), + HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG), + HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG), + IS_SKINNED = (1 << IS_SKINNED_FLAG), + IS_STEREO = (1 << IS_STEREO_FLAG), + IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG), + IS_SHADOW = (1 << IS_SHADOW_FLAG), + IS_MIRROR = (1 << IS_MIRROR_FLAG), + IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG), + }; + typedef unsigned short Flags; + + + + bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } + + bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); } + bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); } + bool hasTangents() const { return isFlag(HAS_TANGENTS); } + bool hasSpecular() const { return isFlag(HAS_SPECULAR); } + bool hasEmissive() const { return isFlag(HAS_EMISSIVE); } + bool isSkinned() const { return isFlag(IS_SKINNED); } + bool isStereo() const { return isFlag(IS_STEREO); } + bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); } + bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing + bool isMirror() const { return isFlag(IS_MIRROR); } + bool isWireFrame() const { return isFlag(IS_WIREFRAME); } + + Flags _flags = 0; + short _spare = 0; + + int getRaw() { return *reinterpret_cast(this); } + + + RenderKey( + bool translucent, bool hasLightmap, + bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : + RenderKey((translucent ? IS_TRANSLUCENT : 0) + | (hasLightmap ? HAS_LIGHTMAP : 0) + | (hasTangents ? HAS_TANGENTS : 0) + | (hasSpecular ? HAS_SPECULAR : 0) + | (isSkinned ? IS_SKINNED : 0) + | (isWireframe ? IS_WIREFRAME : 0) + ) {} + + RenderKey(RenderArgs::RenderMode mode, + bool translucent, float alphaThreshold, bool hasLightmap, + bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : + RenderKey(((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) + | (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly + | (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0) + | (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0) + | (isSkinned ? IS_SKINNED : 0) + | (isWireframe ? IS_WIREFRAME : 0) + | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0) + | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0) + | ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR : 0) + ) {} + + RenderKey(int bitmask) : _flags(bitmask) {} + }; + + + class RenderPipeline { + public: + gpu::PipelinePointer _pipeline; + std::shared_ptr _locations; + RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : + _pipeline(pipeline), _locations(locations) {} + }; + + typedef std::unordered_map BaseRenderPipelineMap; + class RenderPipelineLib : public BaseRenderPipelineMap { + public: + typedef RenderKey Key; + + + void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); + + void initLocations(gpu::ShaderPointer& program, Locations& locations); + }; + static RenderPipelineLib _renderPipelineLib; + + static const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib(); + +}; + + class MeshPartPayload { public: MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex); @@ -41,15 +183,30 @@ public: void render(RenderArgs* args) const; // MeshPartPayload functions to perform render - void bindMesh(gpu::Batch& batch) const; void drawCall(gpu::Batch& batch) const; - + void bindMesh(gpu::Batch& batch) const; + void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const; + void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const; + + + void initCache(); + + // Payload resource cached values model::MeshPointer _drawMesh; model::Mesh::Part _drawPart; model::MaterialPointer _drawMaterial; - + bool _hasColorAttrib = false; + bool _isSkinned = false; + bool _isBlendShaped = false; + mutable render::Item::Bound _bound; mutable bool _isBoundInvalid = true; }; +namespace render { + template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); + template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); + template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); +} + #endif // hifi_ModelRenderPayload_h \ No newline at end of file diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh new file mode 100644 index 0000000000..c1f45f951b --- /dev/null +++ b/libraries/render-utils/src/Skinning.slh @@ -0,0 +1,68 @@ + +<@if not SKINNING_SLH@> +<@def SKINNING_SLH@> + +const int MAX_TEXCOORDS = 2; +const int MAX_CLUSTERS = 128; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 clusterMatrices[MAX_CLUSTERS]; + +void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; + newPosition += clusterMatrix * inPosition * clusterWeight; + } + + skinnedPosition = newPosition; +} + +void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, + out vec4 skinnedPosition, out vec3 skinnedNormal) { + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + } + + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; +} + +void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, + out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; + } + + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; + skinnedTangent = newTangent.xyz; +} + + +<@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/skin_model.slv b/libraries/render-utils/src/skin_model.slv index 53e68727fb..bb2058b5f8 100755 --- a/libraries/render-utils/src/skin_model.slv +++ b/libraries/render-utils/src/skin_model.slv @@ -18,11 +18,8 @@ <$declareStandardTransform()$> -const int MAX_TEXCOORDS = 2; -const int MAX_CLUSTERS = 128; -const int INDICES_PER_VERTEX = 4; +<@include Skinning.slh@> -uniform mat4 clusterMatrices[MAX_CLUSTERS]; uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; out vec4 _position; @@ -32,13 +29,9 @@ out vec3 _color; void main(void) { vec4 position = vec4(0.0, 0.0, 0.0, 0.0); - vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); - for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])]; - float clusterWeight = inSkinClusterWeight[i]; - position += clusterMatrix * inPosition * clusterWeight; - interpolatedNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - } + vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0); + + skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal); // pass along the diffuse color _color = inColor.rgb; diff --git a/libraries/render-utils/src/skin_model_normal_map.slv b/libraries/render-utils/src/skin_model_normal_map.slv index 4c558939d8..f198cb5f77 100755 --- a/libraries/render-utils/src/skin_model_normal_map.slv +++ b/libraries/render-utils/src/skin_model_normal_map.slv @@ -18,11 +18,8 @@ <$declareStandardTransform()$> -const int MAX_TEXCOORDS = 2; -const int MAX_CLUSTERS = 128; -const int INDICES_PER_VERTEX = 4; +<@include Skinning.slh@> -uniform mat4 clusterMatrices[MAX_CLUSTERS]; uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; out vec4 _position; @@ -35,13 +32,8 @@ void main(void) { vec4 position = vec4(0.0, 0.0, 0.0, 0.0); vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0); - for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])]; - float clusterWeight = inSkinClusterWeight[i]; - position += clusterMatrix * inPosition * clusterWeight; - interpolatedNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - interpolatedTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; - } + + skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz); // pass along the diffuse color _color = inColor.rgb; diff --git a/libraries/render-utils/src/skin_model_shadow.slv b/libraries/render-utils/src/skin_model_shadow.slv index 6cb4da25f4..9c00f9065b 100755 --- a/libraries/render-utils/src/skin_model_shadow.slv +++ b/libraries/render-utils/src/skin_model_shadow.slv @@ -16,18 +16,11 @@ <@include gpu/Transform.slh@> <$declareStandardTransform()$> -const int MAX_CLUSTERS = 128; -const int INDICES_PER_VERTEX = 4; - -uniform mat4 clusterMatrices[MAX_CLUSTERS]; +<@include Skinning.slh@> void main(void) { vec4 position = vec4(0.0, 0.0, 0.0, 0.0); - for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])]; - float clusterWeight = inSkinClusterWeight[i]; - position += clusterMatrix * inPosition * clusterWeight; - } + skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position); // standard transform TransformCamera cam = getTransformCamera(); From 4270b83c0f09f5d178c538b4a9cd4998113e6537 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 5 Oct 2015 23:33:58 -0700 Subject: [PATCH 10/19] Uniform buffer for skeleton joint bind pose --- .../render-utils/src/ModelRenderPayload.cpp | 28 ++++---------- .../render-utils/src/ModelRenderPayload.h | 10 ++--- libraries/render-utils/src/Skinning.slh | 38 ++++++++++--------- 3 files changed, 33 insertions(+), 43 deletions(-) diff --git a/libraries/render-utils/src/ModelRenderPayload.cpp b/libraries/render-utils/src/ModelRenderPayload.cpp index e4998e445a..31321f402f 100644 --- a/libraries/render-utils/src/ModelRenderPayload.cpp +++ b/libraries/render-utils/src/ModelRenderPayload.cpp @@ -170,6 +170,8 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; + + slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), ModelRender::SKINNING_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT)); @@ -258,9 +260,7 @@ void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); - locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex"); - locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight"); + locations.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); } @@ -322,10 +322,6 @@ namespace render { template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { return payload->render(args); } - - /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) { - return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); - }*/ } using namespace render; @@ -502,28 +498,20 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio } void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { - Transform transform; - // Still relying on the raw data from the + // Still relying on the raw data from the model const Model::MeshState& state = model->_meshStates.at(meshIndex); - if (_isSkinned) { - const float* bones; - if (model->_cauterizeBones) { - bones = (const float*)state.cauterizedClusterMatrices.constData(); - } else { - bones = (const float*)state.clusterMatrices.constData(); - } - batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones); - - transform.preTranslate(model->_translation); + Transform transform; + if (state.clusterBuffer) { + batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer); } else { if (model->_cauterizeBones) { transform = Transform(state.cauterizedClusterMatrices[0]); } else { transform = Transform(state.clusterMatrices[0]); } - transform.preTranslate(model->_translation); } + transform.preTranslate(model->_translation); batch.setModelTransform(transform); } diff --git a/libraries/render-utils/src/ModelRenderPayload.h b/libraries/render-utils/src/ModelRenderPayload.h index 53285f5780..c193a77540 100644 --- a/libraries/render-utils/src/ModelRenderPayload.h +++ b/libraries/render-utils/src/ModelRenderPayload.h @@ -24,7 +24,8 @@ class Model; class ModelRender { public: - + + static const int SKINNING_GPU_SLOT = 2; static const int MATERIAL_GPU_SLOT = 3; static const int DIFFUSE_MAP_SLOT = 0; static const int NORMAL_MAP_SLOT = 1; @@ -34,7 +35,6 @@ public: class Locations { public: - int tangent; int alphaThreshold; int texcoordMatrices; int diffuseTextureUnit; @@ -45,9 +45,7 @@ public: int glowIntensity; int normalFittingMapUnit; int materialBufferUnit; - int clusterMatrices; - int clusterIndices; - int clusterWeights; + int skinClusterBufferUnit; int lightBufferUnit; }; @@ -159,7 +157,7 @@ public: }; static RenderPipelineLib _renderPipelineLib; - static const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib(); + static const RenderPipelineLib& getRenderPipelineLib(); }; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index c1f45f951b..747f18ab34 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -1,21 +1,25 @@ - -<@if not SKINNING_SLH@> + +<@if not SKINNING_SLH@> <@def SKINNING_SLH@> const int MAX_TEXCOORDS = 2; const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; -uniform mat4 clusterMatrices[MAX_CLUSTERS]; +//uniform mat4 clusterMatrices[MAX_CLUSTERS]; + +layout(std140) uniform skinClusterBuffer { + mat4 clusterMatrices[MAX_CLUSTERS]; +}; void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); @@ -43,8 +47,8 @@ void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPo skinnedPosition = newPosition; skinnedNormal = newNormal.xyz; -} - +} + void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); @@ -62,7 +66,7 @@ void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, ve skinnedPosition = newPosition; skinnedNormal = newNormal.xyz; skinnedTangent = newTangent.xyz; -} - - +} + + <@endif@> \ No newline at end of file From fc7f0c77a5e06f82d773e728c2e4681d87a445bd Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 00:20:51 -0700 Subject: [PATCH 11/19] Rename ModelRenderPayload files to ModelRenderItem --- libraries/render-utils/src/Model.cpp | 2 +- .../src/{ModelRenderPayload.cpp => ModelRenderItem.cpp} | 4 ++-- .../src/{ModelRenderPayload.h => ModelRenderItem.h} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename libraries/render-utils/src/{ModelRenderPayload.cpp => ModelRenderItem.cpp} (99%) rename libraries/render-utils/src/{ModelRenderPayload.h => ModelRenderItem.h} (99%) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a86cd305dc..0d9a403923 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -25,7 +25,7 @@ #include "AnimationHandle.h" #include "DeferredLightingEffect.h" #include "Model.h" -#include "ModelRenderPayload.h" +#include "ModelRenderItem.h" #include "RenderUtilsLogging.h" diff --git a/libraries/render-utils/src/ModelRenderPayload.cpp b/libraries/render-utils/src/ModelRenderItem.cpp similarity index 99% rename from libraries/render-utils/src/ModelRenderPayload.cpp rename to libraries/render-utils/src/ModelRenderItem.cpp index 31321f402f..e2118a8f0b 100644 --- a/libraries/render-utils/src/ModelRenderPayload.cpp +++ b/libraries/render-utils/src/ModelRenderItem.cpp @@ -1,5 +1,5 @@ // -// ModelRenderPayload.cpp +// ModelRenderItem.cpp // interface/src/renderer // // Created by Sam Gateau on 10/3/15. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ModelRenderPayload.h" +#include "ModelRenderItem.h" #include "DeferredLightingEffect.h" diff --git a/libraries/render-utils/src/ModelRenderPayload.h b/libraries/render-utils/src/ModelRenderItem.h similarity index 99% rename from libraries/render-utils/src/ModelRenderPayload.h rename to libraries/render-utils/src/ModelRenderItem.h index c193a77540..658d2d2cae 100644 --- a/libraries/render-utils/src/ModelRenderPayload.h +++ b/libraries/render-utils/src/ModelRenderItem.h @@ -1,5 +1,5 @@ // -// ModelRenderPayload.h +// ModelRenderItem.h // interface/src/renderer // // Created by Sam Gateau on 10/3/15. From 59afbf1a04ba3c19bb78c518b9748ece6b2d4e5c Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 01:15:53 -0700 Subject: [PATCH 12/19] Remove the renderPart call from model.cpp and put the code path in the MeshPartPayload::render() --- libraries/render-utils/src/Model.cpp | 141 ------------------ libraries/render-utils/src/Model.h | 1 - .../render-utils/src/ModelRenderItem.cpp | 131 +++++++++++++++- 3 files changed, 126 insertions(+), 147 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0d9a403923..9a2d9e3dc5 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1140,147 +1140,6 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { return AABox(); } -void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID, const MeshPartPayload* payload) { -// PROFILE_RANGE(__FUNCTION__); - PerformanceTimer perfTimer("Model::renderPart"); - if (!_readyWhenAdded) { - return; // bail asap - } - - auto textureCache = DependencyManager::get(); - - gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; - - auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME - - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const std::vector>& networkMeshes = _geometry->getMeshes(); - - auto networkMaterial = _geometry->getShapeMaterial(shapeID); - if (!networkMaterial) { - return; - }; - auto material = networkMaterial->_material; - if (!material) { - return; - } - - // TODO: Not yet - // auto drawMesh = _geometry->getShapeMesh(shapeID); - // auto drawPart = _geometry->getShapePart(shapeID); - - // guard against partially loaded meshes - if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) { - return; - } - - updateClusterMatrices(); - - const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); - const FBXMesh& mesh = geometry.meshes.at(meshIndex); - const MeshState& state = _meshStates.at(meshIndex); - - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { - _meshGroupsKnown = false; // regenerate these lists next time around. - _readyWhenAdded = false; // in case any of our users are using scenes - invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return; // FIXME! - } - - - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return; // FIXME! - } - - auto drawMaterialKey = material->getKey(); - bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - - bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); - bool hasSpecular = drawMaterialKey.isGlossMap(); // !drawMaterial->specularTextureName.isEmpty(); //mesh.hasSpecularTexture(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); // !drawMaterial->emissiveTextureName.isEmpty(); //mesh.hasEmissiveTexture(); - bool isSkinned = state.clusterMatrices.size() > 1; - bool wireframe = isWireframe(); - - // render the part bounding box - #ifdef DEBUG_BOUNDING_PARTS - { - AABox partBounds = getPartBounds(meshIndex, partIndex); - bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE; - - glm::vec4 cubeColor; - if (isSkinned) { - cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f); - } else if (inView) { - cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f); - } else { - cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); - } - - Transform transform; - transform.setTranslation(partBounds.calcCenter()); - transform.setScale(partBounds.getDimensions()); - batch.setModelTransform(transform); - DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); - } - #endif //def DEBUG_BOUNDING_PARTS - - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } - - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, - args, locations); - - - payload->bindTransform(batch, locations); - - payload->bindMesh(batch); - - // guard against partially loaded meshes - if (partIndex >= mesh.parts.size()) { - return; - } - - - #ifdef WANT_DEBUG - if (material == nullptr) { - qCDebug(renderutils) << "WARNING: material == nullptr!!!"; - } - #endif - - { - // apply material properties - payload->bindMaterial(batch, locations); - - - // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { - PerformanceTimer perfTimer("DLE->setupTransparent()"); - - DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); - } - if (args) { - args->_details._materialSwitches++; - } - } - - { - PerformanceTimer perfTimer("batch.drawIndexed()"); - payload->drawCall(batch); - } - - if (args) { - const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += payload->_drawPart._numIndices / INDICES_PER_TRIANGLE; - } -} - void Model::segregateMeshGroups() { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const std::vector>& networkMeshes = _geometry->getMeshes(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 108480e4ef..8937ecb94c 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -89,7 +89,6 @@ public: bool isVisible() const { return _isVisible; } AABox getPartBounds(int meshIndex, int partIndex); - void renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID, const MeshPartPayload* payload); bool maybeStartBlender(); diff --git a/libraries/render-utils/src/ModelRenderItem.cpp b/libraries/render-utils/src/ModelRenderItem.cpp index e2118a8f0b..4ddb7fac66 100644 --- a/libraries/render-utils/src/ModelRenderItem.cpp +++ b/libraries/render-utils/src/ModelRenderItem.cpp @@ -11,6 +11,8 @@ #include "ModelRenderItem.h" +#include + #include "DeferredLightingEffect.h" #include "Model.h" @@ -268,7 +270,7 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations) { - // PerformanceTimer perfTimer("Model::pickPrograms"); + PerformanceTimer perfTimer("ModelRender::pickPrograms"); getRenderPipelineLib(); RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); @@ -383,10 +385,6 @@ render::Item::Bound MeshPartPayload::getBound() const { return _bound; } -void MeshPartPayload::render(RenderArgs* args) const { - return model->renderPart(args, meshIndex, partIndex, _shapeID, this); -} - void MeshPartPayload::drawCall(gpu::Batch& batch) const { batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); } @@ -515,3 +513,126 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati batch.setModelTransform(transform); } + +void MeshPartPayload::render(RenderArgs* args) const { + PerformanceTimer perfTimer("MeshPartPayload::render"); + if (!model->_readyWhenAdded) { + return; // bail asap + } + + gpu::Batch& batch = *(args->_batch); + auto mode = args->_renderMode; + + auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME + + const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); + const std::vector>& networkMeshes = model->_geometry->getMeshes(); + + // guard against partially loaded meshes + if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)model->_meshStates.size() ) { + return; + } + + // Back to model to update the cluster matrices right now + model->updateClusterMatrices(); + + const FBXMesh& mesh = geometry.meshes.at(meshIndex); + + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { + model->_meshGroupsKnown = false; // regenerate these lists next time around. + model->_readyWhenAdded = false; // in case any of our users are using scenes + model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return; // FIXME! + } + + + int vertexCount = mesh.vertices.size(); + if (vertexCount == 0) { + // sanity check + return; // FIXME! + } + + + // guard against partially loaded meshes + if (partIndex >= mesh.parts.size()) { + return; + } + + model::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + + bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); + bool hasSpecular = drawMaterialKey.isGlossMap(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); + bool isSkinned = _isSkinned; + bool wireframe = model->isWireframe(); + + // render the part bounding box +#ifdef DEBUG_BOUNDING_PARTS + { + AABox partBounds = getPartBounds(meshIndex, partIndex); + bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE; + + glm::vec4 cubeColor; + if (isSkinned) { + cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f); + } else if (inView) { + cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f); + } else { + cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); + } + + Transform transform; + transform.setTranslation(partBounds.calcCenter()); + transform.setScale(partBounds.getDimensions()); + batch.setModelTransform(transform); + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + } +#endif //def DEBUG_BOUNDING_PARTS + + if (wireframe) { + translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + } + + ModelRender::Locations* locations = nullptr; + ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + args, locations); + + + // Bind the model transform and the skinCLusterMatrices if needed + bindTransform(batch, locations); + + //Bind the index buffer and vertex buffer and Blend shapes if needed + bindMesh(batch); + + // apply material properties + bindMaterial(batch, locations); + + + // TODO: We should be able to do that just in the renderTransparentJob + if (translucentMesh && locations->lightBufferUnit >= 0) { + PerformanceTimer perfTimer("DLE->setupTransparent()"); + + DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); + } + if (args) { + args->_details._materialSwitches++; + } + + // Draw! + { + PerformanceTimer perfTimer("batch.drawIndexed()"); + drawCall(batch); + } + + if (args) { + const int INDICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; + } +} + From c92a6d58ab0d3d97f373683906d702e0d4cbd807 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 09:46:32 -0700 Subject: [PATCH 13/19] Dispatch classes in their properly named files to appease the coding standard gods --- .../render-utils/src/MeshPartPayload.cpp | 349 ++++++++++++++++++ libraries/render-utils/src/MeshPartPayload.h | 69 ++++ libraries/render-utils/src/Model.cpp | 3 +- libraries/render-utils/src/Model.h | 2 - .../{ModelRenderItem.cpp => ModelRender.cpp} | 347 +---------------- .../src/{ModelRenderItem.h => ModelRender.h} | 69 +--- 6 files changed, 436 insertions(+), 403 deletions(-) create mode 100644 libraries/render-utils/src/MeshPartPayload.cpp create mode 100644 libraries/render-utils/src/MeshPartPayload.h rename libraries/render-utils/src/{ModelRenderItem.cpp => ModelRender.cpp} (53%) rename libraries/render-utils/src/{ModelRenderItem.h => ModelRender.h} (76%) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp new file mode 100644 index 0000000000..d1db4e6c7f --- /dev/null +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -0,0 +1,349 @@ +// +// MeshPartPayload.cpp +// interface/src/renderer +// +// Created by Sam Gateau on 10/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MeshPartPayload.h" + +#include + +#include "DeferredLightingEffect.h" + +#include "Model.h" + +namespace render { + template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); + } + // Return opaque for lack of a better idea + return ItemKey::Builder::opaqueShape(); + } + + template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return render::Item::Bound(); + } + template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); + } +} + +using namespace render; + +MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : + model(model), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) +{ + initCache(); +} + +void MeshPartPayload::initCache() { + const std::vector>& networkMeshes = model->_geometry->getMeshes(); + const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); + _drawMesh = networkMesh._mesh; + + const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); + const FBXMesh& mesh = geometry.meshes.at(meshIndex); + _hasColorAttrib = !mesh.colors.isEmpty(); + _isBlendShaped = !mesh.blendshapes.isEmpty(); + _isSkinned = !mesh.clusterIndices.isEmpty(); + + + _drawPart = _drawMesh->getPartBuffer().get(partIndex); + + auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID); + if (networkMaterial) { + _drawMaterial = networkMaterial->_material; + }; + +} + +render::ItemKey MeshPartPayload::getKey() const { + ItemKey::Builder builder; + builder.withTypeShape(); + + if (!model->isVisible()) { + builder.withInvisible(); + } + + if (_isBlendShaped || _isSkinned) { + builder.withDeformed(); + } + + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTransparent() || matKey.isTransparentMap()) { + builder.withTransparent(); + } + } + + return builder.build(); +} + +render::Item::Bound MeshPartPayload::getBound() const { + if (_isBoundInvalid) { + model->getPartBounds(meshIndex, partIndex); + _isBoundInvalid = false; + } + return _bound; +} + +void MeshPartPayload::drawCall(gpu::Batch& batch) const { + batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); +} + +void MeshPartPayload::bindMesh(gpu::Batch& batch) const { + if (!_isBlendShaped) { + batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); + + batch.setInputFormat((_drawMesh->getVertexFormat())); + + batch.setInputStream(0, _drawMesh->getVertexStream()); + } else { + batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); + + batch.setInputFormat((_drawMesh->getVertexFormat())); + + batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); + batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); + } + + // TODO: Get rid of that extra call + if (!_hasColorAttrib) { + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } +} + +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const { + if (!_drawMaterial) { + return; + } + + auto textureCache = DependencyManager::get(); + + batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer()); + + auto materialKey = _drawMaterial->getKey(); + auto textureMaps = _drawMaterial->getTextureMaps(); + glm::mat4 texcoordTransform[2]; + + // Diffuse + if (materialKey.isDiffuseMap()) { + auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; + if (diffuseMap && diffuseMap->isDefined()) { + batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); + + if (!diffuseMap->getTextureTransform().isIdentity()) { + diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); + } + } else { + batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); + } + } else { + batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); + } + + // Normal map + if (materialKey.isNormalMap()) { + auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; + if (normalMap && normalMap->isDefined()) { + batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView()); + + // texcoord are assumed to be the same has diffuse + } else { + batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture()); + } + } else { + batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr); + } + + // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that + if (materialKey.isGlossMap()) { + auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; + if (specularMap && specularMap->isDefined()) { + batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView()); + + // texcoord are assumed to be the same has diffuse + } else { + batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); + } + } else { + batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr); + } + + // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too + if (materialKey.isLightmapMap()) { + auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; + + if (lightmapMap && lightmapMap->isDefined()) { + batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); + + auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); + batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); + + if (!lightmapMap->getTextureTransform().isIdentity()) { + lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); + } + } else { + batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); + } + } else { + batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr); + } + + // Texcoord transforms ? + if (locations->texcoordMatrices >= 0) { + batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); + } +} + +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { + // Still relying on the raw data from the model + const Model::MeshState& state = model->_meshStates.at(meshIndex); + + Transform transform; + if (state.clusterBuffer) { + batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer); + } else { + if (model->_cauterizeBones) { + transform = Transform(state.cauterizedClusterMatrices[0]); + } else { + transform = Transform(state.clusterMatrices[0]); + } + } + transform.preTranslate(model->_translation); + batch.setModelTransform(transform); +} + + +void MeshPartPayload::render(RenderArgs* args) const { + PerformanceTimer perfTimer("MeshPartPayload::render"); + if (!model->_readyWhenAdded) { + return; // bail asap + } + + gpu::Batch& batch = *(args->_batch); + auto mode = args->_renderMode; + + auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME + + const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); + const std::vector>& networkMeshes = model->_geometry->getMeshes(); + + // guard against partially loaded meshes + if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)model->_meshStates.size() ) { + return; + } + + // Back to model to update the cluster matrices right now + model->updateClusterMatrices(); + + const FBXMesh& mesh = geometry.meshes.at(meshIndex); + + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { + model->_meshGroupsKnown = false; // regenerate these lists next time around. + model->_readyWhenAdded = false; // in case any of our users are using scenes + model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return; // FIXME! + } + + + int vertexCount = mesh.vertices.size(); + if (vertexCount == 0) { + // sanity check + return; // FIXME! + } + + + // guard against partially loaded meshes + if (partIndex >= mesh.parts.size()) { + return; + } + + model::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + + bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); + bool hasSpecular = drawMaterialKey.isGlossMap(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); + bool isSkinned = _isSkinned; + bool wireframe = model->isWireframe(); + + // render the part bounding box +#ifdef DEBUG_BOUNDING_PARTS + { + AABox partBounds = getPartBounds(meshIndex, partIndex); + bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE; + + glm::vec4 cubeColor; + if (isSkinned) { + cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f); + } else if (inView) { + cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f); + } else { + cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); + } + + Transform transform; + transform.setTranslation(partBounds.calcCenter()); + transform.setScale(partBounds.getDimensions()); + batch.setModelTransform(transform); + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + } +#endif //def DEBUG_BOUNDING_PARTS + + if (wireframe) { + translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + } + + ModelRender::Locations* locations = nullptr; + ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + args, locations); + + + // Bind the model transform and the skinCLusterMatrices if needed + bindTransform(batch, locations); + + //Bind the index buffer and vertex buffer and Blend shapes if needed + bindMesh(batch); + + // apply material properties + bindMaterial(batch, locations); + + + // TODO: We should be able to do that just in the renderTransparentJob + if (translucentMesh && locations->lightBufferUnit >= 0) { + PerformanceTimer perfTimer("DLE->setupTransparent()"); + + DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); + } + if (args) { + args->_details._materialSwitches++; + } + + // Draw! + { + PerformanceTimer perfTimer("batch.drawIndexed()"); + drawCall(batch); + } + + if (args) { + const int INDICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; + } +} + diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h new file mode 100644 index 0000000000..7e476445e6 --- /dev/null +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -0,0 +1,69 @@ +// +// MeshPartPayload.h +// interface/src/renderer +// +// Created by Sam Gateau on 10/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MeshPartPayload_h +#define hifi_MeshPartPayload_h + +#include + +#include + +#include + +#include "ModelRender.h" + +class Model; + +class MeshPartPayload { +public: + MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex); + + typedef render::Payload Payload; + typedef Payload::DataPointer Pointer; + + Model* model; + int meshIndex; + int partIndex; + int _shapeID; + + // Render Item interface + render::ItemKey getKey() const; + render::Item::Bound getBound() const; + void render(RenderArgs* args) const; + + // MeshPartPayload functions to perform render + void drawCall(gpu::Batch& batch) const; + void bindMesh(gpu::Batch& batch) const; + void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const; + void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const; + + + void initCache(); + + // Payload resource cached values + model::MeshPointer _drawMesh; + model::Mesh::Part _drawPart; + model::MaterialPointer _drawMaterial; + bool _hasColorAttrib = false; + bool _isSkinned = false; + bool _isBlendShaped = false; + + mutable render::Item::Bound _bound; + mutable bool _isBoundInvalid = true; +}; + +namespace render { + template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); + template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); + template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); +} + +#endif // hifi_MeshPartPayload_h \ No newline at end of file diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9a2d9e3dc5..2fe95ef64f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -23,9 +23,8 @@ #include "AbstractViewStateInterface.h" #include "AnimationHandle.h" -#include "DeferredLightingEffect.h" #include "Model.h" -#include "ModelRenderItem.h" +#include "MeshPartPayload.h" #include "RenderUtilsLogging.h" diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 8937ecb94c..98341e1a3d 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -24,9 +24,7 @@ #include #include #include -#include #include -#include #include #include diff --git a/libraries/render-utils/src/ModelRenderItem.cpp b/libraries/render-utils/src/ModelRender.cpp similarity index 53% rename from libraries/render-utils/src/ModelRenderItem.cpp rename to libraries/render-utils/src/ModelRender.cpp index 4ddb7fac66..f6b93ce356 100644 --- a/libraries/render-utils/src/ModelRenderItem.cpp +++ b/libraries/render-utils/src/ModelRender.cpp @@ -1,5 +1,5 @@ // -// ModelRenderItem.cpp +// ModelRender.cpp // interface/src/renderer // // Created by Sam Gateau on 10/3/15. @@ -9,14 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ModelRenderItem.h" +#include "ModelRender.h" -#include +#include #include "DeferredLightingEffect.h" -#include "Model.h" - #include "model_vert.h" #include "model_shadow_vert.h" #include "model_normal_map_vert.h" @@ -172,8 +170,6 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; - - slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), ModelRender::SKINNING_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT)); @@ -262,7 +258,9 @@ void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); + locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); + locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex"); + locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight"); } @@ -270,7 +268,7 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations) { - PerformanceTimer perfTimer("ModelRender::pickPrograms"); + // PerformanceTimer perfTimer("Model::pickPrograms"); getRenderPipelineLib(); RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); @@ -305,334 +303,3 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b DependencyManager::get()->getNormalFittingTexture()); } } - -namespace render { - template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getKey(); - } - // Return opaque for lack of a better idea - return ItemKey::Builder::opaqueShape(); - } - - template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getBound(); - } - return render::Item::Bound(); - } - template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { - return payload->render(args); - } -} - -using namespace render; - -MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : - model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) -{ - initCache(); -} - -void MeshPartPayload::initCache() { - const std::vector>& networkMeshes = model->_geometry->getMeshes(); - const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); - _drawMesh = networkMesh._mesh; - - const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); - const FBXMesh& mesh = geometry.meshes.at(meshIndex); - _hasColorAttrib = !mesh.colors.isEmpty(); - _isBlendShaped = !mesh.blendshapes.isEmpty(); - _isSkinned = !mesh.clusterIndices.isEmpty(); - - - _drawPart = _drawMesh->getPartBuffer().get(partIndex); - - auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID); - if (networkMaterial) { - _drawMaterial = networkMaterial->_material; - }; - -} - -render::ItemKey MeshPartPayload::getKey() const { - ItemKey::Builder builder; - builder.withTypeShape(); - - if (!model->isVisible()) { - builder.withInvisible(); - } - - if (_isBlendShaped || _isSkinned) { - builder.withDeformed(); - } - - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { - builder.withTransparent(); - } - } - - return builder.build(); -} - -render::Item::Bound MeshPartPayload::getBound() const { - if (_isBoundInvalid) { - model->getPartBounds(meshIndex, partIndex); - _isBoundInvalid = false; - } - return _bound; -} - -void MeshPartPayload::drawCall(gpu::Batch& batch) const { - batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); -} - -void MeshPartPayload::bindMesh(gpu::Batch& batch) const { - if (!_isBlendShaped) { - batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); - - batch.setInputFormat((_drawMesh->getVertexFormat())); - - batch.setInputStream(0, _drawMesh->getVertexStream()); - } else { - batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); - - batch.setInputFormat((_drawMesh->getVertexFormat())); - - batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); - batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); - } - - // TODO: Get rid of that extra call - if (!_hasColorAttrib) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } -} - -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const { - if (!_drawMaterial) { - return; - } - - auto textureCache = DependencyManager::get(); - - batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer()); - - auto materialKey = _drawMaterial->getKey(); - auto textureMaps = _drawMaterial->getTextureMaps(); - glm::mat4 texcoordTransform[2]; - - // Diffuse - if (materialKey.isDiffuseMap()) { - auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; - if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); - - if (!diffuseMap->getTextureTransform().isIdentity()) { - diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); - } - } else { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); - } - } else { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); - } - - // Normal map - if (materialKey.isNormalMap()) { - auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; - if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView()); - - // texcoord are assumed to be the same has diffuse - } else { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture()); - } - } else { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr); - } - - // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that - if (materialKey.isGlossMap()) { - auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; - if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView()); - - // texcoord are assumed to be the same has diffuse - } else { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); - } - } else { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr); - } - - // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too - if (materialKey.isLightmapMap()) { - auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; - - if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); - - auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); - batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); - - if (!lightmapMap->getTextureTransform().isIdentity()) { - lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); - } - } else { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); - } - } else { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr); - } - - // Texcoord transforms ? - if (locations->texcoordMatrices >= 0) { - batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); - } -} - -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { - // Still relying on the raw data from the model - const Model::MeshState& state = model->_meshStates.at(meshIndex); - - Transform transform; - if (state.clusterBuffer) { - batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer); - } else { - if (model->_cauterizeBones) { - transform = Transform(state.cauterizedClusterMatrices[0]); - } else { - transform = Transform(state.clusterMatrices[0]); - } - } - transform.preTranslate(model->_translation); - batch.setModelTransform(transform); -} - - -void MeshPartPayload::render(RenderArgs* args) const { - PerformanceTimer perfTimer("MeshPartPayload::render"); - if (!model->_readyWhenAdded) { - return; // bail asap - } - - gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; - - auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME - - const FBXGeometry& geometry = model->_geometry->getFBXGeometry(); - const std::vector>& networkMeshes = model->_geometry->getMeshes(); - - // guard against partially loaded meshes - if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)model->_meshStates.size() ) { - return; - } - - // Back to model to update the cluster matrices right now - model->updateClusterMatrices(); - - const FBXMesh& mesh = geometry.meshes.at(meshIndex); - - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { - model->_meshGroupsKnown = false; // regenerate these lists next time around. - model->_readyWhenAdded = false; // in case any of our users are using scenes - model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return; // FIXME! - } - - - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return; // FIXME! - } - - - // guard against partially loaded meshes - if (partIndex >= mesh.parts.size()) { - return; - } - - model::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); - } - bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - - bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); - bool hasSpecular = drawMaterialKey.isGlossMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isSkinned = _isSkinned; - bool wireframe = model->isWireframe(); - - // render the part bounding box -#ifdef DEBUG_BOUNDING_PARTS - { - AABox partBounds = getPartBounds(meshIndex, partIndex); - bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE; - - glm::vec4 cubeColor; - if (isSkinned) { - cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f); - } else if (inView) { - cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f); - } else { - cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); - } - - Transform transform; - transform.setTranslation(partBounds.calcCenter()); - transform.setScale(partBounds.getDimensions()); - batch.setModelTransform(transform); - DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); - } -#endif //def DEBUG_BOUNDING_PARTS - - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } - - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, - args, locations); - - - // Bind the model transform and the skinCLusterMatrices if needed - bindTransform(batch, locations); - - //Bind the index buffer and vertex buffer and Blend shapes if needed - bindMesh(batch); - - // apply material properties - bindMaterial(batch, locations); - - - // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { - PerformanceTimer perfTimer("DLE->setupTransparent()"); - - DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); - } - if (args) { - args->_details._materialSwitches++; - } - - // Draw! - { - PerformanceTimer perfTimer("batch.drawIndexed()"); - drawCall(batch); - } - - if (args) { - const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; - } -} - diff --git a/libraries/render-utils/src/ModelRenderItem.h b/libraries/render-utils/src/ModelRender.h similarity index 76% rename from libraries/render-utils/src/ModelRenderItem.h rename to libraries/render-utils/src/ModelRender.h index 658d2d2cae..934c9a61e8 100644 --- a/libraries/render-utils/src/ModelRenderItem.h +++ b/libraries/render-utils/src/ModelRender.h @@ -1,5 +1,5 @@ // -// ModelRenderItem.h +// ModelRender.h // interface/src/renderer // // Created by Sam Gateau on 10/3/15. @@ -9,22 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_ModelRenderPayload_h -#define hifi_ModelRenderPayload_h - -#include +#ifndef hifi_ModelRender_h +#define hifi_ModelRender_h #include #include -#include - -class Model; - class ModelRender { public: - + static const int SKINNING_GPU_SLOT = 2; static const int MATERIAL_GPU_SLOT = 3; static const int DIFFUSE_MAP_SLOT = 0; @@ -35,6 +29,7 @@ public: class Locations { public: + int tangent; int alphaThreshold; int texcoordMatrices; int diffuseTextureUnit; @@ -45,7 +40,9 @@ public: int glowIntensity; int normalFittingMapUnit; int materialBufferUnit; - int skinClusterBufferUnit; + int clusterMatrices; + int clusterIndices; + int clusterWeights; int lightBufferUnit; }; @@ -157,54 +154,8 @@ public: }; static RenderPipelineLib _renderPipelineLib; - static const RenderPipelineLib& getRenderPipelineLib(); + static const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib(); }; - -class MeshPartPayload { -public: - MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex); - - typedef render::Payload Payload; - typedef Payload::DataPointer Pointer; - - Model* model; - QUrl url; - int meshIndex; - int partIndex; - int _shapeID; - - // Render Item interface - render::ItemKey getKey() const; - render::Item::Bound getBound() const; - void render(RenderArgs* args) const; - - // MeshPartPayload functions to perform render - void drawCall(gpu::Batch& batch) const; - void bindMesh(gpu::Batch& batch) const; - void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const; - void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const; - - - void initCache(); - - // Payload resource cached values - model::MeshPointer _drawMesh; - model::Mesh::Part _drawPart; - model::MaterialPointer _drawMaterial; - bool _hasColorAttrib = false; - bool _isSkinned = false; - bool _isBlendShaped = false; - - mutable render::Item::Bound _bound; - mutable bool _isBoundInvalid = true; -}; - -namespace render { - template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); - template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); - template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); -} - -#endif // hifi_ModelRenderPayload_h \ No newline at end of file +#endif // hifi_ModelRender_h \ No newline at end of file From 429d82e6502b85bf99edb7d06931ac8ae6683440 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 09:54:37 -0700 Subject: [PATCH 14/19] Fixing review comments --- libraries/fbx/src/FBXReader.h | 5 +---- libraries/fbx/src/FBXReader_Mesh.cpp | 12 ++++++------ .../src/model-networking/ModelCache.h | 9 +-------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index a9c3326140..c0cbf5fb18 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -12,8 +12,6 @@ #ifndef hifi_FBXReader_h #define hifi_FBXReader_h -#define USE_MODEL_MESH 1 - #include #include #include @@ -188,9 +186,8 @@ public: QVector blendshapes; unsigned int meshIndex; // the order the meshes appeared in the object file -# if USE_MODEL_MESH + model::MeshPointer _mesh; -# endif }; class ExtractedMesh { diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index c88eaf4137..097862ef38 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -495,8 +495,8 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { return; } - auto ib = std::make_shared(); - ib->resize(totalIndices * sizeof(int)); + auto indexBuffer = std::make_shared(); + indexBuffer->resize(totalIndices * sizeof(int)); int indexNum = 0; int offset = 0; @@ -509,7 +509,7 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { model::Mesh::Part modelPart(indexNum, 0, 0, model::Mesh::TRIANGLES); if (part.quadTrianglesIndices.size()) { - ib->setSubData( offset, + indexBuffer->setSubData(offset, part.quadTrianglesIndices.size() * sizeof(int), (gpu::Byte*) part.quadTrianglesIndices.constData()); offset += part.quadTrianglesIndices.size() * sizeof(int); @@ -518,7 +518,7 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { } if (part.triangleIndices.size()) { - ib->setSubData( offset, + indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int), (gpu::Byte*) part.triangleIndices.constData()); offset += part.triangleIndices.size() * sizeof(int); @@ -529,8 +529,8 @@ void FBXReader::buildModelMesh(ExtractedMesh& extracted, const QString& url) { parts.push_back(modelPart); } - gpu::BufferView ibv(ib, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::XYZ)); - mesh->setIndexBuffer(ibv); + gpu::BufferView indexBufferView(indexBuffer, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::XYZ)); + mesh->setIndexBuffer(indexBufferView); if (parts.size()) { auto pb = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index b53ea18874..cd75794e2b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -192,13 +192,6 @@ public: class NetworkMesh { public: model::MeshPointer _mesh; - -/* gpu::BufferPointer _indexBuffer; - gpu::BufferPointer _vertexBuffer; - - gpu::BufferStreamPointer _vertexStream; - - gpu::Stream::FormatPointer _vertexFormat; -*/}; +}; #endif // hifi_GeometryCache_h From 1788b7b019b0217508e2cdc9488e6427e44a20c1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 10:53:38 -0700 Subject: [PATCH 15/19] Fix the bug created by the previous fix --- libraries/fbx/src/FBXReader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 5b953e5b1b..4b3b3b0fea 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1512,10 +1512,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); -# if USE_MODEL_MESH buildModelMesh(extracted, url); -# endif - + if (extracted.mesh.isEye) { if (maxJointIndex == geometry.leftEyeJointIndex) { geometry.leftEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale; From cf3828629e7f3c7426f0ab0a9af567f1ddec2418 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 11:00:21 -0700 Subject: [PATCH 16/19] Fix build on mac and linux --- libraries/render-utils/src/ModelRender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ModelRender.h b/libraries/render-utils/src/ModelRender.h index 934c9a61e8..517a6d0187 100644 --- a/libraries/render-utils/src/ModelRender.h +++ b/libraries/render-utils/src/ModelRender.h @@ -154,7 +154,7 @@ public: }; static RenderPipelineLib _renderPipelineLib; - static const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib(); + static const RenderPipelineLib& getRenderPipelineLib(); }; From 2b5742b2778170cb809ccb646d9a6773e9bd9217 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 11:13:35 -0700 Subject: [PATCH 17/19] Some code got overwritten when merging to my office mahcine this morning, that i know got back... --- libraries/render-utils/src/ModelRender.cpp | 10 ++++++---- libraries/render-utils/src/ModelRender.h | 5 +---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp index f6b93ce356..a5419733ff 100644 --- a/libraries/render-utils/src/ModelRender.cpp +++ b/libraries/render-utils/src/ModelRender.cpp @@ -13,6 +13,8 @@ #include +#include + #include "DeferredLightingEffect.h" #include "model_vert.h" @@ -170,6 +172,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), ModelRender::SKINNING_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT)); @@ -256,11 +259,10 @@ void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, locations.normalTextureUnit = program->getTextures().findLocation("normalMap"); locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); + locations.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); - locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex"); - locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight"); + } @@ -268,7 +270,7 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations) { - // PerformanceTimer perfTimer("Model::pickPrograms"); + PerformanceTimer perfTimer("Model::pickPrograms"); getRenderPipelineLib(); RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); diff --git a/libraries/render-utils/src/ModelRender.h b/libraries/render-utils/src/ModelRender.h index 517a6d0187..9748710ab1 100644 --- a/libraries/render-utils/src/ModelRender.h +++ b/libraries/render-utils/src/ModelRender.h @@ -29,7 +29,6 @@ public: class Locations { public: - int tangent; int alphaThreshold; int texcoordMatrices; int diffuseTextureUnit; @@ -39,10 +38,8 @@ public: int emissiveParams; int glowIntensity; int normalFittingMapUnit; + int skinClusterBufferUnit; int materialBufferUnit; - int clusterMatrices; - int clusterIndices; - int clusterWeights; int lightBufferUnit; }; From c75c31ddc84cbaae22af512274c7c19c66499346 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 18:04:08 -0700 Subject: [PATCH 18/19] Fixing the index Offset issue with instanced shapes from Geometry cache --- libraries/render-utils/src/GeometryCache.cpp | 9 ++++--- libraries/render-utils/src/ModelRender.cpp | 27 +------------------- libraries/render-utils/src/ModelRender.h | 4 --- libraries/render-utils/src/Skinning.slh | 2 -- 4 files changed, 6 insertions(+), 36 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 7846d95ec4..3fcd556dbb 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -59,7 +59,8 @@ static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT; static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); - +static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT16; +static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint16); void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const VertexVector& vertices) { vertexBuffer->append(vertices); @@ -73,13 +74,13 @@ void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, c void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const IndexVector& indices, const IndexVector& wireIndices) { _indices = indexBuffer; if (!indices.empty()) { - _indexOffset = indexBuffer->getSize(); + _indexOffset = indexBuffer->getSize() / SHAPE_INDEX_SIZE; _indexCount = indices.size(); indexBuffer->append(indices); } if (!wireIndices.empty()) { - _wireIndexOffset = indexBuffer->getSize(); + _wireIndexOffset = indexBuffer->getSize() / SHAPE_INDEX_SIZE; _wireIndexCount = wireIndices.size(); indexBuffer->append(wireIndices); } @@ -88,7 +89,7 @@ void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, con void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); - batch.setIndexBuffer(gpu::UINT16, _indices, 0); + batch.setIndexBuffer(SHAPE_INDEX_TYPE, _indices, 0); } void GeometryCache::ShapeData::draw(gpu::Batch& batch) const { diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp index a5419733ff..c614fae67a 100644 --- a/libraries/render-utils/src/ModelRender.cpp +++ b/libraries/render-utils/src/ModelRender.cpp @@ -220,32 +220,10 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke wireframeState->setFillMode(gpu::State::FILL_LINE); - // create a new RenderPipeline with the same shader side and the mirrorState + // create a new RenderPipeline with the same shader side and the wireframe state auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); } - - // If not a shadow pass, create the mirror version from the same state, just change the FrontFace - if (!key.isShadow()) { - - RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR); - auto mirrorState = std::make_shared(state->getValues()); - - // create a new RenderPipeline with the same shader side and the mirrorState - auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); - insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); - - if (!key.isWireFrame()) { - RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME); - auto wireframeState = std::make_shared(state->getValues()); - - wireframeState->setFillMode(gpu::State::FILL_LINE); - - // create a new RenderPipeline with the same shader side and the mirrorState - auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); - insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); - } - } } @@ -274,9 +252,6 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b getRenderPipelineLib(); RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); - if (mode == RenderArgs::MIRROR_RENDER_MODE) { - key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR); - } auto pipeline = _renderPipelineLib.find(key.getRaw()); if (pipeline == _renderPipelineLib.end()) { qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); diff --git a/libraries/render-utils/src/ModelRender.h b/libraries/render-utils/src/ModelRender.h index 9748710ab1..1528dcfc87 100644 --- a/libraries/render-utils/src/ModelRender.h +++ b/libraries/render-utils/src/ModelRender.h @@ -59,7 +59,6 @@ public: IS_STEREO_FLAG, IS_DEPTH_ONLY_FLAG, IS_SHADOW_FLAG, - IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" IS_WIREFRAME_FLAG, NUM_FLAGS, @@ -75,7 +74,6 @@ public: IS_STEREO = (1 << IS_STEREO_FLAG), IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG), IS_SHADOW = (1 << IS_SHADOW_FLAG), - IS_MIRROR = (1 << IS_MIRROR_FLAG), IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG), }; typedef unsigned short Flags; @@ -93,7 +91,6 @@ public: bool isStereo() const { return isFlag(IS_STEREO); } bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); } bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing - bool isMirror() const { return isFlag(IS_MIRROR); } bool isWireFrame() const { return isFlag(IS_WIREFRAME); } Flags _flags = 0; @@ -124,7 +121,6 @@ public: | (isWireframe ? IS_WIREFRAME : 0) | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0) | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0) - | ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR : 0) ) {} RenderKey(int bitmask) : _flags(bitmask) {} diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 747f18ab34..b34ed3ed2b 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -15,8 +15,6 @@ const int MAX_TEXCOORDS = 2; const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; -//uniform mat4 clusterMatrices[MAX_CLUSTERS]; - layout(std140) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; From dd2aa36a119293baa17ad8b027781a25def23f57 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 23:10:03 -0700 Subject: [PATCH 19/19] FIx the shiny objects by actually using the specular map as it should be... --- libraries/fbx/src/FBXReader_Material.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 6da53dbede..e947a0356e 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -107,6 +107,8 @@ void FBXReader::consolidateFBXMaterials() { if (!specularTextureID.isNull()) { specularTexture = getTexture(specularTextureID); detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity()); + + material.specularTexture = specularTexture; } FBXTexture emissiveTexture;