diff --git a/libraries/render-utils/src/Outline.slf b/libraries/render-utils/src/Outline.slf new file mode 100644 index 0000000000..f3f01ff72b --- /dev/null +++ b/libraries/render-utils/src/Outline.slf @@ -0,0 +1,63 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// +// Add outline effect based on two zbuffers : one containing the total scene z and another +// with the z of only the objects to be outlined +// +// Created by Olivier Prat on 08/09/2017 +// Copyright 2017 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 Outline_shared.slh@> + +uniform outlineParamsBuffer { + OutlineParameters params; +}; + +uniform sampler2D sceneDepthMap; +uniform sampler2D outlinedDepthMap; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +const int BLUR_KERNEL_SIZE = 9; +const float FAR_DISTANCE = 1.0; + +void main(void) { + float outlinedDepth = texture(outlinedDepthMap, varTexCoord0).x; + if (outlinedDepth < FAR_DISTANCE) { + // We're not on the far plane so we are on the outlined object, thus no outline to do! + discard; + } + + //float sceneDepth = texture(sceneDepthMap, varTexCoord0).x; + float outlineIntensity = 0.0; + { + const float deltaUv = params._size / BLUR_KERNEL_SIZE; + vec2 uv; + vec2 startUv = varTexCoord0 - vec2(params._size, params._size) / 2.0; + int x; + int y; + + for (y=0 ; y_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -122,6 +125,69 @@ void PrepareOutline::run(const render::RenderContextPointer& renderContext, cons } } +DrawOutline::DrawOutline() { +} + +void DrawOutline::configure(const Config& config) { + _color = config.color; + _size = config.width; +} + +void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto mainFrameBuffer = inputs.get0(); + + if (mainFrameBuffer) { + auto sceneDepthBuffer = mainFrameBuffer->getPrimaryDepthTexture(); + auto outlinedDepthBuffer = inputs.get1(); + auto pipeline = getPipeline(); + + if (outlinedDepthBuffer) { + auto framebufferSize = glm::ivec2(sceneDepthBuffer->getDimensions()); + auto args = renderContext->args; + { + auto& configuration = _configuration.edit(); + configuration._color = _color; + configuration._size = _size / 1024.f; + } + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); + batch.setPipeline(pipeline); + + batch.setUniformBuffer(0, _configuration); + batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer); + batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthBuffer->getDepthTexture()); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + } + } +} + +const gpu::PipelinePointer& DrawOutline::getPipeline() { + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding("outlineParamsBuffer", 0)); + slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT)); + slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(false); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + _pipeline = gpu::Pipeline::create(program, state); + } + return _pipeline; +} + DebugOutline::DebugOutline() { _geometryId = DependencyManager::get()->allocateID(); } diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index 2b5faf4378..0561510d2b 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -73,6 +73,60 @@ private: gpu::PipelinePointer _copyDepthPipeline; }; +class DrawOutlineConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float width MEMBER width NOTIFY dirty) + Q_PROPERTY(float colorR READ getColorR WRITE setColorR NOTIFY dirty) + Q_PROPERTY(float colorG READ getColorG WRITE setColorG NOTIFY dirty) + Q_PROPERTY(float colorB READ getColorB WRITE setColorB NOTIFY dirty) +public: + + void setColorR(float value) { color.r = value; } + float getColorR() const { return color.r; } + + void setColorG(float value) { color.g = value; } + float getColorG() const { return color.g; } + + void setColorB(float value) { color.b = value; } + float getColorB() const { return color.b; } + + float width{ 5.f }; + glm::vec3 color{ 1.f, 0.7f, 0.2f }; + +signals: + void dirty(); +}; + +class DrawOutline { +public: + using Inputs = render::VaryingSet2; + using Config = DrawOutlineConfig; + using JobModel = render::Job::ModelI; + + DrawOutline(); + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); + +private: + + enum { + SCENE_DEPTH_SLOT = 0, + OUTLINED_DEPTH_SLOT + }; + +#include "Outline_shared.slh" + + using OutlineConfigurationBuffer = gpu::StructBuffer; + + const gpu::PipelinePointer& getPipeline(); + + gpu::PipelinePointer _pipeline; + OutlineConfigurationBuffer _configuration; + glm::vec3 _color; + float _size; +}; + class DebugOutlineConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(bool viewOutlinedDepth MEMBER viewOutlinedDepth NOTIFY dirty) @@ -85,7 +139,6 @@ signals: void dirty(); }; - class DebugOutline { public: using Inputs = OutlineFramebufferPointer; diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh new file mode 100644 index 0000000000..fd1d9aac49 --- /dev/null +++ b/libraries/render-utils/src/Outline_shared.slh @@ -0,0 +1,17 @@ +// glsl / C++ compatible source as interface for Outline +#ifdef __cplusplus +# define VEC3 glm::vec3 +#else +# define VEC3 vec3 +#endif + +struct OutlineParameters +{ + VEC3 _color; + float _size; +}; + +// <@if 1@> +// Trigger Scribe include +// <@endif@> +// diff --git a/libraries/render-utils/src/PickItemsJob.cpp b/libraries/render-utils/src/PickItemsJob.cpp index 3cfbd0f956..5d67f26157 100644 --- a/libraries/render-utils/src/PickItemsJob.cpp +++ b/libraries/render-utils/src/PickItemsJob.cpp @@ -14,17 +14,19 @@ PickItemsJob::PickItemsJob(render::ItemKey::Flags validKeys, render::ItemKey::Fl } void PickItemsJob::configure(const Config& config) { + _isEnabled = config.pick; } void PickItemsJob::run(const render::RenderContextPointer& renderContext, const PickItemsJob::Input& input, PickItemsJob::Output& output) { output.clear(); + if (_isEnabled) { + float minIsectDistance = std::numeric_limits::max(); + auto& itemBounds = input; + auto item = findNearestItem(renderContext, itemBounds, minIsectDistance); - float minIsectDistance = std::numeric_limits::max(); - auto& itemBounds = input; - auto item = findNearestItem(renderContext, itemBounds, minIsectDistance); - - if (render::Item::isValidID(item.id)) { - output.push_back(item); + if (render::Item::isValidID(item.id)) { + output.push_back(item); + } } } diff --git a/libraries/render-utils/src/PickItemsJob.h b/libraries/render-utils/src/PickItemsJob.h index 3e220a4e7f..221ef13b13 100644 --- a/libraries/render-utils/src/PickItemsJob.h +++ b/libraries/render-utils/src/PickItemsJob.h @@ -16,10 +16,15 @@ #include class PickItemsConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(bool pick MEMBER pick NOTIFY dirty) public: - PickItemsConfig() : render::Job::Config(false) {} + bool pick{ false }; + +signals: + void dirty(); }; class PickItemsJob { @@ -40,6 +45,7 @@ private: render::ItemKey::Flags _validKeys; render::ItemKey::Flags _excludeKeys; + bool _isEnabled{ false }; render::ItemBound findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const; }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index b48934f664..945e1c0fe3 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -169,6 +169,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer)); task.addJob("ToneMapping", toneMappingInputs); + // Draw outline + const auto outlineInputs = DrawOutline::Inputs(deferredFramebuffer, outlinedFrameBuffer).hasVarying(); + task.addJob("DrawOutline", outlineInputs); + { // DEbug the bounds of the rendered items, still look at the zbuffer task.addJob("DrawMetaBounds", metas); task.addJob("DrawOpaqueBounds", opaques); diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index 6a456054e1..05b7ffbbc9 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -15,6 +15,6 @@ var window = new OverlayWindow({ title: 'Outline', source: qml, width: 250, - height: 80, + height: 250, }); window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 11a9ecf432..4ba7dad157 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -10,20 +10,22 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 +import "configSlider" Item { id: root property var pickConfig: Render.getConfig("RenderMainView.PickOutlined") property var debugConfig: Render.getConfig("RenderMainView.DebugOutline") + property var drawConfig: Render.getConfig("RenderMainView.DrawOutline") Column { spacing: 8 CheckBox { text: "Edit Outline" - checked: root.pickConfig["enabled"] + checked: root.pickConfig["pick"] onCheckedChanged: { - root.pickConfig["enabled"] = checked; + root.pickConfig["pick"] = checked; } } CheckBox { @@ -33,5 +35,41 @@ Item { root.debugConfig["viewOutlinedDepth"] = checked; } } + ConfigSlider { + label: "Width" + integral: false + config: root.drawConfig + property: "width" + max: 15.0 + min: 0.0 + width: 230 + } + ConfigSlider { + label: "Color R" + integral: false + config: root.drawConfig + property: "colorR" + max: 1.0 + min: 0.0 + width: 230 + } + ConfigSlider { + label: "Color G" + integral: false + config: root.drawConfig + property: "colorG" + max: 1.0 + min: 0.0 + width: 230 + } + ConfigSlider { + label: "Color B" + integral: false + config: root.drawConfig + property: "colorB" + max: 1.0 + min: 0.0 + width: 230 + } } }