From c92a6d58ab0d3d97f373683906d702e0d4cbd807 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Oct 2015 09:46:32 -0700 Subject: [PATCH] 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