diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 88a0d25b7f..a29b6dc551 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -54,6 +54,8 @@ #include "PhysicalEntitySimulation.h" gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; +gpu::PipelinePointer RenderablePolyVoxEntityItem::_wireframePipeline = nullptr; + const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; @@ -697,7 +699,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { !mesh->getIndexBuffer()._buffer) { return; } - + if (!_pipeline) { gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert)); gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag)); @@ -716,6 +718,13 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { state->setDepthTest(true, true, gpu::LESS_EQUAL); _pipeline = gpu::Pipeline::create(program, state); + + auto wireframeState = std::make_shared(); + wireframeState->setCullMode(gpu::State::CULL_BACK); + wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL); + wireframeState->setFillMode(gpu::State::FILL_LINE); + + _wireframePipeline = gpu::Pipeline::create(program, wireframeState); } if (!_vertexFormat) { @@ -726,7 +735,11 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { } gpu::Batch& batch = *args->_batch; - batch.setPipeline(_pipeline); + + // Pick correct Pipeline + bool wireframe = (render::ShapeKey(args->_globalShapeKey).isWireframe()); + auto pipeline = (wireframe ? _wireframePipeline : _pipeline); + batch.setPipeline(pipeline); Transform transform(voxelToWorldMatrix()); batch.setModelTransform(transform); @@ -763,7 +776,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { batch.setResourceTexture(2, DependencyManager::get()->getWhiteTexture()); } - int voxelVolumeSizeLocation = _pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize"); + int voxelVolumeSizeLocation = pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize"); batch._glUniform3f(voxelVolumeSizeLocation, voxelVolumeSize.x, voxelVolumeSize.y, voxelVolumeSize.z); batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)mesh->getNumIndices(), 0); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 7fe45f8d99..363cd45a9d 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -164,6 +164,7 @@ private: const int MATERIAL_GPU_SLOT = 3; render::ItemID _myItem{ render::Item::INVALID_ITEM_ID }; static gpu::PipelinePointer _pipeline; + static gpu::PipelinePointer _wireframePipeline; ShapeInfo _shapeInfo; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index c3e097382c..1ad60bf7c6 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -114,13 +114,22 @@ void RenderableShapeEntityItem::render(RenderArgs* args) { auto outColor = _procedural->getColor(color); outColor.a *= _procedural->isFading() ? Interpolate::calculateFadeRatio(_procedural->getFadeStartTime()) : 1.0f; batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); - DependencyManager::get()->renderShape(batch, MAPPING[_shape]); + if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { + DependencyManager::get()->renderWireShape(batch, MAPPING[_shape]); + } else { + DependencyManager::get()->renderShape(batch, MAPPING[_shape]); + } } else { // FIXME, support instanced multi-shape rendering using multidraw indirect color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; auto geometryCache = DependencyManager::get(); auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); - geometryCache->renderSolidShapeInstance(batch, MAPPING[_shape], color, pipeline); + + if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { + geometryCache->renderWireShapeInstance(batch, MAPPING[_shape], color, pipeline); + } else { + geometryCache->renderSolidShapeInstance(batch, MAPPING[_shape], color, pipeline); + } } static const auto triCount = DependencyManager::get()->getShapeTriangleCount(MAPPING[_shape]); diff --git a/libraries/render-utils/src/LightingModel.cpp b/libraries/render-utils/src/LightingModel.cpp index 47af83da36..bd321bad95 100644 --- a/libraries/render-utils/src/LightingModel.cpp +++ b/libraries/render-utils/src/LightingModel.cpp @@ -133,6 +133,7 @@ void LightingModel::setSpotLight(bool enable) { bool LightingModel::isSpotLightEnabled() const { return (bool)_parametersBuffer.get().enableSpotLight; } + void LightingModel::setShowLightContour(bool enable) { if (enable != isShowLightContourEnabled()) { _parametersBuffer.edit().showLightContour = (float)enable; @@ -142,6 +143,14 @@ bool LightingModel::isShowLightContourEnabled() const { return (bool)_parametersBuffer.get().showLightContour; } +void LightingModel::setWireframe(bool enable) { + if (enable != isWireframeEnabled()) { + _parametersBuffer.edit().enableWireframe = (float)enable; + } +} +bool LightingModel::isWireframeEnabled() const { + return (bool)_parametersBuffer.get().enableWireframe; +} MakeLightingModel::MakeLightingModel() { _lightingModel = std::make_shared(); } @@ -167,6 +176,7 @@ void MakeLightingModel::configure(const Config& config) { _lightingModel->setSpotLight(config.enableSpotLight); _lightingModel->setShowLightContour(config.showLightContour); + _lightingModel->setWireframe(config.enableWireframe); } void MakeLightingModel::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, LightingModelPointer& lightingModel) { diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index 45514654f2..c1189d5160 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -64,6 +64,9 @@ public: void setShowLightContour(bool enable); bool isShowLightContourEnabled() const; + void setWireframe(bool enable); + bool isWireframeEnabled() const; + UniformBufferView getParametersBuffer() const { return _parametersBuffer; } protected: @@ -89,13 +92,12 @@ protected: float enablePointLight{ 1.0f }; float enableSpotLight{ 1.0f }; - float showLightContour{ 0.0f }; // false by default + float showLightContour { 0.0f }; // false by default float enableObscurance{ 1.0f }; float enableMaterialTexturing { 1.0f }; - - float spares{ 0.0f }; + float enableWireframe { 0.0f }; // false by default Parameters() {} }; @@ -129,6 +131,7 @@ class MakeLightingModelConfig : public render::Job::Config { Q_PROPERTY(bool enablePointLight MEMBER enablePointLight NOTIFY dirty) Q_PROPERTY(bool enableSpotLight MEMBER enableSpotLight NOTIFY dirty) + Q_PROPERTY(bool enableWireframe MEMBER enableWireframe NOTIFY dirty) Q_PROPERTY(bool showLightContour MEMBER showLightContour NOTIFY dirty) public: @@ -152,9 +155,10 @@ public: bool enablePointLight{ true }; bool enableSpotLight{ true }; - bool showLightContour { false }; // false by default + bool enableWireframe { false }; // false by default + signals: void dirty(); }; diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 74285aa6a9..209a1f38d6 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -17,7 +17,7 @@ struct LightingModel { vec4 _UnlitEmissiveLightmapBackground; vec4 _ScatteringDiffuseSpecularAlbedo; vec4 _AmbientDirectionalPointSpot; - vec4 _ShowContourObscuranceSpare2; + vec4 _ShowContourObscuranceWireframe; }; uniform lightingModelBuffer{ @@ -37,7 +37,7 @@ float isBackgroundEnabled() { return lightingModel._UnlitEmissiveLightmapBackground.w; } float isObscuranceEnabled() { - return lightingModel._ShowContourObscuranceSpare2.y; + return lightingModel._ShowContourObscuranceWireframe.y; } float isScatteringEnabled() { @@ -67,9 +67,12 @@ float isSpotEnabled() { } float isShowLightContour() { - return lightingModel._ShowContourObscuranceSpare2.x; + return lightingModel._ShowContourObscuranceWireframe.x; } +float isWireframeEnabled() { + return lightingModel._ShowContourObscuranceWireframe.z; +} <@endfunc@> <$declareLightingModel()$> diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 676d176cca..85a782968f 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -259,8 +259,18 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont // Setup lighting model for all items; batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); - renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + // From the lighting model define a global shapKey ORED with individiual keys + ShapeKey::Builder keyBuilder; + if (lightingModel->isWireframeEnabled()) { + keyBuilder.withWireframe(); + } + ShapeKey globalKey = keyBuilder.build(); + args->_globalShapeKey = globalKey._flags.to_ulong(); + + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn, globalKey); + args->_batch = nullptr; + args->_globalShapeKey = 0; }); config->setNumDrawn((int)inItems.size()); @@ -295,12 +305,21 @@ void DrawStateSortDeferred::run(const SceneContextPointer& sceneContext, const R // Setup lighting model for all items; batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); + // From the lighting model define a global shapKey ORED with individiual keys + ShapeKey::Builder keyBuilder; + if (lightingModel->isWireframeEnabled()) { + keyBuilder.withWireframe(); + } + ShapeKey globalKey = keyBuilder.build(); + args->_globalShapeKey = globalKey._flags.to_ulong(); + if (_stateSort) { - renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn, globalKey); } else { - renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn, globalKey); } args->_batch = nullptr; + args->_globalShapeKey = 0; }); config->setNumDrawn((int)inItems.size()); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 2829c6f8e7..e8537e3452 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -39,9 +39,9 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo } } -void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item) { +void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item, const ShapeKey& globalKey) { assert(item.getKey().isShape()); - const auto& key = item.getShapeKey(); + auto key = item.getShapeKey() | globalKey; if (key.isValid() && !key.hasOwnPipeline()) { args->_pipeline = shapeContext->pickPipeline(args, key); if (args->_pipeline) { @@ -56,7 +56,7 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons } void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems) { + const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems, const ShapeKey& globalKey) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->args; @@ -66,12 +66,12 @@ void render::renderShapes(const SceneContextPointer& sceneContext, const RenderC } for (auto i = 0; i < numItemsToDraw; ++i) { auto& item = scene->getItem(inItems[i].id); - renderShape(args, shapeContext, item); + renderShape(args, shapeContext, item, globalKey); } } void render::renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems) { + const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems, const ShapeKey& globalKey) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->args; @@ -91,7 +91,7 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons { assert(item.getKey().isShape()); - const auto key = item.getShapeKey(); + auto key = item.getShapeKey() | globalKey; if (key.isValid() && !key.hasOwnPipeline()) { auto& bucket = sortedShapes[key]; if (bucket.empty()) { diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 6e0e5ba10b..a9c5f3a4d8 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -17,8 +17,8 @@ namespace render { void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1); -void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); -void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1, const ShapeKey& globalKey = ShapeKey()); +void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1, const ShapeKey& globalKey = ShapeKey()); class DrawLightConfig : public Job::Config { Q_OBJECT diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 0c77a15184..73e8f82f24 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -46,6 +46,10 @@ public: ShapeKey() : _flags{ 0 } {} ShapeKey(const Flags& flags) : _flags{flags} {} + friend ShapeKey operator&(const ShapeKey& _Left, const ShapeKey& _Right) { return ShapeKey(_Left._flags & _Right._flags); } + friend ShapeKey operator|(const ShapeKey& _Left, const ShapeKey& _Right) { return ShapeKey(_Left._flags | _Right._flags); } + friend ShapeKey operator^(const ShapeKey& _Left, const ShapeKey& _Right) { return ShapeKey(_Left._flags ^ _Right._flags); } + class Builder { public: Builder() {} @@ -144,7 +148,7 @@ public: bool isSkinned() const { return _flags[SKINNED]; } bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } bool isDepthBiased() const { return _flags[DEPTH_BIAS]; } - bool isWireFrame() const { return _flags[WIREFRAME]; } + bool isWireframe() const { return _flags[WIREFRAME]; } bool isCullFace() const { return !_flags[NO_CULL_FACE]; } bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } @@ -180,7 +184,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) { << "isSkinned:" << key.isSkinned() << "isDepthOnly:" << key.isDepthOnly() << "isDepthBiased:" << key.isDepthBiased() - << "isWireFrame:" << key.isWireFrame() + << "isWireframe:" << key.isWireframe() << "isCullFace:" << key.isCullFace() << "]"; } diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index b2c05b0548..50722c0deb 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -122,6 +122,7 @@ public: gpu::Batch* _batch = nullptr; std::shared_ptr _whiteTexture; + uint32_t _globalShapeKey { 0 }; bool _enableTexturing { true }; RenderDetails _details; diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 99a9f258e3..c7ec8e1153 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -25,7 +25,7 @@ Column { "Lightmap:LightingModel:enableLightmap", "Background:LightingModel:enableBackground", "ssao:AmbientOcclusion:enabled", - "Textures:LightingModel:enableMaterialTexturing", + "Textures:LightingModel:enableMaterialTexturing" ] CheckBox { text: modelData.split(":")[0] @@ -45,6 +45,7 @@ Column { "Diffuse:LightingModel:enableDiffuse", "Specular:LightingModel:enableSpecular", "Albedo:LightingModel:enableAlbedo", + "Wireframe:LightingModel:enableWireframe" ] CheckBox { text: modelData.split(":")[0]