From 12fedb6ff0bb146300043eb997ce81f8c2d95a67 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 5 Oct 2015 18:31:05 -0700 Subject: [PATCH] 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();