diff --git a/examples/dropStuffNearMe.js b/examples/dropStuffNearMe.js new file mode 100644 index 0000000000..1c7c1f4f48 --- /dev/null +++ b/examples/dropStuffNearMe.js @@ -0,0 +1,87 @@ +// +// Created by Philip Rosedale on January 9, 2016 +// 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 +// +// Puts a bunch of entities in front of you, with various adjustable properties for testing. +// +// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly. +// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND +// variable letting you set this speed. If entities are missing from the grid after a relog, this number +// being too high may be the reason. + +var SIZE = 0.5; +var TYPE = "Box"; // Right now this can be "Box" or "Model" or "Sphere" +var MODEL_URL = "http://s3.amazonaws.com/hifi-public/models/content/basketball2.fbx"; +var MODEL_DIMENSION = { x: 0.3, y: 0.3, z: 0.3 }; + +var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast. +var SCRIPT_INTERVAL = 100; +var LIFETIME = 90; + +var NUMBER_TO_CREATE = 300; + +var GRAVITY = { x: 0, y: -9.8, z: 0 }; +var VELOCITY = { x: 0.0, y: 0, z: 0 }; +var ANGULAR_VELOCITY = { x: 1, y: 1, z: 1 }; + +var DAMPING = 0.5; +var ANGULAR_DAMPING = 0.5; + +var collidable = true; +var gravity = true; + + +var x = 0; +var z = 0; +var totalCreated = 0; + +var RANGE = 10; +var HOW_FAR_IN_FRONT_OF_ME = 3 * RANGE; + + +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getFront(Camera.orientation))); + + +function randomVector(range) { + return { + x: (Math.random() - 0.5) * range.x, + y: (Math.random() - 0.5) * range.y, + z: (Math.random() - 0.5) * range.z + } +} + +Vec3.print("Center: ", center); + +Script.setInterval(function () { + if (!Entities.serversExist() || !Entities.canRez() || (totalCreated > NUMBER_TO_CREATE)) { + return; + } + + var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); + for (var i = 0; (i < numToCreate) && (totalCreated < NUMBER_TO_CREATE); i++) { + var position = Vec3.sum(center, randomVector({ x: RANGE, y: RANGE, z: RANGE })); + + Vec3.print("Position: ", position); + Entities.addEntity({ + type: TYPE, + modelURL: MODEL_URL, + name: "gridTest", + position: position, + dimensions: (TYPE == "Model") ? MODEL_DIMENSION : { x: SIZE, y: SIZE, z: SIZE }, + color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 }, + velocity: VELOCITY, + angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY), + damping: DAMPING, + angularDamping: ANGULAR_DAMPING, + gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}), + collisionsWillMove: collidable, + lifetime: LIFETIME + }); + + totalCreated++; + } +}, SCRIPT_INTERVAL); + diff --git a/examples/example/ui/energyBar.js b/examples/example/ui/energyBar.js new file mode 100644 index 0000000000..a45b09f6d4 --- /dev/null +++ b/examples/example/ui/energyBar.js @@ -0,0 +1,102 @@ +// energyBar.js +// examples/ui +// +// Created by Eric Levin on 1/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// This script adds an energy bar overlay which displays the amount of energy a user has left for grabbing and moving objects +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("../../libraries/utils.js"); +var energyColor = {red: 0, green: 200, blue: 0}; +var lowEnergyColor = {red: 255, green: 0, blue: 0}; +var totalWidth = 200; +var paddingRight = 50; +var xPosition = Window.innerWidth - totalWidth - paddingRight; +var lowEnergyThreshold = 0.3; +var currentEnergy = 1.0; +var energyLossRate = 0.003; +var energyChargeRate = 0.003; +var isGrabbing = false; +var refractoryPeriod = 2000; + +var lastAvatarVelocity = MyAvatar.getVelocity(); +var lastAvatarPosition = MyAvatar.position; + +var background = Overlays.addOverlay("text", { + x: xPosition, + y: 20, + width: totalWidth, + height: 10, + backgroundColor: {red: 184, green: 181, blue: 178} +}) + +var bar = Overlays.addOverlay("text", { + x: xPosition, + y: 20, + width: totalWidth, + height: 10, + backgroundColor: energyColor +}); + + +// Takes an energy value between 0 and 1 and sets energy bar width appropriately +function setEnergy(energy) { + energy = clamp(energy, 0, 1); + var barWidth = totalWidth * energy; + var color = energy <= lowEnergyThreshold ? lowEnergyColor: energyColor; + Overlays.editOverlay(bar, { width: barWidth, backgroundColor: color}); +} + +function avatarAccelerationEnergy() { + var AVATAR_MOVEMENT_ENERGY_CONSTANT = 0.001; + var velocity = MyAvatar.getVelocity(); + var dV = Math.abs(Vec3.length(velocity) - Vec3.length(lastAvatarVelocity)); + var dE = Vec3.length(lastAvatarVelocity) * dV * AVATAR_MOVEMENT_ENERGY_CONSTANT; + lastAvatarVelocity = velocity; + return dE; +} + +function teleported() { + var MAX_AVATAR_MOVEMENT_PER_FRAME = 30.0; + var position = MyAvatar.position; + var dP = Vec3.length(Vec3.subtract(position, lastAvatarPosition)); + lastAvatarPosition = position; + return (dP > MAX_AVATAR_MOVEMENT_PER_FRAME); +} + +function audioEnergy() { + var AUDIO_ENERGY_CONSTANT = 0.000001; + return MyAvatar.audioLoudness * AUDIO_ENERGY_CONSTANT; +} + +function update() { + // refill energy + currentEnergy += energyChargeRate; + + // Avatar acceleration + currentEnergy -= avatarAccelerationEnergy(); + + // Teleport cost + if (teleported()) { + currentEnergy = 0; + } + + // Making sounds + currentEnergy -= audioEnergy(); + + + currentEnergy = clamp(currentEnergy, 0, 1); + setEnergy(currentEnergy); +} + +function cleanup() { + Overlays.deleteOverlay(background); + Overlays.deleteOverlay(bar); +} + +Script.update.connect(update); +Script.scriptEnding.connect(cleanup); diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index 115c1bcb65..b2b2902cb0 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -297,3 +297,8 @@ calculateHandSizeRatio = function() { var handSizeRatio = centerHandPoint/standardCenterHandPoint; return handSizeRatio; } + +clamp = function(val, min, max){ + return Math.max(min, Math.min(max, val)) + } + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f2059d103c..2af7f02972 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -448,8 +448,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _bookmarks = new Bookmarks(); // Before setting up the menu - _renderEngine->addTask(make_shared()); - _renderEngine->registerScene(_main3DScene); + _runningScriptsWidget = new RunningScriptsWidget(_window); // start the nodeThread so its event loop is running QThread* nodeThread = new QThread(this); @@ -615,7 +614,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : OffscreenUi::warning(nullptr, "Error Loading Script", filename + " failed to load."); }, Qt::QueuedConnection); - #ifdef _WIN32 WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2, 2), &WsaData); @@ -678,6 +676,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _offscreenContext->makeCurrent(); initializeGL(); + // Start rendering + _renderEngine->addTask(make_shared()); + _renderEngine->registerScene(_main3DScene); _toolWindow = new ToolWindow(); _toolWindow->setWindowFlags((_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint) & ~Qt::WindowMinimizeButtonHint); diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 596d042506..795a259a3c 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -48,7 +48,7 @@ public: // setters for lens attributes void setProjection(const glm::mat4 & projection); - void getFocalLength(float focalLength) { _focalLength = focalLength; } + void setFocalLength(float focalLength) { _focalLength = focalLength; } // getters for lens attributes const glm::mat4& getProjection() const { return _projection; } diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 11e157a50c..ca46ad0ebf 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -70,7 +70,7 @@ uniform SphericalHarmonics ambientSphere; <@include model/Light.slh@> <@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { // Need the light now Light light = getLight(); @@ -93,7 +93,7 @@ vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi <$declareSphericalHarmonics()$> -vec3 evalAmbienSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { // Need the light now Light light = getLight(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index dfb0ecbffb..f00f558122 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,6 +21,8 @@ #include "model/Stage.h" #include "model/Geometry.h" +#include "render/ShapePipeline.h" + class RenderArgs; class SimpleProgramKey; struct LightLocations; @@ -30,7 +32,7 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - static const int NORMAL_FITTING_MAP_SLOT = 10; + static const int NORMAL_FITTING_MAP_SLOT = render::ShapePipeline::Slot::NORMAL_FITTING_MAP; static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; void init(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 414ad9cf97..492021c1a9 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,30 +14,36 @@ #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(); - } +using namespace render; - 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); +namespace render { +template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); } + return ItemKey::Builder::opaqueShape(); // for lack of a better idea } -using namespace render; +template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return Item::Bound(); +} + +template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getShapeKey(); + } + return ShapeKey::Builder::invalid(); +} + +template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); +} +} MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) { @@ -69,7 +75,7 @@ void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; } -render::ItemKey MeshPartPayload::getKey() const { +ItemKey MeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -83,10 +89,32 @@ render::ItemKey MeshPartPayload::getKey() const { return builder.build(); } -render::Item::Bound MeshPartPayload::getBound() const { +Item::Bound MeshPartPayload::getBound() const { return _worldBound; } +ShapeKey MeshPartPayload::getShapeKey() const { + model::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + + ShapeKey::Builder builder; + if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap()) { + builder.withTranslucent(); + } + if (drawMaterialKey.isNormalMap()) { + builder.withTangents(); + } + if (drawMaterialKey.isGlossMap()) { + builder.withSpecular(); + } + if (drawMaterialKey.isLightmapMap()) { + builder.withLightmap(); + } + return builder.build(); +} + void MeshPartPayload::drawCall(gpu::Batch& batch) const { batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); } @@ -104,14 +132,14 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const { +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { if (!_drawMaterial) { return; } auto textureCache = DependencyManager::get(); - batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer()); + batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); auto materialKey = _drawMaterial->getKey(); auto textureMaps = _drawMaterial->getTextureMaps(); @@ -121,44 +149,44 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio if (materialKey.isDiffuseMap()) { auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); if (!diffuseMap->getTextureTransform().isIdentity()) { diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); } } else { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); } // Normal map if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture()); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); } } else { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, 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()); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, nullptr); } // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too @@ -166,7 +194,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -175,10 +203,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? @@ -187,7 +215,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { batch.setModelTransform(_drawTransform); } @@ -195,29 +223,12 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati void MeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("MeshPartPayload::render"); - gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; - model::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); - } - bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - - bool hasTangents = drawMaterialKey.isNormalMap(); - bool hasSpecular = drawMaterialKey.isGlossMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isSkinned = false; - bool wireframe = false; - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } - - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, - args, locations); + ShapeKey key = getShapeKey(); + auto locations = args->_pipeline->locations; + assert(locations); // Bind the model transform and the skinCLusterMatrices if needed bindTransform(batch, locations); @@ -230,7 +241,7 @@ void MeshPartPayload::render(RenderArgs* args) const { // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { + if (key.isTranslucent() && locations->lightBufferUnit >= 0) { PerformanceTimer perfTimer("DLE->setupTransparent()"); DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); @@ -251,29 +262,32 @@ void MeshPartPayload::render(RenderArgs* args) const { } } - - namespace render { - template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::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 ModelMeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getBound(); - } - return render::Item::Bound(); - } - template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) { - return payload->render(args); +template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); } + return ItemKey::Builder::opaqueShape(); // for lack of a better idea } -using namespace render; +template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return Item::Bound(); +} + +template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getShapeKey(); + } + return ShapeKey::Builder::invalid(); +} + +template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); +} +} ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : _model(model), @@ -310,7 +324,7 @@ void ModelMeshPartPayload::notifyLocationChanged() { _model->_needsUpdateClusterMatrices = true; } -render::ItemKey ModelMeshPartPayload::getKey() const { +ItemKey ModelMeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -332,12 +346,79 @@ render::ItemKey ModelMeshPartPayload::getKey() const { return builder.build(); } -render::Item::Bound ModelMeshPartPayload::getBound() const { +Item::Bound ModelMeshPartPayload::getBound() const { // NOTE: we can't cache this bounds because we need to handle the case of a moving // entity or mesh part. return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation()); } +ShapeKey ModelMeshPartPayload::getShapeKey() const { + 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 ShapeKey::Builder::invalid(); + } + + 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 ShapeKey::Builder::invalid(); + } + + + int vertexCount = mesh.vertices.size(); + if (vertexCount == 0) { + // sanity check + return ShapeKey::Builder::invalid(); // FIXME + } + + + model::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + + bool isTranslucent = 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(); + + if (wireframe) { + isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + } + + ShapeKey::Builder builder; + if (isTranslucent) { + builder.withTranslucent(); + } + if (hasTangents) { + builder.withTangents(); + } + if (hasSpecular) { + builder.withSpecular(); + } + if (hasLightmap) { + builder.withLightmap(); + } + if (isSkinned) { + builder.withSkinned(); + } + if (wireframe) { + builder.withWireframe(); + } + return builder.build(); +} + void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { if (!_isBlendShaped) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); @@ -361,16 +442,16 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { // Still relying on the raw data from the model const Model::MeshState& state = _model->_meshStates.at(_meshIndex); Transform transform; if (state.clusterBuffer) { if (_model->_cauterizeBones) { - batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); } else { - batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer); } } else { if (_model->_cauterizeBones) { @@ -387,54 +468,18 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::L void ModelMeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); + if (!_model->_readyWhenAdded || !_model->_isVisible) { return; // bail asap } gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; - 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() ) { + ShapeKey key = getShapeKey(); + if (!key.isValid()) { return; } - - // Back to model to update the cluster matrices right now - _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); - - 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! - } - 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 { @@ -458,19 +503,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { } #endif //def DEBUG_BOUNDING_PARTS - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } - - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, - args, locations); - - if (!locations) { // the pipeline could not be found - return; - } + auto locations = args->_pipeline->locations; + assert(locations); // Bind the model transform and the skinCLusterMatrices if needed + _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); bindTransform(batch, locations); //Bind the index buffer and vertex buffer and Blend shapes if needed @@ -481,7 +518,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { + if (key.isTranslucent() && locations->lightBufferUnit >= 0) { PerformanceTimer perfTimer("DLE->setupTransparent()"); DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index e03d1c8a68..d771a57203 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -15,11 +15,10 @@ #include #include +#include #include -#include "ModelRender.h" - class Model; class MeshPartPayload { @@ -40,13 +39,14 @@ public: // Render Item interface virtual render::ItemKey getKey() const; virtual render::Item::Bound getBound() const; + virtual render::ShapeKey getShapeKey() const; // shape interface virtual void render(RenderArgs* args) const; // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; - virtual void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const; - virtual void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const; + virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; + virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; // Payload resource cached values model::MeshPointer _drawMesh; @@ -67,10 +67,10 @@ public: namespace render { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); + template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload); template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); } - class ModelMeshPartPayload : public MeshPartPayload { public: ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); @@ -83,11 +83,12 @@ public: // Render Item interface render::ItemKey getKey() const override; render::Item::Bound getBound() const override; + render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) const override; - + // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override; + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const override; void initCache(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ef9a837b27..e2d0d02af7 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -22,8 +22,8 @@ #include #include "AbstractViewStateInterface.h" -#include "Model.h" #include "MeshPartPayload.h" +#include "Model.h" #include "RenderUtilsLogging.h" @@ -35,6 +35,8 @@ static int vec3VectorTypeId = qRegisterMetaType >(); float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; #define HTTP_INVALID_COM "http://invalid.com" +model::MaterialPointer Model::_collisionHullMaterial; + Model::Model(RigPointer rig, QObject* parent) : QObject(parent), _translation(0.0f), @@ -1193,8 +1195,13 @@ void Model::segregateMeshGroups() { int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { if (showingCollisionHull) { - _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, ModelRender::getCollisionHullMaterial(), transform, offset); - + if (!_collisionHullMaterial) { + _collisionHullMaterial = std::make_shared(); + _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); + _collisionHullMaterial->setMetallic(0.02f); + _collisionHullMaterial->setGloss(1.0f); + } + _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); } else { _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 3416a9b71e..157c6dbf70 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -347,6 +347,7 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes + static model::MaterialPointer _collisionHullMaterial; bool _meshGroupsKnown; bool _isWireframe; diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp deleted file mode 100644 index 312d34e41b..0000000000 --- a/libraries/render-utils/src/ModelRender.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// -// ModelRender.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 "ModelRender.h" - -#include - -#include - -#include "DeferredLightingEffect.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::Shader::createVertex(std::string(model_vert)); - auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); - auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); - auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); - auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); - auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); - auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); - - // Pixel shaders - auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); - auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); - auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); - auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); - auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); - auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); - auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); - auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); - auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); - auto modelLightmapNormalSpecularMapPixel = 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("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)); - 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::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::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 wireframe state - auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); - insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); - } -} - - -void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) { - locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); - locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); - 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.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); - locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); - locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - -} - - -void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, - Locations*& locations) { - - PerformanceTimer perfTimer("Model::pickPrograms"); - getRenderPipelineLib(); - - RenderKey key(mode, translucent, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); - 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->normalFittingMapUnit > -1)) { - batch.setResourceTexture(locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); - } -} - -model::MaterialPointer ModelRender::_collisionHullMaterial; - -model::MaterialPointer ModelRender::getCollisionHullMaterial() { - if (!_collisionHullMaterial) { - _collisionHullMaterial = std::make_shared(); - _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); - _collisionHullMaterial->setMetallic(0.02f); - _collisionHullMaterial->setGloss(1.0f); - } - return _collisionHullMaterial; -} - diff --git a/libraries/render-utils/src/ModelRender.h b/libraries/render-utils/src/ModelRender.h deleted file mode 100644 index 8331440fb0..0000000000 --- a/libraries/render-utils/src/ModelRender.h +++ /dev/null @@ -1,157 +0,0 @@ -// -// ModelRender.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_ModelRender_h -#define hifi_ModelRender_h - -#include - -#include - -class ModelRender { -public: - - static const int SKINNING_GPU_SLOT = 2; - static const int MATERIAL_GPU_SLOT = 3; - static const int DIFFUSE_MAP_SLOT = 0; - static const int NORMAL_MAP_SLOT = 1; - 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 texcoordMatrices; - int diffuseTextureUnit; - int normalTextureUnit; - int specularTextureUnit; - int emissiveTextureUnit; - int emissiveParams; - int normalFittingMapUnit; - int skinClusterBufferUnit; - int materialBufferUnit; - int lightBufferUnit; - }; - - static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, - 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_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_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 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, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : - RenderKey(((translucent && (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) - ) {} - - 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 RenderPipelineLib& getRenderPipelineLib(); - - // Collision hull Material - static model::MaterialPointer _collisionHullMaterial; - - static model::MaterialPointer getCollisionHullMaterial(); - -}; - -#endif // hifi_ModelRender_h \ No newline at end of file diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 36cd17bdc1..ca25383a8d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -9,7 +9,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "RenderDeferredTask.h" #include #include @@ -29,6 +28,28 @@ #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" +#include "RenderDeferredTask.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 "overlay3D_vert.h" #include "overlay3D_frag.h" @@ -36,6 +57,7 @@ using namespace render; +void initDeferredPipelines(render::ShapePlumber& plumber); void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { DependencyManager::get()->prepare(renderContext->getArgs()); @@ -51,11 +73,15 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren } RenderDeferredTask::RenderDeferredTask() : Task() { + // Prepare the ShapePipelines + ShapePlumberPointer shapePlumber = std::make_shared(); + initDeferredPipelines(*shapePlumber); + // CPU only, create the list of renderedOpaques items addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { context->getItemsConfig().opaque.numFeed = count; })); - addJob("CullOpaque", _jobs.back().getOutput()); + addJob>("CullOpaque", _jobs.back().getOutput()); addJob("DepthSortOpaque", _jobs.back().getOutput()); auto& renderedOpaques = _jobs.back().getOutput(); @@ -66,7 +92,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { context->getItemsConfig().transparent.numFeed = count; } )); - addJob("CullTransparent", _jobs.back().getOutput()); + addJob>("CullTransparent", _jobs.back().getOutput()); addJob("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)); auto& renderedTransparents = _jobs.back().getOutput(); @@ -74,7 +100,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { addJob("PrepareDeferred"); // Render opaque objects in DeferredBuffer - addJob("DrawOpaqueDeferred", renderedOpaques); + addJob("DrawOpaqueDeferred", renderedOpaques, shapePlumber); // Once opaque is all rendered create stencil background addJob("DrawOpaqueStencil"); @@ -99,7 +125,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _antialiasingJobIndex = (int)_jobs.size() - 1; // Render transparent objects forward in LigthingBuffer - addJob("TransparentDeferred", renderedTransparents); + addJob("DrawTransparentDeferred", renderedTransparents, shapePlumber); // Lighting Buffer ready for tone mapping addJob("ToneMapping"); @@ -120,7 +146,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _drawStatusJobIndex = (int)_jobs.size() - 1; } - addJob("DrawOverlay3D"); + addJob("DrawOverlay3D", shapePlumber); addJob("HitEffect"); _jobs.back().setEnabled(false); @@ -173,7 +199,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; @@ -189,7 +215,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, inItems, opaque.maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -199,7 +225,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; @@ -215,11 +241,12 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, inItems, transparent.maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } +// TODO: Move this to the shapePlumber gpu::PipelinePointer DrawOverlay3D::_opaquePipeline; const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() { if (!_opaquePipeline) { @@ -272,7 +299,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon } // Render the items - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; args->_whiteTexture = DependencyManager::get()->getWhiteTexture(); @@ -288,7 +315,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderItems(sceneContext, renderContext, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); @@ -377,8 +404,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, inItems); - + renderLights(sceneContext, renderContext, inItems); }); args->_batch = nullptr; } @@ -482,3 +508,165 @@ int RenderDeferredTask::getToneMappingToneCurve() const { } } +void pipelineBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + if (pipeline.locations->normalFittingMapUnit > -1) { + batch.setResourceTexture(pipeline.locations->normalFittingMapUnit, + DependencyManager::get()->getNormalFittingTexture()); + } +} + +void initDeferredPipelines(render::ShapePlumber& plumber) { + using Key = render::ShapeKey; + using ShaderPointer = gpu::ShaderPointer; + + auto addPipeline = [&plumber](const Key& key, const ShaderPointer& vertexShader, const ShaderPointer& pixelShader) { + auto state = std::make_shared(); + + // Cull backface + state->setCullMode(gpu::State::CULL_BACK); + + // Z test depends on transparency + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + + // Blend if transparent + state->setBlendFunction(key.isTranslucent(), + // For transparency, keep the highlight intensity + gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); + plumber.addPipeline(key, program, state, &pipelineBatchSetter); + + // Add a wireframe version + if (!key.isWireFrame()) { + auto wireFrameKey = Key::Builder(key).withWireframe(); + auto wireFrameState = std::make_shared(state->getValues()); + + wireFrameState->setFillMode(gpu::State::FILL_LINE); + + plumber.addPipeline(wireFrameKey, program, wireFrameState, &pipelineBatchSetter); + } + }; + + // Vertex shaders + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); + auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); + auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + + // Pixel shaders + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); + auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); + auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); + auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); + auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); + + // Fill the pipelineLib + addPipeline( + Key::Builder(), + modelVertex, modelPixel); + + addPipeline( + Key::Builder().withTangents(), + modelNormalMapVertex, modelNormalMapPixel); + + addPipeline( + Key::Builder().withSpecular(), + modelVertex, modelSpecularMapPixel); + + addPipeline( + Key::Builder().withTangents().withSpecular(), + modelNormalMapVertex, modelNormalSpecularMapPixel); + + + addPipeline( + Key::Builder().withTranslucent(), + modelVertex, modelTranslucentPixel); + // FIXME Ignore lightmap for translucents meshpart + addPipeline( + Key::Builder().withTranslucent().withLightmap(), + modelVertex, modelTranslucentPixel); + + addPipeline( + Key::Builder().withTangents().withTranslucent(), + modelNormalMapVertex, modelTranslucentPixel); + + addPipeline( + Key::Builder().withSpecular().withTranslucent(), + modelVertex, modelTranslucentPixel); + + addPipeline( + Key::Builder().withTangents().withSpecular().withTranslucent(), + modelNormalMapVertex, modelTranslucentPixel); + + + addPipeline( + Key::Builder().withLightmap(), + modelLightmapVertex, modelLightmapPixel); + + addPipeline( + Key::Builder().withLightmap().withTangents(), + modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); + + addPipeline( + Key::Builder().withLightmap().withSpecular(), + modelLightmapVertex, modelLightmapSpecularMapPixel); + + addPipeline( + Key::Builder().withLightmap().withTangents().withSpecular(), + modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + + + addPipeline( + Key::Builder().withSkinned(), + skinModelVertex, modelPixel); + + addPipeline( + Key::Builder().withSkinned().withTangents(), + skinModelNormalMapVertex, modelNormalMapPixel); + + addPipeline( + Key::Builder().withSkinned().withSpecular(), + skinModelVertex, modelSpecularMapPixel); + + addPipeline( + Key::Builder().withSkinned().withTangents().withSpecular(), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); + + + addPipeline( + Key::Builder().withSkinned().withTranslucent(), + skinModelVertex, modelTranslucentPixel); + + addPipeline( + Key::Builder().withSkinned().withTangents().withTranslucent(), + skinModelNormalMapVertex, modelTranslucentPixel); + + addPipeline( + Key::Builder().withSkinned().withSpecular().withTranslucent(), + skinModelVertex, modelTranslucentPixel); + + addPipeline( + Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(), + skinModelNormalMapVertex, modelTranslucentPixel); + + + addPipeline( + Key::Builder().withDepthOnly(), + modelShadowVertex, modelShadowPixel); + + + addPipeline( + Key::Builder().withSkinned().withDepthOnly(), + skinModelShadowVertex, modelShadowPixel); +} + diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index b4e926ddb9..85e3e7f211 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -51,26 +51,36 @@ public: class DrawOpaqueDeferred { public: + DrawOpaqueDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); using JobModel = render::Task::Job::ModelI; + +protected: + render::ShapePlumberPointer _shapePlumber; }; class DrawTransparentDeferred { public: + DrawTransparentDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); using JobModel = render::Task::Job::ModelI; + +protected: + render::ShapePlumberPointer _shapePlumber; }; class DrawStencilDeferred { - static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable public: static const gpu::PipelinePointer& getOpaquePipeline(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); using JobModel = render::Task::Job::Model; + +protected: + static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable }; class DrawBackgroundDeferred { @@ -81,13 +91,17 @@ public: }; class DrawOverlay3D { - static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable public: + DrawOverlay3D(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} static const gpu::PipelinePointer& getOpaquePipeline(); - + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); using JobModel = render::Task::Job::Model; + +protected: + static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable + render::ShapePlumberPointer _shapePlumber; }; class Blit { diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index ae3b05862e..a905dbdfd5 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -36,7 +36,7 @@ void main(void) { frag.specularVal.xyz); _fragColor = vec4(color, 1.0); } else { - vec3 color = evalAmbienSphereGlobalColor( + vec3 color = evalAmbientSphereGlobalColor( deferredTransform.viewInverse, 1.0, frag.position.xyz, diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index 22b0157762..eff40df255 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -37,7 +37,7 @@ void main(void) { frag.specularVal.xyz); _fragColor = vec4(color, 1.0); } else { - vec3 color = evalAmbienGlobalColor( + vec3 color = evalAmbientGlobalColor( deferredTransform.viewInverse, 1.0, frag.position.xyz, diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index d9fbc79d1e..2b977081a1 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -65,13 +65,17 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) { auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(_filter); outItems.clear(); - outItems.reserve(items.size()); - for (auto id : items) { - auto& item = scene->getItem(id); - outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); + + const auto& bucket = scene->getMasterBucket(); + const auto& items = bucket.find(_filter); + if (items != bucket.end()) { + outItems.reserve(items->second.size()); + for (auto& id : items->second) { + auto& item = scene->getItem(id); + outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); + } } if (_probeNumItems) { @@ -79,34 +83,6 @@ void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContex } } -void CullItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - - outItems.clear(); - outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); - args->_details.pointTo(RenderDetails::OTHER_ITEM); - cullItems(sceneContext, renderContext, inItems, outItems); -} - -void CullItemsOpaque::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - - outItems.clear(); - outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); - args->_details.pointTo(RenderDetails::OPAQUE_ITEM); - cullItems(sceneContext, renderContext, inItems, outItems); -} - -void CullItemsTransparent::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - - outItems.clear(); - outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); - args->_details.pointTo(RenderDetails::TRANSLUCENT_ITEM); - cullItems(sceneContext, renderContext, inItems, outItems); -} - - struct ItemBound { float _centerDepth = 0.0f; float _nearDepth = 0.0f; @@ -177,29 +153,40 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); } -void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { +void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); - // render - if ((maxDrawnItems < 0) || (maxDrawnItems > (int) inItems.size())) { - for (auto itemDetails : inItems) { - auto item = scene->getItem(itemDetails.id); + + for (const auto& itemDetails : inItems) { + auto& item = scene->getItem(itemDetails.id); + item.render(args); + } +} + +void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item) { + assert(item.getKey().isShape()); + const auto& key = item.getShapeKey(); + if (key.isValid() && !key.hasOwnPipeline()) { + args->_pipeline = shapeContext->pickPipeline(args, key); + if (args->_pipeline) { item.render(args); } + } else if (key.hasOwnPipeline()) { + item.render(args); } else { - int numItems = 0; - for (auto itemDetails : inItems) { - auto item = scene->getItem(itemDetails.id); - if (numItems + 1 >= maxDrawnItems) { - item.render(args); - return; - } - item.render(args); - numItems++; - if (numItems >= maxDrawnItems) { - return; - } - } + qDebug() << "Item could not be rendered: invalid key ?" << key; + } +} + +void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { + auto& scene = sceneContext->_scene; + RenderArgs* args = renderContext->getArgs(); + + auto numItemsToDraw = glm::max((int)inItems.size(), maxDrawnItems); + for (auto i = 0; i < numItemsToDraw; ++i) { + auto& item = scene->getItem(inItems[i].id); + renderShape(args, shapeContext, item); } } @@ -211,7 +198,6 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext auto& scene = sceneContext->_scene; auto& items = scene->getMasterBucket().at(ItemFilter::Builder::light()); - ItemIDsBounds inItems; inItems.reserve(items.size()); for (auto id : items) { @@ -219,15 +205,16 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext inItems.emplace_back(ItemIDAndBounds(id, item.getBound())); } + RenderArgs* args = renderContext->getArgs(); + ItemIDsBounds culledItems; culledItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); args->_details.pointTo(RenderDetails::OTHER_ITEM); cullItems(sceneContext, renderContext, inItems, culledItems); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - renderItems(sceneContext, renderContext, culledItems); + renderLights(sceneContext, renderContext, culledItems); + args->_batch = nullptr; }); - args->_batch = nullptr; } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 3efb06871a..b31ec9763e 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -13,6 +13,7 @@ #define hifi_render_DrawTask_h #include "Engine.h" +#include "ShapePipeline.h" #include "gpu/Batch.h" @@ -20,7 +21,8 @@ namespace render { void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); -void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { @@ -37,22 +39,17 @@ public: using JobModel = Task::Job::ModelO; }; +template class CullItems { public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - using JobModel = Task::Job::ModelIO; -}; + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { + outItems.clear(); + outItems.reserve(inItems.size()); + renderContext->getArgs()->_details.pointTo(T); + render::cullItems(sceneContext, renderContext, inItems, outItems); + } -class CullItemsOpaque { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - using JobModel = Task::Job::ModelIO; -}; - -class CullItemsTransparent { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - using JobModel = Task::Job::ModelIO; + using JobModel = Task::Job::ModelIO, ItemIDsBounds, ItemIDsBounds>; }; class DepthSortItems { diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 1976801c96..567e054a8a 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -25,6 +25,7 @@ #include #include "model/Material.h" +#include "ShapePipeline.h" namespace render { @@ -82,6 +83,9 @@ public: }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} + bool isShape() const { return _flags[TYPE_SHAPE]; } + bool isLight() const { return _flags[TYPE_LIGHT]; } + bool isOpaque() const { return !_flags[TRANSLUCENT]; } bool isTransparent() const { return _flags[TRANSLUCENT]; } @@ -264,7 +268,7 @@ public: virtual void render(RenderArgs* args) = 0; - virtual const model::MaterialKey getMaterialKey() const = 0; + virtual const ShapeKey getShapeKey() const = 0; ~PayloadInterface() {} @@ -301,10 +305,10 @@ public: int getLayer() const { return _payload->getLayer(); } // Render call for the item - void render(RenderArgs* args) { _payload->render(args); } + void render(RenderArgs* args) const { _payload->render(args); } // Shape Type Interface - const model::MaterialKey getMaterialKey() const { return _payload->getMaterialKey(); } + const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -346,7 +350,10 @@ template int payloadGetLayer(const std::shared_ptr& payloadData) { template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } // Shape type interface -template const model::MaterialKey shapeGetMaterialKey(const std::shared_ptr& payloadData) { return model::MaterialKey(); } +// This allows shapes to characterize their pipeline via a ShapeKey, to be picked with a subclass of Shape. +// When creating a new shape payload you need to create a specialized version, or the ShapeKey will be ownPipeline, +// implying that the shape will setup its own pipeline without the use of the ShapeKey. +template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::ownPipeline(); } template class Payload : public Item::PayloadInterface { public: @@ -364,7 +371,7 @@ public: virtual void render(RenderArgs* args) { payloadRender(_data, args); } // Shape Type interface - virtual const model::MaterialKey getMaterialKey() const { return shapeGetMaterialKey(_data); } + virtual const ShapeKey getShapeKey() const { return shapeGetShapeKey(_data); } protected: DataPointer _data; diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp new file mode 100644 index 0000000000..99424cbf4b --- /dev/null +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -0,0 +1,100 @@ +// +// ShapePipeline.cpp +// render/src/render +// +// Created by Zach Pomerantz on 12/31/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 "DependencyManager.h" + +#include "ShapePipeline.h" + +#include + +using namespace render; + +ShapeKey::Filter::Builder::Builder() { + _mask.set(OWN_PIPELINE); + _mask.set(INVALID); +} + +void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) { + // Iterate over all keys + if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { + addPipelineHelper(filter, key, bit + 1, pipeline); + if (!filter._mask[bit]) { + // Toggle bits set as insignificant in filter._mask + key._flags.flip(bit); + addPipelineHelper(filter, key, bit + 1, pipeline); + } + } else { + // Add the brand new pipeline and cache its location in the lib + _pipelineMap.insert(PipelineMap::value_type(key, pipeline)); + } +} + +void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter) { + addPipeline(Filter{key}, program, state, batchSetter); +} + +void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter) { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Slot::DIFFUSE_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::SPECULAR_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::LIGHTMAP_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::LIGHT_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING_MAP)); + + gpu::Shader::makeProgram(*program, slotBindings); + + auto locations = std::make_shared(); + locations->texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); + locations->emissiveParams = program->getUniforms().findLocation("emissiveParams"); + 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->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); + locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); + locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + + ShapeKey key{filter._flags}; + auto gpuPipeline = gpu::Pipeline::create(program, state); + auto shapePipeline = std::make_shared(gpuPipeline, locations, batchSetter); + addPipelineHelper(filter, key, 0, shapePipeline); +} + +const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Key& key) const { + assert(!_pipelineMap.empty()); + assert(args); + assert(args->_batch); + + PerformanceTimer perfTimer("ShapePlumber::pickPipeline"); + + const auto& pipelineIterator = _pipelineMap.find(key); + if (pipelineIterator == _pipelineMap.end()) { + qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key; + return PipelinePointer(nullptr); + } + + PipelinePointer shapePipeline(pipelineIterator->second); + auto& batch = args->_batch; + + // Run the pipeline's BatchSetter on the passed in batch + shapePipeline->batchSetter(*shapePipeline, *batch); + + // Setup the one pipeline (to rule them all) + batch->setPipeline(shapePipeline->pipeline); + + return shapePipeline; +} diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h new file mode 100644 index 0000000000..3d189f15fa --- /dev/null +++ b/libraries/render/src/render/ShapePipeline.h @@ -0,0 +1,249 @@ +// +// ShapePipeline.h +// render/src/render +// +// Created by Zach Pomerantz on 12/31/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_render_ShapePipeline_h +#define hifi_render_ShapePipeline_h + +#include +#include + +namespace render { + +class ShapeKey { +public: + enum FlagBit { + TRANSLUCENT = 0, + LIGHTMAP, + TANGENTS, + SPECULAR, + EMISSIVE, + SKINNED, + STEREO, + DEPTH_ONLY, + WIREFRAME, + + OWN_PIPELINE, + INVALID, + + NUM_FLAGS, // Not a valid flag + }; + using Flags = std::bitset; + + Flags _flags; + + ShapeKey() : _flags{0} {} + ShapeKey(const Flags& flags) : _flags{flags} {} + + class Builder { + public: + Builder() {} + Builder(ShapeKey key) : _flags{key._flags} {} + + ShapeKey build() const { return ShapeKey{_flags}; } + + Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); } + Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); } + Builder& withTangents() { _flags.set(TANGENTS); return (*this); } + Builder& withSpecular() { _flags.set(SPECULAR); return (*this); } + Builder& withEmissive() { _flags.set(EMISSIVE); return (*this); } + Builder& withSkinned() { _flags.set(SKINNED); return (*this); } + Builder& withStereo() { _flags.set(STEREO); return (*this); } + Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } + Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } + + Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); } + Builder& invalidate() { _flags.set(INVALID); return (*this); } + + static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); } + static const ShapeKey invalid() { return Builder().invalidate(); } + + protected: + friend class ShapeKey; + Flags _flags{0}; + }; + ShapeKey(const Builder& builder) : ShapeKey{builder._flags} {} + + class Filter { + public: + Filter(Flags flags, Flags mask) : _flags{flags}, _mask{mask} {} + Filter(const ShapeKey& key) : _flags{ key._flags } { _mask.set(); } + + // Build a standard filter (will always exclude OWN_PIPELINE, INVALID) + class Builder { + public: + Builder(); + + Filter build() const { return Filter(_flags, _mask); } + + Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } + Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } + + Builder& withLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } + Builder& withoutLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } + + Builder& withTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); } + Builder& withoutTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); } + + Builder& withSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); } + Builder& withoutSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); } + + Builder& withEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); } + Builder& withoutEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); } + + Builder& withSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); } + Builder& withoutSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); } + + Builder& withStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); } + Builder& withoutStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); } + + Builder& withDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + Builder& withoutDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + + Builder& withWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + Builder& withoutWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + + protected: + friend class Filter; + Flags _flags{0}; + Flags _mask{0}; + }; + Filter(const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {} + protected: + friend class ShapePlumber; + Flags _flags{0}; + Flags _mask{0}; + }; + + bool hasLightmap() const { return _flags[LIGHTMAP]; } + bool hasTangents() const { return _flags[TANGENTS]; } + bool hasSpecular() const { return _flags[SPECULAR]; } + bool hasEmissive() const { return _flags[EMISSIVE]; } + bool isTranslucent() const { return _flags[TRANSLUCENT]; } + bool isSkinned() const { return _flags[SKINNED]; } + bool isStereo() const { return _flags[STEREO]; } + bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } + bool isWireFrame() const { return _flags[WIREFRAME]; } + + bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } + bool isValid() const { return !_flags[INVALID]; } + + // Hasher for use in unordered_maps + class Hash { + public: + size_t operator() (const ShapeKey& key) const { + return std::hash()(key._flags); + } + }; + + // Comparator for use in unordered_maps + class KeyEqual { + public: + bool operator()(const ShapeKey& lhs, const ShapeKey& rhs) const { return lhs._flags == rhs._flags; } + }; +}; + +inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { + if (renderKey.isValid()) { + if (renderKey.hasOwnPipeline()) { + debug << "[ShapeKey: OWN_PIPELINE]"; + } else { + debug << "[ShapeKey:" + << "hasLightmap:" << renderKey.hasLightmap() + << "hasTangents:" << renderKey.hasTangents() + << "hasSpecular:" << renderKey.hasSpecular() + << "hasEmissive:" << renderKey.hasEmissive() + << "isTranslucent:" << renderKey.isTranslucent() + << "isSkinned:" << renderKey.isSkinned() + << "isStereo:" << renderKey.isStereo() + << "isDepthOnly:" << renderKey.isDepthOnly() + << "isWireFrame:" << renderKey.isWireFrame() + << "]"; + } + } else { + debug << "[ShapeKey: INVALID]"; + } + return debug; +} + +// Rendering abstraction over gpu::Pipeline and map locations +// Meta-information (pipeline and locations) to render a shape +class ShapePipeline { +public: + class Slot { + public: + static const int SKINNING_GPU = 2; + static const int MATERIAL_GPU = 3; + static const int DIFFUSE_MAP = 0; + static const int NORMAL_MAP = 1; + static const int SPECULAR_MAP = 2; + static const int LIGHTMAP_MAP = 3; + static const int LIGHT_BUFFER = 4; + static const int NORMAL_FITTING_MAP = 10; + }; + + class Locations { + public: + int texcoordMatrices; + int diffuseTextureUnit; + int normalTextureUnit; + int specularTextureUnit; + int emissiveTextureUnit; + int emissiveParams; + int normalFittingMapUnit; + int skinClusterBufferUnit; + int materialBufferUnit; + int lightBufferUnit; + }; + using LocationsPointer = std::shared_ptr; + + using BatchSetter = std::function; + + ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) : + pipeline(pipeline), locations(locations), batchSetter(batchSetter) {} + + gpu::PipelinePointer pipeline; + std::shared_ptr locations; + +protected: + friend class ShapePlumber; + + BatchSetter batchSetter; +}; +using ShapePipelinePointer = std::shared_ptr; + +class ShapePlumber { +public: + using Key = ShapeKey; + using Filter = Key::Filter; + using Pipeline = ShapePipeline; + using PipelinePointer = ShapePipelinePointer; + using PipelineMap = std::unordered_map; + using Slot = Pipeline::Slot; + using Locations = Pipeline::Locations; + using LocationsPointer = Pipeline::LocationsPointer; + using BatchSetter = Pipeline::BatchSetter; + + void addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter = nullptr); + void addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter = nullptr); + + const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const; + +protected: + void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline); + PipelineMap _pipelineMap; +}; +using ShapePlumberPointer = std::shared_ptr; + +} + +#endif // hifi_render_ShapePipeline_h diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 640ccdcb1f..789033b826 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -20,6 +20,7 @@ class AABox; class OctreeRenderer; class ViewFrustum; + namespace gpu { class Batch; class Context; @@ -27,6 +28,10 @@ class Texture; class Framebuffer; } +namespace render { +class ShapePipeline; +} + class RenderDetails { public: enum Type { @@ -103,6 +108,7 @@ public: std::shared_ptr _context = nullptr; std::shared_ptr _blitFramebuffer = nullptr; + std::shared_ptr _pipeline = nullptr; OctreeRenderer* _renderer = nullptr; ViewFrustum* _viewFrustum = nullptr; glm::ivec4 _viewport{ 0, 0, 1, 1 }; diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index 3d83c310cf..6b985da4c9 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -3,5 +3,5 @@ AUTOSCRIBE_SHADER_LIB(gpu model render-utils) # This is not a testcase -- just set it up as a regular hifi project setup_hifi_project(Quick Gui OpenGL Script Widgets) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") -link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render-utils ) +link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render render-utils ) package_libraries_for_deployment() \ No newline at end of file