From 8071c04e98d1837ae2f2bef4c28b0c6c1f121e47 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 27 Apr 2017 10:31:06 +0200 Subject: [PATCH 01/38] Added fade effect prototype version --- interface/resources/images/fadeMask.png | Bin 0 -> 68932 bytes libraries/render-utils/src/Fade.slh | 59 +++++++++++++++ .../render-utils/src/MeshPartPayload.cpp | 68 +++++++++++------ libraries/render-utils/src/MeshPartPayload.h | 7 +- .../render-utils/src/RenderDeferredTask.cpp | 25 ++++++- .../render-utils/src/RenderDeferredTask.h | 8 +- .../render-utils/src/RenderPipelines.cpp | 22 ++++++ libraries/render-utils/src/model_fade.slf | 65 ++++++++++++++++ libraries/render-utils/src/model_fade.slv | 44 +++++++++++ .../src/model_normal_map_fade.slf | 70 ++++++++++++++++++ .../src/model_normal_map_fade.slv | 48 ++++++++++++ libraries/render/src/render/ShapePipeline.cpp | 4 + libraries/render/src/render/ShapePipeline.h | 11 +++ libraries/shared/src/RenderArgs.h | 3 +- 14 files changed, 407 insertions(+), 27 deletions(-) create mode 100644 interface/resources/images/fadeMask.png create mode 100644 libraries/render-utils/src/Fade.slh create mode 100644 libraries/render-utils/src/model_fade.slf create mode 100644 libraries/render-utils/src/model_fade.slv create mode 100644 libraries/render-utils/src/model_normal_map_fade.slf create mode 100644 libraries/render-utils/src/model_normal_map_fade.slv diff --git a/interface/resources/images/fadeMask.png b/interface/resources/images/fadeMask.png new file mode 100644 index 0000000000000000000000000000000000000000..9c342ba7888ab0d66a59dc448e30d9bdfd8204d7 GIT binary patch literal 68932 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 literal 0 HcmV?d00001 diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh new file mode 100644 index 0000000000..a40f1048a8 --- /dev/null +++ b/libraries/render-utils/src/Fade.slh @@ -0,0 +1,59 @@ +// Generated on <$_SCRIBE_DATE$> +// +// Created by Olivier Prat on 04/12/17. +// 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 +// +<@if not FADE_SLH@> +<@def FADE_SLH@> + +<@func declareFade()@> + +struct Fade { + vec3 _Offset; + float _Percent; +}; + +uniform fadeBuffer { + Fade fade; +}; + +uniform sampler2D fadeMaskMap; + +vec2 hash2D(vec3 position) { + return position.xy* vec2(0.1677, 0.221765) + position.z*0.561; +} + +float evalFadeMask(vec3 position, vec3 normal) { + const float FADE_MASK_INV_SCALE = 3.0; + + // Do tri-linear interpolation + vec3 noisePosition = position * FADE_MASK_INV_SCALE; + vec3 noisePositionFloored = floor(noisePosition) + fade._Offset; + vec3 noisePositionFraction = fract(noisePosition); + float noiseLowXLowYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored), 0).r; + float noiseLowXHighYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,1,0)), 0).r; + float noiseHighXLowYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,0,0)), 0).r; + float noiseHighXHighYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,1,0)), 0).r; + float noiseLowXLowYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,0,1)), 0).r; + float noiseLowXHighYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,1,1)), 0).r; + float noiseHighXLowYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,0,1)), 0).r; + float noiseHighXHighYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,1,1)), 0).r; + vec4 maskLowZ = vec4(noiseLowXLowYLowZ, noiseLowXHighYLowZ, noiseHighXLowYLowZ, noiseHighXHighYLowZ); + vec4 maskHighZ = vec4(noiseLowXLowYHighZ, noiseLowXHighYHighZ, noiseHighXLowYHighZ, noiseHighXHighYHighZ); + vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z); + vec2 maskY = mix(maskXY.xy, maskXY.zw, noisePositionFraction.x); + + return mix(maskY.x, maskY.y, noisePositionFraction.y); +} + +void applyFade(vec3 position, vec3 normal) { + if (evalFadeMask(position, normal) < fade._Percent) { + discard; + } +} +<@endfunc@> + +<@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 51ce0fffa7..57070479b6 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -321,11 +321,20 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } } +struct ModelMeshPartPayload::Fade +{ + glm::vec3 _offset; // The noise offset + float _percent; // The fade percent +}; + ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : _model(model), _meshIndex(_meshIndex), _shapeID(shapeIndex) { + Fade fade; + _fadeBuffer = gpu::BufferView(std::make_shared(sizeof(Fade), (const gpu::Byte*) &fade)); + assert(_model && _model->isLoaded()); auto& modelMesh = _model->getGeometry()->getMeshes().at(_meshIndex); updateMeshPart(modelMesh, partIndex); @@ -461,7 +470,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { ShapeKey::Builder builder; builder.withMaterial(); - if (isTranslucent || _fadeState != FADE_COMPLETE) { + if (isTranslucent) { builder.withTranslucent(); } if (hasTangents) { @@ -482,6 +491,9 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { if (wireframe) { builder.withWireframe(); } + if (_fadeState != FADE_COMPLETE) { + builder.withFade(); + } return builder.build(); } @@ -501,12 +513,6 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { batch.setInputBuffer(1, _model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); } - - if (_fadeState != FADE_COMPLETE) { - batch._glColor4f(1.0f, 1.0f, 1.0f, computeFadeAlpha()); - } else if (!_hasColorAttrib) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } } void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { @@ -517,23 +523,40 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: batch.setModelTransform(_transform); } -float ModelMeshPartPayload::computeFadeAlpha() const { - if (_fadeState == FADE_WAITING_TO_START) { - return 0.0f; +float ModelMeshPartPayload::computeFadePercent(bool isDebugEnabled) const { + if (!isDebugEnabled) { + if (_fadeState == FADE_WAITING_TO_START) { + return 0.0f; + } + float fadeAlpha = 1.0f; + const float INV_FADE_PERIOD = 1.0f / (float)(1 * USECS_PER_SECOND); + float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; + if (fraction < 1.0f) { + fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); + } + if (fadeAlpha >= 1.0f) { + _fadeState = FADE_COMPLETE; + // when fade-in completes we flag model for one last "render item update" + _model->setRenderItemsNeedUpdate(); + return 1.0f; + } + return Interpolate::simpleNonLinearBlend(fadeAlpha); } - float fadeAlpha = 1.0f; - const float INV_FADE_PERIOD = 1.0f / (float)(1 * USECS_PER_SECOND); - float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; - if (fraction < 1.0f) { - fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); + else { + // Animate fade for debugging purposes during repeated 3 second cycles + return (usecTimestampNow() % (3 * USECS_PER_SECOND)) / (float)(3 * USECS_PER_SECOND); } - if (fadeAlpha >= 1.0f) { - _fadeState = FADE_COMPLETE; - // when fade-in completes we flag model for one last "render item update" - _model->setRenderItemsNeedUpdate(); - return 1.0f; +} + +void ModelMeshPartPayload::bindFade(gpu::Batch& batch, bool isDebugEnabled) const { + if (_fadeState != FADE_COMPLETE || isDebugEnabled) { + auto& fade = _fadeBuffer.edit(); + glm::vec3 offset = _transform.getTranslation(); + + fade._percent = computeFadePercent(isDebugEnabled); + fade._offset = offset; + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::FADE, _fadeBuffer); } - return Interpolate::simpleNonLinearBlend(fadeAlpha); } void ModelMeshPartPayload::render(RenderArgs* args) const { @@ -576,6 +599,9 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { // apply material properties bindMaterial(batch, locations, args->_enableTexturing); + // Apply fade effect + bindFade(batch, (args->_debugFlags & RenderArgs::RENDER_DEBUG_FADE) != 0); + args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index ef74011c40..ffffb9ec88 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -93,7 +93,7 @@ public: const Transform& boundTransform, const gpu::BufferPointer& buffer); - float computeFadeAlpha() const; + float computeFadePercent(bool isDebugEnabled) const; // Render Item interface render::ItemKey getKey() const override; @@ -104,6 +104,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void bindFade(gpu::Batch& batch, bool isDebugEnabled) const; void initCache(); @@ -119,6 +120,10 @@ public: bool _isBlendShaped{ false }; private: + + struct Fade; + + mutable gpu::BufferView _fadeBuffer; mutable quint64 _fadeStartTime { 0 }; mutable uint8_t _fadeState { FADE_WAITING_TO_START }; }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 313b176f19..1dd212fea3 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -86,9 +86,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); + // Fade texture mask + auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; + auto fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); + // Render opaque objects in DeferredBuffer const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); - task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); + task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber, fadeMaskMap); // Once opaque is all rendered create stencil background task.addJob("DrawOpaqueStencil", deferredFramebuffer); @@ -310,11 +314,21 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const // 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 + // From the lighting model define a global shapeKey ORED with individiual keys ShapeKey::Builder keyBuilder; if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } + + // Prepare fade effect + batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); + if (_debugFade) { + args->_debugFlags = static_cast(args->_debugFlags | + static_cast(RenderArgs::RENDER_DEBUG_FADE)); + // Force fade for everyone + keyBuilder.withFade(); + } + ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -325,6 +339,13 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const } args->_batch = nullptr; args->_globalShapeKey = 0; + + // Not sure this is really needed... + if (_debugFade) { + // Turn off fade debug + args->_debugFlags = static_cast(args->_debugFlags & + ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); + } }); config->setNumDrawn((int)inItems.size()); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 12ecd5ecaf..c8f3326486 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -86,6 +86,7 @@ class DrawStateSortConfig : public render::Job::Config { Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) Q_PROPERTY(bool stateSort MEMBER stateSort NOTIFY dirty) + Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) public: int getNumDrawn() { return numDrawn; } @@ -93,6 +94,7 @@ public: int maxDrawn{ -1 }; bool stateSort{ true }; + bool debugFade{ false }; signals: void numDrawnChanged(); @@ -109,15 +111,17 @@ public: using Config = DrawStateSortConfig; using JobModel = render::Job::ModelI; - DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, _fadeMaskMap{ fadeMaskMap } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; _debugFade = config.debugFade; } void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; + gpu::TexturePointer _fadeMaskMap; int _maxDrawn; // initialized by Config bool _stateSort; + bool _debugFade; }; class DeferredFramebuffer; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index da264cbf7d..763fca04ed 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -41,6 +41,12 @@ #include "model_normal_specular_map_frag.h" #include "model_specular_map_frag.h" +#include "model_fade_vert.h" +#include "model_normal_map_fade_vert.h" + +#include "model_fade_frag.h" +#include "model_normal_map_fade_frag.h" + #include "forward_model_frag.h" #include "forward_model_unlit_frag.h" #include "forward_model_normal_map_frag.h" @@ -151,6 +157,10 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + // Only models can have fade applied to them (?) + auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert)); + auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert)); + // Pixel shaders auto simplePixel = gpu::Shader::createPixel(std::string(simple_textured_frag)); auto simpleUnlitPixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag)); @@ -169,6 +179,10 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { 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)); + // Only models can have fade applied to them (?) + auto modelFadePixel = gpu::Shader::createPixel(std::string(model_fade_frag)); + auto modelNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_map_fade_frag)); + using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); // TODO: Refactor this to use a filter @@ -194,6 +208,14 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); + // Same thing but with Fade on + addPipeline( + Key::Builder().withMaterial().withFade(), + modelFadeVertex, modelFadePixel); + addPipeline( + Key::Builder().withMaterial().withTangents().withFade(), + modelNormalMapFadeVertex, modelNormalMapFadePixel); + // Translucents addPipeline( Key::Builder().withMaterial().withTranslucent(), diff --git a/libraries/render-utils/src/model_fade.slf b/libraries/render-utils/src/model_fade.slf new file mode 100644 index 0000000000..06b2695d2b --- /dev/null +++ b/libraries/render-utils/src/model_fade.slf @@ -0,0 +1,65 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// model_fade.frag +// fragment shader +// +// Created by Olivier Prat on 04/19/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> + +<@include Fade.slh@> +<$declareFade()$> + +in vec4 _position; +in vec4 _worldPosition; +in vec3 _normal; +in vec3 _color; +in vec2 _texCoord0; +in vec2 _texCoord1; + + +void main(void) { + applyFade(_worldPosition.xyz, _normal); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + float scattering = getMaterialScattering(mat); + + packDeferredFragment( + normalize(_normal.xyz), + opacity, + albedo, + roughness, + getMaterialMetallic(mat), + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/model_fade.slv b/libraries/render-utils/src/model_fade.slv new file mode 100644 index 0000000000..4e6e02c1ad --- /dev/null +++ b/libraries/render-utils/src/model_fade.slv @@ -0,0 +1,44 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// model_fade.slv +// vertex shader +// +// Created by Olivier Prat on 04/24/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTexMapArrayBuffer()$> + +out vec3 _color; +out float _alpha; +out vec2 _texCoord0; +out vec2 _texCoord1; +out vec4 _position; +out vec4 _worldPosition; +out vec3 _normal; + +void main(void) { + _color = colorToLinearRGB(inColor.xyz); + _alpha = inColor.w; + + TexMapArray texMapArray = getTexMapArray(); + <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> + <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$> + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToWorldPos(obj, inPosition, _worldPosition)$> + <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> +} diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf new file mode 100644 index 0000000000..4586fe555a --- /dev/null +++ b/libraries/render-utils/src/model_normal_map_fade.slf @@ -0,0 +1,70 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_normal_map_fade.frag +// fragment shader +// +// Created by Olivier Prat on 04/19/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION, SCATTERING)$> + +<@include Fade.slh@> +<$declareFade()$> + +in vec4 _position; +in vec4 _worldPosition; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _tangent; +in vec3 _color; + +void main(void) { + applyFade(_worldPosition.xyz, _normal); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, scatteringTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 viewNormal; + <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$> + + float scattering = getMaterialScattering(mat); + <$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>; + + packDeferredFragment( + viewNormal, + opacity, + albedo, + roughness, + getMaterialMetallic(mat), + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/model_normal_map_fade.slv b/libraries/render-utils/src/model_normal_map_fade.slv new file mode 100644 index 0000000000..a71900d5c3 --- /dev/null +++ b/libraries/render-utils/src/model_normal_map_fade.slv @@ -0,0 +1,48 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_normal_map_fade.vert +// vertex shader +// +// Created by Olivier Prat on 04/24/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTexMapArrayBuffer()$> + +out vec4 _position; +out vec4 _worldPosition; +out vec2 _texCoord0; +out vec2 _texCoord1; +out vec3 _normal; +out vec3 _tangent; +out vec3 _color; +out float _alpha; + +void main(void) { + // pass along the color + _color = colorToLinearRGB(inColor.rgb); + _alpha = inColor.a; + + TexMapArray texMapArray = getTexMapArray(); + <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> + <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$> + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToWorldPos(obj, inPosition, _worldPosition)$> + <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> + <$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$> +} diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index d51d7f8cb6..77f7f61801 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -69,6 +69,8 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT)); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK)); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeBuffer"), Slot::BUFFER::FADE)); gpu::Shader::makeProgram(*program, slotBindings); @@ -87,6 +89,8 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer"); locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer"); locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap"); + locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap"); + locations->fadeBufferUnit = program->getUniformBuffers().findLocation("fadeBuffer"); ShapeKey key{filter._flags}; auto gpuPipeline = gpu::Pipeline::create(program, state); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 73e8f82f24..b8045dfbcc 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -33,6 +33,7 @@ public: DEPTH_BIAS, WIREFRAME, NO_CULL_FACE, + FADE, OWN_PIPELINE, INVALID, @@ -68,6 +69,7 @@ public: Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); return (*this); } + Builder& withFade() { _flags.set(FADE); return (*this); } Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } @@ -126,6 +128,9 @@ public: Builder& withCullFace() { _flags.reset(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); } Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); } + Builder& withFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); } + Builder& withoutFade() { _flags.set(FADE); _mask.set(FADE); return (*this); } + protected: friend class Filter; Flags _flags{0}; @@ -150,6 +155,7 @@ public: bool isDepthBiased() const { return _flags[DEPTH_BIAS]; } bool isWireframe() const { return _flags[WIREFRAME]; } bool isCullFace() const { return !_flags[NO_CULL_FACE]; } + bool isFaded() const { return _flags[FADE]; } bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } bool isValid() const { return !_flags[INVALID]; } @@ -186,6 +192,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) { << "isDepthBiased:" << key.isDepthBiased() << "isWireframe:" << key.isWireframe() << "isCullFace:" << key.isCullFace() + << "isFaded:" << key.isFaded() << "]"; } } else { @@ -207,6 +214,7 @@ public: LIGHTING_MODEL, LIGHT, LIGHT_AMBIENT_BUFFER, + FADE, }; enum MAP { @@ -218,6 +226,7 @@ public: OCCLUSION, SCATTERING, LIGHT_AMBIENT, + FADE_MASK, }; }; @@ -236,6 +245,8 @@ public: int lightBufferUnit; int lightAmbientBufferUnit; int lightAmbientMapUnit; + int fadeBufferUnit; + int fadeMaskTextureUnit; }; using LocationsPointer = std::shared_ptr; diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 10a9a20287..8fe65fb5a6 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -79,7 +79,8 @@ public: enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; enum DebugFlags { RENDER_DEBUG_NONE = 0, - RENDER_DEBUG_HULLS = 1 + RENDER_DEBUG_HULLS = 1, + RENDER_DEBUG_FADE = 2, }; RenderArgs(std::shared_ptr context = nullptr, From 111f0762eac9203aadc33be5db15fbc5b46e7367 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Sun, 30 Apr 2017 14:42:27 +0200 Subject: [PATCH 02/38] Added debug scripts and fade position is now stable --- libraries/render-utils/src/Fade.slh | 15 ++++-- .../render-utils/src/MeshPartPayload.cpp | 51 ++++++++++--------- libraries/render-utils/src/MeshPartPayload.h | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 1 + .../render-utils/src/RenderDeferredTask.h | 5 +- libraries/render-utils/src/model_fade.slf | 6 +-- libraries/render-utils/src/model_fade.slv | 6 ++- .../src/model_normal_map_fade.slf | 6 +-- .../src/model_normal_map_fade.slv | 6 ++- libraries/shared/src/RenderArgs.h | 1 + .../developer/utilities/render/debugFade.js | 21 ++++++++ scripts/developer/utilities/render/fade.qml | 33 ++++++++++++ 12 files changed, 114 insertions(+), 41 deletions(-) create mode 100644 scripts/developer/utilities/render/debugFade.js create mode 100644 scripts/developer/utilities/render/fade.qml diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 2c897a25f4..8c64710fde 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -9,11 +9,18 @@ <@if not FADE_SLH@> <@def FADE_SLH@> -<@func declareFade()@> +<@func transformModelToFadePos(objectTransform, objectPosition, fadePosition)@> + { + <$transformModelToWorldPos($objectTransform$, $objectPosition$, $fadePosition$)$> + <$fadePosition$> -= vec4(<$objectTransform$>._model[3].xyz, 0.f); + } +<@endfunc@> + +<@func declareFadeFragment()@> struct Fade { vec3 _Offset; - float _Percent; + float _Percent; }; uniform fadeBuffer { @@ -30,8 +37,8 @@ float evalFadeMask(vec3 position, vec3 normal) { const float FADE_MASK_INV_SCALE = 1.0; // Do tri-linear interpolation - vec3 noisePosition = position * FADE_MASK_INV_SCALE; - vec3 noisePositionFloored = floor(noisePosition) + fade._Offset; + vec3 noisePosition = position * FADE_MASK_INV_SCALE + fade._Offset; + vec3 noisePositionFloored = floor(noisePosition); vec3 noisePositionFraction = fract(noisePosition); float noiseLowXLowYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored), 0).r; float noiseLowXHighYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,1,0)), 0).r; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 276e6652be..5503f4a49d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -523,37 +523,40 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: batch.setModelTransform(_transform); } -float ModelMeshPartPayload::computeFadePercent(bool isDebugEnabled) const { - if (!isDebugEnabled) { - if (_fadeState == FADE_WAITING_TO_START) { - return 0.0f; - } - float fadeAlpha = 1.0f; - const float INV_FADE_PERIOD = 1.0f / (float)(3 * USECS_PER_SECOND); - float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; - if (fraction < 1.0f) { - fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); - } - if (fadeAlpha >= 1.0f) { - _fadeState = FADE_COMPLETE; - // when fade-in completes we flag model for one last "render item update" - _model->setRenderItemsNeedUpdate(); - return 1.0f; - } - return Interpolate::simpleNonLinearBlend(fadeAlpha); +float ModelMeshPartPayload::computeFadePercent() const { + if (_fadeState == FADE_WAITING_TO_START) { + return 0.0f; } - else { - // Animate fade for debugging purposes during repeated 3 second cycles - return (usecTimestampNow() % (3 * USECS_PER_SECOND)) / (float)(3 * USECS_PER_SECOND); + float fadeAlpha = 1.0f; + const float INV_FADE_PERIOD = 1.0f / (float)(3 * USECS_PER_SECOND); + float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; + if (fraction < 1.0f) { + fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); } + if (fadeAlpha >= 1.0f) { + _fadeState = FADE_COMPLETE; + // when fade-in completes we flag model for one last "render item update" + _model->setRenderItemsNeedUpdate(); + return 1.0f; + } + return Interpolate::simpleNonLinearBlend(fadeAlpha); } -void ModelMeshPartPayload::bindFade(gpu::Batch& batch, bool isDebugEnabled) const { +void ModelMeshPartPayload::bindFade(gpu::Batch& batch, const RenderArgs* args) const { + const bool isDebugEnabled = (args->_debugFlags & RenderArgs::RENDER_DEBUG_FADE) != 0; + if (_fadeState != FADE_COMPLETE || isDebugEnabled) { auto& fade = _fadeBuffer.edit(); glm::vec3 offset = _transform.getTranslation(); - fade._percent = computeFadePercent(isDebugEnabled); + // A bit ugly to have the test at every bind... + if (!isDebugEnabled) { + fade._percent = computeFadePercent(); + } + else { + fade._percent = args->_debugFadePercent; + } + fade._offset = offset; batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::FADE, _fadeBuffer); } @@ -605,7 +608,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMaterial(batch, locations, args->_enableTexturing); // Apply fade effect - bindFade(batch, (args->_debugFlags & RenderArgs::RENDER_DEBUG_FADE) != 0); + bindFade(batch, args); args->_details._materialSwitches++; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 359cfe086c..2f6b62f94d 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -93,7 +93,7 @@ public: const Transform& boundTransform, const gpu::BufferPointer& buffer); - float computeFadePercent(bool isDebugEnabled) const; + float computeFadePercent() const; // Render Item interface render::ItemKey getKey() const override; @@ -104,7 +104,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; - void bindFade(gpu::Batch& batch, bool isDebugEnabled) const; + void bindFade(gpu::Batch& batch, const RenderArgs* args) const; void initCache(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1dd212fea3..a9232300e7 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -325,6 +325,7 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const if (_debugFade) { args->_debugFlags = static_cast(args->_debugFlags | static_cast(RenderArgs::RENDER_DEBUG_FADE)); + args->_debugFadePercent = _debugFadePercent; // Force fade for everyone keyBuilder.withFade(); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index c8f3326486..4ab4915358 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -87,12 +87,14 @@ class DrawStateSortConfig : public render::Job::Config { Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) Q_PROPERTY(bool stateSort MEMBER stateSort NOTIFY dirty) Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) + Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty) public: int getNumDrawn() { return numDrawn; } void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } int maxDrawn{ -1 }; + float debugFadePercent{ 0.f }; bool stateSort{ true }; bool debugFade{ false }; @@ -113,13 +115,14 @@ public: DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, _fadeMaskMap{ fadeMaskMap } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; _debugFade = config.debugFade; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; _debugFadePercent = config.debugFadePercent; _debugFade = config.debugFade; } void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; gpu::TexturePointer _fadeMaskMap; int _maxDrawn; // initialized by Config + float _debugFadePercent; bool _stateSort; bool _debugFade; }; diff --git a/libraries/render-utils/src/model_fade.slf b/libraries/render-utils/src/model_fade.slf index 06b2695d2b..4c497228c8 100644 --- a/libraries/render-utils/src/model_fade.slf +++ b/libraries/render-utils/src/model_fade.slf @@ -19,10 +19,10 @@ <$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> <@include Fade.slh@> -<$declareFade()$> +<$declareFadeFragment()$> in vec4 _position; -in vec4 _worldPosition; +in vec4 _worldFadePosition; in vec3 _normal; in vec3 _color; in vec2 _texCoord0; @@ -30,7 +30,7 @@ in vec2 _texCoord1; void main(void) { - applyFade(_worldPosition.xyz, _normal); + applyFade(_worldFadePosition.xyz, _normal); Material mat = getMaterial(); int matKey = getMaterialKey(mat); diff --git a/libraries/render-utils/src/model_fade.slv b/libraries/render-utils/src/model_fade.slv index 4e6e02c1ad..1db3103553 100644 --- a/libraries/render-utils/src/model_fade.slv +++ b/libraries/render-utils/src/model_fade.slv @@ -19,12 +19,14 @@ <@include MaterialTextures.slh@> <$declareMaterialTexMapArrayBuffer()$> +<@include Fade.slh@> + out vec3 _color; out float _alpha; out vec2 _texCoord0; out vec2 _texCoord1; out vec4 _position; -out vec4 _worldPosition; +out vec4 _worldFadePosition; out vec3 _normal; void main(void) { @@ -39,6 +41,6 @@ void main(void) { TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> - <$transformModelToWorldPos(obj, inPosition, _worldPosition)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> } diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf index 4586fe555a..9f85a956d0 100644 --- a/libraries/render-utils/src/model_normal_map_fade.slf +++ b/libraries/render-utils/src/model_normal_map_fade.slf @@ -20,10 +20,10 @@ <$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION, SCATTERING)$> <@include Fade.slh@> -<$declareFade()$> +<$declareFadeFragment()$> in vec4 _position; -in vec4 _worldPosition; +in vec4 _worldFadePosition; in vec2 _texCoord0; in vec2 _texCoord1; in vec3 _normal; @@ -31,7 +31,7 @@ in vec3 _tangent; in vec3 _color; void main(void) { - applyFade(_worldPosition.xyz, _normal); + applyFade(_worldFadePosition.xyz, _normal); Material mat = getMaterial(); int matKey = getMaterialKey(mat); diff --git a/libraries/render-utils/src/model_normal_map_fade.slv b/libraries/render-utils/src/model_normal_map_fade.slv index a71900d5c3..7250c1e842 100644 --- a/libraries/render-utils/src/model_normal_map_fade.slv +++ b/libraries/render-utils/src/model_normal_map_fade.slv @@ -20,8 +20,10 @@ <@include MaterialTextures.slh@> <$declareMaterialTexMapArrayBuffer()$> +<@include Fade.slh@> + out vec4 _position; -out vec4 _worldPosition; +out vec4 _worldFadePosition; out vec2 _texCoord0; out vec2 _texCoord1; out vec3 _normal; @@ -42,7 +44,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> - <$transformModelToWorldPos(obj, inPosition, _worldPosition)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> <$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$> } diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 8fe65fb5a6..ce31013918 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -133,6 +133,7 @@ public: RenderDetails _details; render::ScenePointer _scene; // HACK int8_t _cameraMode { -1 }; // HACK + float _debugFadePercent{ 0.f }; // HACK too }; #endif // hifi_RenderArgs_h diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js new file mode 100644 index 0000000000..8b79905e11 --- /dev/null +++ b/scripts/developer/utilities/render/debugFade.js @@ -0,0 +1,21 @@ +// +// debugFade.js +// developer/utilities/render +// +// Olivier Prat, created on 30/04/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 +// + +// Set up the qml ui +var qml = Script.resolvePath('fade.qml'); +var window = new OverlayWindow({ + title: 'Fade', + source: qml, + width: 400, + height: 80 +}); +window.setPosition(50, 50); +window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml new file mode 100644 index 0000000000..3d391923ff --- /dev/null +++ b/scripts/developer/utilities/render/fade.qml @@ -0,0 +1,33 @@ +// +// fade.qml +// developer/utilities/render +// +// Olivier Prat, created on 30/04/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "configSlider" + +Column { + id: root + spacing: 8 + property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred"); + + CheckBox { + text: "Force Fade" + checked: drawOpaqueConfig["debugFade"] + onCheckedChanged: { drawOpaqueConfig["debugFade"] = checked } + } + ConfigSlider { + label: "Percent" + integral: false + config: drawOpaqueConfig + property: "debugFadePercent" + max: 1.0 + min: 0.0 + } +} From 08fcd6c357bfa41492307cdfe758aecf81d69983 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 5 Jun 2017 16:32:36 +0200 Subject: [PATCH 03/38] Added new shaders --- libraries/render-utils/src/Fade.slh | 6 +- .../render-utils/src/MeshPartPayload.cpp | 14 +-- .../render-utils/src/RenderDeferredTask.cpp | 19 +++- .../render-utils/src/RenderDeferredTask.h | 33 ++++--- .../render-utils/src/RenderPipelines.cpp | 78 ++++++++++++++- libraries/render-utils/src/model_fade.slf | 2 +- .../render-utils/src/model_lightmap_fade.slf | 50 ++++++++++ .../render-utils/src/model_lightmap_fade.slv | 48 +++++++++ .../src/model_lightmap_normal_map_fade.slf | 53 ++++++++++ .../src/model_lightmap_normal_map_fade.slv | 48 +++++++++ ...odel_lightmap_normal_specular_map_fade.slf | 53 ++++++++++ .../src/model_lightmap_specular_map_fade.slf | 49 ++++++++++ .../src/model_normal_map_fade.slf | 2 +- .../src/model_normal_specular_map_fade.slf | 72 ++++++++++++++ .../src/model_specular_map_fade.slf | 68 +++++++++++++ .../render-utils/src/model_unlit_fade.slf | 50 ++++++++++ libraries/render-utils/src/simple_fade.slf | 97 +++++++++++++++++++ libraries/render-utils/src/simple_fade.slv | 42 ++++++++ .../render-utils/src/simple_textured_fade.slf | 60 ++++++++++++ .../src/simple_textured_unlit_fade.slf | 54 +++++++++++ .../render-utils/src/skin_model_fade.slv | 55 +++++++++++ .../src/skin_model_normal_map_fade.slv | 64 ++++++++++++ plugins/openvr/src/ViveControllerManager.h | 2 +- .../developer/utilities/render/debugFade.js | 2 +- scripts/developer/utilities/render/fade.qml | 53 +++++++--- 25 files changed, 1030 insertions(+), 44 deletions(-) create mode 100644 libraries/render-utils/src/model_lightmap_fade.slf create mode 100644 libraries/render-utils/src/model_lightmap_fade.slv create mode 100644 libraries/render-utils/src/model_lightmap_normal_map_fade.slf create mode 100644 libraries/render-utils/src/model_lightmap_normal_map_fade.slv create mode 100644 libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf create mode 100644 libraries/render-utils/src/model_lightmap_specular_map_fade.slf create mode 100644 libraries/render-utils/src/model_normal_specular_map_fade.slf create mode 100644 libraries/render-utils/src/model_specular_map_fade.slf create mode 100644 libraries/render-utils/src/model_unlit_fade.slf create mode 100644 libraries/render-utils/src/simple_fade.slf create mode 100644 libraries/render-utils/src/simple_fade.slv create mode 100644 libraries/render-utils/src/simple_textured_fade.slf create mode 100644 libraries/render-utils/src/simple_textured_unlit_fade.slf create mode 100644 libraries/render-utils/src/skin_model_fade.slv create mode 100644 libraries/render-utils/src/skin_model_normal_map_fade.slv diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 8c64710fde..06eed5b21f 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -33,7 +33,7 @@ vec2 hash2D(vec3 position) { return position.xy* vec2(0.1677, 0.221765) + position.z*0.561; } -float evalFadeMask(vec3 position, vec3 normal) { +float evalFadeMask(vec3 position) { const float FADE_MASK_INV_SCALE = 1.0; // Do tri-linear interpolation @@ -56,8 +56,8 @@ float evalFadeMask(vec3 position, vec3 normal) { return mix(maskY.x, maskY.y, noisePositionFraction.y); } -void applyFade(vec3 position, vec3 normal) { - if (evalFadeMask(position, normal) < fade._Percent) { +void applyFade(vec3 position) { + if (evalFadeMask(position) > fade._Percent) { discard; } } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 81f8dc3228..39f07e0232 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -400,10 +400,6 @@ ItemKey ModelMeshPartPayload::getKey() const { builder.withTransparent(); } } - - if (_fadeState != FADE_COMPLETE) { - builder.withTransparent(); - } } return builder.build(); } @@ -537,9 +533,9 @@ float ModelMeshPartPayload::computeFadePercent() const { return 0.0f; } float fadeAlpha = 1.0f; - const float INV_FADE_PERIOD = 1.0f / (float)(3 * USECS_PER_SECOND); - float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; - if (fraction < 1.0f) { + const double INV_FADE_PERIOD = 1.0 / (double)(10 * USECS_PER_SECOND); + double fraction = (double)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; + if (fraction < 1.0) { fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); } if (fadeAlpha >= 1.0f) { @@ -549,9 +545,9 @@ float ModelMeshPartPayload::computeFadePercent() const { if (model) { model->setRenderItemsNeedUpdate(); } - return 1.0f; + fadeAlpha = 1.0f; } - return Interpolate::simpleNonLinearBlend(fadeAlpha); + return fadeAlpha; } void ModelMeshPartPayload::bindFade(gpu::Batch& batch, const RenderArgs* args) const { diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index fa6f72f3b5..412d74fe87 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -147,7 +147,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); - task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); + task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber, fadeMaskMap); // LIght Cluster Grid Debuging job { @@ -276,6 +276,16 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } + // Prepare fade effect + batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); + if (_debugFade) { + args->_debugFlags = static_cast(args->_debugFlags | + static_cast(RenderArgs::RENDER_DEBUG_FADE)); + args->_debugFadePercent = _debugFadePercent; + // Force fade for everyone + keyBuilder.withFade(); + } + ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -283,6 +293,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& args->_batch = nullptr; args->_globalShapeKey = 0; + + // Not sure this is really needed... + if (_debugFade) { + // Turn off fade debug + args->_debugFlags = static_cast(args->_debugFlags & + ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); + } }); config->setNumDrawn((int)inItems.size()); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 4ab4915358..ebb7d34606 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -45,17 +45,31 @@ protected: }; +class DrawFadableDeferred { +protected: + DrawFadableDeferred(gpu::TexturePointer fadeMaskMap) : _fadeMaskMap{ fadeMaskMap } {} + + gpu::TexturePointer _fadeMaskMap; + float _debugFadePercent; + bool _stateSort; + bool _debugFade; +}; + class DrawConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY newStats) - Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) + Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) + Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty) + public: int getNumDrawn() { return _numDrawn; } void setNumDrawn(int numDrawn) { _numDrawn = numDrawn; emit newStats(); } int maxDrawn{ -1 }; + float debugFadePercent{ 0.f }; + bool debugFade{ false }; signals: void newStats(); @@ -65,15 +79,15 @@ protected: int _numDrawn{ 0 }; }; -class DrawDeferred { +class DrawDeferred : public DrawFadableDeferred { public: using Inputs = render::VaryingSet2 ; using Config = DrawConfig; using JobModel = render::Job::ModelI; - DrawDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + DrawDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, DrawFadableDeferred{ fadeMaskMap } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _debugFadePercent = config.debugFadePercent; _debugFade = config.debugFade; } void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: @@ -94,8 +108,8 @@ public: void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } int maxDrawn{ -1 }; - float debugFadePercent{ 0.f }; bool stateSort{ true }; + float debugFadePercent{ 0.f }; bool debugFade{ false }; signals: @@ -106,25 +120,21 @@ protected: int numDrawn{ 0 }; }; -class DrawStateSortDeferred { +class DrawStateSortDeferred : public DrawFadableDeferred { public: using Inputs = render::VaryingSet2 ; using Config = DrawStateSortConfig; using JobModel = render::Job::ModelI; - DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, _fadeMaskMap{ fadeMaskMap } {} + DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, DrawFadableDeferred{ fadeMaskMap } {} void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; _debugFadePercent = config.debugFadePercent; _debugFade = config.debugFade; } void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; - gpu::TexturePointer _fadeMaskMap; int _maxDrawn; // initialized by Config - float _debugFadePercent; - bool _stateSort; - bool _debugFade; }; class DeferredFramebuffer; @@ -207,6 +217,7 @@ public: RenderDeferredTask() {} void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); + }; #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 763fca04ed..d771b0f5cc 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -28,12 +28,22 @@ #include "skin_model_shadow_vert.h" #include "skin_model_normal_map_vert.h" +#include "skin_model_fade_vert.h" +#include "skin_model_normal_map_fade_vert.h" + +#include "model_lightmap_fade_vert.h" +#include "model_lightmap_normal_map_fade_vert.h" + #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" #include "simple_transparent_textured_frag.h" #include "simple_transparent_textured_unlit_frag.h" +#include "simple_fade_vert.h" +#include "simple_textured_fade_frag.h" +#include "simple_textured_unlit_fade_frag.h" + #include "model_frag.h" #include "model_unlit_frag.h" #include "model_shadow_frag.h" @@ -45,7 +55,10 @@ #include "model_normal_map_fade_vert.h" #include "model_fade_frag.h" +#include "model_unlit_fade_frag.h" #include "model_normal_map_fade_frag.h" +#include "model_normal_specular_map_fade_frag.h" +#include "model_specular_map_fade_frag.h" #include "forward_model_frag.h" #include "forward_model_unlit_frag.h" @@ -60,6 +73,11 @@ #include "model_translucent_frag.h" #include "model_translucent_unlit_frag.h" +#include "model_lightmap_fade_frag.h" +#include "model_lightmap_normal_map_fade_frag.h" +#include "model_lightmap_normal_specular_map_fade_frag.h" +#include "model_lightmap_specular_map_fade_frag.h" + #include "overlay3D_vert.h" #include "overlay3D_frag.h" #include "overlay3D_model_frag.h" @@ -156,10 +174,15 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { 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)); + auto modelLightmapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_fade_vert)); + auto modelLightmapNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_fade_vert)); + auto skinModelFadeVertex = gpu::Shader::createVertex(std::string(skin_model_fade_vert)); + auto skinModelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_fade_vert)); // Only models can have fade applied to them (?) auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert)); auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert)); + auto simpleFadeVertex = gpu::Shader::createVertex(std::string(simple_fade_vert)); // Pixel shaders auto simplePixel = gpu::Shader::createPixel(std::string(simple_textured_frag)); @@ -178,10 +201,18 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { 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)); + auto modelLightmapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_fade_frag)); + auto modelLightmapNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_fade_frag)); + auto modelLightmapSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_fade_frag)); + auto modelLightmapNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_fade_frag)); - // Only models can have fade applied to them (?) auto modelFadePixel = gpu::Shader::createPixel(std::string(model_fade_frag)); + auto modelUnlitFadePixel = gpu::Shader::createPixel(std::string(model_unlit_fade_frag)); auto modelNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_map_fade_frag)); + auto modelSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_specular_map_fade_frag)); + auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag)); + auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag)); + auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag)); using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); @@ -212,9 +243,24 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withFade(), modelFadeVertex, modelFadePixel); + addPipeline( + Key::Builder().withFade(), + simpleFadeVertex, simpleFadePixel); + addPipeline( + Key::Builder().withMaterial().withUnlit().withFade(), + modelFadeVertex, modelUnlitFadePixel); + addPipeline( + Key::Builder().withUnlit().withFade(), + simpleFadeVertex, simpleUnlitFadePixel); addPipeline( Key::Builder().withMaterial().withTangents().withFade(), modelNormalMapFadeVertex, modelNormalMapFadePixel); + addPipeline( + Key::Builder().withMaterial().withSpecular().withFade(), + modelFadeVertex, modelSpecularMapFadePixel); + addPipeline( + Key::Builder().withMaterial().withTangents().withSpecular().withFade(), + modelNormalMapFadeVertex, modelNormalSpecularMapFadePixel); // Translucents addPipeline( @@ -242,6 +288,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { // FIXME: Ignore lightmap for translucents meshpart Key::Builder().withMaterial().withTranslucent().withLightmap(), modelVertex, modelTranslucentPixel); + // Lightmapped addPipeline( Key::Builder().withMaterial().withLightmap(), @@ -255,6 +302,20 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withLightmap().withTangents().withSpecular(), modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + // Same thing but with Fade on + addPipeline( + Key::Builder().withMaterial().withLightmap().withFade(), + modelLightmapFadeVertex, modelLightmapFadePixel); + addPipeline( + Key::Builder().withMaterial().withLightmap().withTangents().withFade(), + modelLightmapNormalMapFadeVertex, modelLightmapNormalMapFadePixel); + addPipeline( + Key::Builder().withMaterial().withLightmap().withSpecular().withFade(), + modelLightmapFadeVertex, modelLightmapSpecularMapFadePixel); + addPipeline( + Key::Builder().withMaterial().withLightmap().withTangents().withSpecular().withFade(), + modelLightmapNormalMapFadeVertex, modelLightmapNormalSpecularMapFadePixel); + // Skinned addPipeline( Key::Builder().withMaterial().withSkinned(), @@ -268,6 +329,20 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(), skinModelNormalMapVertex, modelNormalSpecularMapPixel); + // Same thing but with Fade on + addPipeline( + Key::Builder().withMaterial().withSkinned().withFade(), + skinModelFadeVertex, modelFadePixel); + addPipeline( + Key::Builder().withMaterial().withSkinned().withTangents().withFade(), + skinModelNormalMapFadeVertex, modelNormalMapFadePixel); + addPipeline( + Key::Builder().withMaterial().withSkinned().withSpecular().withFade(), + skinModelFadeVertex, modelSpecularMapFadePixel); + addPipeline( + Key::Builder().withMaterial().withSkinned().withTangents().withSpecular().withFade(), + skinModelNormalMapFadeVertex, modelNormalSpecularMapFadePixel); + // Skinned and Translucent addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent(), @@ -281,6 +356,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(), skinModelNormalMapVertex, modelTranslucentPixel); + // Depth-only addPipeline( Key::Builder().withDepthOnly(), diff --git a/libraries/render-utils/src/model_fade.slf b/libraries/render-utils/src/model_fade.slf index 4c497228c8..1526dea7c2 100644 --- a/libraries/render-utils/src/model_fade.slf +++ b/libraries/render-utils/src/model_fade.slf @@ -30,7 +30,7 @@ in vec2 _texCoord1; void main(void) { - applyFade(_worldFadePosition.xyz, _normal); + applyFade(_worldFadePosition.xyz); Material mat = getMaterial(); int matKey = getMaterialKey(mat); diff --git a/libraries/render-utils/src/model_lightmap_fade.slf b/libraries/render-utils/src/model_lightmap_fade.slf new file mode 100644 index 0000000000..f2055e7ffc --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_fade.slf @@ -0,0 +1,50 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_lightmap_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS)$> +<$declareMaterialLightmap()$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _color; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$> + + + packDeferredFragmentLightmap( + normalize(_normal), + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat) * roughness, + getMaterialMetallic(mat), + getMaterialFresnel(mat), + lightmapVal); +} diff --git a/libraries/render-utils/src/model_lightmap_fade.slv b/libraries/render-utils/src/model_lightmap_fade.slv new file mode 100644 index 0000000000..8ba9717b4c --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_fade.slv @@ -0,0 +1,48 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_lightmap_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/05/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Fade.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTexMapArrayBuffer()$> + +out vec4 _position; +out vec2 _texCoord0; +out vec2 _texCoord1; +out vec3 _normal; +out vec3 _color; +out vec4 _worldFadePosition; + +void main(void) { + // pass along the color in linear space + _color = colorToLinearRGB(inColor.xyz); + + // and the texture coordinates + TexMapArray texMapArray = getTexMapArray(); + <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> + <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord1)$> + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> +} + diff --git a/libraries/render-utils/src/model_lightmap_normal_map_fade.slf b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf new file mode 100644 index 0000000000..137e40dd3c --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf @@ -0,0 +1,53 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_lightmap_normal_map_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL)$> +<$declareMaterialLightmap()$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _tangent; +in vec3 _color; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$> + + vec3 viewNormal; + <$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$> + + packDeferredFragmentLightmap( + normalize(viewNormal.xyz), + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat), + getMaterialMetallic(mat), + getMaterialFresnel(mat), + lightmapVal); +} diff --git a/libraries/render-utils/src/model_lightmap_normal_map_fade.slv b/libraries/render-utils/src/model_lightmap_normal_map_fade.slv new file mode 100644 index 0000000000..e081db103b --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_normal_map_fade.slv @@ -0,0 +1,48 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_lightmap_normal_map_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/05/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Fade.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTexMapArrayBuffer()$> + +out vec4 _position; +out vec2 _texCoord0; +out vec2 _texCoord1; +out vec3 _normal; +out vec3 _tangent; +out vec3 _color; +out vec4 _worldFadePosition; + +void main(void) { + // pass along the color in linear space + _color = colorToLinearRGB(inColor.xyz); + + TexMapArray texMapArray = getTexMapArray(); + <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> + <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord1)$> + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> + <$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$> +} diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf new file mode 100644 index 0000000000..b6cdfbd2a2 --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf @@ -0,0 +1,53 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_lightmap_normal_specular_map_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$> +<$declareMaterialLightmap()$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _tangent; +in vec3 _color; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$> + + vec3 viewNormal; + <$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$> + + packDeferredFragmentLightmap( + normalize(viewNormal.xyz), + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat) * roughness, + getMaterialMetallic(mat) * metallicTex, + /*specular, // no use of */ getMaterialFresnel(mat), + lightmapVal); +} diff --git a/libraries/render-utils/src/model_lightmap_specular_map_fade.slf b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf new file mode 100644 index 0000000000..e6d82b778d --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf @@ -0,0 +1,49 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_lightmap_specular_map_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$> +<$declareMaterialLightmap()$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _color; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$> + + packDeferredFragmentLightmap( + normalize(_normal), + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat) * roughness, + getMaterialMetallic(mat) * metallicTex, + /*metallicTex, // no use of */getMaterialFresnel(mat), + lightmapVal); +} diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf index 9f85a956d0..61314fc834 100644 --- a/libraries/render-utils/src/model_normal_map_fade.slf +++ b/libraries/render-utils/src/model_normal_map_fade.slf @@ -31,7 +31,7 @@ in vec3 _tangent; in vec3 _color; void main(void) { - applyFade(_worldFadePosition.xyz, _normal); + applyFade(_worldFadePosition.xyz); Material mat = getMaterial(); int matKey = getMaterialKey(mat); diff --git a/libraries/render-utils/src/model_normal_specular_map_fade.slf b/libraries/render-utils/src/model_normal_specular_map_fade.slf new file mode 100644 index 0000000000..d9c4288e29 --- /dev/null +++ b/libraries/render-utils/src/model_normal_specular_map_fade.slf @@ -0,0 +1,72 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_normal_specular_map_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC, EMISSIVE, OCCLUSION)$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _tangent; +in vec3 _color; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 viewNormal; + <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$> + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + float scattering = getMaterialScattering(mat); + + packDeferredFragment( + normalize(viewNormal.xyz), + opacity, + albedo, + roughness, + metallic, + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/model_specular_map_fade.slf b/libraries/render-utils/src/model_specular_map_fade.slf new file mode 100644 index 0000000000..3579cf1059 --- /dev/null +++ b/libraries/render-utils/src/model_specular_map_fade.slf @@ -0,0 +1,68 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_specular_map_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC, EMISSIVE, OCCLUSION)$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _color; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + float scattering = getMaterialScattering(mat); + + packDeferredFragment( + normalize(_normal), + opacity, + albedo, + roughness, + metallic, + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/model_unlit_fade.slf b/libraries/render-utils/src/model_unlit_fade.slf new file mode 100644 index 0000000000..be0af7afea --- /dev/null +++ b/libraries/render-utils/src/model_unlit_fade.slf @@ -0,0 +1,50 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_unlit_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> +<@include LightingModel.slh@> +<@include model/Material.slh@> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO)$> + +in vec2 _texCoord0; +in vec3 _normal; +in vec3 _color; +in float _alpha; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + packDeferredFragmentUnlit( + normalize(_normal), + opacity, + albedo * isUnlitEnabled()); +} diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf new file mode 100644 index 0000000000..c082ea26f3 --- /dev/null +++ b/libraries/render-utils/src/simple_fade.slf @@ -0,0 +1,97 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 DeferredBufferWrite.slh@> +<@include model/Material.slh@> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +// the interpolated normal +in vec3 _normal; +in vec3 _modelNormal; +in vec4 _color; +in vec2 _texCoord0; +in vec4 _position; +in vec4 _worldFadePosition; + +//PROCEDURAL_COMMON_BLOCK + +#line 1001 +//PROCEDURAL_BLOCK + +#line 2030 +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material material = getMaterial(); + vec3 normal = normalize(_normal.xyz); + vec3 diffuse = _color.rgb; + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; + float emissiveAmount = 0.0; + +#ifdef PROCEDURAL + +#ifdef PROCEDURAL_V1 + specular = getProceduralColor().rgb; + // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline + //specular = pow(specular, vec3(2.2)); + emissiveAmount = 1.0; +#else + emissiveAmount = getProceduralColors(diffuse, specular, shininess); +#endif + +#endif + + const float ALPHA_THRESHOLD = 0.999; + if (_color.a < ALPHA_THRESHOLD) { + if (emissiveAmount > 0.0) { + packDeferredFragmentTranslucent( + normal, + _color.a, + specular, + DEFAULT_FRESNEL, + DEFAULT_ROUGHNESS); + } else { + packDeferredFragmentTranslucent( + normal, + _color.a, + diffuse, + DEFAULT_FRESNEL, + DEFAULT_ROUGHNESS); + } + } else { + if (emissiveAmount > 0.0) { + packDeferredFragmentLightmap( + normal, + 1.0, + diffuse, + max(0, 1.0 - shininess / 128.0), + DEFAULT_METALLIC, + specular, + specular); + } else { + packDeferredFragment( + normal, + 1.0, + diffuse, + max(0, 1.0 - shininess / 128.0), + length(specular), + DEFAULT_EMISSIVE, + DEFAULT_OCCLUSION, + DEFAULT_SCATTERING); + } + } +} diff --git a/libraries/render-utils/src/simple_fade.slv b/libraries/render-utils/src/simple_fade.slv new file mode 100644 index 0000000000..866d4cc35e --- /dev/null +++ b/libraries/render-utils/src/simple_fade.slv @@ -0,0 +1,42 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/045/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Fade.slh@> + +// the interpolated normal +out vec3 _normal; +out vec3 _modelNormal; +out vec4 _color; +out vec2 _texCoord0; +out vec4 _position; +out vec4 _worldFadePosition; + +void main(void) { + _color = colorToLinearRGBA(inColor); + _texCoord0 = inTexCoord0.st; + _position = inPosition; + _modelNormal = inNormal.xyz; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$> +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_textured_fade.slf b/libraries/render-utils/src/simple_textured_fade.slf new file mode 100644 index 0000000000..c939a8d676 --- /dev/null +++ b/libraries/render-utils/src/simple_textured_fade.slf @@ -0,0 +1,60 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_textured_fade.slf +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 gpu/Color.slh@> +<@include DeferredBufferWrite.slh@> +<@include model/Material.slh@> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + vec4 texel = texture(originalTexture, _texCoord0); + float colorAlpha = _color.a; + if (_color.a <= 0.0) { + texel = colorToLinearRGBA(texel); + colorAlpha = -_color.a; + } + + const float ALPHA_THRESHOLD = 0.999; + if (colorAlpha * texel.a < ALPHA_THRESHOLD) { + packDeferredFragmentTranslucent( + normalize(_normal), + colorAlpha * texel.a, + _color.rgb * texel.rgb, + DEFAULT_FRESNEL, + DEFAULT_ROUGHNESS); + } else { + packDeferredFragment( + normalize(_normal), + 1.0, + _color.rgb * texel.rgb, + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_EMISSIVE, + DEFAULT_OCCLUSION, + DEFAULT_SCATTERING); + } +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf new file mode 100644 index 0000000000..2db2dfa222 --- /dev/null +++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf @@ -0,0 +1,54 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_textured_unlit_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 gpu/Color.slh@> +<@include DeferredBufferWrite.slh@> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + vec4 texel = texture(originalTexture, _texCoord0.st); + float colorAlpha = _color.a; + if (_color.a <= 0.0) { + texel = colorToLinearRGBA(texel); + colorAlpha = -_color.a; + } + + const float ALPHA_THRESHOLD = 0.999; + if (colorAlpha * texel.a < ALPHA_THRESHOLD) { + packDeferredFragmentTranslucent( + normalize(_normal), + colorAlpha * texel.a, + _color.rgb * texel.rgb, + DEFAULT_FRESNEL, + DEFAULT_ROUGHNESS); + } else { + packDeferredFragmentUnlit( + normalize(_normal), + 1.0, + _color.rgb * texel.rgb); + } +} \ No newline at end of file diff --git a/libraries/render-utils/src/skin_model_fade.slv b/libraries/render-utils/src/skin_model_fade.slv new file mode 100644 index 0000000000..a96c948470 --- /dev/null +++ b/libraries/render-utils/src/skin_model_fade.slv @@ -0,0 +1,55 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/045/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Skinning.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTexMapArrayBuffer()$> + +<@include Fade.slh@> + +out vec4 _position; +out vec2 _texCoord0; +out vec2 _texCoord1; +out vec3 _normal; +out vec3 _color; +out float _alpha; +out vec4 _worldFadePosition; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0); + + skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal); + + // pass along the color + _color = colorToLinearRGB(inColor.rgb); + _alpha = inColor.a; + + TexMapArray texMapArray = getTexMapArray(); + <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> + <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$> + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, _normal.xyz)$> +} diff --git a/libraries/render-utils/src/skin_model_normal_map_fade.slv b/libraries/render-utils/src/skin_model_normal_map_fade.slv new file mode 100644 index 0000000000..5169aa5d75 --- /dev/null +++ b/libraries/render-utils/src/skin_model_normal_map_fade.slv @@ -0,0 +1,64 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model_normal_map_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/045/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Skinning.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTexMapArrayBuffer()$> + +<@include Fade.slh@> + +out vec4 _position; +out vec2 _texCoord0; +out vec2 _texCoord1; +out vec3 _normal; +out vec3 _tangent; +out vec3 _color; +out float _alpha; +out vec4 _worldFadePosition; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); + vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0); + + skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz); + + // pass along the color + _color = colorToLinearRGB(inColor.rgb); + _alpha = inColor.a; + + TexMapArray texMapArray = getTexMapArray(); + <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$> + <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$> + + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); + interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> + <$transformModelToWorldDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$> + + _normal = interpolatedNormal.xyz; + _tangent = interpolatedTangent.xyz; +} diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index c32579b0d8..f674fad50b 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -143,7 +143,7 @@ private: int _trackedControllers { 0 }; vr::IVRSystem*& _system; - quint64 _timeTilCalibration { 0.0f }; + quint64 _timeTilCalibration { 0 }; float _leftHapticStrength { 0.0f }; float _leftHapticDuration { 0.0f }; float _rightHapticStrength { 0.0f }; diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js index 8b79905e11..064337dae1 100644 --- a/scripts/developer/utilities/render/debugFade.js +++ b/scripts/developer/utilities/render/debugFade.js @@ -14,7 +14,7 @@ var qml = Script.resolvePath('fade.qml'); var window = new OverlayWindow({ title: 'Fade', source: qml, - width: 400, + width: 500, height: 80 }); window.setPosition(50, 50); diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 3d391923ff..d5622c353d 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -12,22 +12,45 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "configSlider" -Column { - id: root - spacing: 8 - property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred"); +Row { + property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred"); + property var drawTransparentConfig: Render.getConfig("DrawDeferred"); + spacing: 4 + Column { + spacing: 8 - CheckBox { - text: "Force Fade" - checked: drawOpaqueConfig["debugFade"] - onCheckedChanged: { drawOpaqueConfig["debugFade"] = checked } + CheckBox { + text: "Force Fade Opaque" + checked: drawOpaqueConfig["debugFade"] + onCheckedChanged: { drawOpaqueConfig["debugFade"] = checked } + } + CheckBox { + text: "Force Fade Transparent" + checked: drawTransparentConfig["debugFade"] + onCheckedChanged: { drawTransparentConfig["debugFade"] = checked } + } } - ConfigSlider { - label: "Percent" - integral: false - config: drawOpaqueConfig - property: "debugFadePercent" - max: 1.0 - min: 0.0 + Column { + spacing: 8 + + ConfigSlider { + label: "Percent" + integral: false + config: drawOpaqueConfig + property: "debugFadePercent" + max: 1.0 + min: 0.0 + width: 250 + } + ConfigSlider { + label: "Percent" + integral: false + config: drawTransparentConfig + property: "debugFadePercent" + max: 1.0 + min: 0.0 + width: 250 + } } } + From 74bb3213e47de07e5b9a1ffa2b2ecb61ef619a4d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 5 Jun 2017 16:44:32 +0200 Subject: [PATCH 04/38] Added shadow shader variants --- .../render-utils/src/RenderPipelines.cpp | 18 ++++++++-- .../render-utils/src/model_shadow_fade.slf | 27 +++++++++++++++ .../render-utils/src/model_shadow_fade.slv | 31 +++++++++++++++++ .../src/skin_model_shadow_fade.slv | 34 +++++++++++++++++++ 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 libraries/render-utils/src/model_shadow_fade.slf create mode 100644 libraries/render-utils/src/model_shadow_fade.slv create mode 100644 libraries/render-utils/src/skin_model_shadow_fade.slv diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index d771b0f5cc..3a9464395a 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -28,11 +28,12 @@ #include "skin_model_shadow_vert.h" #include "skin_model_normal_map_vert.h" -#include "skin_model_fade_vert.h" -#include "skin_model_normal_map_fade_vert.h" - +#include "model_shadow_fade_vert.h" #include "model_lightmap_fade_vert.h" #include "model_lightmap_normal_map_fade_vert.h" +#include "skin_model_fade_vert.h" +#include "skin_model_shadow_fade_vert.h" +#include "skin_model_normal_map_fade_vert.h" #include "simple_vert.h" #include "simple_textured_frag.h" @@ -55,6 +56,7 @@ #include "model_normal_map_fade_vert.h" #include "model_fade_frag.h" +#include "model_shadow_fade_frag.h" #include "model_unlit_fade_frag.h" #include "model_normal_map_fade_frag.h" #include "model_normal_specular_map_fade_frag.h" @@ -183,6 +185,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert)); auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert)); auto simpleFadeVertex = gpu::Shader::createVertex(std::string(simple_fade_vert)); + auto modelShadowFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); + auto skinModelShadowFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); // Pixel shaders auto simplePixel = gpu::Shader::createPixel(std::string(simple_textured_frag)); @@ -211,6 +215,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto modelNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_map_fade_frag)); auto modelSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_specular_map_fade_frag)); auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag)); + auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag)); auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag)); @@ -364,6 +369,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withSkinned().withDepthOnly(), skinModelShadowVertex, modelShadowPixel); + // Same thing but with Fade on + addPipeline( + Key::Builder().withDepthOnly().withFade(), + modelShadowFadeVertex, modelShadowFadePixel); + addPipeline( + Key::Builder().withSkinned().withDepthOnly().withFade(), + skinModelShadowFadeVertex, modelShadowFadePixel); } void initForwardPipelines(render::ShapePlumber& plumber) { diff --git a/libraries/render-utils/src/model_shadow_fade.slf b/libraries/render-utils/src/model_shadow_fade.slf new file mode 100644 index 0000000000..635917b9f4 --- /dev/null +++ b/libraries/render-utils/src/model_shadow_fade.slf @@ -0,0 +1,27 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_shadow_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 Fade.slh@> +<$declareFadeFragment()$> + +layout(location = 0) out vec4 _fragColor; + +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + // pass-through to set z-buffer + _fragColor = vec4(1.0, 1.0, 1.0, 0.0); +} diff --git a/libraries/render-utils/src/model_shadow_fade.slv b/libraries/render-utils/src/model_shadow_fade.slv new file mode 100644 index 0000000000..4b6e2e1dc1 --- /dev/null +++ b/libraries/render-utils/src/model_shadow_fade.slv @@ -0,0 +1,31 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_shadow_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/045/17. +// 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 gpu/Inputs.slh@> + +<@include gpu/Transform.slh@> + +<@include Fade.slh@> + +<$declareStandardTransform()$> + +out vec4 _worldFadePosition; + +void main(void) { + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> +} diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slv b/libraries/render-utils/src/skin_model_shadow_fade.slv new file mode 100644 index 0000000000..84d50ae754 --- /dev/null +++ b/libraries/render-utils/src/skin_model_shadow_fade.slv @@ -0,0 +1,34 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model_shadow_fade.vert +// vertex shader +// +// Created by Olivier Prat on 06/045/17. +// 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 gpu/Inputs.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Fade.slh@> + +<@include Skinning.slh@> + +out vec4 _worldFadePosition; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position); + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, position, gl_Position)$> + <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> +} From cce99ef8c45576db84cb71efe154fe91c9ad3409 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 5 Jun 2017 16:56:57 +0200 Subject: [PATCH 05/38] Added translucent shaders --- .../render-utils/src/RenderPipelines.cpp | 47 ++++++++++ .../src/model_translucent_fade.slf | 87 +++++++++++++++++++ .../src/model_translucent_unlit_fade.slf | 46 ++++++++++ .../src/simple_transparent_textured_fade.slf | 68 +++++++++++++++ ...simple_transparent_textured_unlit_fade.slf | 41 +++++++++ 5 files changed, 289 insertions(+) create mode 100644 libraries/render-utils/src/model_translucent_fade.slf create mode 100644 libraries/render-utils/src/model_translucent_unlit_fade.slf create mode 100644 libraries/render-utils/src/simple_transparent_textured_fade.slf create mode 100644 libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 3a9464395a..2cdad86156 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -44,6 +44,8 @@ #include "simple_fade_vert.h" #include "simple_textured_fade_frag.h" #include "simple_textured_unlit_fade_frag.h" +#include "simple_transparent_textured_fade_frag.h" +#include "simple_transparent_textured_unlit_fade_frag.h" #include "model_frag.h" #include "model_unlit_frag.h" @@ -79,6 +81,8 @@ #include "model_lightmap_normal_map_fade_frag.h" #include "model_lightmap_normal_specular_map_fade_frag.h" #include "model_lightmap_specular_map_fade_frag.h" +#include "model_translucent_fade_frag.h" +#include "model_translucent_unlit_fade_frag.h" #include "overlay3D_vert.h" #include "overlay3D_frag.h" @@ -216,8 +220,12 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto modelSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_specular_map_fade_frag)); auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag)); auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); + auto modelTranslucentFadePixel = gpu::Shader::createPixel(std::string(model_translucent_fade_frag)); + auto modelTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_fade_frag)); auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag)); auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag)); + auto simpleTranslucentFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_fade_frag)); + auto simpleTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_unlit_fade_frag)); using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); @@ -293,6 +301,32 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { // FIXME: Ignore lightmap for translucents meshpart Key::Builder().withMaterial().withTranslucent().withLightmap(), modelVertex, modelTranslucentPixel); + // Same thing but with Fade on + addPipeline( + Key::Builder().withMaterial().withTranslucent().withFade(), + modelFadeVertex, modelTranslucentFadePixel); + addPipeline( + Key::Builder().withTranslucent().withFade(), + simpleFadeVertex, simpleTranslucentFadePixel); + addPipeline( + Key::Builder().withMaterial().withTranslucent().withUnlit().withFade(), + modelFadeVertex, modelTranslucentUnlitFadePixel); + addPipeline( + Key::Builder().withTranslucent().withUnlit().withFade(), + simpleFadeVertex, simpleTranslucentUnlitFadePixel); + addPipeline( + Key::Builder().withMaterial().withTranslucent().withTangents().withFade(), + modelNormalMapFadeVertex, modelTranslucentFadePixel); + addPipeline( + Key::Builder().withMaterial().withTranslucent().withSpecular().withFade(), + modelFadeVertex, modelTranslucentFadePixel); + addPipeline( + Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular().withFade(), + modelNormalMapFadeVertex, modelTranslucentFadePixel); + addPipeline( + // FIXME: Ignore lightmap for translucents meshpart + Key::Builder().withMaterial().withTranslucent().withLightmap().withFade(), + modelFadeVertex, modelTranslucentFadePixel); // Lightmapped addPipeline( @@ -361,6 +395,19 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(), skinModelNormalMapVertex, modelTranslucentPixel); + // Same thing but with Fade on + addPipeline( + Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(), + skinModelFadeVertex, modelTranslucentFadePixel); + addPipeline( + Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withFade(), + skinModelNormalMapFadeVertex, modelTranslucentFadePixel); + addPipeline( + Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular().withFade(), + skinModelFadeVertex, modelTranslucentFadePixel); + addPipeline( + Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(), + skinModelNormalMapFadeVertex, modelTranslucentFadePixel); // Depth-only addPipeline( diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf new file mode 100644 index 0000000000..3bbfdabc7f --- /dev/null +++ b/libraries/render-utils/src/model_translucent_fade.slf @@ -0,0 +1,87 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_translucent_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 model/Material.slh@> + +<@include DeferredGlobalLight.slh@> + +<$declareEvalGlobalLightingAlphaBlended()$> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in float _alpha; +in vec4 _worldFadePosition; + +out vec4 _fragColor; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = getMaterialOpacity(mat) * _alpha; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + float metallic = getMaterialMetallic(mat); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } else { + fresnel = albedo; + metallic = 1.0; + } + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + + TransformCamera cam = getTransformCamera(); + + _fragColor = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + occlusionTex, + fragPosition, + fragNormal, + albedo, + fresnel, + metallic, + emissive, + roughness, opacity), + opacity); +} diff --git a/libraries/render-utils/src/model_translucent_unlit_fade.slf b/libraries/render-utils/src/model_translucent_unlit_fade.slf new file mode 100644 index 0000000000..dd885f66d7 --- /dev/null +++ b/libraries/render-utils/src/model_translucent_unlit_fade.slf @@ -0,0 +1,46 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_translucent_unlit_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> +<@include LightingModel.slh@> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +in vec2 _texCoord0; +in vec3 _color; +in float _alpha; +in vec4 _worldFadePosition; + +out vec4 _fragColor; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$> + + float opacity = getMaterialOpacity(mat) * _alpha; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + _fragColor = vec4(albedo * isUnlitEnabled(), opacity); +} diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf new file mode 100644 index 0000000000..84cdffeeec --- /dev/null +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -0,0 +1,68 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_transparent_textured_fade.slf +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 gpu/Color.slh@> + +<@include DeferredBufferWrite.slh@> +<@include DeferredGlobalLight.slh@> +<$declareEvalGlobalLightingAlphaBlended()$> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec4 _position; +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; +in vec4 _worldFadePosition; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + vec4 texel = texture(originalTexture, _texCoord0.st); + float opacity = _color.a; + if (_color.a <= 0.0) { + texel = colorToLinearRGBA(texel); + opacity = -_color.a; + } + opacity *= texel.a; + vec3 albedo = _color.rgb * texel.rgb; + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + + TransformCamera cam = getTransformCamera(); + + _fragColor0 = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + 1.0, + fragPosition, + fragNormal, + albedo, + DEFAULT_FRESNEL, + 0.0, + vec3(0.0f), + DEFAULT_ROUGHNESS, + opacity), + opacity); + +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf new file mode 100644 index 0000000000..688e1de422 --- /dev/null +++ b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf @@ -0,0 +1,41 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_transparent_textured_unlit_fade.slf +// fragment shader +// +// Created by Olivier Prat on 06/05/17. +// 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 gpu/Color.slh@> + +<@include Fade.slh@> +<$declareFadeFragment()$> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; +in vec4 _worldFadePosition; + +layout(location = 0) out vec4 _fragColor0; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + vec4 texel = texture(originalTexture, _texCoord0.st); + float colorAlpha = _color.a; + if (_color.a <= 0.0) { + texel = colorToLinearRGBA(texel); + colorAlpha = -_color.a; + } + _fragColor0 = vec4(_color.rgb * texel.rgb, colorAlpha * texel.a); +} \ No newline at end of file From 1936c209a597040cde336a691b7a53ae4349a4d6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 5 Jun 2017 17:21:33 +0200 Subject: [PATCH 06/38] Working fade debugging scripts for both opaque and transparents --- libraries/render-utils/src/RenderPipelines.cpp | 1 - scripts/developer/utilities/render/fade.qml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 2cdad86156..f199e10b95 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -185,7 +185,6 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto skinModelFadeVertex = gpu::Shader::createVertex(std::string(skin_model_fade_vert)); auto skinModelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_fade_vert)); - // Only models can have fade applied to them (?) auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert)); auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert)); auto simpleFadeVertex = gpu::Shader::createVertex(std::string(simple_fade_vert)); diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index d5622c353d..48316789ea 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -14,7 +14,7 @@ import "configSlider" Row { property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred"); - property var drawTransparentConfig: Render.getConfig("DrawDeferred"); + property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred"); spacing: 4 Column { spacing: 8 From e7eca7728f791f52457948bafbbdf668c055b6fd Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 6 Jun 2017 14:57:52 +0200 Subject: [PATCH 07/38] Debug fade management moved out of the inner render loop --- .../render-utils/src/MeshPartPayload.cpp | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 64 ++++++++++--------- .../render-utils/src/RenderDeferredTask.h | 2 +- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 39f07e0232..70adcdd98e 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -533,7 +533,7 @@ float ModelMeshPartPayload::computeFadePercent() const { return 0.0f; } float fadeAlpha = 1.0f; - const double INV_FADE_PERIOD = 1.0 / (double)(10 * USECS_PER_SECOND); + const double INV_FADE_PERIOD = 1.0 / (double)(3 * USECS_PER_SECOND); double fraction = (double)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; if (fraction < 1.0) { fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 412d74fe87..8d4a92ff7d 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -252,6 +252,15 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; + ShapeKey::Builder defaultKeyBuilder; + + if (_debugFade) { + args->_debugFlags = static_cast(args->_debugFlags | + static_cast(RenderArgs::RENDER_DEBUG_FADE)); + args->_debugFadePercent = _debugFadePercent; + // Force fade for everyone + defaultKeyBuilder.withFade(); + } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -272,19 +281,12 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); // From the lighting model define a global shapKey ORED with individiual keys - ShapeKey::Builder keyBuilder; + ShapeKey::Builder keyBuilder = defaultKeyBuilder; if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } // Prepare fade effect batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); - if (_debugFade) { - args->_debugFlags = static_cast(args->_debugFlags | - static_cast(RenderArgs::RENDER_DEBUG_FADE)); - args->_debugFadePercent = _debugFadePercent; - // Force fade for everyone - keyBuilder.withFade(); - } ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -293,15 +295,15 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& args->_batch = nullptr; args->_globalShapeKey = 0; - - // Not sure this is really needed... - if (_debugFade) { - // Turn off fade debug - args->_debugFlags = static_cast(args->_debugFlags & - ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); - } }); + // Not sure this is really needed... + if (_debugFade) { + // Turn off fade debug + args->_debugFlags = static_cast(args->_debugFlags & + ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); + } + config->setNumDrawn((int)inItems.size()); } @@ -315,6 +317,15 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; + ShapeKey::Builder defaultKeyBuilder; + + if (_debugFade) { + args->_debugFlags = static_cast(args->_debugFlags | + static_cast(RenderArgs::RENDER_DEBUG_FADE)); + args->_debugFadePercent = _debugFadePercent; + // Force fade for everyone + defaultKeyBuilder.withFade(); + } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -335,20 +346,13 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); // From the lighting model define a global shapeKey ORED with individiual keys - ShapeKey::Builder keyBuilder; + ShapeKey::Builder keyBuilder = defaultKeyBuilder; if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } // Prepare fade effect batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); - if (_debugFade) { - args->_debugFlags = static_cast(args->_debugFlags | - static_cast(RenderArgs::RENDER_DEBUG_FADE)); - args->_debugFadePercent = _debugFadePercent; - // Force fade for everyone - keyBuilder.withFade(); - } ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -360,15 +364,15 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const } args->_batch = nullptr; args->_globalShapeKey = 0; - - // Not sure this is really needed... - if (_debugFade) { - // Turn off fade debug - args->_debugFlags = static_cast(args->_debugFlags & - ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); - } }); + // Not sure this is really needed... + if (_debugFade) { + // Turn off fade debug + args->_debugFlags = static_cast(args->_debugFlags & + ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); + } + config->setNumDrawn((int)inItems.size()); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index ebb7d34606..1f20615328 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -51,7 +51,6 @@ protected: gpu::TexturePointer _fadeMaskMap; float _debugFadePercent; - bool _stateSort; bool _debugFade; }; @@ -135,6 +134,7 @@ public: protected: render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config + bool _stateSort; }; class DeferredFramebuffer; From 8af2f759968d8827f349d73e874a8abf070fc223 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 6 Jun 2017 16:11:12 +0200 Subject: [PATCH 08/38] Added FadeManager to centralize some common fade effect data and functions --- libraries/render-utils/src/FadeManager.cpp | 25 +++++++++ libraries/render-utils/src/FadeManager.h | 43 ++++++++++++++ .../render-utils/src/MeshPartPayload.cpp | 9 +-- libraries/render-utils/src/MeshPartPayload.h | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 56 ++++++------------- .../render-utils/src/RenderDeferredTask.h | 47 ++++++++-------- libraries/shared/src/RenderArgs.h | 2 - scripts/developer/utilities/render/fade.qml | 25 ++------- 8 files changed, 118 insertions(+), 91 deletions(-) create mode 100644 libraries/render-utils/src/FadeManager.cpp create mode 100644 libraries/render-utils/src/FadeManager.h diff --git a/libraries/render-utils/src/FadeManager.cpp b/libraries/render-utils/src/FadeManager.cpp new file mode 100644 index 0000000000..f70e2e94d0 --- /dev/null +++ b/libraries/render-utils/src/FadeManager.cpp @@ -0,0 +1,25 @@ +#include "FadeManager.h" +#include "TextureCache.h" + +#include + +FadeManager::FadeManager() : + _isDebugEnabled{ false }, + _debugFadePercent{ 0.f } +{ + auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; + _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); +} + +render::ShapeKey::Builder FadeManager::getKeyBuilder() const +{ + render::ShapeKey::Builder builder; + + if (_isDebugEnabled) { + // Force fade for everyone + builder.withFade(); + } + + return builder; +} + diff --git a/libraries/render-utils/src/FadeManager.h b/libraries/render-utils/src/FadeManager.h new file mode 100644 index 0000000000..d42447fc26 --- /dev/null +++ b/libraries/render-utils/src/FadeManager.h @@ -0,0 +1,43 @@ +// +// FadeManager.h +// libraries/render-utils/src/ +// +// Created by Olivier Prat on 06/06/17. +// 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 +// +#ifndef hifi_FadeManager_h +#define hifi_FadeManager_h + +#include +#include +#include + +// Centralizes fade effect data and functions +class FadeManager : public Dependency { + SINGLETON_DEPENDENCY +public: + + FadeManager(); + + const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } + + void setDebugEnabled(bool isEnabled) { _isDebugEnabled = isEnabled; } + bool isDebugEnabled() const { return _isDebugEnabled; } + + void setDebugFadePercent(float value) { assert(value >= 0.f && value <= 1.f); _debugFadePercent = value; } + float getDebugFadePercent() const { return _debugFadePercent; } + + render::ShapeKey::Builder getKeyBuilder() const; + +private: + + gpu::TexturePointer _fadeMaskMap; + float _debugFadePercent; + bool _isDebugEnabled; + +}; + +#endif // hifi_FadeManager_h diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 70adcdd98e..87ac019030 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -15,6 +15,7 @@ #include "DeferredLightingEffect.h" #include "EntityItem.h" +#include "FadeManager.h" using namespace render; @@ -550,8 +551,8 @@ float ModelMeshPartPayload::computeFadePercent() const { return fadeAlpha; } -void ModelMeshPartPayload::bindFade(gpu::Batch& batch, const RenderArgs* args) const { - const bool isDebugEnabled = (args->_debugFlags & RenderArgs::RENDER_DEBUG_FADE) != 0; +void ModelMeshPartPayload::bindFade(gpu::Batch& batch) const { + const bool isDebugEnabled = DependencyManager::get()->isDebugEnabled(); if (_fadeState != FADE_COMPLETE || isDebugEnabled) { auto& fade = _fadeBuffer.edit(); @@ -562,7 +563,7 @@ void ModelMeshPartPayload::bindFade(gpu::Batch& batch, const RenderArgs* args) c fade._percent = computeFadePercent(); } else { - fade._percent = args->_debugFadePercent; + fade._percent = DependencyManager::get()->getDebugFadePercent(); } fade._offset = offset; @@ -617,7 +618,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMaterial(batch, locations, args->_enableTexturing); // Apply fade effect - bindFade(batch, args); + bindFade(batch); args->_details._materialSwitches++; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index f29c482bd9..0d3a8df576 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -106,7 +106,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; - void bindFade(gpu::Batch& batch, const RenderArgs* args) const; + void bindFade(gpu::Batch& batch) const; void initCache(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 8d4a92ff7d..4d91d7d512 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,6 +35,7 @@ #include "HitEffect.h" #include "TextureCache.h" #include "ZoneRenderer.h" +#include "FadeManager.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" @@ -50,6 +51,12 @@ using namespace render; extern void initOverlay3DPipelines(render::ShapePlumber& plumber); extern void initDeferredPipelines(render::ShapePlumber& plumber); +void RenderDeferredTask::configure(const Config& config) +{ + DependencyManager::get()->setDebugEnabled(config.debugFade); + DependencyManager::get()->setDebugFadePercent(config.debugFadePercent); +} + void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get(); @@ -85,13 +92,11 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); - // Fade texture mask - auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; - auto fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); + DependencyManager::set(); // Render opaque objects in DeferredBuffer const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); - task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber, fadeMaskMap); + task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); // Once opaque is all rendered create stencil background task.addJob("DrawOpaqueStencil", deferredFramebuffer); @@ -147,7 +152,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); - task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber, fadeMaskMap); + task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); // LIght Cluster Grid Debuging job { @@ -252,15 +257,8 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder; - - if (_debugFade) { - args->_debugFlags = static_cast(args->_debugFlags | - static_cast(RenderArgs::RENDER_DEBUG_FADE)); - args->_debugFadePercent = _debugFadePercent; - // Force fade for everyone - defaultKeyBuilder.withFade(); - } + ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -285,8 +283,9 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } + // Prepare fade effect - batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); + batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, fadeMaskMap); ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -297,13 +296,6 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& args->_globalShapeKey = 0; }); - // Not sure this is really needed... - if (_debugFade) { - // Turn off fade debug - args->_debugFlags = static_cast(args->_debugFlags & - ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); - } - config->setNumDrawn((int)inItems.size()); } @@ -317,15 +309,8 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder; - - if (_debugFade) { - args->_debugFlags = static_cast(args->_debugFlags | - static_cast(RenderArgs::RENDER_DEBUG_FADE)); - args->_debugFadePercent = _debugFadePercent; - // Force fade for everyone - defaultKeyBuilder.withFade(); - } + ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -352,7 +337,7 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const } // Prepare fade effect - batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); + batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, fadeMaskMap); ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -366,13 +351,6 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const args->_globalShapeKey = 0; }); - // Not sure this is really needed... - if (_debugFade) { - // Turn off fade debug - args->_debugFlags = static_cast(args->_debugFlags & - ~static_cast(RenderArgs::RENDER_DEBUG_FADE)); - } - config->setNumDrawn((int)inItems.size()); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 1f20615328..37f274896b 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -44,22 +44,10 @@ public: protected: }; - -class DrawFadableDeferred { -protected: - DrawFadableDeferred(gpu::TexturePointer fadeMaskMap) : _fadeMaskMap{ fadeMaskMap } {} - - gpu::TexturePointer _fadeMaskMap; - float _debugFadePercent; - bool _debugFade; -}; - class DrawConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY newStats) Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) - Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) - Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty) public: @@ -67,8 +55,6 @@ public: void setNumDrawn(int numDrawn) { _numDrawn = numDrawn; emit newStats(); } int maxDrawn{ -1 }; - float debugFadePercent{ 0.f }; - bool debugFade{ false }; signals: void newStats(); @@ -78,15 +64,15 @@ protected: int _numDrawn{ 0 }; }; -class DrawDeferred : public DrawFadableDeferred { +class DrawDeferred { public: using Inputs = render::VaryingSet2 ; using Config = DrawConfig; using JobModel = render::Job::ModelI; - DrawDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, DrawFadableDeferred{ fadeMaskMap } {} + DrawDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; _debugFadePercent = config.debugFadePercent; _debugFade = config.debugFade; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; } void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: @@ -99,8 +85,6 @@ class DrawStateSortConfig : public render::Job::Config { Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) Q_PROPERTY(bool stateSort MEMBER stateSort NOTIFY dirty) - Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) - Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty) public: int getNumDrawn() { return numDrawn; } @@ -108,8 +92,6 @@ public: int maxDrawn{ -1 }; bool stateSort{ true }; - float debugFadePercent{ 0.f }; - bool debugFade{ false }; signals: void numDrawnChanged(); @@ -119,16 +101,16 @@ protected: int numDrawn{ 0 }; }; -class DrawStateSortDeferred : public DrawFadableDeferred { +class DrawStateSortDeferred { public: using Inputs = render::VaryingSet2 ; using Config = DrawStateSortConfig; using JobModel = render::Job::ModelI; - DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber, gpu::TexturePointer fadeMaskMap) : _shapePlumber{ shapePlumber }, DrawFadableDeferred{ fadeMaskMap } {} + DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; _debugFadePercent = config.debugFadePercent; _debugFade = config.debugFade; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; } void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: @@ -209,13 +191,28 @@ public: void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer); }; +class RenderDeferredTaskConfig : public render::Task::Config { + Q_OBJECT + Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) + Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty) +public: + float debugFadePercent{ 0.f }; + bool debugFade{ false }; + +signals: + void dirty(); + +}; + class RenderDeferredTask { public: using Input = RenderFetchCullSortTask::Output; - using JobModel = render::Task::ModelI; + using Config = RenderDeferredTaskConfig; + using JobModel = render::Task::ModelI; RenderDeferredTask() {} + void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); }; diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index ce31013918..7ad3672c08 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -80,7 +80,6 @@ public: enum DebugFlags { RENDER_DEBUG_NONE = 0, RENDER_DEBUG_HULLS = 1, - RENDER_DEBUG_FADE = 2, }; RenderArgs(std::shared_ptr context = nullptr, @@ -133,7 +132,6 @@ public: RenderDetails _details; render::ScenePointer _scene; // HACK int8_t _cameraMode { -1 }; // HACK - float _debugFadePercent{ 0.f }; // HACK too }; #endif // hifi_RenderArgs_h diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 48316789ea..137e45d08d 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -13,21 +13,15 @@ import QtQuick.Controls 1.4 import "configSlider" Row { - property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred"); - property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred"); + property var taskConfig: Render.getConfig("RenderDeferredTask"); spacing: 4 Column { spacing: 8 CheckBox { - text: "Force Fade Opaque" - checked: drawOpaqueConfig["debugFade"] - onCheckedChanged: { drawOpaqueConfig["debugFade"] = checked } - } - CheckBox { - text: "Force Fade Transparent" - checked: drawTransparentConfig["debugFade"] - onCheckedChanged: { drawTransparentConfig["debugFade"] = checked } + text: "Force Fade" + checked: taskConfig["debugFade"] + onCheckedChanged: { taskConfig["debugFade"] = checked } } } Column { @@ -36,16 +30,7 @@ Row { ConfigSlider { label: "Percent" integral: false - config: drawOpaqueConfig - property: "debugFadePercent" - max: 1.0 - min: 0.0 - width: 250 - } - ConfigSlider { - label: "Percent" - integral: false - config: drawTransparentConfig + config: taskConfig property: "debugFadePercent" max: 1.0 min: 0.0 From a9ab9d247625c851889e54f689723cce05229bd7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 6 Jun 2017 16:27:56 +0200 Subject: [PATCH 09/38] Renamed FadeManager to FadeEffect --- .../src/{FadeManager.cpp => FadeEffect.cpp} | 6 +++--- .../src/{FadeManager.h => FadeEffect.h} | 12 ++++++------ libraries/render-utils/src/MeshPartPayload.cpp | 6 +++--- .../render-utils/src/RenderDeferredTask.cpp | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) rename libraries/render-utils/src/{FadeManager.cpp => FadeEffect.cpp} (79%) rename libraries/render-utils/src/{FadeManager.h => FadeEffect.h} (86%) diff --git a/libraries/render-utils/src/FadeManager.cpp b/libraries/render-utils/src/FadeEffect.cpp similarity index 79% rename from libraries/render-utils/src/FadeManager.cpp rename to libraries/render-utils/src/FadeEffect.cpp index f70e2e94d0..f750798914 100644 --- a/libraries/render-utils/src/FadeManager.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -1,9 +1,9 @@ -#include "FadeManager.h" +#include "FadeEffect.h" #include "TextureCache.h" #include -FadeManager::FadeManager() : +FadeEffect::FadeEffect() : _isDebugEnabled{ false }, _debugFadePercent{ 0.f } { @@ -11,7 +11,7 @@ FadeManager::FadeManager() : _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); } -render::ShapeKey::Builder FadeManager::getKeyBuilder() const +render::ShapeKey::Builder FadeEffect::getKeyBuilder() const { render::ShapeKey::Builder builder; diff --git a/libraries/render-utils/src/FadeManager.h b/libraries/render-utils/src/FadeEffect.h similarity index 86% rename from libraries/render-utils/src/FadeManager.h rename to libraries/render-utils/src/FadeEffect.h index d42447fc26..6c5b2c90c8 100644 --- a/libraries/render-utils/src/FadeManager.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -1,5 +1,5 @@ // -// FadeManager.h +// FadeEffect.h // libraries/render-utils/src/ // // Created by Olivier Prat on 06/06/17. @@ -8,19 +8,19 @@ // 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_FadeManager_h -#define hifi_FadeManager_h +#ifndef hifi_FadeEffect_h +#define hifi_FadeEffect_h #include #include #include // Centralizes fade effect data and functions -class FadeManager : public Dependency { +class FadeEffect : public Dependency { SINGLETON_DEPENDENCY public: - FadeManager(); + FadeEffect(); const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } @@ -40,4 +40,4 @@ private: }; -#endif // hifi_FadeManager_h +#endif // hifi_FadeEffect_h diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 87ac019030..1d6ddea70f 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -15,7 +15,7 @@ #include "DeferredLightingEffect.h" #include "EntityItem.h" -#include "FadeManager.h" +#include "FadeEffect.h" using namespace render; @@ -552,7 +552,7 @@ float ModelMeshPartPayload::computeFadePercent() const { } void ModelMeshPartPayload::bindFade(gpu::Batch& batch) const { - const bool isDebugEnabled = DependencyManager::get()->isDebugEnabled(); + const bool isDebugEnabled = DependencyManager::get()->isDebugEnabled(); if (_fadeState != FADE_COMPLETE || isDebugEnabled) { auto& fade = _fadeBuffer.edit(); @@ -563,7 +563,7 @@ void ModelMeshPartPayload::bindFade(gpu::Batch& batch) const { fade._percent = computeFadePercent(); } else { - fade._percent = DependencyManager::get()->getDebugFadePercent(); + fade._percent = DependencyManager::get()->getDebugFadePercent(); } fade._offset = offset; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 4d91d7d512..1e8673b385 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,7 +35,7 @@ #include "HitEffect.h" #include "TextureCache.h" #include "ZoneRenderer.h" -#include "FadeManager.h" +#include "FadeEffect.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" @@ -53,8 +53,8 @@ extern void initDeferredPipelines(render::ShapePlumber& plumber); void RenderDeferredTask::configure(const Config& config) { - DependencyManager::get()->setDebugEnabled(config.debugFade); - DependencyManager::get()->setDebugFadePercent(config.debugFadePercent); + DependencyManager::get()->setDebugEnabled(config.debugFade); + DependencyManager::get()->setDebugFadePercent(config.debugFadePercent); } void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { @@ -92,7 +92,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); - DependencyManager::set(); + DependencyManager::set(); // Render opaque objects in DeferredBuffer const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); @@ -257,8 +257,8 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); - gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); + ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -309,8 +309,8 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); - gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); + ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; From de143d0ea28592ade76fed5cdc8fc4904b0168f1 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 6 Jun 2017 17:07:20 +0200 Subject: [PATCH 10/38] Switched to uniforms for sending fade shader data. Moved more fade functions to FadeEffect class --- libraries/render-utils/src/Fade.slh | 15 ++--- libraries/render-utils/src/FadeEffect.cpp | 39 +++++++++++- libraries/render-utils/src/FadeEffect.h | 10 +++ .../render-utils/src/MeshPartPayload.cpp | 61 ++----------------- libraries/render-utils/src/MeshPartPayload.h | 13 +--- .../render-utils/src/RenderDeferredTask.cpp | 6 +- 6 files changed, 60 insertions(+), 84 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 06eed5b21f..d634473dd0 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -18,15 +18,8 @@ <@func declareFadeFragment()@> -struct Fade { - vec3 _Offset; - float _Percent; -}; - -uniform fadeBuffer { - Fade fade; -}; - +uniform vec3 fadeOffset; +uniform float fadePercent; uniform sampler2D fadeMaskMap; vec2 hash2D(vec3 position) { @@ -37,7 +30,7 @@ float evalFadeMask(vec3 position) { const float FADE_MASK_INV_SCALE = 1.0; // Do tri-linear interpolation - vec3 noisePosition = position * FADE_MASK_INV_SCALE + fade._Offset; + vec3 noisePosition = position * FADE_MASK_INV_SCALE + fadeOffset; vec3 noisePositionFloored = floor(noisePosition); vec3 noisePositionFraction = fract(noisePosition); float noiseLowXLowYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored), 0).r; @@ -57,7 +50,7 @@ float evalFadeMask(vec3 position) { } void applyFade(vec3 position) { - if (evalFadeMask(position) > fade._Percent) { + if (evalFadeMask(position) > fadePercent) { discard; } } diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index f750798914..0bca42ad12 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -2,6 +2,9 @@ #include "TextureCache.h" #include +#include +#include +#include FadeEffect::FadeEffect() : _isDebugEnabled{ false }, @@ -11,8 +14,7 @@ FadeEffect::FadeEffect() : _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); } -render::ShapeKey::Builder FadeEffect::getKeyBuilder() const -{ +render::ShapeKey::Builder FadeEffect::getKeyBuilder() const { render::ShapeKey::Builder builder; if (_isDebugEnabled) { @@ -23,3 +25,36 @@ render::ShapeKey::Builder FadeEffect::getKeyBuilder() const return builder; } +void FadeEffect::bindPerBatch(gpu::Batch& batch) const +{ + batch.setResourceTexture(render::ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); +} + +float FadeEffect::computeFadePercent(quint64 startTime) const { + float fadeAlpha = 1.0f; + const double INV_FADE_PERIOD = 1.0 / (double)(3 * USECS_PER_SECOND); + double fraction = (double)(usecTimestampNow() - startTime) * INV_FADE_PERIOD; + if (fraction < 1.0) { + fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); + } + return fadeAlpha; +} + +void FadeEffect::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, State state) const { + if (state != Complete || _isDebugEnabled) { + const gpu::ShaderPointer& program = args->_pipeline->pipeline->getProgram(); + int fadeOffsetLoc = program->getUniforms().findLocation("fadeOffset"); + int fadePercentLoc = program->getUniforms().findLocation("fadePercent"); + float percent; + + // A bit ugly to have the test at every bind... + if (!_isDebugEnabled) { + percent = computeFadePercent(startTime); + } + else { + percent = _debugFadePercent; + } + batch._glUniform1f(fadePercentLoc, percent); + batch._glUniform3f(fadeOffsetLoc, offset.x, offset.y, offset.z); + } +} diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 6c5b2c90c8..b1cbf0cb29 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -20,6 +20,12 @@ class FadeEffect : public Dependency { SINGLETON_DEPENDENCY public: + enum State : uint8_t { + WaitingToStart = 0, + InProgress = 1, + Complete = 2, + }; + FadeEffect(); const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } @@ -32,6 +38,10 @@ public: render::ShapeKey::Builder getKeyBuilder() const; + void bindPerBatch(gpu::Batch& batch) const; + void bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, State state = InProgress) const; + float computeFadePercent(quint64 startTime) const; + private: gpu::TexturePointer _fadeMaskMap; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1d6ddea70f..a44974cc92 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -321,19 +321,10 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } } -struct ModelMeshPartPayload::Fade -{ - glm::vec3 _offset; // The noise offset - float _percent; // The fade percent -}; - ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : _meshIndex(_meshIndex), _shapeID(shapeIndex) { - Fade fade; - _fadeBuffer = gpu::BufferView(std::make_shared(sizeof(Fade), (const gpu::Byte*) &fade)); - assert(model && model->isLoaded()); _model = model; auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); @@ -493,7 +484,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { if (wireframe) { builder.withWireframe(); } - if (_fadeState != FADE_COMPLETE) { + if (_fadeState != FadeEffect::Complete) { builder.withFade(); } return builder.build(); @@ -529,48 +520,6 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: batch.setModelTransform(_transform); } -float ModelMeshPartPayload::computeFadePercent() const { - if (_fadeState == FADE_WAITING_TO_START) { - return 0.0f; - } - float fadeAlpha = 1.0f; - const double INV_FADE_PERIOD = 1.0 / (double)(3 * USECS_PER_SECOND); - double fraction = (double)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD; - if (fraction < 1.0) { - fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); - } - if (fadeAlpha >= 1.0f) { - _fadeState = FADE_COMPLETE; - // when fade-in completes we flag model for one last "render item update" - ModelPointer model = _model.lock(); - if (model) { - model->setRenderItemsNeedUpdate(); - } - fadeAlpha = 1.0f; - } - return fadeAlpha; -} - -void ModelMeshPartPayload::bindFade(gpu::Batch& batch) const { - const bool isDebugEnabled = DependencyManager::get()->isDebugEnabled(); - - if (_fadeState != FADE_COMPLETE || isDebugEnabled) { - auto& fade = _fadeBuffer.edit(); - glm::vec3 offset = _transform.getTranslation(); - - // A bit ugly to have the test at every bind... - if (!isDebugEnabled) { - fade._percent = computeFadePercent(); - } - else { - fade._percent = DependencyManager::get()->getDebugFadePercent(); - } - - fade._offset = offset; - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::FADE, _fadeBuffer); - } -} - void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); @@ -579,13 +528,13 @@ void ModelMeshPartPayload::render(RenderArgs* args) { return; // bail asap } - if (_fadeState == FADE_WAITING_TO_START) { + if (_fadeState == FadeEffect::WaitingToStart) { if (model->isLoaded()) { if (EntityItem::getEntitiesShouldFadeFunction()()) { _fadeStartTime = usecTimestampNow(); - _fadeState = FADE_IN_PROGRESS; + _fadeState = FadeEffect::InProgress; } else { - _fadeState = FADE_COMPLETE; + _fadeState = FadeEffect::Complete; } model->setRenderItemsNeedUpdate(); } else { @@ -618,7 +567,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMaterial(batch, locations, args->_enableTexturing); // Apply fade effect - bindFade(batch); + DependencyManager::get()->bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime, _fadeState); args->_details._materialSwitches++; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 0d3a8df576..6762601738 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -22,10 +22,7 @@ #include #include "Model.h" - -const uint8_t FADE_WAITING_TO_START = 0; -const uint8_t FADE_IN_PROGRESS = 1; -const uint8_t FADE_COMPLETE = 2; +#include "FadeEffect.h" class Model; @@ -95,8 +92,6 @@ public: const Transform& boundTransform, const gpu::BufferPointer& buffer); - float computeFadePercent() const; - // Render Item interface render::ItemKey getKey() const override; int getLayer() const; @@ -106,7 +101,6 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; - void bindFade(gpu::Batch& batch) const; void initCache(); @@ -124,11 +118,8 @@ public: private: - struct Fade; - - mutable gpu::BufferView _fadeBuffer; mutable quint64 _fadeStartTime { 0 }; - mutable uint8_t _fadeState { FADE_WAITING_TO_START }; + mutable FadeEffect::State _fadeState { FadeEffect::WaitingToStart } ; }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1e8673b385..8b2a232c87 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -258,7 +258,6 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); - gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -285,7 +284,7 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& } // Prepare fade effect - batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, fadeMaskMap); + DependencyManager::get()->bindPerBatch(batch); ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -310,7 +309,6 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); - gpu::TexturePointer fadeMaskMap = DependencyManager::get()->getFadeMaskMap(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -337,7 +335,7 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const } // Prepare fade effect - batch.setResourceTexture(ShapePipeline::Slot::MAP::FADE_MASK, fadeMaskMap); + DependencyManager::get()->bindPerBatch(batch); ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); From 20d4fcbbc73de7cd7db13cb73200cf3017430544 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Jun 2017 09:24:12 +0200 Subject: [PATCH 11/38] Fixed fading on skinned objects. Added initialiazeShapePipelines on GeometryCache to postpone simple pipeline creation after initializeGL --- interface/src/Application.cpp | 2 + .../src/RenderableShapeEntityItem.cpp | 6 +- libraries/render-utils/src/Fade.slh | 31 +++-- libraries/render-utils/src/FadeEffect.cpp | 38 +++--- libraries/render-utils/src/FadeEffect.h | 4 +- libraries/render-utils/src/GeometryCache.cpp | 119 ++++++++++++------ libraries/render-utils/src/GeometryCache.h | 22 +++- .../render-utils/src/skin_model_fade.slv | 2 +- 8 files changed, 151 insertions(+), 73 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 851c07c501..b798f10376 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -907,6 +907,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Make sure we don't time out during slow operations at startup updateHeartbeat(); + // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. + DependencyManager::get()->initializeShapePipelines(); // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 1ad60bf7c6..58ab8f5bc5 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -120,11 +121,14 @@ void RenderableShapeEntityItem::render(RenderArgs* args) { DependencyManager::get()->renderShape(batch, MAPPING[_shape]); } } else { - // FIXME, support instanced multi-shape rendering using multidraw indirect color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; + // FIXME, support instanced multi-shape rendering using multidraw indirect auto geometryCache = DependencyManager::get(); + auto fadeEffect = DependencyManager::get(); auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); + assert(pipeline != nullptr); + if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { geometryCache->renderWireShapeInstance(batch, MAPPING[_shape], color, pipeline); } else { diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index d634473dd0..38fad9321a 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -11,8 +11,8 @@ <@func transformModelToFadePos(objectTransform, objectPosition, fadePosition)@> { - <$transformModelToWorldPos($objectTransform$, $objectPosition$, $fadePosition$)$> - <$fadePosition$> -= vec4(<$objectTransform$>._model[3].xyz, 0.f); + vec4 objectVector = vec4(<$objectPosition$>.xyz, 0.f); + <$transformModelToWorldPos($objectTransform$, objectVector, $fadePosition$)$> } <@endfunc@> @@ -26,6 +26,17 @@ vec2 hash2D(vec3 position) { return position.xy* vec2(0.1677, 0.221765) + position.z*0.561; } +float noise3D(vec3 position) { + return textureLod(fadeMaskMap, hash2D(position), 0).r; + /*const float ONE_OVER_MAX_POSITIVE_INT = (1.f / 2147483648.f); + int3 iPosition = int3(position); + int position = iPosition.x + (iPosition.y*57) + (iPosition.z*3023); + int bits = (position << 13) ^ position; + int pseudoRandomPositiveInt = (bits * ((bits*bits*15731)+789221)+1376312589) & 0x7fffffff; + float pseudoRandomFloatZeroToOne = ONE_OVER_MAX_POSITIVE_INT * (float)pseudoRandomPositiveInt; + return pseudoRandomFloatZeroToOne;*/ +} + float evalFadeMask(vec3 position) { const float FADE_MASK_INV_SCALE = 1.0; @@ -33,14 +44,14 @@ float evalFadeMask(vec3 position) { vec3 noisePosition = position * FADE_MASK_INV_SCALE + fadeOffset; vec3 noisePositionFloored = floor(noisePosition); vec3 noisePositionFraction = fract(noisePosition); - float noiseLowXLowYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored), 0).r; - float noiseLowXHighYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,1,0)), 0).r; - float noiseHighXLowYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,0,0)), 0).r; - float noiseHighXHighYLowZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,1,0)), 0).r; - float noiseLowXLowYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,0,1)), 0).r; - float noiseLowXHighYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(0,1,1)), 0).r; - float noiseHighXLowYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,0,1)), 0).r; - float noiseHighXHighYHighZ = textureLod(fadeMaskMap, hash2D(noisePositionFloored+vec3(1,1,1)), 0).r; + float noiseLowXLowYLowZ = noise3D(noisePositionFloored); + float noiseLowXHighYLowZ = noise3D(noisePositionFloored+vec3(0,1,0)); + float noiseHighXLowYLowZ = noise3D(noisePositionFloored+vec3(1,0,0)); + float noiseHighXHighYLowZ = noise3D(noisePositionFloored+vec3(1,1,0)); + float noiseLowXLowYHighZ = noise3D(noisePositionFloored+vec3(0,0,1)); + float noiseLowXHighYHighZ = noise3D(noisePositionFloored+vec3(0,1,1)); + float noiseHighXLowYHighZ = noise3D(noisePositionFloored+vec3(1,0,1)); + float noiseHighXHighYHighZ = noise3D(noisePositionFloored+vec3(1,1,1)); vec4 maskLowZ = vec4(noiseLowXLowYLowZ, noiseLowXHighYLowZ, noiseHighXLowYLowZ, noiseHighXHighYLowZ); vec4 maskHighZ = vec4(noiseLowXLowYHighZ, noiseLowXHighYHighZ, noiseHighXLowYHighZ, noiseHighXHighYHighZ); vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z); diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 0bca42ad12..ceec55c448 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -14,14 +14,11 @@ FadeEffect::FadeEffect() : _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); } -render::ShapeKey::Builder FadeEffect::getKeyBuilder() const { - render::ShapeKey::Builder builder; - +render::ShapeKey::Builder FadeEffect::getKeyBuilder(render::ShapeKey::Builder builder) const { if (_isDebugEnabled) { // Force fade for everyone builder.withFade(); } - return builder; } @@ -41,20 +38,27 @@ float FadeEffect::computeFadePercent(quint64 startTime) const { } void FadeEffect::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, State state) const { - if (state != Complete || _isDebugEnabled) { - const gpu::ShaderPointer& program = args->_pipeline->pipeline->getProgram(); - int fadeOffsetLoc = program->getUniforms().findLocation("fadeOffset"); - int fadePercentLoc = program->getUniforms().findLocation("fadePercent"); - float percent; + bindPerItem(batch, args->_pipeline->pipeline.get(), offset, startTime, state); +} - // A bit ugly to have the test at every bind... - if (!_isDebugEnabled) { - percent = computeFadePercent(startTime); +void FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, State state) const { + if (state != Complete || _isDebugEnabled) { + auto& program = pipeline->getProgram(); + auto fadeOffsetLoc = program->getUniforms().findLocation("fadeOffset"); + auto fadePercentLoc = program->getUniforms().findLocation("fadePercent"); + + if (fadeOffsetLoc >= 0 && fadePercentLoc >= 0) { + float percent; + + // A bit ugly to have the test at every bind... + if (!_isDebugEnabled) { + percent = computeFadePercent(startTime); + } + else { + percent = _debugFadePercent; + } + batch._glUniform1f(fadePercentLoc, percent); + batch._glUniform3f(fadeOffsetLoc, offset.x, offset.y, offset.z); } - else { - percent = _debugFadePercent; - } - batch._glUniform1f(fadePercentLoc, percent); - batch._glUniform3f(fadeOffsetLoc, offset.x, offset.y, offset.z); } } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index b1cbf0cb29..dea14e5678 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -36,10 +36,12 @@ public: void setDebugFadePercent(float value) { assert(value >= 0.f && value <= 1.f); _debugFadePercent = value; } float getDebugFadePercent() const { return _debugFadePercent; } - render::ShapeKey::Builder getKeyBuilder() const; + render::ShapeKey::Builder getKeyBuilder(render::ShapeKey::Builder builder = render::ShapeKey::Builder()) const; void bindPerBatch(gpu::Batch& batch) const; void bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, State state = InProgress) const; + void bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, State state = InProgress) const; + float computeFadePercent(quint64 startTime) const; private: diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index f1c995b943..fae59491bc 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -24,6 +24,7 @@ #include "TextureCache.h" #include "RenderUtilsLogging.h" +#include "FadeEffect.h" #include "gpu/StandardShaderLib.h" @@ -35,6 +36,9 @@ #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" +#include "simple_fade_vert.h" +#include "simple_textured_fade_frag.h" +#include "simple_textured_unlit_fade_frag.h" #include "simple_opaque_web_browser_frag.h" #include "simple_opaque_web_browser_overlay_frag.h" #include "simple_transparent_web_browser_frag.h" @@ -403,30 +407,13 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() { render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline; render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline; +render::ShapePipelinePointer GeometryCache::_simpleOpaqueFadePipeline; +render::ShapePipelinePointer GeometryCache::_simpleTransparentFadePipeline; render::ShapePipelinePointer GeometryCache::_simpleWirePipeline; GeometryCache::GeometryCache() : _nextID(0) { buildShapes(); - GeometryCache::_simpleOpaquePipeline = - std::make_shared(getSimplePipeline(false, false, true, false), nullptr, - [](const render::ShapePipeline&, gpu::Batch& batch) { - // Set the defaults needed for a simple program - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, - DependencyManager::get()->getWhiteTexture()); - } - ); - GeometryCache::_simpleTransparentPipeline = - std::make_shared(getSimplePipeline(false, true, true, false), nullptr, - [](const render::ShapePipeline&, gpu::Batch& batch) { - // Set the defaults needed for a simple program - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, - DependencyManager::get()->getWhiteTexture()); - } - ); - GeometryCache::_simpleWirePipeline = - std::make_shared(getSimplePipeline(false, false, true, true), nullptr, - [](const render::ShapePipeline&, gpu::Batch& batch) {}); } GeometryCache::~GeometryCache() { @@ -471,6 +458,35 @@ void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) { batch.setInputBuffer(gpu::Stream::COLOR, colorView); } +void GeometryCache::initializeShapePipelines() { + GeometryCache::_simpleOpaquePipeline = getShapePipeline(false, false, true, false); + GeometryCache::_simpleTransparentPipeline = getShapePipeline(false, true, true, false); + GeometryCache::_simpleOpaqueFadePipeline = getShapePipeline(false, false, true, false, false, true); + GeometryCache::_simpleTransparentFadePipeline = getShapePipeline(false, true, true, false, false, true); + GeometryCache::_simpleWirePipeline = getShapePipeline(false, false, true, true); +} + +render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool transparent, bool culled, + bool unlit, bool depthBias, bool fading) { + return std::make_shared(getSimplePipeline(textured, transparent, culled, unlit, depthBias, fading), nullptr, + [](const render::ShapePipeline&, gpu::Batch& batch) { + // Set the defaults needed for a simple program + batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, + DependencyManager::get()->getWhiteTexture()); + } + ); +} + +render::ShapePipelinePointer GeometryCache::getOpaqueShapePipeline(bool isFading) { + isFading = isFading || DependencyManager::get()->isDebugEnabled(); + return isFading ? _simpleOpaqueFadePipeline : _simpleOpaquePipeline; +} + +render::ShapePipelinePointer GeometryCache::getTransparentShapePipeline(bool isFading) { + isFading = isFading || DependencyManager::get()->isDebugEnabled(); + return isFading ? _simpleTransparentFadePipeline : _simpleTransparentPipeline; +} + void GeometryCache::renderShape(gpu::Batch& batch, Shape shape) { batch.setInputFormat(getSolidStreamFormat()); _shapes[shape].draw(batch); @@ -1714,6 +1730,7 @@ public: IS_CULLED_FLAG, IS_UNLIT_FLAG, HAS_DEPTH_BIAS_FLAG, + IS_FADING_FLAG, NUM_FLAGS, }; @@ -1724,6 +1741,7 @@ public: IS_CULLED = (1 << IS_CULLED_FLAG), IS_UNLIT = (1 << IS_UNLIT_FLAG), HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), + IS_FADING = (1 << IS_FADING_FLAG), }; typedef unsigned short Flags; @@ -1734,6 +1752,7 @@ public: bool isCulled() const { return isFlag(IS_CULLED); } bool isUnlit() const { return isFlag(IS_UNLIT); } bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } + bool isFading() const { return isFlag(IS_FADING); } Flags _flags = 0; short _spare = 0; @@ -1742,9 +1761,9 @@ public: SimpleProgramKey(bool textured = false, bool transparent = false, bool culled = true, - bool unlit = false, bool depthBias = false) { + bool unlit = false, bool depthBias = false, bool fading = false) { _flags = (textured ? IS_TEXTURED : 0) | (transparent ? IS_TRANSPARENT : 0) | (culled ? IS_CULLED : 0) | - (unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); + (unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0) | (fading ? IS_FADING : 0); } SimpleProgramKey(int bitmask) : _flags(bitmask) {} @@ -1818,23 +1837,8 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool tra } } -gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) { - SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased }; - - // Compile the shaders - static std::once_flag once; - std::call_once(once, [&]() { - auto VS = gpu::Shader::createVertex(std::string(simple_vert)); - auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); - auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag)); - - _simpleShader = gpu::Shader::createProgram(VS, PS); - _unlitShader = gpu::Shader::createProgram(VS, PSUnlit); - - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*_simpleShader, slotBindings); - gpu::Shader::makeProgram(*_unlitShader, slotBindings); - }); +gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased, bool fading) { + SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased, fading }; // If the pipeline already exists, return it auto it = _simplePrograms.find(config); @@ -1842,6 +1846,37 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp return it.value(); } + // Compile the shaders + if (!fading) { + static std::once_flag once; + std::call_once(once, [&]() { + auto VS = gpu::Shader::createVertex(std::string(simple_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); + auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag)); + + _simpleShader = gpu::Shader::createProgram(VS, PS); + _unlitShader = gpu::Shader::createProgram(VS, PSUnlit); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*_simpleShader, slotBindings); + gpu::Shader::makeProgram(*_unlitShader, slotBindings); + }); + } else { + static std::once_flag once; + std::call_once(once, [&]() { + auto VS = gpu::Shader::createVertex(std::string(simple_fade_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_textured_fade_frag)); + auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag)); + + _simpleFadeShader = gpu::Shader::createProgram(VS, PS); + _unlitFadeShader = gpu::Shader::createProgram(VS, PSUnlit); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*_simpleFadeShader, slotBindings); + gpu::Shader::makeProgram(*_unlitFadeShader, slotBindings); + }); + } + // If the pipeline did not exist, make it auto state = std::make_shared(); if (config.isCulled()) { @@ -1858,7 +1893,7 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - gpu::ShaderPointer program = (config.isUnlit()) ? _unlitShader : _simpleShader; + gpu::ShaderPointer program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) : (config.isFading() ? _simpleFadeShader : _simpleShader); gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); _simplePrograms.insert(config, pipeline); return pipeline; @@ -1900,19 +1935,23 @@ void renderInstances(gpu::Batch& batch, const glm::vec4& color, bool isWire, } void GeometryCache::renderSolidShapeInstance(gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { + assert(pipeline != nullptr); renderInstances(batch, color, false, pipeline, shape); } void GeometryCache::renderWireShapeInstance(gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { + assert(pipeline != nullptr); renderInstances(batch, color, true, pipeline, shape); } void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { + assert(pipeline != nullptr); renderInstances(batch, color, false, pipeline, GeometryCache::Sphere); } void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { + assert(pipeline != nullptr); renderInstances(batch, color, true, pipeline, GeometryCache::Sphere); } @@ -1921,6 +1960,7 @@ void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& //#define DEBUG_SHAPES void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { + assert(pipeline != nullptr); #ifdef DEBUG_SHAPES static auto startTime = usecTimestampNow(); renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { @@ -1960,5 +2000,6 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { static const std::string INSTANCE_NAME = __FUNCTION__; + assert(pipeline != nullptr); renderInstances(batch, color, true, pipeline, GeometryCache::Cube); } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index e0a610a095..acaaf8eba3 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -156,7 +156,7 @@ public: bool unlit = false, bool depthBias = false); // Get the pipeline to render static geometry gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true, - bool unlit = false, bool depthBias = false); + bool unlit = false, bool depthBias = false, bool fading = false); void bindOpaqueWebBrowserProgram(gpu::Batch& batch, bool isAA); gpu::PipelinePointer getOpaqueWebBrowserProgram(bool isAA); @@ -164,9 +164,19 @@ public: void bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isAA); gpu::PipelinePointer getTransparentWebBrowserProgram(bool isAA); - render::ShapePipelinePointer getOpaqueShapePipeline() { return GeometryCache::_simpleOpaquePipeline; } - render::ShapePipelinePointer getTransparentShapePipeline() { return GeometryCache::_simpleTransparentPipeline; } - render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; } + void initializeShapePipelines(); + + render::ShapePipelinePointer getShapePipeline(bool textured = false, bool transparent = false, bool culled = true, + bool unlit = false, bool depthBias = false, bool fading = false); + + render::ShapePipelinePointer getOpaqueShapePipeline() { assert(_simpleOpaquePipeline != nullptr); return _simpleOpaquePipeline; } + render::ShapePipelinePointer getTransparentShapePipeline() { assert(_simpleTransparentPipeline != nullptr); return _simpleTransparentPipeline; } + render::ShapePipelinePointer getOpaqueFadeShapePipeline() { assert(_simpleOpaqueFadePipeline != nullptr); return _simpleOpaqueFadePipeline; } + render::ShapePipelinePointer getTransparentFadeShapePipeline() { assert(_simpleTransparentFadePipeline != nullptr); return _simpleTransparentFadePipeline; } + render::ShapePipelinePointer getOpaqueShapePipeline(bool isFading); + render::ShapePipelinePointer getTransparentShapePipeline(bool isFading); + render::ShapePipelinePointer getWireShapePipeline() { assert(_simpleWirePipeline != nullptr); return GeometryCache::_simpleWirePipeline; } + // Static (instanced) geometry void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer); @@ -418,8 +428,12 @@ private: gpu::ShaderPointer _simpleShader; gpu::ShaderPointer _unlitShader; + gpu::ShaderPointer _simpleFadeShader; + gpu::ShaderPointer _unlitFadeShader; static render::ShapePipelinePointer _simpleOpaquePipeline; static render::ShapePipelinePointer _simpleTransparentPipeline; + static render::ShapePipelinePointer _simpleOpaqueFadePipeline; + static render::ShapePipelinePointer _simpleTransparentFadePipeline; static render::ShapePipelinePointer _simpleOpaqueOverlayPipeline; static render::ShapePipelinePointer _simpleTransparentOverlayPipeline; static render::ShapePipelinePointer _simpleWirePipeline; diff --git a/libraries/render-utils/src/skin_model_fade.slv b/libraries/render-utils/src/skin_model_fade.slv index a96c948470..bce60b4242 100644 --- a/libraries/render-utils/src/skin_model_fade.slv +++ b/libraries/render-utils/src/skin_model_fade.slv @@ -50,6 +50,6 @@ void main(void) { TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> - <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToFadePos(obj, position, _worldFadePosition)$> <$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, _normal.xyz)$> } From cba70e6be0e8728410edb3d40c4479401838f864 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Jun 2017 14:57:09 +0200 Subject: [PATCH 12/38] Fade working on voxel objects --- .../src/RenderablePolyVoxEntityItem.cpp | 40 +++++++++---- .../src/RenderablePolyVoxEntityItem.h | 7 ++- .../entities-renderer/src/polyvox_fade.slf | 60 +++++++++++++++++++ .../entities-renderer/src/polyvox_fade.slv | 35 +++++++++++ libraries/render-utils/src/FadeEffect.cpp | 20 ++++--- libraries/render-utils/src/FadeEffect.h | 13 ++-- .../render-utils/src/MeshPartPayload.cpp | 10 ++-- libraries/render-utils/src/MeshPartPayload.h | 8 ++- libraries/render/src/render/ShapePipeline.cpp | 2 - libraries/render/src/render/ShapePipeline.h | 2 - 10 files changed, 155 insertions(+), 42 deletions(-) create mode 100644 libraries/entities-renderer/src/polyvox_fade.slf create mode 100644 libraries/entities-renderer/src/polyvox_fade.slv diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index fd5346093b..e5eecfd66c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -48,13 +48,17 @@ #include "model/Geometry.h" #include "EntityTreeRenderer.h" #include "polyvox_vert.h" +#include "polyvox_fade_vert.h" #include "polyvox_frag.h" +#include "polyvox_fade_frag.h" #include "RenderablePolyVoxEntityItem.h" #include "EntityEditPacketSender.h" #include "PhysicalEntitySimulation.h" -gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; -gpu::PipelinePointer RenderablePolyVoxEntityItem::_wireframePipeline = nullptr; +#include "FadeEffect.h" + +gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipelines[2] = { nullptr, nullptr }; +gpu::PipelinePointer RenderablePolyVoxEntityItem::_wireframePipelines[2] = { nullptr, nullptr }; const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; @@ -727,31 +731,34 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { return; } - if (!_pipeline) { - gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert)); - gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag)); + if (!_pipelines[0]) { + gpu::ShaderPointer vertexShaders[2] = { gpu::Shader::createVertex(std::string(polyvox_vert)), gpu::Shader::createVertex(std::string(polyvox_fade_vert)) }; + gpu::ShaderPointer pixelShaders[2] = { gpu::Shader::createPixel(std::string(polyvox_frag)), gpu::Shader::createPixel(std::string(polyvox_fade_frag)) }; gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0)); slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2)); - - gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); - gpu::Shader::makeProgram(*program, slotBindings); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), 3)); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); 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); + // Two sets of pipelines: normal and fading + for (auto i = 0; i < 2; i++) { + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShaders[i], pixelShaders[i]); + gpu::Shader::makeProgram(*program, slotBindings); + + _pipelines[i] = gpu::Pipeline::create(program, state); + _wireframePipelines[i] = gpu::Pipeline::create(program, wireframeState); + } } if (!_vertexFormat) { @@ -765,7 +772,8 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { // Pick correct Pipeline bool wireframe = (render::ShapeKey(args->_globalShapeKey).isWireframe()); - auto pipeline = (wireframe ? _wireframePipeline : _pipeline); + auto pipelineVariation = isFading() & 1; + auto pipeline = (wireframe ? _wireframePipelines[pipelineVariation]: _pipelines[pipelineVariation]); batch.setPipeline(pipeline); Transform transform(voxelToWorldMatrix()); @@ -809,6 +817,12 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { batch.setResourceTexture(2, DependencyManager::get()->getWhiteTexture()); } + // Apply fade effect + auto fadeEffect = DependencyManager::get(); + if (fadeEffect->bindPerItem(batch, pipeline.get(), glm::vec3(0, 0, 0), _fadeStartTime, isFading())) { + fadeEffect->bindPerBatch(batch, 3); + } + int voxelVolumeSizeLocation = pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize"); batch._glUniform3f(voxelVolumeSizeLocation, voxelVolumeSize.x, voxelVolumeSize.y, voxelVolumeSize.z); @@ -1611,7 +1625,7 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() { void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { EntityItem::locationChanged(tellPhysics); - if (!_pipeline || !render::Item::isValidID(_myItem)) { + if (!_pipelines[0] || !render::Item::isValidID(_myItem)) { return; } render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ff97f09ee1..d6216f3eff 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -143,7 +143,7 @@ public: void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); } - // Transparent polyvox didn't seem to be working so disable for now + // Transparent polyvox didn't seem to be working so disable for now. bool isTransparent() override { return false; } bool getMeshes(MeshProxyList& result) override; @@ -166,8 +166,9 @@ private: const int MATERIAL_GPU_SLOT = 3; render::ItemID _myItem{ render::Item::INVALID_ITEM_ID }; - static gpu::PipelinePointer _pipeline; - static gpu::PipelinePointer _wireframePipeline; + + static gpu::PipelinePointer _pipelines[2]; + static gpu::PipelinePointer _wireframePipelines[2]; ShapeInfo _shapeInfo; diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf new file mode 100644 index 0000000000..ac2d77564b --- /dev/null +++ b/libraries/entities-renderer/src/polyvox_fade.slf @@ -0,0 +1,60 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// polyvox_fade.frag +// fragment shader +// +// Created by Olivier Prat on 2017-06-08 +// 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 model/Material.slh@> +<@include DeferredBufferWrite.slh@> + +<@include Fade.slh@> + +in vec3 _normal; +in vec4 _position; +in vec4 _worldPosition; +in vec4 _worldFadePosition; + +uniform sampler2D xMap; +uniform sampler2D yMap; +uniform sampler2D zMap; +uniform vec3 voxelVolumeSize; + +// Declare after all samplers to prevent sampler location mix up with voxel shading (sampler locations are hardcoded in RenderablePolyVoxEntityItem) +<$declareFadeFragment()$> + +void main(void) { + applyFade(_worldFadePosition.xyz); + + vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz)); + worldNormal = normalize(worldNormal); + + float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x; + float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y; + float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z; + + vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY)); + vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ)); + vec4 yzDiffuse = texture(zMap, vec2(inPositionZ, -inPositionY)); + + vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z); + vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y); + vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x); + vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0); + + packDeferredFragment( + _normal, + 1.0, + vec3(diffuse), + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_EMISSIVE, + DEFAULT_OCCLUSION, + DEFAULT_SCATTERING); +} diff --git a/libraries/entities-renderer/src/polyvox_fade.slv b/libraries/entities-renderer/src/polyvox_fade.slv new file mode 100644 index 0000000000..f024957677 --- /dev/null +++ b/libraries/entities-renderer/src/polyvox_fade.slv @@ -0,0 +1,35 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// polyvox_fade.vert +// vertex shader +// +// Created by Seth Alves on 2015-8-3 +// 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 gpu/Inputs.slh@> + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +<@include Fade.slh@> + +out vec4 _position; +out vec4 _worldPosition; +out vec3 _normal; +out vec4 _worldFadePosition; + +void main(void) { + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> + <$transformModelToWorldPos(obj, inPosition, _worldFadePosition)$> + _worldPosition = inPosition; +} diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index ceec55c448..f2a799dbc6 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -22,9 +22,13 @@ render::ShapeKey::Builder FadeEffect::getKeyBuilder(render::ShapeKey::Builder bu return builder; } -void FadeEffect::bindPerBatch(gpu::Batch& batch) const -{ - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::FADE_MASK, _fadeMaskMap); +void FadeEffect::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation) const { + batch.setResourceTexture(fadeMaskMapLocation, _fadeMaskMap); +} + +void FadeEffect::bindPerBatch(gpu::Batch& batch, const gpu::PipelinePointer& pipeline) const { + auto slot = pipeline->getProgram()->getTextures().findLocation("fadeMaskMap"); + batch.setResourceTexture(slot, _fadeMaskMap); } float FadeEffect::computeFadePercent(quint64 startTime) const { @@ -37,12 +41,12 @@ float FadeEffect::computeFadePercent(quint64 startTime) const { return fadeAlpha; } -void FadeEffect::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, State state) const { - bindPerItem(batch, args->_pipeline->pipeline.get(), offset, startTime, state); +bool FadeEffect::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, bool isFading) const { + return bindPerItem(batch, args->_pipeline->pipeline.get(), offset, startTime, isFading); } -void FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, State state) const { - if (state != Complete || _isDebugEnabled) { +bool FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, bool isFading) const { + if (isFading || _isDebugEnabled) { auto& program = pipeline->getProgram(); auto fadeOffsetLoc = program->getUniforms().findLocation("fadeOffset"); auto fadePercentLoc = program->getUniforms().findLocation("fadePercent"); @@ -60,5 +64,7 @@ void FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, g batch._glUniform1f(fadePercentLoc, percent); batch._glUniform3f(fadeOffsetLoc, offset.x, offset.y, offset.z); } + return true; } + return false; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index dea14e5678..5be1288120 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -20,12 +20,6 @@ class FadeEffect : public Dependency { SINGLETON_DEPENDENCY public: - enum State : uint8_t { - WaitingToStart = 0, - InProgress = 1, - Complete = 2, - }; - FadeEffect(); const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } @@ -38,9 +32,10 @@ public: render::ShapeKey::Builder getKeyBuilder(render::ShapeKey::Builder builder = render::ShapeKey::Builder()) const; - void bindPerBatch(gpu::Batch& batch) const; - void bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, State state = InProgress) const; - void bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, State state = InProgress) const; + void bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation = render::ShapePipeline::Slot::MAP::FADE_MASK) const; + void bindPerBatch(gpu::Batch& batch, const gpu::PipelinePointer& pipeline) const; + bool bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, bool isFading) const; + bool bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, bool isFading) const; float computeFadePercent(quint64 startTime) const; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index a44974cc92..46989eaba7 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -484,7 +484,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { if (wireframe) { builder.withWireframe(); } - if (_fadeState != FadeEffect::Complete) { + if (_fadeState != STATE_COMPLETE) { builder.withFade(); } return builder.build(); @@ -528,13 +528,13 @@ void ModelMeshPartPayload::render(RenderArgs* args) { return; // bail asap } - if (_fadeState == FadeEffect::WaitingToStart) { + if (_fadeState == STATE_WAITING_TO_START) { if (model->isLoaded()) { if (EntityItem::getEntitiesShouldFadeFunction()()) { _fadeStartTime = usecTimestampNow(); - _fadeState = FadeEffect::InProgress; + _fadeState = STATE_IN_PROGRESS; } else { - _fadeState = FadeEffect::Complete; + _fadeState = STATE_COMPLETE; } model->setRenderItemsNeedUpdate(); } else { @@ -567,7 +567,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMaterial(batch, locations, args->_enableTexturing); // Apply fade effect - DependencyManager::get()->bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime, _fadeState); + DependencyManager::get()->bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime, _fadeState!=STATE_COMPLETE); args->_details._materialSwitches++; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 6762601738..b68a542bce 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -118,8 +118,14 @@ public: private: + enum State : uint8_t { + STATE_WAITING_TO_START = 0, + STATE_IN_PROGRESS = 1, + STATE_COMPLETE = 2, + }; + mutable quint64 _fadeStartTime { 0 }; - mutable FadeEffect::State _fadeState { FadeEffect::WaitingToStart } ; + mutable State _fadeState { STATE_WAITING_TO_START } ; }; diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 77f7f61801..b521ff12ee 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -70,7 +70,6 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT)); slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK)); - slotBindings.insert(gpu::Shader::Binding(std::string("fadeBuffer"), Slot::BUFFER::FADE)); gpu::Shader::makeProgram(*program, slotBindings); @@ -90,7 +89,6 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer"); locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap"); locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap"); - locations->fadeBufferUnit = program->getUniformBuffers().findLocation("fadeBuffer"); ShapeKey key{filter._flags}; auto gpuPipeline = gpu::Pipeline::create(program, state); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index b8045dfbcc..1c18f2a26e 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -214,7 +214,6 @@ public: LIGHTING_MODEL, LIGHT, LIGHT_AMBIENT_BUFFER, - FADE, }; enum MAP { @@ -245,7 +244,6 @@ public: int lightBufferUnit; int lightAmbientBufferUnit; int lightAmbientMapUnit; - int fadeBufferUnit; int fadeMaskTextureUnit; }; using LocationsPointer = std::shared_ptr; From 7d58c9a741d0eca2b46326847e79170a17ed8652 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Jun 2017 17:09:08 +0200 Subject: [PATCH 13/38] Fixed fade for shadow job --- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderShadowTask.cpp | 34 ++++++++++++++++--- .../src/skin_model_normal_map_fade.slv | 2 +- .../render-utils/src/skin_model_shadow.slf | 2 +- .../src/skin_model_shadow_fade.slf | 27 +++++++++++++++ .../src/skin_model_shadow_fade.slv | 2 +- libraries/render/src/render/ShapePipeline.cpp | 2 +- libraries/render/src/render/ShapePipeline.h | 4 +-- 8 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 libraries/render-utils/src/skin_model_shadow_fade.slf diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 8b2a232c87..df27f48271 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -308,7 +308,7 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index d7ec087174..33d260c2da 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -14,6 +14,7 @@ #include #include +#include "FadeEffect.h" #include #include @@ -28,6 +29,12 @@ #include "model_shadow_frag.h" #include "skin_model_shadow_frag.h" +#include "model_shadow_fade_vert.h" +#include "skin_model_shadow_fade_vert.h" + +#include "model_shadow_fade_frag.h" +#include "skin_model_shadow_fade_frag.h" + using namespace render; void RenderShadowMap::run(const render::RenderContextPointer& renderContext, @@ -46,6 +53,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, const auto& fbo = shadow->framebuffer; RenderArgs* args = renderContext->args; + ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -61,8 +70,11 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, batch.setProjectionTransform(shadow->getProjection()); batch.setViewTransform(shadow->getView(), false); - auto shadowPipeline = _shapePlumber->pickPipeline(args, ShapeKey()); - auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, ShapeKey::Builder().withSkinned()); + auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); + auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); + + // Prepare fade effect + DependencyManager::get()->bindPerBatch(batch); std::vector skinnedShapeKeys{}; @@ -103,15 +115,29 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); shapePlumber->addPipeline( - ShapeKey::Filter::Builder().withoutSkinned(), + ShapeKey::Filter::Builder().withoutSkinned().withoutFade(), modelProgram, state); auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag)); gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel); shapePlumber->addPipeline( - ShapeKey::Filter::Builder().withSkinned(), + ShapeKey::Filter::Builder().withSkinned().withoutFade(), skinProgram, state); + + auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); + auto modelFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); + gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel); + shapePlumber->addPipeline( + ShapeKey::Filter::Builder().withoutSkinned().withFade(), + modelFadeProgram, state); + + auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); + auto skinFadePixel = gpu::Shader::createPixel(std::string(skin_model_shadow_fade_frag)); + gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, skinFadePixel); + shapePlumber->addPipeline( + ShapeKey::Filter::Builder().withSkinned().withFade(), + skinFadeProgram, state); } const auto cachedMode = task.addJob("Setup"); diff --git a/libraries/render-utils/src/skin_model_normal_map_fade.slv b/libraries/render-utils/src/skin_model_normal_map_fade.slv index 5169aa5d75..7c88c68537 100644 --- a/libraries/render-utils/src/skin_model_normal_map_fade.slv +++ b/libraries/render-utils/src/skin_model_normal_map_fade.slv @@ -55,7 +55,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> - <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToFadePos(obj, position, _worldFadePosition)$> <$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> <$transformModelToWorldDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$> diff --git a/libraries/render-utils/src/skin_model_shadow.slf b/libraries/render-utils/src/skin_model_shadow.slf index 178ea7b387..e464d6e6c8 100644 --- a/libraries/render-utils/src/skin_model_shadow.slf +++ b/libraries/render-utils/src/skin_model_shadow.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// model_shadow.frag +// skin_model_shadow.frag // fragment shader // // Created by Andrzej Kapolka on 3/24/14. diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slf b/libraries/render-utils/src/skin_model_shadow_fade.slf new file mode 100644 index 0000000000..7b164f5db1 --- /dev/null +++ b/libraries/render-utils/src/skin_model_shadow_fade.slf @@ -0,0 +1,27 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model_shadow_fade.frag +// fragment shader +// +// Created by Olivier Prat on 06/08/17. +// 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 Fade.slh@> +<$declareFadeFragment()$> + +in vec4 _worldFadePosition; + +layout(location = 0) out vec4 _fragColor; + +void main(void) { + applyFade(_worldFadePosition.xyz); + + // pass-through to set z-buffer + _fragColor = vec4(1.0, 1.0, 1.0, 0.0); +} diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slv b/libraries/render-utils/src/skin_model_shadow_fade.slv index 84d50ae754..03b060b59b 100644 --- a/libraries/render-utils/src/skin_model_shadow_fade.slv +++ b/libraries/render-utils/src/skin_model_shadow_fade.slv @@ -30,5 +30,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, position, gl_Position)$> - <$transformModelToFadePos(obj, inPosition, _worldFadePosition)$> + <$transformModelToFadePos(obj, position, _worldFadePosition)$> } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index b521ff12ee..6a52f90297 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -103,7 +103,7 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke PerformanceTimer perfTimer("ShapePlumber::pickPipeline"); - const auto& pipelineIterator = _pipelineMap.find(key); + auto pipelineIterator = _pipelineMap.find(key); if (pipelineIterator == _pipelineMap.end()) { // The first time we can't find a pipeline, we should log it if (_missingKeys.find(key) == _missingKeys.end()) { diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 1c18f2a26e..cfcd358287 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -128,8 +128,8 @@ public: Builder& withCullFace() { _flags.reset(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); } Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); } - Builder& withFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); } - Builder& withoutFade() { _flags.set(FADE); _mask.set(FADE); return (*this); } + Builder& withFade() { _flags.set(FADE); _mask.set(FADE); return (*this); } + Builder& withoutFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); } protected: friend class Filter; From f3d252ee6576e4637c603943c78cd3e405ff7d93 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 13 Jun 2017 08:50:50 +0200 Subject: [PATCH 14/38] Switched fade curve to easeInOutQuad --- libraries/render-utils/src/FadeEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index f2a799dbc6..dbfcfb780a 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -36,7 +36,7 @@ float FadeEffect::computeFadePercent(quint64 startTime) const { const double INV_FADE_PERIOD = 1.0 / (double)(3 * USECS_PER_SECOND); double fraction = (double)(usecTimestampNow() - startTime) * INV_FADE_PERIOD; if (fraction < 1.0) { - fadeAlpha = Interpolate::simpleNonLinearBlend(fraction); + fadeAlpha = Interpolate::easeInOutQuad(fraction); } return fadeAlpha; } From ace301945c70ecec603ce381e5f4baa023fc2439 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 13 Jun 2017 15:31:04 +0200 Subject: [PATCH 15/38] Added scale and duration debug parameters in debugFade.qml --- libraries/render-utils/src/Fade.slh | 12 ++------- libraries/render-utils/src/FadeEffect.cpp | 27 +++++++++++-------- libraries/render-utils/src/FadeEffect.h | 9 ++++++- .../render-utils/src/RenderDeferredTask.cpp | 12 +++++++-- .../render-utils/src/RenderDeferredTask.h | 4 +++ scripts/developer/utilities/render/fade.qml | 20 +++++++++++++- 6 files changed, 59 insertions(+), 25 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 38fad9321a..351cbad863 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -20,6 +20,7 @@ uniform vec3 fadeOffset; uniform float fadePercent; +uniform float fadeInvScale; uniform sampler2D fadeMaskMap; vec2 hash2D(vec3 position) { @@ -28,20 +29,11 @@ vec2 hash2D(vec3 position) { float noise3D(vec3 position) { return textureLod(fadeMaskMap, hash2D(position), 0).r; - /*const float ONE_OVER_MAX_POSITIVE_INT = (1.f / 2147483648.f); - int3 iPosition = int3(position); - int position = iPosition.x + (iPosition.y*57) + (iPosition.z*3023); - int bits = (position << 13) ^ position; - int pseudoRandomPositiveInt = (bits * ((bits*bits*15731)+789221)+1376312589) & 0x7fffffff; - float pseudoRandomFloatZeroToOne = ONE_OVER_MAX_POSITIVE_INT * (float)pseudoRandomPositiveInt; - return pseudoRandomFloatZeroToOne;*/ } float evalFadeMask(vec3 position) { - const float FADE_MASK_INV_SCALE = 1.0; - // Do tri-linear interpolation - vec3 noisePosition = position * FADE_MASK_INV_SCALE + fadeOffset; + vec3 noisePosition = position * fadeInvScale + fadeOffset; vec3 noisePositionFloored = floor(noisePosition); vec3 noisePositionFraction = fract(noisePosition); float noiseLowXLowYLowZ = noise3D(noisePositionFloored); diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index dbfcfb780a..71e33549a6 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -7,8 +7,10 @@ #include FadeEffect::FadeEffect() : - _isDebugEnabled{ false }, - _debugFadePercent{ 0.f } + _invScale{ 1.f }, + _duration{ 3.f }, + _debugFadePercent{ 0.f }, + _isDebugEnabled{ false } { auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); @@ -27,13 +29,14 @@ void FadeEffect::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation) const } void FadeEffect::bindPerBatch(gpu::Batch& batch, const gpu::PipelinePointer& pipeline) const { - auto slot = pipeline->getProgram()->getTextures().findLocation("fadeMaskMap"); - batch.setResourceTexture(slot, _fadeMaskMap); + auto program = pipeline->getProgram(); + auto maskMapLocation = program->getTextures().findLocation("fadeMaskMap"); + bindPerBatch(batch, maskMapLocation); } float FadeEffect::computeFadePercent(quint64 startTime) const { float fadeAlpha = 1.0f; - const double INV_FADE_PERIOD = 1.0 / (double)(3 * USECS_PER_SECOND); + const double INV_FADE_PERIOD = 1.0 / (double)(_duration * USECS_PER_SECOND); double fraction = (double)(usecTimestampNow() - startTime) * INV_FADE_PERIOD; if (fraction < 1.0) { fadeAlpha = Interpolate::easeInOutQuad(fraction); @@ -47,11 +50,12 @@ bool FadeEffect::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offs bool FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, bool isFading) const { if (isFading || _isDebugEnabled) { - auto& program = pipeline->getProgram(); - auto fadeOffsetLoc = program->getUniforms().findLocation("fadeOffset"); - auto fadePercentLoc = program->getUniforms().findLocation("fadePercent"); + auto& uniforms = pipeline->getProgram()->getUniforms(); + auto fadeScaleLocation = uniforms.findLocation("fadeInvScale"); + auto fadeOffsetLocation = uniforms.findLocation("fadeOffset"); + auto fadePercentLocation = uniforms.findLocation("fadePercent"); - if (fadeOffsetLoc >= 0 && fadePercentLoc >= 0) { + if (fadeScaleLocation >= 0 || fadeOffsetLocation >= 0 || fadePercentLocation>=0) { float percent; // A bit ugly to have the test at every bind... @@ -61,8 +65,9 @@ bool FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, g else { percent = _debugFadePercent; } - batch._glUniform1f(fadePercentLoc, percent); - batch._glUniform3f(fadeOffsetLoc, offset.x, offset.y, offset.z); + batch._glUniform1f(fadeScaleLocation, _invScale); + batch._glUniform1f(fadePercentLocation, percent); + batch._glUniform3f(fadeOffsetLocation, offset.x, offset.y, offset.z); } return true; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 5be1288120..80e3b79e2e 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -24,6 +24,12 @@ public: const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } + void setScale(float value) { assert(value > 0.f); _invScale = 1.f / value; } + float getScale() const { return 1.f / _invScale; } + + void setDuration(float seconds) { assert(seconds > 0.f); _duration = seconds; } + float getDuration() const { return 1.f / _duration; } + void setDebugEnabled(bool isEnabled) { _isDebugEnabled = isEnabled; } bool isDebugEnabled() const { return _isDebugEnabled; } @@ -42,9 +48,10 @@ public: private: gpu::TexturePointer _fadeMaskMap; + float _invScale; + float _duration; float _debugFadePercent; bool _isDebugEnabled; - }; #endif // hifi_FadeEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ae3dbc058f..a752b18da8 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -51,8 +51,16 @@ extern void initDeferredPipelines(render::ShapePlumber& plumber); void RenderDeferredTask::configure(const Config& config) { - DependencyManager::get()->setDebugEnabled(config.debugFade); - DependencyManager::get()->setDebugFadePercent(config.debugFadePercent); + const float SCALE_MIN = 0.01f; + const float SCALE_MAX = 5.f; + + auto fadeEffect = DependencyManager::get(); + float scale = SCALE_MIN + (SCALE_MAX - SCALE_MIN)*config.fadeScale*config.fadeScale*config.fadeScale; + + fadeEffect->setScale(scale); + fadeEffect->setDuration(config.fadeDuration); + fadeEffect->setDebugEnabled(config.debugFade); + fadeEffect->setDebugFadePercent(config.debugFadePercent); } void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index d46f9b53f4..65ae062a9a 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -164,9 +164,13 @@ public: class RenderDeferredTaskConfig : public render::Task::Config { Q_OBJECT + Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty) + Q_PROPERTY(float fadeDuration MEMBER fadeDuration NOTIFY dirty) Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty) Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty) public: + float fadeScale{ 0.5f }; + float fadeDuration{ 3.0f }; float debugFadePercent{ 0.f }; bool debugFade{ false }; diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 137e45d08d..0a99ca2e7e 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -19,7 +19,7 @@ Row { spacing: 8 CheckBox { - text: "Force Fade" + text: "Manual Fade" checked: taskConfig["debugFade"] onCheckedChanged: { taskConfig["debugFade"] = checked } } @@ -36,6 +36,24 @@ Row { min: 0.0 width: 250 } + ConfigSlider { + label: "Scale" + integral: false + config: taskConfig + property: "fadeScale" + max: 1.0 + min: 0.0 + width: 250 + } + ConfigSlider { + label: "Duration" + integral: false + config: taskConfig + property: "fadeDuration" + max: 10.0 + min: 0.1 + width: 250 + } } } From 5eeff5aa28902033d0ea99de4062f24cb6346a3b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 14 Jun 2017 10:23:12 +0200 Subject: [PATCH 16/38] Fixed unwanted red tint due to unreset color attrib in ModelMeshPartPayload --- libraries/render-utils/src/MeshPartPayload.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 46989eaba7..bfa4b6770e 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -510,6 +510,11 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } } + + // TODO: Get rid of that extra call + if (!_hasColorAttrib) { + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } } void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { From 2e3ffe77217efbba7cc7c379c7868b3858e35344 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 19 Jun 2017 18:19:36 +0200 Subject: [PATCH 17/38] Disabled check on enabled physics when deciding is fade is adequate --- libraries/render-utils/src/FadeEffect.cpp | 3 ++- libraries/render-utils/src/MeshPartPayload.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 71e33549a6..516fd56478 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -68,8 +68,9 @@ bool FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, g batch._glUniform1f(fadeScaleLocation, _invScale); batch._glUniform1f(fadePercentLocation, percent); batch._glUniform3f(fadeOffsetLocation, offset.x, offset.y, offset.z); + + return percent < 1.f; } - return true; } return false; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index bfa4b6770e..5365988fbb 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -572,7 +572,10 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMaterial(batch, locations, args->_enableTexturing); // Apply fade effect - DependencyManager::get()->bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime, _fadeState!=STATE_COMPLETE); + if (!DependencyManager::get()->bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime, _fadeState != STATE_COMPLETE)) { + // TODO : very ugly way to update the fade state. Need to improve this with global fade manager. + _fadeState = STATE_COMPLETE; + } args->_details._materialSwitches++; From b6b1875dd3790f9a53dc3932a73a0dd074fddac5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 19 Jun 2017 18:19:54 +0200 Subject: [PATCH 18/38] Disabled check on enabled physics when deciding is fade is adequate --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b53807b1cf..cf3cc172e0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1503,7 +1503,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo EntityItem::setEntitiesShouldFadeFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); - return entityServerNode && !isPhysicsEnabled(); + return entityServerNode; /*&& !isPhysicsEnabled()*/ // Why shouldn't we fade when physics is enabled??; }); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); From 0211338657ab5d9cd6201aac9fd21fb19eee4c9c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 19 Jun 2017 20:38:47 +0200 Subject: [PATCH 19/38] Put back test if not physics enabled in entity items should fade function as it gives too many undesired refades --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 10855dfa46..289003a69f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1504,7 +1504,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo EntityItem::setEntitiesShouldFadeFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); - return entityServerNode; /*&& !isPhysicsEnabled()*/ // Why shouldn't we fade when physics is enabled??; + return entityServerNode && !isPhysicsEnabled(); }); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); From 8a12d0c106be25a3db8b55aa80579b04b9bb73b0 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Jun 2017 08:54:23 +0200 Subject: [PATCH 20/38] Fade effect working again for basic enter domain but with various Fade jobs --- .../src/RenderablePolyVoxEntityItem.cpp | 16 +- .../src/RenderablePolyVoxEntityItem.h | 2 + .../src/RenderableShapeEntityItem.cpp | 1 - .../entities-renderer/src/polyvox_fade.slf | 5 +- libraries/entities/src/EntityItem.h | 1 + libraries/render-utils/src/Fade.slh | 78 ++++- libraries/render-utils/src/FadeEffect.cpp | 238 +++++++++++--- libraries/render-utils/src/FadeEffect.h | 307 ++++++++++++++++-- libraries/render-utils/src/GeometryCache.cpp | 2 - .../render-utils/src/MeshPartPayload.cpp | 20 +- libraries/render-utils/src/MeshPartPayload.h | 2 + .../render-utils/src/RenderDeferredTask.cpp | 39 +-- .../render-utils/src/RenderShadowTask.cpp | 4 +- libraries/render-utils/src/model_fade.slf | 5 +- .../render-utils/src/model_lightmap_fade.slf | 6 +- .../src/model_lightmap_normal_map_fade.slf | 6 +- ...odel_lightmap_normal_specular_map_fade.slf | 6 +- .../src/model_lightmap_specular_map_fade.slf | 6 +- .../src/model_normal_map_fade.slf | 4 +- .../src/model_normal_specular_map_fade.slf | 6 +- .../render-utils/src/model_shadow_fade.slf | 2 +- .../src/model_specular_map_fade.slf | 6 +- .../src/model_translucent_fade.slf | 6 +- .../src/model_translucent_unlit_fade.slf | 6 +- .../render-utils/src/model_unlit_fade.slf | 6 +- libraries/render-utils/src/simple_fade.slf | 12 +- .../render-utils/src/simple_textured_fade.slf | 8 +- .../src/simple_textured_unlit_fade.slf | 8 +- .../src/simple_transparent_textured_fade.slf | 8 +- ...simple_transparent_textured_unlit_fade.slf | 6 +- .../src/skin_model_shadow_fade.slf | 2 +- libraries/render/src/render/Args.h | 1 + libraries/render/src/render/Item.h | 7 +- .../src/render/RenderFetchCullSortTask.cpp | 3 +- .../src/render/RenderFetchCullSortTask.h | 2 +- libraries/render/src/render/ShapePipeline.cpp | 4 +- libraries/render/src/render/ShapePipeline.h | 2 + libraries/render/src/task/Varying.h | 5 + .../developer/utilities/render/debugFade.js | 2 +- scripts/developer/utilities/render/fade.qml | 237 ++++++++++++-- 40 files changed, 900 insertions(+), 187 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 614af2c64e..32e71389ab 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -740,10 +740,11 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), render::ShapePipeline::Slot::BUFFER::FADE_PARAMETERS)); slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0)); slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2)); - slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), 3)); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), render::ShapePipeline::Slot::MAP::FADE_MASK)); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); @@ -823,9 +824,9 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { } // Apply fade effect - auto fadeEffect = DependencyManager::get(); - if (fadeEffect->bindPerItem(batch, pipeline.get(), glm::vec3(0, 0, 0), _fadeStartTime, isFading())) { - fadeEffect->bindPerBatch(batch, 3); + if (args->_enableFade) { + FadeRenderJob::bindPerBatch(batch, render::ShapePipeline::Slot::MAP::FADE_MASK, render::ShapePipeline::Slot::BUFFER::FADE_PARAMETERS); + FadeRenderJob::bindPerItem(batch, pipeline.get(), glm::vec3(0, 0, 0), _fadeStartTime); } int voxelVolumeSizeLocation = pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize"); @@ -882,6 +883,13 @@ namespace render { payload->_owner->getRenderableInterface()->render(args); } } + + template <> bool payloadMustFade(const PolyVoxPayload::Pointer& payload) { + if (payload && payload->_owner) { + return payload->_owner->mustFade(); + } + return false; + } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 73ab0e5937..72871f0439 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -38,6 +38,7 @@ namespace render { template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload); template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args); + template <> bool payloadMustFade(const PolyVoxPayload::Pointer& payload); } @@ -205,4 +206,5 @@ private: bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, int x, int y, int z); + #endif // hifi_RenderablePolyVoxEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 917b97dc29..a8ead00771 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -126,7 +126,6 @@ void RenderableShapeEntityItem::render(RenderArgs* args) { color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; // FIXME, support instanced multi-shape rendering using multidraw indirect auto geometryCache = DependencyManager::get(); - auto fadeEffect = DependencyManager::get(); auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); assert(pipeline != nullptr); diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf index ac2d77564b..29bd51200a 100644 --- a/libraries/entities-renderer/src/polyvox_fade.slf +++ b/libraries/entities-renderer/src/polyvox_fade.slf @@ -30,7 +30,8 @@ uniform vec3 voxelVolumeSize; <$declareFadeFragment()$> void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 emissive; + applyFade(_worldFadePosition.xyz, emissive); vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz)); worldNormal = normalize(worldNormal); @@ -54,7 +55,7 @@ void main(void) { vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, - DEFAULT_EMISSIVE, + DEFAULT_EMISSIVE+emissive, DEFAULT_OCCLUSION, DEFAULT_SCATTERING); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0318c72991..6cd8e18a27 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -459,6 +459,7 @@ public: bool isFading() const { return _isFading; } float getFadingRatio() const { return (isFading() ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f); } + bool mustFade() const { return _isFading; } virtual void emitScriptEvent(const QVariant& message) {} diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 351cbad863..776343dc53 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -18,9 +18,26 @@ <@func declareFadeFragment()@> -uniform vec3 fadeOffset; -uniform float fadePercent; -uniform float fadeInvScale; +struct FadeParameters +{ + vec4 _baseInvSizeAndLevel; + vec4 _noiseInvSizeAndLevel; + vec3 _innerEdgeColor; + vec3 _outerEdgeColor; + vec2 _edgeWidthInvWidth; + int _invertBase; + float _padding; +}; + +#define EVENT_CATEGORY_COUNT 5 + +uniform fadeParametersBuffer { + FadeParameters fadeParameters[EVENT_CATEGORY_COUNT]; +}; +uniform int fadeCategory; +uniform vec3 fadeNoiseOffset; +uniform vec3 fadeBaseOffset; +uniform float fadeThreshold; uniform sampler2D fadeMaskMap; vec2 hash2D(vec3 position) { @@ -31,9 +48,9 @@ float noise3D(vec3 position) { return textureLod(fadeMaskMap, hash2D(position), 0).r; } -float evalFadeMask(vec3 position) { +float evalFadeNoiseGradient(vec3 position) { // Do tri-linear interpolation - vec3 noisePosition = position * fadeInvScale + fadeOffset; + vec3 noisePosition = position * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.xyz + fadeNoiseOffset; vec3 noisePositionFloored = floor(noisePosition); vec3 noisePositionFraction = fract(noisePosition); float noiseLowXLowYLowZ = noise3D(noisePositionFloored); @@ -49,14 +66,59 @@ float evalFadeMask(vec3 position) { vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z); vec2 maskY = mix(maskXY.xy, maskXY.zw, noisePositionFraction.x); - return mix(maskY.x, maskY.y, noisePositionFraction.y); + return mix(maskY.x, maskY.y, noisePositionFraction.y) * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.w; } -void applyFade(vec3 position) { - if (evalFadeMask(position) > fadePercent) { +float evalFadeBaseGradient(vec3 position) { + float gradient = length((position - fadeBaseOffset) * fadeParameters[fadeCategory]._baseInvSizeAndLevel.xyz); + if (fadeParameters[fadeCategory]._invertBase!=0) { + gradient = 1.0 - gradient; + } + gradient *= fadeParameters[fadeCategory]._baseInvSizeAndLevel.w; + return gradient; +} + +float evalFadeGradient(vec3 position) { + float baseGradient = evalFadeBaseGradient(position); + float noiseGradient = evalFadeNoiseGradient(position); + float gradient = (noiseGradient-0.5*fadeParameters[fadeCategory]._baseInvSizeAndLevel.w); + + // This is to be sure the noise is zero at the start of the gradient + gradient *= (1-baseGradient*baseGradient); + gradient += baseGradient; + return gradient; +} + +float evalFadeAlpha(vec3 position) { +/* float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; + float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold); + + return evalFadeGradient(position)-cutoff;*/ + return evalFadeNoiseGradient(position)-fadeThreshold; +} + +void applyFadeClip(vec3 position) { + if (evalFadeAlpha(position) < 0) { discard; } } + +void applyFade(vec3 position, out vec3 emissive) { + float alpha = evalFadeAlpha(position); + if (alpha < 0) { + discard; + } + /* + float edgeMask = alpha * fadeParameters[fadeCategory]._edgeWidthInvWidth.y; + float edgeAlpha = 1.0-clamp(edgeMask, 0, 1); + + edgeMask = step(edgeMask, 1.f); + edgeAlpha *= edgeAlpha; // Square to have a nice ease out + emissive = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha); + emissive *= edgeMask; + */ + emissive = vec3(0,0,0); +} <@endfunc@> <@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 516fd56478..d2bad0d1ef 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -4,73 +4,223 @@ #include #include #include -#include +#include -FadeEffect::FadeEffect() : - _invScale{ 1.f }, - _duration{ 3.f }, - _debugFadePercent{ 0.f }, - _isDebugEnabled{ false } +void FadeSwitchJob::configure(const Config& config) { + _isEditEnabled = config.editFade; +} + +void FadeSwitchJob::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { + auto& normalOutputs = output.edit0(); + auto& fadeOutputs = output.edit1(); + + // Only shapes are affected by fade at this time. + normalOutputs[RenderFetchCullSortTask::LIGHT] = input[RenderFetchCullSortTask::LIGHT]; + normalOutputs[RenderFetchCullSortTask::META] = input[RenderFetchCullSortTask::META]; + normalOutputs[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE] = input[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + normalOutputs[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE] = input[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + normalOutputs[RenderFetchCullSortTask::BACKGROUND] = input[RenderFetchCullSortTask::BACKGROUND]; + normalOutputs[RenderFetchCullSortTask::SPATIAL_SELECTION] = input[RenderFetchCullSortTask::SPATIAL_SELECTION]; + + // Now, distribute items that need to be faded accross both outputs + distribute(renderContext, input[RenderFetchCullSortTask::OPAQUE_SHAPE], normalOutputs[RenderFetchCullSortTask::OPAQUE_SHAPE], fadeOutputs[OPAQUE_SHAPE]); + distribute(renderContext, input[RenderFetchCullSortTask::TRANSPARENT_SHAPE], normalOutputs[RenderFetchCullSortTask::TRANSPARENT_SHAPE], fadeOutputs[TRANSPARENT_SHAPE]); +} + +void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext, const render::Varying& input, + render::Varying& normalOutput, render::Varying& fadeOutput) const { + auto& scene = renderContext->_scene; + assert(_parameters); + const double fadeDuration = double(_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]) * USECS_PER_SECOND; + const auto& inputItems = input.get(); + + // Clear previous values + normalOutput.template edit().clear(); + fadeOutput.template edit().clear(); + + for (const auto& itemBound : inputItems) { + auto& item = scene->getItem(itemBound.id); + + if (!item.mustFade()) { + // No need to fade + normalOutput.template edit().emplace_back(itemBound); + } + else { + fadeOutput.template edit().emplace_back(itemBound); + } + } +/* if (!_isEditEnabled) { + + }*/ +} + +FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) : + _parameters{ commonParams } { auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); } -render::ShapeKey::Builder FadeEffect::getKeyBuilder(render::ShapeKey::Builder builder) const { - if (_isDebugEnabled) { - // Force fade for everyone - builder.withFade(); - } - return builder; +void FadeConfigureJob::configure(const Config& config) { + assert(_parameters); + for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) { + auto& configuration = _configurations[i]; + + _parameters->_durations[i] = config.duration[i]; + configuration._baseInvSizeAndLevel.x = 1.f / config.baseSize[i].x; + configuration._baseInvSizeAndLevel.y = 1.f / config.baseSize[i].y; + configuration._baseInvSizeAndLevel.z = 1.f / config.baseSize[i].z; + configuration._baseInvSizeAndLevel.w = config.baseLevel[i]; + configuration._noiseInvSizeAndLevel.x = 1.f / config.noiseSize[i].x; + configuration._noiseInvSizeAndLevel.y = 1.f / config.noiseSize[i].y; + configuration._noiseInvSizeAndLevel.z = 1.f / config.noiseSize[i].z; + configuration._noiseInvSizeAndLevel.w = config.noiseLevel[i]; + configuration._invertBase = config.baseInverted[i]; + configuration._edgeWidthInvWidth.x = config.edgeWidth[i]; + configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; + configuration._innerEdgeColor.r = config.edgeInnerColor[i].r * config.edgeInnerColor[i].a; + configuration._innerEdgeColor.g = config.edgeInnerColor[i].g * config.edgeInnerColor[i].a; + configuration._innerEdgeColor.b = config.edgeInnerColor[i].b * config.edgeInnerColor[i].a; + configuration._outerEdgeColor.r = config.edgeOuterColor[i].r * config.edgeOuterColor[i].a; + configuration._outerEdgeColor.g = config.edgeOuterColor[i].g * config.edgeOuterColor[i].a; + configuration._outerEdgeColor.b = config.edgeOuterColor[i].b * config.edgeOuterColor[i].a; + } + _isBufferDirty = true; } -void FadeEffect::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation) const { - batch.setResourceTexture(fadeMaskMapLocation, _fadeMaskMap); +void FadeConfigureJob::run(const render::RenderContextPointer& renderContext, Output& output) { + if (_isBufferDirty) { + auto& configurations = output.edit1().edit(); + std::copy(_configurations, _configurations + FadeJobConfig::EVENT_CATEGORY_COUNT, configurations.parameters); + _isBufferDirty = false; + } + output.edit0() = _fadeMaskMap; } -void FadeEffect::bindPerBatch(gpu::Batch& batch, const gpu::PipelinePointer& pipeline) const { - auto program = pipeline->getProgram(); - auto maskMapLocation = program->getTextures().findLocation("fadeMaskMap"); - bindPerBatch(batch, maskMapLocation); -} +const FadeRenderJob* FadeRenderJob::_currentInstance{ nullptr }; +gpu::TexturePointer FadeRenderJob::_currentFadeMaskMap; +const gpu::BufferView* FadeRenderJob::_currentFadeBuffer{ nullptr }; -float FadeEffect::computeFadePercent(quint64 startTime) const { +float FadeRenderJob::computeFadePercent(quint64 startTime) { + assert(_currentInstance); float fadeAlpha = 1.0f; - const double INV_FADE_PERIOD = 1.0 / (double)(_duration * USECS_PER_SECOND); - double fraction = (double)(usecTimestampNow() - startTime) * INV_FADE_PERIOD; + const double INV_FADE_PERIOD = 1.0 / (double)(_currentInstance->_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] * USECS_PER_SECOND); + double fraction = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) * INV_FADE_PERIOD; + fraction = std::max(fraction, 0.0); if (fraction < 1.0) { fadeAlpha = Interpolate::easeInOutQuad(fraction); } return fadeAlpha; } -bool FadeEffect::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, bool isFading) const { - return bindPerItem(batch, args->_pipeline->pipeline.get(), offset, startTime, isFading); +void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const Input& inputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + + const auto& inItems = inputs.get0(); + + if (!inItems.empty()) { + const auto& lightingModel = inputs.get1(); + const auto& configuration = inputs.get2(); + const auto& fadeMaskMap = configuration.get0(); + const auto& fadeParamBuffer = configuration.get1(); + + // Very, very ugly hack to keep track of the current fade render job + RenderArgs* args = renderContext->args; + render::ShapeKey::Builder defaultKeyBuilder; + + defaultKeyBuilder.withFade(); + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + _currentInstance = this; + _currentFadeMaskMap = fadeMaskMap; + _currentFadeBuffer = &fadeParamBuffer; + + // Setup camera, projection and viewport for all items + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + // 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 + render::ShapeKey::Builder keyBuilder = defaultKeyBuilder; + if (lightingModel->isWireframeEnabled()) { + keyBuilder.withWireframe(); + } + + // Prepare fade effect + bindPerBatch(batch, fadeMaskMap, render::ShapePipeline::Slot::MAP::FADE_MASK, &fadeParamBuffer, render::ShapePipeline::Slot::BUFFER::FADE_PARAMETERS); + + render::ShapeKey globalKey = keyBuilder.build(); + args->_globalShapeKey = globalKey._flags.to_ulong(); + args->_enableFade = true; + + renderShapes(renderContext, _shapePlumber, inItems, -1, globalKey); + + args->_enableFade = false; + args->_batch = nullptr; + args->_globalShapeKey = 0; + + // Very, very ugly hack to keep track of the current fade render job + _currentInstance = nullptr; + _currentFadeMaskMap.reset(); + _currentFadeBuffer = nullptr; + }); + } } -bool FadeEffect::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, bool isFading) const { - if (isFading || _isDebugEnabled) { - auto& uniforms = pipeline->getProgram()->getUniforms(); - auto fadeScaleLocation = uniforms.findLocation("fadeInvScale"); - auto fadeOffsetLocation = uniforms.findLocation("fadeOffset"); - auto fadePercentLocation = uniforms.findLocation("fadePercent"); +void FadeRenderJob::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation) { + assert(_currentFadeMaskMap); + assert(_currentFadeBuffer!=nullptr); + bindPerBatch(batch, _currentFadeMaskMap, fadeMaskMapLocation, _currentFadeBuffer, fadeBufferLocation); +} - if (fadeScaleLocation >= 0 || fadeOffsetLocation >= 0 || fadePercentLocation>=0) { - float percent; +void FadeRenderJob::bindPerBatch(gpu::Batch& batch, gpu::TexturePointer texture, int fadeMaskMapLocation, const gpu::BufferView* buffer, int fadeBufferLocation) { + batch.setResourceTexture(fadeMaskMapLocation, texture); + batch.setUniformBuffer(fadeBufferLocation, *buffer); +} - // A bit ugly to have the test at every bind... - if (!_isDebugEnabled) { - percent = computeFadePercent(startTime); - } - else { - percent = _debugFadePercent; - } - batch._glUniform1f(fadeScaleLocation, _invScale); - batch._glUniform1f(fadePercentLocation, percent); - batch._glUniform3f(fadeOffsetLocation, offset.x, offset.y, offset.z); +void FadeRenderJob::bindPerBatch(gpu::Batch& batch, gpu::TexturePointer texture, const gpu::BufferView* buffer, const gpu::PipelinePointer& pipeline) { + auto program = pipeline->getProgram(); + auto maskMapLocation = program->getTextures().findLocation("fadeMaskMap"); + auto bufferLocation = program->getUniformBuffers().findLocation("fadeParametersBuffer"); + bindPerBatch(batch, texture, maskMapLocation, buffer, bufferLocation); +} - return percent < 1.f; - } +bool FadeRenderJob::bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime) { + return bindPerItem(batch, args->_pipeline->pipeline.get(), offset, startTime); +} + +bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime) { + auto& uniforms = pipeline->getProgram()->getUniforms(); + auto fadeNoiseOffsetLocation = uniforms.findLocation("fadeNoiseOffset"); + auto fadeBaseOffsetLocation = uniforms.findLocation("fadeBaseOffset"); + auto fadeThresholdLocation = uniforms.findLocation("fadeThreshold"); + auto fadeCategoryLocation = uniforms.findLocation("fadeCategory"); + + if (fadeNoiseOffsetLocation >= 0 || fadeBaseOffsetLocation>=0 || fadeThresholdLocation >= 0 || fadeCategoryLocation>=0) { + float percent; + + percent = computeFadePercent(startTime); + batch._glUniform1i(fadeCategoryLocation, FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN); + batch._glUniform1f(fadeThresholdLocation, 1.f-percent); + // This is really temporary + batch._glUniform3f(fadeNoiseOffsetLocation, offset.x, offset.y, offset.z); + // This is really temporary + batch._glUniform3f(fadeBaseOffsetLocation, offset.x, offset.y, offset.z); + + return percent < 1.f; } return false; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 80e3b79e2e..295dbb333a 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -11,47 +11,304 @@ #ifndef hifi_FadeEffect_h #define hifi_FadeEffect_h -#include #include #include +#include + +#include "LightingModel.h" + +class FadeSwitchJobConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(bool editFade MEMBER editFade NOTIFY dirty) -// Centralizes fade effect data and functions -class FadeEffect : public Dependency { - SINGLETON_DEPENDENCY public: - FadeEffect(); + bool editFade{ false }; - const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } +signals: + void dirty(); - void setScale(float value) { assert(value > 0.f); _invScale = 1.f / value; } - float getScale() const { return 1.f / _invScale; } +}; - void setDuration(float seconds) { assert(seconds > 0.f); _duration = seconds; } - float getDuration() const { return 1.f / _duration; } +class FadeJobConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(int editedCategory MEMBER editedCategory WRITE setEditedCategory NOTIFY dirty) + Q_PROPERTY(float duration READ getDuration WRITE setDuration NOTIFY dirty) + Q_PROPERTY(float baseSizeX READ getBaseSizeX WRITE setBaseSizeX NOTIFY dirty) + Q_PROPERTY(float baseSizeY READ getBaseSizeY WRITE setBaseSizeY NOTIFY dirty) + Q_PROPERTY(float baseSizeZ READ getBaseSizeZ WRITE setBaseSizeZ NOTIFY dirty) + Q_PROPERTY(float baseLevel READ getBaseLevel WRITE setBaseLevel NOTIFY dirty) + Q_PROPERTY(bool baseInverted READ isBaseInverted WRITE setBaseInverted NOTIFY dirty) + Q_PROPERTY(float noiseSizeX READ getNoiseSizeX WRITE setNoiseSizeX NOTIFY dirty) + Q_PROPERTY(float noiseSizeY READ getNoiseSizeY WRITE setNoiseSizeY NOTIFY dirty) + Q_PROPERTY(float noiseSizeZ READ getNoiseSizeZ WRITE setNoiseSizeZ NOTIFY dirty) + Q_PROPERTY(float noiseLevel READ getNoiseLevel WRITE setNoiseLevel NOTIFY dirty) + Q_PROPERTY(float edgeWidth READ getEdgeWidth WRITE setEdgeWidth NOTIFY dirty) + Q_PROPERTY(float edgeInnerColorR READ getEdgeInnerColorR WRITE setEdgeInnerColorR NOTIFY dirty) + Q_PROPERTY(float edgeInnerColorG READ getEdgeInnerColorG WRITE setEdgeInnerColorG NOTIFY dirty) + Q_PROPERTY(float edgeInnerColorB READ getEdgeInnerColorB WRITE setEdgeInnerColorB NOTIFY dirty) + Q_PROPERTY(float edgeInnerIntensity READ getEdgeInnerIntensity WRITE setEdgeInnerIntensity NOTIFY dirty) + Q_PROPERTY(float edgeOuterColorR READ getEdgeOuterColorR WRITE setEdgeOuterColorR NOTIFY dirty) + Q_PROPERTY(float edgeOuterColorG READ getEdgeOuterColorG WRITE setEdgeOuterColorG NOTIFY dirty) + Q_PROPERTY(float edgeOuterColorB READ getEdgeOuterColorB WRITE setEdgeOuterColorB NOTIFY dirty) + Q_PROPERTY(float edgeOuterIntensity READ getEdgeOuterIntensity WRITE setEdgeOuterIntensity NOTIFY dirty) - void setDebugEnabled(bool isEnabled) { _isDebugEnabled = isEnabled; } - bool isDebugEnabled() const { return _isDebugEnabled; } +public: - void setDebugFadePercent(float value) { assert(value >= 0.f && value <= 1.f); _debugFadePercent = value; } - float getDebugFadePercent() const { return _debugFadePercent; } + enum EventCategory { + ELEMENT_ENTER_LEAVE_DOMAIN = 0, + BUBBLE_ISECT_OWNER, + BUBBLE_ISECT_TRESPASSER, + USER_ENTER_LEAVE_DOMAIN, + AVATAR_CHANGE, - render::ShapeKey::Builder getKeyBuilder(render::ShapeKey::Builder builder = render::ShapeKey::Builder()) const; + // Don't forget to modify Fade.slh to reflect the change in number of categories + EVENT_CATEGORY_COUNT + }; - void bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation = render::ShapePipeline::Slot::MAP::FADE_MASK) const; - void bindPerBatch(gpu::Batch& batch, const gpu::PipelinePointer& pipeline) const; - bool bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime, bool isFading) const; - bool bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime, bool isFading) const; + void setEditedCategory(int value) { assert(value < EVENT_CATEGORY_COUNT); editedCategory = std::min(EVENT_CATEGORY_COUNT, value); } - float computeFadePercent(quint64 startTime) const; + void setDuration(float value) { duration[editedCategory] = value; } + float getDuration() const { return duration[editedCategory]; } + + void setBaseSizeX(float value) { baseSize[editedCategory].x = value; } + float getBaseSizeX() const { return baseSize[editedCategory].x; } + + void setBaseSizeY(float value) { baseSize[editedCategory].y = value; } + float getBaseSizeY() const { return baseSize[editedCategory].y; } + + void setBaseSizeZ(float value) { baseSize[editedCategory].z = value; } + float getBaseSizeZ() const { return baseSize[editedCategory].z; } + + void setBaseLevel(float value) { baseLevel[editedCategory] = value; } + float getBaseLevel() const { return baseLevel[editedCategory]; } + + void setBaseInverted(bool value) { baseInverted[editedCategory] = value; } + bool isBaseInverted() const { return baseInverted[editedCategory]; } + + void setNoiseSizeX(float value) { noiseSize[editedCategory].x = value; } + float getNoiseSizeX() const { return noiseSize[editedCategory].x; } + + void setNoiseSizeY(float value) { noiseSize[editedCategory].y = value; } + float getNoiseSizeY() const { return noiseSize[editedCategory].y; } + + void setNoiseSizeZ(float value) { noiseSize[editedCategory].z = value; } + float getNoiseSizeZ() const { return noiseSize[editedCategory].z; } + + void setNoiseLevel(float value) { noiseLevel[editedCategory] = value; } + float getNoiseLevel() const { return noiseLevel[editedCategory]; } + + void setEdgeWidth(float value) { edgeWidth[editedCategory] = value; } + float getEdgeWidth() const { return edgeWidth[editedCategory]; } + + void setEdgeInnerColorR(float value) { edgeInnerColor[editedCategory].r = value; } + float getEdgeInnerColorR() const { return edgeInnerColor[editedCategory].r; } + + void setEdgeInnerColorG(float value) { edgeInnerColor[editedCategory].g = value; } + float getEdgeInnerColorG() const { return edgeInnerColor[editedCategory].g; } + + void setEdgeInnerColorB(float value) { edgeInnerColor[editedCategory].b = value; } + float getEdgeInnerColorB() const { return edgeInnerColor[editedCategory].b; } + + void setEdgeInnerIntensity(float value) { edgeInnerColor[editedCategory].a = value; } + float getEdgeInnerIntensity() const { return edgeInnerColor[editedCategory].a; } + + void setEdgeOuterColorR(float value) { edgeOuterColor[editedCategory].r = value; } + float getEdgeOuterColorR() const { return edgeOuterColor[editedCategory].r; } + + void setEdgeOuterColorG(float value) { edgeOuterColor[editedCategory].g = value; } + float getEdgeOuterColorG() const { return edgeOuterColor[editedCategory].g; } + + void setEdgeOuterColorB(float value) { edgeOuterColor[editedCategory].b = value; } + float getEdgeOuterColorB() const { return edgeOuterColor[editedCategory].b; } + + void setEdgeOuterIntensity(float value) { edgeOuterColor[editedCategory].a = value; } + float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } + + int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; + glm::vec3 baseSize[EVENT_CATEGORY_COUNT]{ + { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + }; + float baseLevel[EVENT_CATEGORY_COUNT]{ + 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 1.0f, // BUBBLE_ISECT_OWNER + 1.0f, // BUBBLE_ISECT_TRESPASSER + 1.0f, // USER_ENTER_LEAVE_DOMAIN + 1.0f, // AVATAR_CHANGE + }; + bool baseInverted[EVENT_CATEGORY_COUNT]{ + false, // ELEMENT_ENTER_LEAVE_DOMAIN + false, // BUBBLE_ISECT_OWNER + false, // BUBBLE_ISECT_TRESPASSER + false, // USER_ENTER_LEAVE_DOMAIN + false, // AVATAR_CHANGE + }; + glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ + { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + }; + float noiseLevel[EVENT_CATEGORY_COUNT]{ + 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 1.0f, // BUBBLE_ISECT_OWNER + 1.0f, // BUBBLE_ISECT_TRESPASSER + 1.0f, // USER_ENTER_LEAVE_DOMAIN + 1.0f, // AVATAR_CHANGE + }; + float duration[EVENT_CATEGORY_COUNT]{ + 5.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.0f, // BUBBLE_ISECT_OWNER + 0.0f, // BUBBLE_ISECT_TRESPASSER + 3.0f, // USER_ENTER_LEAVE_DOMAIN + 3.0f, // AVATAR_CHANGE + }; + float edgeWidth[EVENT_CATEGORY_COUNT]{ + 0.1f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.1f, // BUBBLE_ISECT_OWNER + 0.1f, // BUBBLE_ISECT_TRESPASSER + 0.1f, // USER_ENTER_LEAVE_DOMAIN + 0.1f, // AVATAR_CHANGE + }; + glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]{ + { 1.0f, 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 1.0f, 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + }; + glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]{ + { 1.0f, 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 1.0f, 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + }; + +signals: + void dirty(); + +}; + +struct FadeCommonParameters +{ + using Pointer = std::shared_ptr; + + float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]{ + 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.0f, // BUBBLE_ISECT_OWNER + 0.0f, // BUBBLE_ISECT_TRESPASSER + 3.0f, // USER_ENTER_LEAVE_DOMAIN + 3.0f, // AVATAR_CHANGE + }; +}; + +class FadeSwitchJob { +public: + + enum FadeBuckets { + OPAQUE_SHAPE = 0, + TRANSPARENT_SHAPE, + + NUM_BUCKETS + }; + + using FadeOutput = render::VaryingArray; + + using Input = RenderFetchCullSortTask::Output; + using Output = render::VaryingSet2; + using Config = FadeSwitchJobConfig; + using JobModel = render::Job::ModelIO; + + FadeSwitchJob(FadeCommonParameters::Pointer commonParams) : _parameters{ commonParams } {} + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, const Input& input, Output& output); private: - gpu::TexturePointer _fadeMaskMap; - float _invScale; - float _duration; - float _debugFadePercent; - bool _isDebugEnabled; + FadeCommonParameters::Pointer _parameters; + bool _isEditEnabled{ false }; + + void distribute(const render::RenderContextPointer& renderContext, const render::Varying& input, + render::Varying& normalOutput, render::Varying& fadeOutput) const; +}; + +struct FadeParameters +{ + glm::vec4 _baseInvSizeAndLevel; + glm::vec4 _noiseInvSizeAndLevel; + glm::vec3 _innerEdgeColor; + glm::vec3 _outerEdgeColor; + glm::vec2 _edgeWidthInvWidth; + glm::int32 _invertBase; + glm::float32 _padding; +}; + +struct FadeConfiguration +{ + FadeParameters parameters[FadeJobConfig::EVENT_CATEGORY_COUNT]; +}; + +class FadeConfigureJob { + +public: + + using UniformBuffer = gpu::StructBuffer; + using Output = render::VaryingSet2; + using Config = FadeJobConfig; + using JobModel = render::Job::ModelO; + + FadeConfigureJob(FadeCommonParameters::Pointer commonParams); + + const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, Output& output); + +private: + + FadeCommonParameters::Pointer _parameters; + bool _isBufferDirty{ true }; + gpu::TexturePointer _fadeMaskMap; + FadeParameters _configurations[FadeJobConfig::EVENT_CATEGORY_COUNT]; +}; + +class FadeRenderJob { + +public: + + using Input = render::VaryingSet3; + using JobModel = render::Job::ModelI; + + FadeRenderJob(FadeCommonParameters::Pointer commonParams, render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber }, _parameters{ commonParams } {} + + void run(const render::RenderContextPointer& renderContext, const Input& inputs); + + static void bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation); + static void bindPerBatch(gpu::Batch& batch, gpu::TexturePointer texture, int fadeMaskMapLocation, const gpu::BufferView* buffer, int fadeBufferLocation); + static void bindPerBatch(gpu::Batch& batch, gpu::TexturePointer texture, const gpu::BufferView* buffer, const gpu::PipelinePointer& pipeline); + + static bool bindPerItem(gpu::Batch& batch, RenderArgs* args, glm::vec3 offset, quint64 startTime); + static bool bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline, glm::vec3 offset, quint64 startTime); + + static float computeFadePercent(quint64 startTime); + +private: + + static const FadeRenderJob* _currentInstance; + static gpu::TexturePointer _currentFadeMaskMap; + static const gpu::BufferView* _currentFadeBuffer; + + render::ShapePlumberPointer _shapePlumber; + FadeCommonParameters::Pointer _parameters; + + }; #endif // hifi_FadeEffect_h diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 9179354435..5c1632167e 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -523,12 +523,10 @@ render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool } render::ShapePipelinePointer GeometryCache::getOpaqueShapePipeline(bool isFading) { - isFading = isFading || DependencyManager::get()->isDebugEnabled(); return isFading ? _simpleOpaqueFadePipeline : _simpleOpaquePipeline; } render::ShapePipelinePointer GeometryCache::getTransparentShapePipeline(bool isFading) { - isFading = isFading || DependencyManager::get()->isDebugEnabled(); return isFading ? _simpleTransparentFadePipeline : _simpleTransparentPipeline; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 3e75666fcb..7db75a4df4 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -319,6 +319,11 @@ template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) { return payload->render(args); } + +template <> bool payloadMustFade(const ModelMeshPartPayload::Pointer& payload) { + return payload->mustFade(); +} + } ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : @@ -525,6 +530,10 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: batch.setModelTransform(_transform); } +bool ModelMeshPartPayload::mustFade() const { + return _fadeState != STATE_COMPLETE; +} + void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); @@ -572,11 +581,16 @@ void ModelMeshPartPayload::render(RenderArgs* args) { // apply material properties bindMaterial(batch, locations, args->_enableTexturing); - // Apply fade effect - if (!DependencyManager::get()->bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime, _fadeState != STATE_COMPLETE)) { + if (args->_enableFade) { + // Apply fade effect + if (!FadeRenderJob::bindPerItem(batch, args, _transform.getTranslation(), _fadeStartTime)) { + _fadeState = STATE_COMPLETE; + } + } + /* else { // TODO : very ugly way to update the fade state. Need to improve this with global fade manager. _fadeState = STATE_COMPLETE; - } + }*/ args->_details._materialSwitches++; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b68a542bce..620976804f 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -97,6 +97,7 @@ public: int getLayer() const; render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; + bool mustFade() const; // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; @@ -135,6 +136,7 @@ namespace render { template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload); template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); + template <> bool payloadMustFade(const ModelMeshPartPayload::Pointer& payload); } #endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c9a67fea3f..a8ead6e76e 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -50,20 +50,15 @@ extern void initDeferredPipelines(render::ShapePlumber& plumber); void RenderDeferredTask::configure(const Config& config) { - const float SCALE_MIN = 0.01f; - const float SCALE_MAX = 5.f; - - auto fadeEffect = DependencyManager::get(); - float scale = SCALE_MIN + (SCALE_MAX - SCALE_MIN)*config.fadeScale*config.fadeScale*config.fadeScale; - - fadeEffect->setScale(scale); - fadeEffect->setDuration(config.fadeDuration); - fadeEffect->setDebugEnabled(config.debugFade); - fadeEffect->setDebugFadePercent(config.debugFadePercent); } void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { - auto items = input.get(); + auto commonFadeParameters = std::make_shared(); + const auto fadeSwitchOutputs = task.addJob("FadeSwitch", input, commonFadeParameters).get(); + const auto fadeConfigureOutputs = task.addJob("FadeConfigure", commonFadeParameters).get(); + + const auto& items = fadeSwitchOutputs.get0(); + const auto& fadeItems = fadeSwitchOutputs.get1(); // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); @@ -97,8 +92,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); - DependencyManager::set(); - // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", primaryFramebuffer); @@ -106,6 +99,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); + const auto fadeOpaques = fadeItems[FadeSwitchJob::OPAQUE_SHAPE]; + const auto fadeOpaqueInputs = FadeRenderJob::Input(fadeOpaques, lightingModel, fadeConfigureOutputs).hasVarying(); + task.addJob("DrawFadeOpaque", fadeOpaqueInputs, commonFadeParameters, shapePlumber); + task.addJob("OpaqueRangeTimer", opaqueRangeTimer); @@ -159,6 +156,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); + const auto fadeTransparents = fadeItems[FadeSwitchJob::TRANSPARENT_SHAPE]; + const auto fadeTransparentInputs = FadeRenderJob::Input(fadeTransparents, lightingModel, fadeConfigureOutputs).hasVarying(); + task.addJob("DrawFadeTransparent", fadeTransparentInputs, commonFadeParameters, shapePlumber); + // LIght Cluster Grid Debuging job { const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying(); @@ -262,7 +263,6 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -283,14 +283,11 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); // From the lighting model define a global shapKey ORED with individiual keys - ShapeKey::Builder keyBuilder = defaultKeyBuilder; + ShapeKey::Builder keyBuilder; if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } - // Prepare fade effect - DependencyManager::get()->bindPerBatch(batch); - ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); @@ -313,7 +310,6 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const const auto& lightingModel = inputs.get1(); RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -334,14 +330,11 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); // From the lighting model define a global shapeKey ORED with individiual keys - ShapeKey::Builder keyBuilder = defaultKeyBuilder; + ShapeKey::Builder keyBuilder; if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } - // Prepare fade effect - DependencyManager::get()->bindPerBatch(batch); - ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index a74a814630..c0d7f43516 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -53,7 +53,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, const auto& fbo = shadow->framebuffer; RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder = DependencyManager::get()->getKeyBuilder(); + ShapeKey::Builder defaultKeyBuilder;// TODO: support fade on shadows = DependencyManager::get()->getKeyBuilder(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -75,7 +75,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); // Prepare fade effect - DependencyManager::get()->bindPerBatch(batch); + // TODO: support fade on shadows DependencyManager::get()->bindPerBatch(batch); std::vector skinnedShapeKeys{}; diff --git a/libraries/render-utils/src/model_fade.slf b/libraries/render-utils/src/model_fade.slf index 1526dea7c2..7d145bc76b 100644 --- a/libraries/render-utils/src/model_fade.slf +++ b/libraries/render-utils/src/model_fade.slf @@ -30,7 +30,9 @@ in vec2 _texCoord1; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -50,6 +52,7 @@ void main(void) { vec3 emissive = getMaterialEmissive(mat); <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + emissive += fadeEmissive; float scattering = getMaterialScattering(mat); diff --git a/libraries/render-utils/src/model_lightmap_fade.slf b/libraries/render-utils/src/model_lightmap_fade.slf index f2055e7ffc..ccad86214a 100644 --- a/libraries/render-utils/src/model_lightmap_fade.slf +++ b/libraries/render-utils/src/model_lightmap_fade.slf @@ -31,7 +31,9 @@ in vec3 _color; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -46,5 +48,5 @@ void main(void) { getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), getMaterialFresnel(mat), - lightmapVal); + lightmapVal+fadeEmissive); } diff --git a/libraries/render-utils/src/model_lightmap_normal_map_fade.slf b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf index 137e40dd3c..a1dbd398ee 100644 --- a/libraries/render-utils/src/model_lightmap_normal_map_fade.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf @@ -32,7 +32,9 @@ in vec3 _color; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -49,5 +51,5 @@ void main(void) { getMaterialRoughness(mat), getMaterialMetallic(mat), getMaterialFresnel(mat), - lightmapVal); + lightmapVal+fadeEmissive); } diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf index b6cdfbd2a2..d7a8697b7a 100644 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf @@ -32,7 +32,9 @@ in vec3 _color; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -49,5 +51,5 @@ void main(void) { getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat) * metallicTex, /*specular, // no use of */ getMaterialFresnel(mat), - lightmapVal); + lightmapVal+fadeEmissive); } diff --git a/libraries/render-utils/src/model_lightmap_specular_map_fade.slf b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf index e6d82b778d..c4280ed6d1 100644 --- a/libraries/render-utils/src/model_lightmap_specular_map_fade.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf @@ -31,7 +31,9 @@ in vec3 _color; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -45,5 +47,5 @@ void main(void) { getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat) * metallicTex, /*metallicTex, // no use of */getMaterialFresnel(mat), - lightmapVal); + lightmapVal+fadeEmissive); } diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf index 61314fc834..7c70dabda2 100644 --- a/libraries/render-utils/src/model_normal_map_fade.slf +++ b/libraries/render-utils/src/model_normal_map_fade.slf @@ -31,7 +31,9 @@ in vec3 _tangent; in vec3 _color; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); diff --git a/libraries/render-utils/src/model_normal_specular_map_fade.slf b/libraries/render-utils/src/model_normal_specular_map_fade.slf index d9c4288e29..bdf917efea 100644 --- a/libraries/render-utils/src/model_normal_specular_map_fade.slf +++ b/libraries/render-utils/src/model_normal_specular_map_fade.slf @@ -31,7 +31,9 @@ in vec3 _color; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -66,7 +68,7 @@ void main(void) { albedo, roughness, metallic, - emissive, + emissive+fadeEmissive, occlusionTex, scattering); } diff --git a/libraries/render-utils/src/model_shadow_fade.slf b/libraries/render-utils/src/model_shadow_fade.slf index 635917b9f4..76720d6053 100644 --- a/libraries/render-utils/src/model_shadow_fade.slf +++ b/libraries/render-utils/src/model_shadow_fade.slf @@ -20,7 +20,7 @@ layout(location = 0) out vec4 _fragColor; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + applyFadeClip(_worldFadePosition.xyz); // pass-through to set z-buffer _fragColor = vec4(1.0, 1.0, 1.0, 0.0); diff --git a/libraries/render-utils/src/model_specular_map_fade.slf b/libraries/render-utils/src/model_specular_map_fade.slf index 3579cf1059..75db1d72a2 100644 --- a/libraries/render-utils/src/model_specular_map_fade.slf +++ b/libraries/render-utils/src/model_specular_map_fade.slf @@ -30,7 +30,9 @@ in vec3 _color; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -62,7 +64,7 @@ void main(void) { albedo, roughness, metallic, - emissive, + emissive+fadeEmissive, occlusionTex, scattering); } diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf index 3bbfdabc7f..9802e863b0 100644 --- a/libraries/render-utils/src/model_translucent_fade.slf +++ b/libraries/render-utils/src/model_translucent_fade.slf @@ -38,7 +38,9 @@ in vec4 _worldFadePosition; out vec4 _fragColor; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -81,7 +83,7 @@ void main(void) { albedo, fresnel, metallic, - emissive, + emissive+fadeEmissive, roughness, opacity), opacity); } diff --git a/libraries/render-utils/src/model_translucent_unlit_fade.slf b/libraries/render-utils/src/model_translucent_unlit_fade.slf index dd885f66d7..6c6846228e 100644 --- a/libraries/render-utils/src/model_translucent_unlit_fade.slf +++ b/libraries/render-utils/src/model_translucent_unlit_fade.slf @@ -29,7 +29,9 @@ in vec4 _worldFadePosition; out vec4 _fragColor; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -41,6 +43,6 @@ void main(void) { vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; - + albedo += fadeEmissive; _fragColor = vec4(albedo * isUnlitEnabled(), opacity); } diff --git a/libraries/render-utils/src/model_unlit_fade.slf b/libraries/render-utils/src/model_unlit_fade.slf index be0af7afea..59fdc87bee 100644 --- a/libraries/render-utils/src/model_unlit_fade.slf +++ b/libraries/render-utils/src/model_unlit_fade.slf @@ -29,7 +29,9 @@ in float _alpha; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -42,7 +44,7 @@ void main(void) { vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; - + albedo += fadeEmissive; packDeferredFragmentUnlit( normalize(_normal), opacity, diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf index c082ea26f3..526b7157d9 100644 --- a/libraries/render-utils/src/simple_fade.slf +++ b/libraries/render-utils/src/simple_fade.slf @@ -33,7 +33,9 @@ in vec4 _worldFadePosition; #line 2030 void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); Material material = getMaterial(); vec3 normal = normalize(_normal.xyz); @@ -61,14 +63,14 @@ void main(void) { packDeferredFragmentTranslucent( normal, _color.a, - specular, + specular+fadeEmissive, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); } else { packDeferredFragmentTranslucent( normal, _color.a, - diffuse, + diffuse+fadeEmissive, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); } @@ -77,7 +79,7 @@ void main(void) { packDeferredFragmentLightmap( normal, 1.0, - diffuse, + diffuse+fadeEmissive, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, @@ -89,7 +91,7 @@ void main(void) { diffuse, max(0, 1.0 - shininess / 128.0), length(specular), - DEFAULT_EMISSIVE, + DEFAULT_EMISSIVE+fadeEmissive, DEFAULT_OCCLUSION, DEFAULT_SCATTERING); } diff --git a/libraries/render-utils/src/simple_textured_fade.slf b/libraries/render-utils/src/simple_textured_fade.slf index c939a8d676..5130720277 100644 --- a/libraries/render-utils/src/simple_textured_fade.slf +++ b/libraries/render-utils/src/simple_textured_fade.slf @@ -29,7 +29,9 @@ in vec2 _texCoord0; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); vec4 texel = texture(originalTexture, _texCoord0); float colorAlpha = _color.a; @@ -43,7 +45,7 @@ void main(void) { packDeferredFragmentTranslucent( normalize(_normal), colorAlpha * texel.a, - _color.rgb * texel.rgb, + _color.rgb * texel.rgb + fadeEmissive, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); } else { @@ -53,7 +55,7 @@ void main(void) { _color.rgb * texel.rgb, DEFAULT_ROUGHNESS, DEFAULT_METALLIC, - DEFAULT_EMISSIVE, + DEFAULT_EMISSIVE + fadeEmissive, DEFAULT_OCCLUSION, DEFAULT_SCATTERING); } diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf index 2db2dfa222..60b6921ae3 100644 --- a/libraries/render-utils/src/simple_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf @@ -28,7 +28,9 @@ in vec2 _texCoord0; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); vec4 texel = texture(originalTexture, _texCoord0.st); float colorAlpha = _color.a; @@ -42,13 +44,13 @@ void main(void) { packDeferredFragmentTranslucent( normalize(_normal), colorAlpha * texel.a, - _color.rgb * texel.rgb, + _color.rgb * texel.rgb+fadeEmissive, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); } else { packDeferredFragmentUnlit( normalize(_normal), 1.0, - _color.rgb * texel.rgb); + _color.rgb * texel.rgb+fadeEmissive); } } \ No newline at end of file diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf index 84cdffeeec..8aa7bf176b 100644 --- a/libraries/render-utils/src/simple_transparent_textured_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -35,7 +35,9 @@ in vec2 _texCoord0; in vec4 _worldFadePosition; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); vec4 texel = texture(originalTexture, _texCoord0.st); float opacity = _color.a; @@ -59,8 +61,8 @@ void main(void) { fragNormal, albedo, DEFAULT_FRESNEL, - 0.0, - vec3(0.0f), + 0.0f, + fadeEmissive, DEFAULT_ROUGHNESS, opacity), opacity); diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf index 688e1de422..9f74eacc96 100644 --- a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf @@ -29,7 +29,9 @@ in vec4 _worldFadePosition; layout(location = 0) out vec4 _fragColor0; void main(void) { - applyFade(_worldFadePosition.xyz); + vec3 fadeEmissive; + + applyFade(_worldFadePosition.xyz, fadeEmissive); vec4 texel = texture(originalTexture, _texCoord0.st); float colorAlpha = _color.a; @@ -37,5 +39,5 @@ void main(void) { texel = colorToLinearRGBA(texel); colorAlpha = -_color.a; } - _fragColor0 = vec4(_color.rgb * texel.rgb, colorAlpha * texel.a); + _fragColor0 = vec4(_color.rgb * texel.rgb+fadeEmissive, colorAlpha * texel.a); } \ No newline at end of file diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slf b/libraries/render-utils/src/skin_model_shadow_fade.slf index 7b164f5db1..666525a3ae 100644 --- a/libraries/render-utils/src/skin_model_shadow_fade.slf +++ b/libraries/render-utils/src/skin_model_shadow_fade.slf @@ -20,7 +20,7 @@ in vec4 _worldFadePosition; layout(location = 0) out vec4 _fragColor; void main(void) { - applyFade(_worldFadePosition.xyz); + applyFadeClip(_worldFadePosition.xyz); // pass-through to set z-buffer _fragColor = vec4(1.0, 1.0, 1.0, 0.0); diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index a75488ce7a..6f0bb226ca 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -115,6 +115,7 @@ namespace render { uint32_t _globalShapeKey { 0 }; bool _enableTexturing { true }; + bool _enableFade{ false }; RenderDetails _details; render::ScenePointer _scene; diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 007b34395d..4690f0de74 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -316,7 +316,7 @@ public: virtual const ItemKey getKey() const = 0; virtual const Bound getBound() const = 0; virtual int getLayer() const = 0; - + virtual bool mustFade() const = 0; virtual void render(RenderArgs* args) = 0; virtual const ShapeKey getShapeKey() const = 0; @@ -364,6 +364,8 @@ public: // Get the layer where the item belongs. 0 by default meaning NOT LAYERED int getLayer() const { return _payload->getLayer(); } + bool mustFade() const { return _payload->mustFade(); } + // Render call for the item void render(RenderArgs* args) const { _payload->render(args); } @@ -409,6 +411,7 @@ template const ItemKey payloadGetKey(const std::shared_ptr& payload template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData) { return Item::Bound(); } template int payloadGetLayer(const std::shared_ptr& payloadData) { return 0; } template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } +template bool payloadMustFade(const std::shared_ptr& payloadData) { return false; } // Shape type interface // This allows shapes to characterize their pipeline via a ShapeKey, to be picked with a subclass of Shape. @@ -435,7 +438,7 @@ public: virtual const ItemKey getKey() const override { return payloadGetKey(_data); } virtual const Item::Bound getBound() const override { return payloadGetBound(_data); } virtual int getLayer() const override { return payloadGetLayer(_data); } - + virtual bool mustFade() const override { return payloadMustFade(_data); } virtual void render(RenderArgs* args) override { payloadRender(_data, args); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index d735afa52d..6e5d723ce6 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -65,6 +65,5 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto overlayTransparents = task.addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; - output = Varying(Output{{ - opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }}); + output = Output{opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection}; } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index f32293f001..f3f326aae8 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -31,7 +31,7 @@ public: NUM_BUCKETS }; - using Output = std::array; + using Output = render::VaryingArray; using JobModel = render::Task::ModelO; RenderFetchCullSortTask() {} diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 6a52f90297..57cfa6342e 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -70,6 +70,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT)); slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK)); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS)); gpu::Shader::makeProgram(*program, slotBindings); @@ -89,7 +90,8 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer"); locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap"); locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap"); - + locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer"); + ShapeKey key{filter._flags}; auto gpuPipeline = gpu::Pipeline::create(program, state); auto shapePipeline = std::make_shared(gpuPipeline, locations, batchSetter); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 06ca1ba15c..5d747a924d 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -215,6 +215,7 @@ public: LIGHTING_MODEL, LIGHT, LIGHT_AMBIENT_BUFFER, + FADE_PARAMETERS, }; enum MAP { @@ -246,6 +247,7 @@ public: int lightAmbientBufferUnit; int lightAmbientMapUnit; int fadeMaskTextureUnit; + int fadeParameterBufferUnit; }; using LocationsPointer = std::shared_ptr; diff --git a/libraries/render/src/task/Varying.h b/libraries/render/src/task/Varying.h index 50f4acd414..d5021383fb 100644 --- a/libraries/render/src/task/Varying.h +++ b/libraries/render/src/task/Varying.h @@ -281,6 +281,11 @@ public: (*this)[i] = Varying(T()); } } + + VaryingArray(std::initializer_list list) { + assert(list.size() == NUM); + std::copy(list.begin(), list.end(), begin()); + } }; } diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js index 064337dae1..80c2deff73 100644 --- a/scripts/developer/utilities/render/debugFade.js +++ b/scripts/developer/utilities/render/debugFade.js @@ -15,7 +15,7 @@ var window = new OverlayWindow({ title: 'Fade', source: qml, width: 500, - height: 80 + height: 900 }); window.setPosition(50, 50); window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 0a99ca2e7e..ba7ed59398 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -12,47 +12,228 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "configSlider" -Row { - property var taskConfig: Render.getConfig("RenderDeferredTask"); - spacing: 4 - Column { +Column { + property var config: Render.getConfig("RenderDeferredTask"); + spacing: 8 + Row { spacing: 8 CheckBox { - text: "Manual Fade" - checked: taskConfig["debugFade"] - onCheckedChanged: { taskConfig["debugFade"] = checked } + text: "Edit Fade" + checked: config["editFade"] + onCheckedChanged: { config["editFade"] = checked } + } + ComboBox { + width: 400 + model: ["Elements enter/leave domain", "Bubble isect. - Owner POV", "Bubble isect. - Trespasser POV", "Another user leaves/arrives", "Changing an avatar"] + onCurrentIndexChanged: { config["editedCategory"] = currentIndex } } } Column { spacing: 8 - ConfigSlider { - label: "Percent" - integral: false - config: taskConfig - property: "debugFadePercent" - max: 1.0 - min: 0.0 - width: 250 - } - ConfigSlider { - label: "Scale" - integral: false - config: taskConfig - property: "fadeScale" - max: 1.0 - min: 0.0 - width: 250 - } ConfigSlider { label: "Duration" integral: false - config: taskConfig - property: "fadeDuration" + config: config + property: "duration" max: 10.0 min: 0.1 - width: 250 + width: 400 + } + GroupBox { + title: "Base Gradient" + width: 500 + Column { + spacing: 8 + + ConfigSlider { + label: "Size X" + integral: false + config: config + property: "baseSizeX" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Y" + integral: false + config: config + property: "baseSizeY" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Z" + integral: false + config: config + property: "baseSizeZ" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Level" + integral: false + config: config + property: "baseLevel" + max: 1.0 + min: 0.0 + width: 400 + } + CheckBox { + text: "Invert" + checked: config["baseInverted"] + onCheckedChanged: { config["baseInverted"] = checked } + } + } + } + GroupBox { + title: "Noise Gradient" + width: 500 + Column { + spacing: 8 + + ConfigSlider { + label: "Size X" + integral: false + config: config + property: "noiseSizeX" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Y" + integral: false + config: config + property: "noiseSizeY" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Z" + integral: false + config: config + property: "noiseSizeZ" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Level" + integral: false + config: config + property: "noiseLevel" + max: 1.0 + min: 0.0 + width: 400 + } + } + } + GroupBox { + title: "Edge" + width: 500 + Column { + spacing: 8 + + ConfigSlider { + label: "Width" + integral: false + config: config + property: "edgeWidth" + max: 1.0 + min: 0.0 + width: 400 + } + GroupBox { + title: "Inner color" + Column { + spacing: 8 + ConfigSlider { + label: "Color R" + integral: false + config: config + property: "edgeInnerColorR" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color G" + integral: false + config: config + property: "edgeInnerColorG" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color B" + integral: false + config: config + property: "edgeInnerColorB" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color intensity" + integral: false + config: config + property: "edgeInnerIntensity" + max: 5.0 + min: 0.0 + width: 400 + } + } + } + GroupBox { + title: "Outer color" + Column { + spacing: 8 + ConfigSlider { + label: "Color R" + integral: false + config: config + property: "edgeOuterColorR" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color G" + integral: false + config: config + property: "edgeOuterColorG" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color B" + integral: false + config: config + property: "edgeOuterColorB" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color intensity" + integral: false + config: config + property: "edgeOuterIntensity" + max: 5.0 + min: 0.0 + width: 400 + } + } + } + } } } } From 6a31dc2659d1355593a9f9e3a76076173fda1ad7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Jun 2017 12:13:55 +0200 Subject: [PATCH 21/38] Selection of edited object working --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 2 +- libraries/render-utils/src/FadeEffect.cpp | 254 ++++++++++++++++-- libraries/render-utils/src/FadeEffect.h | 52 ++-- .../render-utils/src/RenderDeferredTask.cpp | 2 + libraries/render/src/render/Args.h | 1 + .../developer/utilities/render/debugFade.js | 3 +- scripts/developer/utilities/render/fade.qml | 50 ++-- 7 files changed, 291 insertions(+), 73 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 3441407f62..960e98d620 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -448,7 +448,7 @@ void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) { } updatePipeline(); - glUniform1f( + glUniform1i( GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int), batch._params[paramOffset + 0]._int); (void)CHECK_GL_ERROR(); diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index d2bad0d1ef..a9ac26c891 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -7,7 +7,7 @@ #include void FadeSwitchJob::configure(const Config& config) { - _isEditEnabled = config.editFade; + _parameters->_isEditEnabled = config.editFade; } void FadeSwitchJob::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { @@ -22,13 +22,50 @@ void FadeSwitchJob::run(const render::RenderContextPointer& renderContext, const normalOutputs[RenderFetchCullSortTask::BACKGROUND] = input[RenderFetchCullSortTask::BACKGROUND]; normalOutputs[RenderFetchCullSortTask::SPATIAL_SELECTION] = input[RenderFetchCullSortTask::SPATIAL_SELECTION]; + // Find the nearest item that intersects the view direction + const render::Item* editedItem = nullptr; + if (_parameters->_isEditEnabled) { + float nearestOpaqueDistance = std::numeric_limits::max(); + float nearestTransparentDistance = std::numeric_limits::max(); + const render::Item* nearestItem; + + editedItem = findNearestItem(renderContext, input[RenderFetchCullSortTask::OPAQUE_SHAPE], nearestOpaqueDistance); + nearestItem = findNearestItem(renderContext, input[RenderFetchCullSortTask::TRANSPARENT_SHAPE], nearestTransparentDistance); + if (nearestTransparentDistance < nearestOpaqueDistance) { + editedItem = nearestItem; + } + } + // Now, distribute items that need to be faded accross both outputs - distribute(renderContext, input[RenderFetchCullSortTask::OPAQUE_SHAPE], normalOutputs[RenderFetchCullSortTask::OPAQUE_SHAPE], fadeOutputs[OPAQUE_SHAPE]); - distribute(renderContext, input[RenderFetchCullSortTask::TRANSPARENT_SHAPE], normalOutputs[RenderFetchCullSortTask::TRANSPARENT_SHAPE], fadeOutputs[TRANSPARENT_SHAPE]); + distribute(renderContext, input[RenderFetchCullSortTask::OPAQUE_SHAPE], normalOutputs[RenderFetchCullSortTask::OPAQUE_SHAPE], fadeOutputs[OPAQUE_SHAPE], editedItem); + distribute(renderContext, input[RenderFetchCullSortTask::TRANSPARENT_SHAPE], normalOutputs[RenderFetchCullSortTask::TRANSPARENT_SHAPE], fadeOutputs[TRANSPARENT_SHAPE], editedItem); +} + +const render::Item* FadeSwitchJob::findNearestItem(const render::RenderContextPointer& renderContext, const render::Varying& input, float& minIsectDistance) const { + const glm::vec3 rayOrigin = renderContext->args->getViewFrustum().getPosition(); + const glm::vec3 rayDirection = renderContext->args->getViewFrustum().getDirection(); + const auto& inputItems = input.get(); + auto& scene = renderContext->_scene; + BoxFace face; + glm::vec3 normal; + float isectDistance; + const render::Item* nearestItem = nullptr; + const float minDistance = 5.f; + + for (const auto& itemBound : inputItems) { + if (itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { + if (isectDistance>minDistance && isectDistance < minIsectDistance) { + auto& item = scene->getItem(itemBound.id); + nearestItem = &item; + minIsectDistance = isectDistance; + } + } + } + return nearestItem; } void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext, const render::Varying& input, - render::Varying& normalOutput, render::Varying& fadeOutput) const { + render::Varying& normalOutput, render::Varying& fadeOutput, const render::Item* editedItem) const { auto& scene = renderContext->_scene; assert(_parameters); const double fadeDuration = double(_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]) * USECS_PER_SECOND; @@ -41,7 +78,7 @@ void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext for (const auto& itemBound : inputItems) { auto& item = scene->getItem(itemBound.id); - if (!item.mustFade()) { + if (!item.mustFade() && &item!=editedItem) { // No need to fade normalOutput.template edit().emplace_back(itemBound); } @@ -49,9 +86,107 @@ void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext fadeOutput.template edit().emplace_back(itemBound); } } -/* if (!_isEditEnabled) { +} - }*/ +void FadeJobConfig::setEditedCategory(int value) { + assert(value < EVENT_CATEGORY_COUNT); + editedCategory = std::min(EVENT_CATEGORY_COUNT, value); + emit dirty(); +} + +void FadeJobConfig::setDuration(float value) { + duration[editedCategory] = value; + emit dirty(); +} + +void FadeJobConfig::setBaseSizeX(float value) { + baseSize[editedCategory].x = value; + emit dirty(); +} + +void FadeJobConfig::setBaseSizeY(float value) { + baseSize[editedCategory].y = value; + emit dirty(); +} + +void FadeJobConfig::setBaseSizeZ(float value) { + baseSize[editedCategory].z = value; + emit dirty(); +} + +void FadeJobConfig::setBaseLevel(float value) { + baseLevel[editedCategory] = value; + emit dirty(); +} + +void FadeJobConfig::setBaseInverted(bool value) { + baseInverted[editedCategory] = value; + emit dirty(); +} + +void FadeJobConfig::setNoiseSizeX(float value) { + noiseSize[editedCategory].x = value; + emit dirty(); +} + +void FadeJobConfig::setNoiseSizeY(float value) { + noiseSize[editedCategory].y = value; + emit dirty(); +} + +void FadeJobConfig::setNoiseSizeZ(float value) { + noiseSize[editedCategory].z = value; + emit dirty(); +} + +void FadeJobConfig::setNoiseLevel(float value) { + noiseLevel[editedCategory] = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeWidth(float value) { + edgeWidth[editedCategory] = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeInnerColorR(float value) { + edgeInnerColor[editedCategory].r = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeInnerColorG(float value) { + edgeInnerColor[editedCategory].g = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeInnerColorB(float value) { + edgeInnerColor[editedCategory].b = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeInnerIntensity(float value) { + edgeInnerColor[editedCategory].a = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeOuterColorR(float value) { + edgeOuterColor[editedCategory].r = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeOuterColorG(float value) { + edgeOuterColor[editedCategory].g = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeOuterColorB(float value) { + edgeOuterColor[editedCategory].b = value; + emit dirty(); +} + +void FadeJobConfig::setEdgeOuterIntensity(float value) { + edgeOuterColor[editedCategory].a = value; + emit dirty(); } FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) : @@ -63,6 +198,7 @@ FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) : void FadeConfigureJob::configure(const Config& config) { assert(_parameters); + _parameters->_editedCategory = config.editedCategory; for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) { auto& configuration = _configurations[i]; @@ -101,18 +237,6 @@ const FadeRenderJob* FadeRenderJob::_currentInstance{ nullptr }; gpu::TexturePointer FadeRenderJob::_currentFadeMaskMap; const gpu::BufferView* FadeRenderJob::_currentFadeBuffer{ nullptr }; -float FadeRenderJob::computeFadePercent(quint64 startTime) { - assert(_currentInstance); - float fadeAlpha = 1.0f; - const double INV_FADE_PERIOD = 1.0 / (double)(_currentInstance->_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] * USECS_PER_SECOND); - double fraction = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) * INV_FADE_PERIOD; - fraction = std::max(fraction, 0.0); - if (fraction < 1.0) { - fadeAlpha = Interpolate::easeInOutQuad(fraction); - } - return fadeAlpha; -} - void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const Input& inputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -125,15 +249,23 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const const auto& fadeMaskMap = configuration.get0(); const auto& fadeParamBuffer = configuration.get1(); - // Very, very ugly hack to keep track of the current fade render job RenderArgs* args = renderContext->args; render::ShapeKey::Builder defaultKeyBuilder; defaultKeyBuilder.withFade(); + // Update interactive edit effect + if (_parameters->_isEditEnabled) { + updateFadeEdit(); + } + else { + _editStartTime = 0; + } + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; + // Very, very ugly hack to keep track of the current fade render job _currentInstance = this; _currentFadeMaskMap = fadeMaskMap; _currentFadeBuffer = &fadeParamBuffer; @@ -180,6 +312,69 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const } } +float FadeRenderJob::computeElementEnterThreshold(double time) const { + float fadeAlpha = 1.0f; + const double INV_FADE_PERIOD = 1.0 / (double)(_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]); + double fraction = time * INV_FADE_PERIOD; + fraction = std::max(fraction, 0.0); + if (fraction < 1.0) { + fadeAlpha = Interpolate::easeInOutQuad(fraction); + } + return fadeAlpha; +} + +float FadeRenderJob::computeFadePercent(quint64 startTime) { + const double time = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) / (double)(USECS_PER_SECOND); + assert(_currentInstance); + return _currentInstance->computeElementEnterThreshold(time); +} + +void FadeRenderJob::updateFadeEdit() { + if (_editStartTime == 0) { + _editStartTime = usecTimestampNow(); + } + + const double time = (int64_t(usecTimestampNow()) - int64_t(_editStartTime)) / double(USECS_PER_SECOND); + + switch (_parameters->_editedCategory) { + case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: + { + const double waitTime = 0.5; // Wait between fade in and out + const float eventDuration = _parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]; + double cycleTime = fmod(time, (eventDuration+waitTime) * 2.0); + + if (cycleTime < eventDuration) { + _editThreshold = 1.f-computeElementEnterThreshold(cycleTime); + } + else if (cycleTime < (eventDuration + waitTime)) { + _editThreshold = 0.f; + } + else if (cycleTime < (2 * eventDuration + waitTime)) { + _editThreshold = computeElementEnterThreshold(cycleTime- (eventDuration + waitTime)); + } + else { + _editThreshold = 1.f; + } + } + break; + + case FadeJobConfig::BUBBLE_ISECT_OWNER: + break; + + case FadeJobConfig::BUBBLE_ISECT_TRESPASSER: + break; + + case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: + break; + + case FadeJobConfig::AVATAR_CHANGE: + break; + + default: + assert(false); + } +} + void FadeRenderJob::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation) { assert(_currentFadeMaskMap); assert(_currentFadeBuffer!=nullptr); @@ -210,17 +405,26 @@ bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline auto fadeCategoryLocation = uniforms.findLocation("fadeCategory"); if (fadeNoiseOffsetLocation >= 0 || fadeBaseOffsetLocation>=0 || fadeThresholdLocation >= 0 || fadeCategoryLocation>=0) { - float percent; + float threshold; + int eventCategory = FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN; - percent = computeFadePercent(startTime); - batch._glUniform1i(fadeCategoryLocation, FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN); - batch._glUniform1f(fadeThresholdLocation, 1.f-percent); + threshold = 1.f-computeFadePercent(startTime); + + // Manage interactive edition override + assert(_currentInstance); + if (_currentInstance->_parameters->_isEditEnabled) { + eventCategory = _currentInstance->_parameters->_editedCategory; + threshold = _currentInstance->_editThreshold; + } + + batch._glUniform1i(fadeCategoryLocation, eventCategory); + batch._glUniform1f(fadeThresholdLocation, threshold); // This is really temporary batch._glUniform3f(fadeNoiseOffsetLocation, offset.x, offset.y, offset.z); // This is really temporary batch._glUniform3f(fadeBaseOffsetLocation, offset.x, offset.y, offset.z); - return percent < 1.f; + return threshold > 0.f; } return false; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 295dbb333a..2ac9954575 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -66,63 +66,63 @@ public: EVENT_CATEGORY_COUNT }; - void setEditedCategory(int value) { assert(value < EVENT_CATEGORY_COUNT); editedCategory = std::min(EVENT_CATEGORY_COUNT, value); } + void setEditedCategory(int value); - void setDuration(float value) { duration[editedCategory] = value; } + void setDuration(float value); float getDuration() const { return duration[editedCategory]; } - void setBaseSizeX(float value) { baseSize[editedCategory].x = value; } + void setBaseSizeX(float value); float getBaseSizeX() const { return baseSize[editedCategory].x; } - void setBaseSizeY(float value) { baseSize[editedCategory].y = value; } + void setBaseSizeY(float value); float getBaseSizeY() const { return baseSize[editedCategory].y; } - void setBaseSizeZ(float value) { baseSize[editedCategory].z = value; } + void setBaseSizeZ(float value); float getBaseSizeZ() const { return baseSize[editedCategory].z; } - void setBaseLevel(float value) { baseLevel[editedCategory] = value; } + void setBaseLevel(float value); float getBaseLevel() const { return baseLevel[editedCategory]; } - void setBaseInverted(bool value) { baseInverted[editedCategory] = value; } + void setBaseInverted(bool value); bool isBaseInverted() const { return baseInverted[editedCategory]; } - void setNoiseSizeX(float value) { noiseSize[editedCategory].x = value; } + void setNoiseSizeX(float value); float getNoiseSizeX() const { return noiseSize[editedCategory].x; } - void setNoiseSizeY(float value) { noiseSize[editedCategory].y = value; } + void setNoiseSizeY(float value); float getNoiseSizeY() const { return noiseSize[editedCategory].y; } - void setNoiseSizeZ(float value) { noiseSize[editedCategory].z = value; } + void setNoiseSizeZ(float value); float getNoiseSizeZ() const { return noiseSize[editedCategory].z; } - void setNoiseLevel(float value) { noiseLevel[editedCategory] = value; } + void setNoiseLevel(float value); float getNoiseLevel() const { return noiseLevel[editedCategory]; } - void setEdgeWidth(float value) { edgeWidth[editedCategory] = value; } + void setEdgeWidth(float value); float getEdgeWidth() const { return edgeWidth[editedCategory]; } - void setEdgeInnerColorR(float value) { edgeInnerColor[editedCategory].r = value; } + void setEdgeInnerColorR(float value); float getEdgeInnerColorR() const { return edgeInnerColor[editedCategory].r; } - void setEdgeInnerColorG(float value) { edgeInnerColor[editedCategory].g = value; } + void setEdgeInnerColorG(float value); float getEdgeInnerColorG() const { return edgeInnerColor[editedCategory].g; } - void setEdgeInnerColorB(float value) { edgeInnerColor[editedCategory].b = value; } + void setEdgeInnerColorB(float value); float getEdgeInnerColorB() const { return edgeInnerColor[editedCategory].b; } - void setEdgeInnerIntensity(float value) { edgeInnerColor[editedCategory].a = value; } + void setEdgeInnerIntensity(float value); float getEdgeInnerIntensity() const { return edgeInnerColor[editedCategory].a; } - void setEdgeOuterColorR(float value) { edgeOuterColor[editedCategory].r = value; } + void setEdgeOuterColorR(float value); float getEdgeOuterColorR() const { return edgeOuterColor[editedCategory].r; } - void setEdgeOuterColorG(float value) { edgeOuterColor[editedCategory].g = value; } + void setEdgeOuterColorG(float value); float getEdgeOuterColorG() const { return edgeOuterColor[editedCategory].g; } - void setEdgeOuterColorB(float value) { edgeOuterColor[editedCategory].b = value; } + void setEdgeOuterColorB(float value); float getEdgeOuterColorB() const { return edgeOuterColor[editedCategory].b; } - void setEdgeOuterIntensity(float value) { edgeOuterColor[editedCategory].a = value; } + void setEdgeOuterIntensity(float value); float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; @@ -199,6 +199,8 @@ struct FadeCommonParameters { using Pointer = std::shared_ptr; + bool _isEditEnabled{ false }; + int _editedCategory{ FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN }; float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]{ 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN 0.0f, // BUBBLE_ISECT_OWNER @@ -233,10 +235,10 @@ public: private: FadeCommonParameters::Pointer _parameters; - bool _isEditEnabled{ false }; void distribute(const render::RenderContextPointer& renderContext, const render::Varying& input, - render::Varying& normalOutput, render::Varying& fadeOutput) const; + render::Varying& normalOutput, render::Varying& fadeOutput, const render::Item* editedItem = nullptr) const; + const render::Item* findNearestItem(const render::RenderContextPointer& renderContext, const render::Varying& input, float& minIsectDistance) const; }; struct FadeParameters @@ -308,7 +310,13 @@ private: render::ShapePlumberPointer _shapePlumber; FadeCommonParameters::Pointer _parameters; + float computeElementEnterThreshold(double time) const; + // Everything needed for interactive edition + uint64_t _editStartTime{ 0 }; + float _editThreshold{ 0.f }; + + void updateFadeEdit(); }; #endif // hifi_FadeEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index a8ead6e76e..ca7f4a10d9 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -103,6 +103,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto fadeOpaqueInputs = FadeRenderJob::Input(fadeOpaques, lightingModel, fadeConfigureOutputs).hasVarying(); task.addJob("DrawFadeOpaque", fadeOpaqueInputs, commonFadeParameters, shapePlumber); + task.addJob("OpaqueRangeTimer", opaqueRangeTimer); @@ -173,6 +174,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("ToneMapping", toneMappingInputs); { // DEbug the bounds of the rendered items, still look at the zbuffer + task.addJob("DrawFadedOpaqueBounds", fadeOpaques); task.addJob("DrawMetaBounds", metas); task.addJob("DrawOpaqueBounds", opaques); task.addJob("DrawTransparentBounds", transparents); diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index 6f0bb226ca..d17e6628d3 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -115,6 +115,7 @@ namespace render { uint32_t _globalShapeKey { 0 }; bool _enableTexturing { true }; + bool _enableFade{ false }; RenderDetails _details; diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js index 80c2deff73..df18e0370a 100644 --- a/scripts/developer/utilities/render/debugFade.js +++ b/scripts/developer/utilities/render/debugFade.js @@ -18,4 +18,5 @@ var window = new OverlayWindow({ height: 900 }); window.setPosition(50, 50); -window.closed.connect(function() { Script.stop(); }); \ No newline at end of file +window.closed.connect(function() { Script.stop(); }); +Render.getConfig("RenderMainView.DrawFadedOpaqueBounds").enabled = true \ No newline at end of file diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index ba7ed59398..3aff96d7cd 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -13,20 +13,22 @@ import QtQuick.Controls 1.4 import "configSlider" Column { - property var config: Render.getConfig("RenderDeferredTask"); + id: root + property var config: Render.getConfig("RenderMainView.FadeConfigure"); + property var switchConfig: Render.getConfig("RenderMainView.FadeSwitch"); spacing: 8 Row { spacing: 8 CheckBox { text: "Edit Fade" - checked: config["editFade"] - onCheckedChanged: { config["editFade"] = checked } + checked: root.switchConfig["editFade"] + onCheckedChanged: { root.switchConfig["editFade"] = checked } } ComboBox { width: 400 model: ["Elements enter/leave domain", "Bubble isect. - Owner POV", "Bubble isect. - Trespasser POV", "Another user leaves/arrives", "Changing an avatar"] - onCurrentIndexChanged: { config["editedCategory"] = currentIndex } + onCurrentIndexChanged: { root.config["editedCategory"] = currentIndex } } } Column { @@ -35,7 +37,7 @@ Column { ConfigSlider { label: "Duration" integral: false - config: config + config: root.config property: "duration" max: 10.0 min: 0.1 @@ -50,7 +52,7 @@ Column { ConfigSlider { label: "Size X" integral: false - config: config + config: root.config property: "baseSizeX" max: 1.0 min: 0.0 @@ -59,7 +61,7 @@ Column { ConfigSlider { label: "Size Y" integral: false - config: config + config: root.config property: "baseSizeY" max: 1.0 min: 0.0 @@ -68,7 +70,7 @@ Column { ConfigSlider { label: "Size Z" integral: false - config: config + config: root.config property: "baseSizeZ" max: 1.0 min: 0.0 @@ -77,7 +79,7 @@ Column { ConfigSlider { label: "Level" integral: false - config: config + config: root.config property: "baseLevel" max: 1.0 min: 0.0 @@ -85,8 +87,8 @@ Column { } CheckBox { text: "Invert" - checked: config["baseInverted"] - onCheckedChanged: { config["baseInverted"] = checked } + checked: root.config["baseInverted"] + onCheckedChanged: { root.config["baseInverted"] = checked } } } } @@ -99,7 +101,7 @@ Column { ConfigSlider { label: "Size X" integral: false - config: config + config: root.config property: "noiseSizeX" max: 1.0 min: 0.0 @@ -108,7 +110,7 @@ Column { ConfigSlider { label: "Size Y" integral: false - config: config + config: root.config property: "noiseSizeY" max: 1.0 min: 0.0 @@ -117,7 +119,7 @@ Column { ConfigSlider { label: "Size Z" integral: false - config: config + config: root.config property: "noiseSizeZ" max: 1.0 min: 0.0 @@ -126,7 +128,7 @@ Column { ConfigSlider { label: "Level" integral: false - config: config + config: root.config property: "noiseLevel" max: 1.0 min: 0.0 @@ -143,7 +145,7 @@ Column { ConfigSlider { label: "Width" integral: false - config: config + config: root.config property: "edgeWidth" max: 1.0 min: 0.0 @@ -156,7 +158,7 @@ Column { ConfigSlider { label: "Color R" integral: false - config: config + config: root.config property: "edgeInnerColorR" max: 1.0 min: 0.0 @@ -165,7 +167,7 @@ Column { ConfigSlider { label: "Color G" integral: false - config: config + config: root.config property: "edgeInnerColorG" max: 1.0 min: 0.0 @@ -174,7 +176,7 @@ Column { ConfigSlider { label: "Color B" integral: false - config: config + config: root.config property: "edgeInnerColorB" max: 1.0 min: 0.0 @@ -183,7 +185,7 @@ Column { ConfigSlider { label: "Color intensity" integral: false - config: config + config: root.config property: "edgeInnerIntensity" max: 5.0 min: 0.0 @@ -198,7 +200,7 @@ Column { ConfigSlider { label: "Color R" integral: false - config: config + config: root.config property: "edgeOuterColorR" max: 1.0 min: 0.0 @@ -207,7 +209,7 @@ Column { ConfigSlider { label: "Color G" integral: false - config: config + config: root.config property: "edgeOuterColorG" max: 1.0 min: 0.0 @@ -216,7 +218,7 @@ Column { ConfigSlider { label: "Color B" integral: false - config: config + config: root.config property: "edgeOuterColorB" max: 1.0 min: 0.0 @@ -225,7 +227,7 @@ Column { ConfigSlider { label: "Color intensity" integral: false - config: config + config: root.config property: "edgeOuterIntensity" max: 5.0 min: 0.0 From fb33b8d1c1e567d8b72e7601d7c981984d96b7b2 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Jun 2017 12:59:43 +0200 Subject: [PATCH 22/38] Working edition and emissive edge on fade element enter/leave --- libraries/render-utils/src/Fade.slh | 15 ++++---- libraries/render-utils/src/FadeEffect.cpp | 25 +++++++------- libraries/render-utils/src/FadeEffect.h | 42 +++++++++++------------ 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 776343dc53..5ee7bb2178 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -22,8 +22,8 @@ struct FadeParameters { vec4 _baseInvSizeAndLevel; vec4 _noiseInvSizeAndLevel; - vec3 _innerEdgeColor; - vec3 _outerEdgeColor; + vec4 _innerEdgeColor; + vec4 _outerEdgeColor; vec2 _edgeWidthInvWidth; int _invertBase; float _padding; @@ -108,16 +108,15 @@ void applyFade(vec3 position, out vec3 emissive) { if (alpha < 0) { discard; } - /* + float edgeMask = alpha * fadeParameters[fadeCategory]._edgeWidthInvWidth.y; float edgeAlpha = 1.0-clamp(edgeMask, 0, 1); - edgeMask = step(edgeMask, 1.f); + //edgeMask = step(edgeMask, 1.f); + edgeMask = edgeMask > 1.f ? 0.f : 1.f; edgeAlpha *= edgeAlpha; // Square to have a nice ease out - emissive = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha); - emissive *= edgeMask; - */ - emissive = vec3(0,0,0); + vec4 color = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha); + emissive = color.rgb * edgeMask * color.a; } <@endfunc@> diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index a9ac26c891..ef15953b2b 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -6,6 +6,9 @@ #include #include +#define FADE_MIN_SCALE 0.001f +#define FADE_MAX_SCALE 100000.f + void FadeSwitchJob::configure(const Config& config) { _parameters->_isEditEnabled = config.editFade; } @@ -100,17 +103,17 @@ void FadeJobConfig::setDuration(float value) { } void FadeJobConfig::setBaseSizeX(float value) { - baseSize[editedCategory].x = value; + baseSize[editedCategory].x = FADE_MIN_SCALE*powf(FADE_MAX_SCALE/ FADE_MIN_SCALE, value); emit dirty(); } void FadeJobConfig::setBaseSizeY(float value) { - baseSize[editedCategory].y = value; + baseSize[editedCategory].y = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } void FadeJobConfig::setBaseSizeZ(float value) { - baseSize[editedCategory].z = value; + baseSize[editedCategory].z = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } @@ -125,17 +128,17 @@ void FadeJobConfig::setBaseInverted(bool value) { } void FadeJobConfig::setNoiseSizeX(float value) { - noiseSize[editedCategory].x = value; + noiseSize[editedCategory].x = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } void FadeJobConfig::setNoiseSizeY(float value) { - noiseSize[editedCategory].y = value; + noiseSize[editedCategory].y = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } void FadeJobConfig::setNoiseSizeZ(float value) { - noiseSize[editedCategory].z = value; + noiseSize[editedCategory].z = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } @@ -145,7 +148,7 @@ void FadeJobConfig::setNoiseLevel(float value) { } void FadeJobConfig::setEdgeWidth(float value) { - edgeWidth[editedCategory] = value; + edgeWidth[editedCategory] = value * value; emit dirty(); } @@ -214,12 +217,8 @@ void FadeConfigureJob::configure(const Config& config) { configuration._invertBase = config.baseInverted[i]; configuration._edgeWidthInvWidth.x = config.edgeWidth[i]; configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; - configuration._innerEdgeColor.r = config.edgeInnerColor[i].r * config.edgeInnerColor[i].a; - configuration._innerEdgeColor.g = config.edgeInnerColor[i].g * config.edgeInnerColor[i].a; - configuration._innerEdgeColor.b = config.edgeInnerColor[i].b * config.edgeInnerColor[i].a; - configuration._outerEdgeColor.r = config.edgeOuterColor[i].r * config.edgeOuterColor[i].a; - configuration._outerEdgeColor.g = config.edgeOuterColor[i].g * config.edgeOuterColor[i].a; - configuration._outerEdgeColor.b = config.edgeOuterColor[i].b * config.edgeOuterColor[i].a; + configuration._innerEdgeColor = config.edgeInnerColor[i]; + configuration._outerEdgeColor = config.edgeOuterColor[i]; } _isBufferDirty = true; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 2ac9954575..c3e82c6c5d 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -127,11 +127,11 @@ public: int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; glm::vec3 baseSize[EVENT_CATEGORY_COUNT]{ - { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + { 0.35f, 0.35f, 0.35f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_OWNER + { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_TRESPASSER + { 0.35f, 0.35f, 0.35f }, // USER_ENTER_LEAVE_DOMAIN + { 0.35f, 0.35f, 0.35f }, // AVATAR_CHANGE }; float baseLevel[EVENT_CATEGORY_COUNT]{ 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN @@ -148,11 +148,11 @@ public: false, // AVATAR_CHANGE }; glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ - { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + { 0.35f, 0.35f, 0.35f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_OWNER + { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_TRESPASSER + { 0.35f, 0.35f, 0.35f }, // USER_ENTER_LEAVE_DOMAIN + { 0.35f, 0.35f, 0.35f }, // AVATAR_CHANGE }; float noiseLevel[EVENT_CATEGORY_COUNT]{ 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN @@ -169,22 +169,22 @@ public: 3.0f, // AVATAR_CHANGE }; float edgeWidth[EVENT_CATEGORY_COUNT]{ - 0.1f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.1f, // BUBBLE_ISECT_OWNER - 0.1f, // BUBBLE_ISECT_TRESPASSER - 0.1f, // USER_ENTER_LEAVE_DOMAIN - 0.1f, // AVATAR_CHANGE + 0.05f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.05f, // BUBBLE_ISECT_OWNER + 0.05f, // BUBBLE_ISECT_TRESPASSER + 0.05f, // USER_ENTER_LEAVE_DOMAIN + 0.05f, // AVATAR_CHANGE }; glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]{ - { 1.0f, 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER { 1.0f, 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE }; glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]{ - { 1.0f, 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_OWNER + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER { 1.0f, 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE @@ -245,8 +245,8 @@ struct FadeParameters { glm::vec4 _baseInvSizeAndLevel; glm::vec4 _noiseInvSizeAndLevel; - glm::vec3 _innerEdgeColor; - glm::vec3 _outerEdgeColor; + glm::vec4 _innerEdgeColor; + glm::vec4 _outerEdgeColor; glm::vec2 _edgeWidthInvWidth; glm::int32 _invertBase; glm::float32 _padding; From c5ca23f4eae42c7eb2a79febd205ee3e08c58b87 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Jun 2017 17:14:20 +0200 Subject: [PATCH 23/38] Changing edited fade category properly updates widgets in edit window --- libraries/render-utils/src/FadeEffect.cpp | 41 +- libraries/render-utils/src/FadeEffect.h | 55 +-- .../render/configSlider/ConfigSlider.qml | 1 + .../developer/utilities/render/debugFade.js | 3 +- scripts/developer/utilities/render/fade.qml | 418 +++++++++--------- 5 files changed, 290 insertions(+), 228 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index ef15953b2b..7c975ef201 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -94,29 +94,46 @@ void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext void FadeJobConfig::setEditedCategory(int value) { assert(value < EVENT_CATEGORY_COUNT); editedCategory = std::min(EVENT_CATEGORY_COUNT, value); + emit dirtyCategory(); emit dirty(); } void FadeJobConfig::setDuration(float value) { - duration[editedCategory] = value; + _duration[editedCategory] = value; emit dirty(); } +float FadeJobConfig::getDuration() const { + return _duration[editedCategory]; +} + void FadeJobConfig::setBaseSizeX(float value) { baseSize[editedCategory].x = FADE_MIN_SCALE*powf(FADE_MAX_SCALE/ FADE_MIN_SCALE, value); emit dirty(); } +float FadeJobConfig::getBaseSizeX() const { + return logf(baseSize[editedCategory].x / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); +} + void FadeJobConfig::setBaseSizeY(float value) { baseSize[editedCategory].y = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } +float FadeJobConfig::getBaseSizeY() const { + return logf(baseSize[editedCategory].y / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); +} + void FadeJobConfig::setBaseSizeZ(float value) { baseSize[editedCategory].z = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } +float FadeJobConfig::getBaseSizeZ() const { + return logf(baseSize[editedCategory].z / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); +} + void FadeJobConfig::setBaseLevel(float value) { baseLevel[editedCategory] = value; emit dirty(); @@ -127,21 +144,37 @@ void FadeJobConfig::setBaseInverted(bool value) { emit dirty(); } +bool FadeJobConfig::isBaseInverted() const { + return baseInverted[editedCategory]; +} + void FadeJobConfig::setNoiseSizeX(float value) { noiseSize[editedCategory].x = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } +float FadeJobConfig::getNoiseSizeX() const { + return logf(noiseSize[editedCategory].x / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); +} + void FadeJobConfig::setNoiseSizeY(float value) { noiseSize[editedCategory].y = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } +float FadeJobConfig::getNoiseSizeY() const { + return logf(noiseSize[editedCategory].y / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); +} + void FadeJobConfig::setNoiseSizeZ(float value) { noiseSize[editedCategory].z = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); emit dirty(); } +float FadeJobConfig::getNoiseSizeZ() const { + return logf(noiseSize[editedCategory].z / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); +} + void FadeJobConfig::setNoiseLevel(float value) { noiseLevel[editedCategory] = value; emit dirty(); @@ -152,6 +185,10 @@ void FadeJobConfig::setEdgeWidth(float value) { emit dirty(); } +float FadeJobConfig::getEdgeWidth() const { + return sqrtf(edgeWidth[editedCategory]); +} + void FadeJobConfig::setEdgeInnerColorR(float value) { edgeInnerColor[editedCategory].r = value; emit dirty(); @@ -205,7 +242,7 @@ void FadeConfigureJob::configure(const Config& config) { for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) { auto& configuration = _configurations[i]; - _parameters->_durations[i] = config.duration[i]; + _parameters->_durations[i] = config._duration[i]; configuration._baseInvSizeAndLevel.x = 1.f / config.baseSize[i].x; configuration._baseInvSizeAndLevel.y = 1.f / config.baseSize[i].y; configuration._baseInvSizeAndLevel.z = 1.f / config.baseSize[i].z; diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index c3e82c6c5d..122449e08a 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -32,7 +32,7 @@ signals: class FadeJobConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int editedCategory MEMBER editedCategory WRITE setEditedCategory NOTIFY dirty) + Q_PROPERTY(int editedCategory MEMBER editedCategory WRITE setEditedCategory NOTIFY dirtyCategory) Q_PROPERTY(float duration READ getDuration WRITE setDuration NOTIFY dirty) Q_PROPERTY(float baseSizeX READ getBaseSizeX WRITE setBaseSizeX NOTIFY dirty) Q_PROPERTY(float baseSizeY READ getBaseSizeY WRITE setBaseSizeY NOTIFY dirty) @@ -69,37 +69,37 @@ public: void setEditedCategory(int value); void setDuration(float value); - float getDuration() const { return duration[editedCategory]; } + float getDuration() const; void setBaseSizeX(float value); - float getBaseSizeX() const { return baseSize[editedCategory].x; } + float getBaseSizeX() const; void setBaseSizeY(float value); - float getBaseSizeY() const { return baseSize[editedCategory].y; } + float getBaseSizeY() const; void setBaseSizeZ(float value); - float getBaseSizeZ() const { return baseSize[editedCategory].z; } + float getBaseSizeZ() const; void setBaseLevel(float value); float getBaseLevel() const { return baseLevel[editedCategory]; } void setBaseInverted(bool value); - bool isBaseInverted() const { return baseInverted[editedCategory]; } + bool isBaseInverted() const; void setNoiseSizeX(float value); - float getNoiseSizeX() const { return noiseSize[editedCategory].x; } + float getNoiseSizeX() const; void setNoiseSizeY(float value); - float getNoiseSizeY() const { return noiseSize[editedCategory].y; } + float getNoiseSizeY() const; void setNoiseSizeZ(float value); - float getNoiseSizeZ() const { return noiseSize[editedCategory].z; } + float getNoiseSizeZ() const; void setNoiseLevel(float value); float getNoiseLevel() const { return noiseLevel[editedCategory]; } void setEdgeWidth(float value); - float getEdgeWidth() const { return edgeWidth[editedCategory]; } + float getEdgeWidth() const; void setEdgeInnerColorR(float value); float getEdgeInnerColorR() const { return edgeInnerColor[editedCategory].r; } @@ -127,11 +127,11 @@ public: int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; glm::vec3 baseSize[EVENT_CATEGORY_COUNT]{ - { 0.35f, 0.35f, 0.35f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_OWNER - { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_TRESPASSER - { 0.35f, 0.35f, 0.35f }, // USER_ENTER_LEAVE_DOMAIN - { 0.35f, 0.35f, 0.35f }, // AVATAR_CHANGE + { 0.4f, 0.4f, 0.4f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER + { 0.875f, 0.4f, 0.875f }, // USER_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE }; float baseLevel[EVENT_CATEGORY_COUNT]{ 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN @@ -144,15 +144,15 @@ public: false, // ELEMENT_ENTER_LEAVE_DOMAIN false, // BUBBLE_ISECT_OWNER false, // BUBBLE_ISECT_TRESPASSER - false, // USER_ENTER_LEAVE_DOMAIN + true, // USER_ENTER_LEAVE_DOMAIN false, // AVATAR_CHANGE }; glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ - { 0.35f, 0.35f, 0.35f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_OWNER - { 0.35f, 0.35f, 0.35f }, // BUBBLE_ISECT_TRESPASSER - { 0.35f, 0.35f, 0.35f }, // USER_ENTER_LEAVE_DOMAIN - { 0.35f, 0.35f, 0.35f }, // AVATAR_CHANGE + { 0.41f, 0.41f, 0.41f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER + { 0.4f, 0.4f, 0.4f }, // USER_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE }; float noiseLevel[EVENT_CATEGORY_COUNT]{ 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN @@ -161,18 +161,18 @@ public: 1.0f, // USER_ENTER_LEAVE_DOMAIN 1.0f, // AVATAR_CHANGE }; - float duration[EVENT_CATEGORY_COUNT]{ - 5.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + float _duration[EVENT_CATEGORY_COUNT]{ + 4.0f, // ELEMENT_ENTER_LEAVE_DOMAIN 0.0f, // BUBBLE_ISECT_OWNER 0.0f, // BUBBLE_ISECT_TRESPASSER 3.0f, // USER_ENTER_LEAVE_DOMAIN 3.0f, // AVATAR_CHANGE }; float edgeWidth[EVENT_CATEGORY_COUNT]{ - 0.05f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.05f, // BUBBLE_ISECT_OWNER - 0.05f, // BUBBLE_ISECT_TRESPASSER - 0.05f, // USER_ENTER_LEAVE_DOMAIN + 0.10f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.10f, // BUBBLE_ISECT_OWNER + 0.10f, // BUBBLE_ISECT_TRESPASSER + 0.10f, // USER_ENTER_LEAVE_DOMAIN 0.05f, // AVATAR_CHANGE }; glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]{ @@ -192,6 +192,7 @@ public: signals: void dirty(); + void dirtyCategory(); }; diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index 996cf4b34c..c1a6d6b7f3 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -38,6 +38,7 @@ Item { } Label { + id: labelValue text: sliderControl.value.toFixed(root.integral ? 0 : 2) anchors.left: root.left anchors.leftMargin: 200 diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js index df18e0370a..6632cd8094 100644 --- a/scripts/developer/utilities/render/debugFade.js +++ b/scripts/developer/utilities/render/debugFade.js @@ -15,8 +15,7 @@ var window = new OverlayWindow({ title: 'Fade', source: qml, width: 500, - height: 900 + height: 900, }); window.setPosition(50, 50); window.closed.connect(function() { Script.stop(); }); -Render.getConfig("RenderMainView.DrawFadedOpaqueBounds").enabled = true \ No newline at end of file diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 3aff96d7cd..9b6ef95837 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -23,220 +23,244 @@ Column { CheckBox { text: "Edit Fade" checked: root.switchConfig["editFade"] - onCheckedChanged: { root.switchConfig["editFade"] = checked } + onCheckedChanged: { + root.switchConfig["editFade"] = checked; + Render.getConfig("RenderMainView.DrawFadedOpaqueBounds").enabled = checked; + } } ComboBox { + id: categoryBox width: 400 model: ["Elements enter/leave domain", "Bubble isect. - Owner POV", "Bubble isect. - Trespasser POV", "Another user leaves/arrives", "Changing an avatar"] - onCurrentIndexChanged: { root.config["editedCategory"] = currentIndex } + Timer { + id: postpone + interval: 100; running: false; repeat: false + onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets } + } + onCurrentIndexChanged: { + root.config["editedCategory"] = currentIndex; + // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component + // by setting the loader source to Null and then recreate it 100ms later + paramWidgetLoader.sourceComponent = undefined; + postpone.start() + } } } - Column { - spacing: 8 - ConfigSlider { - label: "Duration" - integral: false - config: root.config - property: "duration" - max: 10.0 - min: 0.1 - width: 400 - } - GroupBox { - title: "Base Gradient" - width: 500 - Column { - spacing: 8 + Component { + id: paramWidgets - ConfigSlider { - label: "Size X" - integral: false - config: root.config - property: "baseSizeX" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Y" - integral: false - config: root.config - property: "baseSizeY" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Z" - integral: false - config: root.config - property: "baseSizeZ" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Level" - integral: false - config: root.config - property: "baseLevel" - max: 1.0 - min: 0.0 - width: 400 - } - CheckBox { - text: "Invert" - checked: root.config["baseInverted"] - onCheckedChanged: { root.config["baseInverted"] = checked } - } + Column { + spacing: 8 + + ConfigSlider { + label: "Duration" + integral: false + config: root.config + property: "duration" + max: 10.0 + min: 0.1 + width: 400 } - } - GroupBox { - title: "Noise Gradient" - width: 500 - Column { - spacing: 8 + GroupBox { + title: "Base Gradient" + width: 500 + Column { + spacing: 8 - ConfigSlider { - label: "Size X" - integral: false - config: root.config - property: "noiseSizeX" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Y" - integral: false - config: root.config - property: "noiseSizeY" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Z" - integral: false - config: root.config - property: "noiseSizeZ" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Level" - integral: false - config: root.config - property: "noiseLevel" - max: 1.0 - min: 0.0 - width: 400 - } - } - } - GroupBox { - title: "Edge" - width: 500 - Column { - spacing: 8 - - ConfigSlider { - label: "Width" - integral: false - config: root.config - property: "edgeWidth" - max: 1.0 - min: 0.0 - width: 400 - } - GroupBox { - title: "Inner color" - Column { - spacing: 8 - ConfigSlider { - label: "Color R" - integral: false - config: root.config - property: "edgeInnerColorR" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color G" - integral: false - config: root.config - property: "edgeInnerColorG" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color B" - integral: false - config: root.config - property: "edgeInnerColorB" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color intensity" - integral: false - config: root.config - property: "edgeInnerIntensity" - max: 5.0 - min: 0.0 - width: 400 - } + ConfigSlider { + label: "Size X" + integral: false + config: root.config + property: "baseSizeX" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Y" + integral: false + config: root.config + property: "baseSizeY" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Z" + integral: false + config: root.config + property: "baseSizeZ" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Level" + integral: false + config: root.config + property: "baseLevel" + max: 1.0 + min: 0.0 + width: 400 + } + CheckBox { + text: "Invert" + checked: root.config["baseInverted"] + onCheckedChanged: { root.config["baseInverted"] = checked } } } - GroupBox { - title: "Outer color" - Column { - spacing: 8 - ConfigSlider { - label: "Color R" - integral: false - config: root.config - property: "edgeOuterColorR" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color G" - integral: false - config: root.config - property: "edgeOuterColorG" - max: 1.0 - min: 0.0 - width: 400 + } + GroupBox { + title: "Noise Gradient" + width: 500 + Column { + spacing: 8 + + ConfigSlider { + label: "Size X" + integral: false + config: root.config + property: "noiseSizeX" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Y" + integral: false + config: root.config + property: "noiseSizeY" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Z" + integral: false + config: root.config + property: "noiseSizeZ" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Level" + integral: false + config: root.config + property: "noiseLevel" + max: 1.0 + min: 0.0 + width: 400 + } + } + } + GroupBox { + title: "Edge" + width: 500 + Column { + spacing: 8 + + ConfigSlider { + label: "Width" + integral: false + config: root.config + property: "edgeWidth" + max: 1.0 + min: 0.0 + width: 400 + } + GroupBox { + title: "Inner color" + Column { + spacing: 8 + ConfigSlider { + label: "Color R" + integral: false + config: root.config + property: "edgeInnerColorR" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color G" + integral: false + config: root.config + property: "edgeInnerColorG" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color B" + integral: false + config: root.config + property: "edgeInnerColorB" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color intensity" + integral: false + config: root.config + property: "edgeInnerIntensity" + max: 5.0 + min: 0.0 + width: 400 + } } - ConfigSlider { - label: "Color B" - integral: false - config: root.config - property: "edgeOuterColorB" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color intensity" - integral: false - config: root.config - property: "edgeOuterIntensity" - max: 5.0 - min: 0.0 - width: 400 + } + GroupBox { + title: "Outer color" + Column { + spacing: 8 + ConfigSlider { + label: "Color R" + integral: false + config: root.config + property: "edgeOuterColorR" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color G" + integral: false + config: root.config + property: "edgeOuterColorG" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color B" + integral: false + config: root.config + property: "edgeOuterColorB" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color intensity" + integral: false + config: root.config + property: "edgeOuterIntensity" + max: 5.0 + min: 0.0 + width: 400 + } } } } } } } + + Loader { + id: paramWidgetLoader + sourceComponent: paramWidgets + } } - From 87833abd31160a610f2e538916c654ae6b4a25ae Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 30 Jun 2017 16:46:25 +0200 Subject: [PATCH 24/38] Sky working again. --- libraries/render-utils/src/Fade.slh | 5 +- libraries/render-utils/src/FadeEffect.cpp | 138 ++++++++++++------ libraries/render-utils/src/FadeEffect.h | 53 +++---- .../render-utils/src/RenderDeferredTask.cpp | 52 +++---- .../render-utils/src/RenderForwardTask.cpp | 16 +- libraries/render/src/render/FilterTask.cpp | 2 +- .../src/render/RenderFetchCullSortTask.cpp | 2 +- .../src/render/RenderFetchCullSortTask.h | 4 +- libraries/render/src/task/Varying.h | 14 +- 9 files changed, 169 insertions(+), 117 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 5ee7bb2178..e3a801ff8b 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -90,11 +90,10 @@ float evalFadeGradient(vec3 position) { } float evalFadeAlpha(vec3 position) { -/* float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; + float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold); - return evalFadeGradient(position)-cutoff;*/ - return evalFadeNoiseGradient(position)-fadeThreshold; + return evalFadeGradient(position)-cutoff; } void applyFadeClip(vec3 position) { diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 7c975ef201..82dc684d2f 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -6,24 +6,32 @@ #include #include -#define FADE_MIN_SCALE 0.001f -#define FADE_MAX_SCALE 100000.f +#define FADE_MIN_SCALE 0.001 +#define FADE_MAX_SCALE 10000.0 + +inline float parameterToValuePow(float parameter, const double minValue, const double maxOverMinValue) { + return (float)(minValue * pow(maxOverMinValue, parameter)); +} + +inline float valueToParameterPow(float value, const double minValue, const double maxOverMinValue) { + return (float)(log(value / minValue) / log(maxOverMinValue)); +} void FadeSwitchJob::configure(const Config& config) { _parameters->_isEditEnabled = config.editFade; } void FadeSwitchJob::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { - auto& normalOutputs = output.edit0(); + auto& normalOutputs = output.edit0().edit0(); auto& fadeOutputs = output.edit1(); // Only shapes are affected by fade at this time. - normalOutputs[RenderFetchCullSortTask::LIGHT] = input[RenderFetchCullSortTask::LIGHT]; - normalOutputs[RenderFetchCullSortTask::META] = input[RenderFetchCullSortTask::META]; - normalOutputs[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE] = input[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; - normalOutputs[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE] = input[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; - normalOutputs[RenderFetchCullSortTask::BACKGROUND] = input[RenderFetchCullSortTask::BACKGROUND]; - normalOutputs[RenderFetchCullSortTask::SPATIAL_SELECTION] = input[RenderFetchCullSortTask::SPATIAL_SELECTION]; + normalOutputs[RenderFetchCullSortTask::LIGHT].edit() = input.get0()[RenderFetchCullSortTask::LIGHT].get(); + normalOutputs[RenderFetchCullSortTask::META].edit() = input.get0()[RenderFetchCullSortTask::META].get(); + normalOutputs[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE].edit() = input.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE].get(); + normalOutputs[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE].edit() = input.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE].get(); + normalOutputs[RenderFetchCullSortTask::BACKGROUND].edit() = input.get0()[RenderFetchCullSortTask::BACKGROUND].get(); + output.edit0().edit1() = input.get1(); // Find the nearest item that intersects the view direction const render::Item* editedItem = nullptr; @@ -32,16 +40,20 @@ void FadeSwitchJob::run(const render::RenderContextPointer& renderContext, const float nearestTransparentDistance = std::numeric_limits::max(); const render::Item* nearestItem; - editedItem = findNearestItem(renderContext, input[RenderFetchCullSortTask::OPAQUE_SHAPE], nearestOpaqueDistance); - nearestItem = findNearestItem(renderContext, input[RenderFetchCullSortTask::TRANSPARENT_SHAPE], nearestTransparentDistance); + editedItem = findNearestItem(renderContext, input.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE], nearestOpaqueDistance); + nearestItem = findNearestItem(renderContext, input.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE], nearestTransparentDistance); if (nearestTransparentDistance < nearestOpaqueDistance) { editedItem = nearestItem; } + + if (editedItem) { + output.edit2() = editedItem->getBound(); + } } // Now, distribute items that need to be faded accross both outputs - distribute(renderContext, input[RenderFetchCullSortTask::OPAQUE_SHAPE], normalOutputs[RenderFetchCullSortTask::OPAQUE_SHAPE], fadeOutputs[OPAQUE_SHAPE], editedItem); - distribute(renderContext, input[RenderFetchCullSortTask::TRANSPARENT_SHAPE], normalOutputs[RenderFetchCullSortTask::TRANSPARENT_SHAPE], fadeOutputs[TRANSPARENT_SHAPE], editedItem); + distribute(renderContext, input.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE], normalOutputs[RenderFetchCullSortTask::OPAQUE_SHAPE], fadeOutputs[OPAQUE_SHAPE], editedItem); + distribute(renderContext, input.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE], normalOutputs[RenderFetchCullSortTask::TRANSPARENT_SHAPE], fadeOutputs[TRANSPARENT_SHAPE], editedItem); } const render::Item* FadeSwitchJob::findNearestItem(const render::RenderContextPointer& renderContext, const render::Varying& input, float& minIsectDistance) const { @@ -71,22 +83,21 @@ void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext render::Varying& normalOutput, render::Varying& fadeOutput, const render::Item* editedItem) const { auto& scene = renderContext->_scene; assert(_parameters); - const double fadeDuration = double(_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]) * USECS_PER_SECOND; const auto& inputItems = input.get(); // Clear previous values - normalOutput.template edit().clear(); - fadeOutput.template edit().clear(); + normalOutput.edit().clear(); + fadeOutput.edit().clear(); for (const auto& itemBound : inputItems) { auto& item = scene->getItem(itemBound.id); if (!item.mustFade() && &item!=editedItem) { // No need to fade - normalOutput.template edit().emplace_back(itemBound); + normalOutput.edit().emplace_back(itemBound); } else { - fadeOutput.template edit().emplace_back(itemBound); + fadeOutput.edit().emplace_back(itemBound); } } } @@ -108,30 +119,30 @@ float FadeJobConfig::getDuration() const { } void FadeJobConfig::setBaseSizeX(float value) { - baseSize[editedCategory].x = FADE_MIN_SCALE*powf(FADE_MAX_SCALE/ FADE_MIN_SCALE, value); + baseSize[editedCategory].x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getBaseSizeX() const { - return logf(baseSize[editedCategory].x / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(baseSize[editedCategory].x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setBaseSizeY(float value) { - baseSize[editedCategory].y = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); + baseSize[editedCategory].y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getBaseSizeY() const { - return logf(baseSize[editedCategory].y / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(baseSize[editedCategory].y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setBaseSizeZ(float value) { - baseSize[editedCategory].z = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); + baseSize[editedCategory].z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getBaseSizeZ() const { - return logf(baseSize[editedCategory].z / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(baseSize[editedCategory].z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setBaseLevel(float value) { @@ -149,30 +160,30 @@ bool FadeJobConfig::isBaseInverted() const { } void FadeJobConfig::setNoiseSizeX(float value) { - noiseSize[editedCategory].x = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); + noiseSize[editedCategory].x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getNoiseSizeX() const { - return logf(noiseSize[editedCategory].x / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(noiseSize[editedCategory].x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setNoiseSizeY(float value) { - noiseSize[editedCategory].y = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); + noiseSize[editedCategory].y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getNoiseSizeY() const { - return logf(noiseSize[editedCategory].y / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(noiseSize[editedCategory].y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setNoiseSizeZ(float value) { - noiseSize[editedCategory].z = FADE_MIN_SCALE*powf(FADE_MAX_SCALE / FADE_MIN_SCALE, value); + noiseSize[editedCategory].z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getNoiseSizeZ() const { - return logf(noiseSize[editedCategory].z / FADE_MIN_SCALE) / logf(FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(noiseSize[editedCategory].z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setNoiseLevel(float value) { @@ -251,7 +262,7 @@ void FadeConfigureJob::configure(const Config& config) { configuration._noiseInvSizeAndLevel.y = 1.f / config.noiseSize[i].y; configuration._noiseInvSizeAndLevel.z = 1.f / config.noiseSize[i].z; configuration._noiseInvSizeAndLevel.w = config.noiseLevel[i]; - configuration._invertBase = config.baseInverted[i]; + configuration._invertBase = config.baseInverted[i] & 1; configuration._edgeWidthInvWidth.x = config.edgeWidth[i]; configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; configuration._innerEdgeColor = config.edgeInnerColor[i]; @@ -260,10 +271,13 @@ void FadeConfigureJob::configure(const Config& config) { _isBufferDirty = true; } -void FadeConfigureJob::run(const render::RenderContextPointer& renderContext, Output& output) { - if (_isBufferDirty) { +void FadeConfigureJob::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { + if (_isBufferDirty || _parameters->_isEditEnabled) { auto& configurations = output.edit1().edit(); std::copy(_configurations, _configurations + FadeJobConfig::EVENT_CATEGORY_COUNT, configurations.parameters); + if (_parameters->_editedCategory == FadeJobConfig::USER_ENTER_LEAVE_DOMAIN) { + configurations.parameters[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._baseInvSizeAndLevel.y = 2.f / input.getDimensions().y; + } _isBufferDirty = false; } output.edit0() = _fadeMaskMap; @@ -290,14 +304,6 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const defaultKeyBuilder.withFade(); - // Update interactive edit effect - if (_parameters->_isEditEnabled) { - updateFadeEdit(); - } - else { - _editStartTime = 0; - } - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -306,6 +312,14 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const _currentFadeMaskMap = fadeMaskMap; _currentFadeBuffer = &fadeParamBuffer; + // Update interactive edit effect + if (_parameters->_isEditEnabled) { + updateFadeEdit(inItems.front()); + } + else { + _editStartTime = 0; + } + // Setup camera, projection and viewport for all items batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); @@ -365,18 +379,18 @@ float FadeRenderJob::computeFadePercent(quint64 startTime) { return _currentInstance->computeElementEnterThreshold(time); } -void FadeRenderJob::updateFadeEdit() { +void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) { if (_editStartTime == 0) { _editStartTime = usecTimestampNow(); } const double time = (int64_t(usecTimestampNow()) - int64_t(_editStartTime)) / double(USECS_PER_SECOND); + const float eventDuration = _parameters->_durations[_parameters->_editedCategory]; switch (_parameters->_editedCategory) { case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: { const double waitTime = 0.5; // Wait between fade in and out - const float eventDuration = _parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]; double cycleTime = fmod(time, (eventDuration+waitTime) * 2.0); if (cycleTime < eventDuration) { @@ -401,7 +415,35 @@ void FadeRenderJob::updateFadeEdit() { break; case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: - break; + { + const double waitTime = 0.5; // Wait between fade in and out + double cycleTime = fmod(time, (eventDuration + waitTime) * 2.0); + + _editNoiseOffset.x = time*0.5; + _editNoiseOffset.y = 0.f; + _editNoiseOffset.z = time*0.75; + + _editBaseOffset.x = 0.f; + _editBaseOffset.y = -itemBounds.bound.getDimensions().y; + _editBaseOffset.z = 0.f; + { + + } + + if (cycleTime < eventDuration) { + _editThreshold = 1.f - computeElementEnterThreshold(cycleTime); + } + else if (cycleTime < (eventDuration + waitTime)) { + _editThreshold = 0.f; + } + else if (cycleTime < (2 * eventDuration + waitTime)) { + _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime)); + } + else { + _editThreshold = 1.f; + } + } + break; case FadeJobConfig::AVATAR_CHANGE: break; @@ -443,6 +485,8 @@ bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline if (fadeNoiseOffsetLocation >= 0 || fadeBaseOffsetLocation>=0 || fadeThresholdLocation >= 0 || fadeCategoryLocation>=0) { float threshold; int eventCategory = FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN; + glm::vec3 noiseOffset = offset; + glm::vec3 baseOffset = offset; threshold = 1.f-computeFadePercent(startTime); @@ -451,14 +495,16 @@ bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline if (_currentInstance->_parameters->_isEditEnabled) { eventCategory = _currentInstance->_parameters->_editedCategory; threshold = _currentInstance->_editThreshold; + noiseOffset += _currentInstance->_editNoiseOffset; + baseOffset += _currentInstance->_editBaseOffset; } batch._glUniform1i(fadeCategoryLocation, eventCategory); batch._glUniform1f(fadeThresholdLocation, threshold); // This is really temporary - batch._glUniform3f(fadeNoiseOffsetLocation, offset.x, offset.y, offset.z); + batch._glUniform3f(fadeNoiseOffsetLocation, noiseOffset.x, noiseOffset.y, noiseOffset.z); // This is really temporary - batch._glUniform3f(fadeBaseOffsetLocation, offset.x, offset.y, offset.z); + batch._glUniform3f(fadeBaseOffsetLocation, baseOffset.x, baseOffset.y, baseOffset.z); return threshold > 0.f; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 122449e08a..dce5687151 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -126,15 +126,29 @@ public: float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; - glm::vec3 baseSize[EVENT_CATEGORY_COUNT]{ - { 0.4f, 0.4f, 0.4f }, // ELEMENT_ENTER_LEAVE_DOMAIN + glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ + { 1.f, 1.f, 1.f }, // ELEMENT_ENTER_LEAVE_DOMAIN { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER - { 0.875f, 0.4f, 0.875f }, // USER_ENTER_LEAVE_DOMAIN + { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE + }; + float noiseLevel[EVENT_CATEGORY_COUNT]{ + 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 1.0f, // BUBBLE_ISECT_OWNER + 1.0f, // BUBBLE_ISECT_TRESPASSER + 0.70f, // USER_ENTER_LEAVE_DOMAIN + 1.0f, // AVATAR_CHANGE + }; + glm::vec3 baseSize[EVENT_CATEGORY_COUNT]{ + { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER + { 10000.f, 1.0f, 10000.0f }, // USER_ENTER_LEAVE_DOMAIN { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE }; float baseLevel[EVENT_CATEGORY_COUNT]{ - 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.0f, // ELEMENT_ENTER_LEAVE_DOMAIN 1.0f, // BUBBLE_ISECT_OWNER 1.0f, // BUBBLE_ISECT_TRESPASSER 1.0f, // USER_ENTER_LEAVE_DOMAIN @@ -147,20 +161,6 @@ public: true, // USER_ENTER_LEAVE_DOMAIN false, // AVATAR_CHANGE }; - glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ - { 0.41f, 0.41f, 0.41f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER - { 0.4f, 0.4f, 0.4f }, // USER_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE - }; - float noiseLevel[EVENT_CATEGORY_COUNT]{ - 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 1.0f, // BUBBLE_ISECT_OWNER - 1.0f, // BUBBLE_ISECT_TRESPASSER - 1.0f, // USER_ENTER_LEAVE_DOMAIN - 1.0f, // AVATAR_CHANGE - }; float _duration[EVENT_CATEGORY_COUNT]{ 4.0f, // ELEMENT_ENTER_LEAVE_DOMAIN 0.0f, // BUBBLE_ISECT_OWNER @@ -172,21 +172,21 @@ public: 0.10f, // ELEMENT_ENTER_LEAVE_DOMAIN 0.10f, // BUBBLE_ISECT_OWNER 0.10f, // BUBBLE_ISECT_TRESPASSER - 0.10f, // USER_ENTER_LEAVE_DOMAIN + 0.529f, // USER_ENTER_LEAVE_DOMAIN 0.05f, // AVATAR_CHANGE }; glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]{ { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 1.0f, 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }, // USER_ENTER_LEAVE_DOMAIN { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE }; glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]{ { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 1.0f, 1.0f, 1.0f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE }; @@ -224,7 +224,7 @@ public: using FadeOutput = render::VaryingArray; using Input = RenderFetchCullSortTask::Output; - using Output = render::VaryingSet2; + using Output = render::VaryingSet3 < RenderFetchCullSortTask::Output, FadeOutput, render::Item::Bound > ; using Config = FadeSwitchJobConfig; using JobModel = render::Job::ModelIO; @@ -263,16 +263,17 @@ class FadeConfigureJob { public: using UniformBuffer = gpu::StructBuffer; + using Input = render::Item::Bound ; using Output = render::VaryingSet2; using Config = FadeJobConfig; - using JobModel = render::Job::ModelO; + using JobModel = render::Job::ModelIO; FadeConfigureJob(FadeCommonParameters::Pointer commonParams); const gpu::TexturePointer getFadeMaskMap() const { return _fadeMaskMap; } void configure(const Config& config); - void run(const render::RenderContextPointer& renderContext, Output& output); + void run(const render::RenderContextPointer& renderContext, const Input& input, Output& output); private: @@ -316,8 +317,10 @@ private: // Everything needed for interactive edition uint64_t _editStartTime{ 0 }; float _editThreshold{ 0.f }; + glm::vec3 _editNoiseOffset{ 0.f, 0.f, 0.f }; + glm::vec3 _editBaseOffset{ 0.f, 0.f, 0.f }; - void updateFadeEdit(); + void updateFadeEdit(const render::ItemBound& itemBounds); }; #endif // hifi_FadeEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ca7f4a10d9..aa62038bb6 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -55,24 +55,26 @@ void RenderDeferredTask::configure(const Config& config) void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto commonFadeParameters = std::make_shared(); const auto fadeSwitchOutputs = task.addJob("FadeSwitch", input, commonFadeParameters).get(); - const auto fadeConfigureOutputs = task.addJob("FadeConfigure", commonFadeParameters).get(); const auto& items = fadeSwitchOutputs.get0(); const auto& fadeItems = fadeSwitchOutputs.get1(); + const auto& fadeEditedItem = fadeSwitchOutputs[2]; + + const auto fadeConfigureOutputs = task.addJob("FadeConfigure", fadeEditedItem, commonFadeParameters).get(); // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); // Extract opaques / transparents / lights / metas / overlays / background - const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; - const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; - const auto lights = items[RenderFetchCullSortTask::LIGHT]; - const auto metas = items[RenderFetchCullSortTask::META]; - const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; - const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; - const auto background = items[RenderFetchCullSortTask::BACKGROUND]; - const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; + const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT]; + const auto& metas = items.get0()[RenderFetchCullSortTask::META]; + const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND]; + const auto& spatialSelection = items[1]; // Filter the non antialiaased overlays const int LAYER_NO_AA = 3; @@ -87,7 +89,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto opaqueRangeTimer = task.addJob("BeginOpaqueRangeTimer", "DrawOpaques"); - const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying(); + const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).asVarying(); const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); @@ -96,11 +98,11 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("PrepareStencil", primaryFramebuffer); // Render opaque objects in DeferredBuffer - const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); + const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).asVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); const auto fadeOpaques = fadeItems[FadeSwitchJob::OPAQUE_SHAPE]; - const auto fadeOpaqueInputs = FadeRenderJob::Input(fadeOpaques, lightingModel, fadeConfigureOutputs).hasVarying(); + const auto fadeOpaqueInputs = FadeRenderJob::Input(fadeOpaques, lightingModel, fadeConfigureOutputs).asVarying(); task.addJob("DrawFadeOpaque", fadeOpaqueInputs, commonFadeParameters, shapePlumber); @@ -110,12 +112,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Opaque all rendered // Linear Depth Pass - const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying(); + const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).asVarying(); const auto linearDepthPassOutputs = task.addJob("LinearDepth", linearDepthPassInputs); const auto linearDepthTarget = linearDepthPassOutputs.getN(0); // Curvature pass - const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); + const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).asVarying(); const auto surfaceGeometryPassOutputs = task.addJob("SurfaceGeometry", surfaceGeometryPassInputs); const auto surfaceGeometryFramebuffer = surfaceGeometryPassOutputs.getN(0); const auto curvatureFramebuffer = surfaceGeometryPassOutputs.getN(1); @@ -126,7 +128,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto scatteringResource = task.addJob("Scattering"); // AO job - const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); + const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).asVarying(); const auto ambientOcclusionOutputs = task.addJob("AmbientOcclusion", ambientOcclusionInputs); const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(1); @@ -140,13 +142,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Light Clustering // Create the cluster grid of lights, cpu job for now - const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying(); + const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).asVarying(); const auto lightClusters = task.addJob("LightClustering", lightClusteringPassInputs); // DeferredBuffer is complete, now let's shade it into the LightingBuffer const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, - surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).hasVarying(); + surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).asVarying(); task.addJob("RenderDeferred", deferredLightingInputs); @@ -154,16 +156,16 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawBackgroundDeferred", lightingModel); // Render transparent objects forward in LightingBuffer - const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); + const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); const auto fadeTransparents = fadeItems[FadeSwitchJob::TRANSPARENT_SHAPE]; - const auto fadeTransparentInputs = FadeRenderJob::Input(fadeTransparents, lightingModel, fadeConfigureOutputs).hasVarying(); + const auto fadeTransparentInputs = FadeRenderJob::Input(fadeTransparents, lightingModel, fadeConfigureOutputs).asVarying(); task.addJob("DrawFadeTransparent", fadeTransparentInputs, commonFadeParameters, shapePlumber); // LIght Cluster Grid Debuging job { - const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying(); + const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).asVarying(); task.addJob("DebugLightClusters", debugLightClustersInputs); } @@ -184,8 +186,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren } // Overlays - const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying(); - const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying(); + const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).asVarying(); + const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).asVarying(); task.addJob("DrawOverlay3DOpaque", overlayOpaquesInputs, true); task.addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); @@ -201,10 +203,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DebugDeferredBuffer", debugFramebuffers); const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, - surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); + surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).asVarying(); task.addJob("DebugScattering", debugSubsurfaceScatteringInputs); - const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); + const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).asVarying(); task.addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); // Scene Octree Debugging job @@ -229,7 +231,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("Antialiasing", primaryFramebuffer); // Draw 2DWeb non AA - const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying(); + const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).asVarying(); task.addJob("Draw2DWebSurfaces", nonAAOverlaysInputs, false); task.addJob("ToneAndPostRangeTimer", toneAndPostRangeTimer); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index a77d741aa5..ef9cfe8613 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -36,14 +36,14 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend initForwardPipelines(*shapePlumber); // Extract opaques / transparents / lights / metas / overlays / background - const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; - const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; - const auto lights = items[RenderFetchCullSortTask::LIGHT]; - const auto metas = items[RenderFetchCullSortTask::META]; - const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; - const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; - const auto background = items[RenderFetchCullSortTask::BACKGROUND]; - const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; + const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT]; + const auto& metas = items.get0()[RenderFetchCullSortTask::META]; + const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND]; + const auto& spatialSelection = items[1]; const auto framebuffer = task.addJob("PrepareFramebuffer"); diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index f6b765cd9d..19953f3399 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -28,7 +28,7 @@ void FilterLayeredItems::run(const RenderContextPointer& renderContext, const It outItems.clear(); // For each item, filter it into one bucket - for (auto itemBound : inItems) { + for (auto& itemBound : inItems) { auto& item = scene->getItem(itemBound.id); if (item.getLayer() == _keepLayer) { outItems.emplace_back(itemBound); diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 6e5d723ce6..b9f65f48a0 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -65,5 +65,5 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto overlayTransparents = task.addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; - output = Output{opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection}; + output = Output(BucketList{ opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background }, spatialSelection); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index f3f326aae8..b25480ae3a 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -26,12 +26,12 @@ public: OVERLAY_OPAQUE_SHAPE, OVERLAY_TRANSPARENT_SHAPE, BACKGROUND, - SPATIAL_SELECTION, NUM_BUCKETS }; - using Output = render::VaryingArray; + using BucketList = render::VaryingArray; + using Output = render::VaryingSet2; using JobModel = render::Task::ModelO; RenderFetchCullSortTask() {} diff --git a/libraries/render/src/task/Varying.h b/libraries/render/src/task/Varying.h index d5021383fb..c9eb78fd71 100644 --- a/libraries/render/src/task/Varying.h +++ b/libraries/render/src/task/Varying.h @@ -40,6 +40,8 @@ public: template Varying getN (uint8_t index) const { return get()[index]; } template Varying editN (uint8_t index) { return edit()[index]; } + bool isNull() const { return _concept == nullptr; } + protected: class Concept { public: @@ -93,7 +95,7 @@ public: } virtual uint8_t length() const { return 2; } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; @@ -126,7 +128,7 @@ public: } virtual uint8_t length() const { return 3; } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; template @@ -163,7 +165,7 @@ public: } virtual uint8_t length() const { return 4; } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; @@ -206,7 +208,7 @@ public: } virtual uint8_t length() const { return 5; } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; template @@ -236,7 +238,7 @@ public: const T5& get5() const { return std::get<5>((*this)).template get(); } T5& edit5() { return std::get<5>((*this)).template edit(); } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; template @@ -269,7 +271,7 @@ public: const T6& get6() const { return std::get<6>((*this)).template get(); } T6& edit6() { return std::get<6>((*this)).template edit(); } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; From af7957491b21507b11c8914b70d2ce5f3f0a595e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 3 Jul 2017 12:40:58 +0200 Subject: [PATCH 25/38] Working avater enter/leaves + manual threshold --- libraries/render-utils/src/Fade.slh | 26 +++---- libraries/render-utils/src/FadeEffect.cpp | 67 +++++++++++-------- libraries/render-utils/src/FadeEffect.h | 18 +++-- .../src/model_normal_map_fade.slf | 2 +- scripts/developer/utilities/render/fade.qml | 19 ++++++ 5 files changed, 85 insertions(+), 47 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index e3a801ff8b..cc79c26f07 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -66,14 +66,14 @@ float evalFadeNoiseGradient(vec3 position) { vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z); vec2 maskY = mix(maskXY.xy, maskXY.zw, noisePositionFraction.x); - return mix(maskY.x, maskY.y, noisePositionFraction.y) * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.w; + float noise = mix(maskY.x, maskY.y, noisePositionFraction.y); + noise -= 0.5; // Center on value 0 + return noise * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.w; } float evalFadeBaseGradient(vec3 position) { float gradient = length((position - fadeBaseOffset) * fadeParameters[fadeCategory]._baseInvSizeAndLevel.xyz); - if (fadeParameters[fadeCategory]._invertBase!=0) { - gradient = 1.0 - gradient; - } + gradient = mod(gradient, 1.0)-0.5; // Center on value 0.5 gradient *= fadeParameters[fadeCategory]._baseInvSizeAndLevel.w; return gradient; } @@ -81,17 +81,15 @@ float evalFadeBaseGradient(vec3 position) { float evalFadeGradient(vec3 position) { float baseGradient = evalFadeBaseGradient(position); float noiseGradient = evalFadeNoiseGradient(position); - float gradient = (noiseGradient-0.5*fadeParameters[fadeCategory]._baseInvSizeAndLevel.w); + float gradient = noiseGradient+baseGradient+0.5; - // This is to be sure the noise is zero at the start of the gradient - gradient *= (1-baseGradient*baseGradient); - gradient += baseGradient; return gradient; } float evalFadeAlpha(vec3 position) { - float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; - float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold); + //float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; + //float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold); + float cutoff = fadeThreshold; return evalFadeGradient(position)-cutoff; } @@ -104,6 +102,10 @@ void applyFadeClip(vec3 position) { void applyFade(vec3 position, out vec3 emissive) { float alpha = evalFadeAlpha(position); + if (fadeParameters[fadeCategory]._invertBase!=0) { + alpha = -alpha; + } + if (alpha < 0) { discard; } @@ -111,12 +113,12 @@ void applyFade(vec3 position, out vec3 emissive) { float edgeMask = alpha * fadeParameters[fadeCategory]._edgeWidthInvWidth.y; float edgeAlpha = 1.0-clamp(edgeMask, 0, 1); - //edgeMask = step(edgeMask, 1.f); - edgeMask = edgeMask > 1.f ? 0.f : 1.f; + edgeMask = step(edgeMask, 1.f); edgeAlpha *= edgeAlpha; // Square to have a nice ease out vec4 color = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha); emissive = color.rgb * edgeMask * color.a; } + <@endfunc@> <@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 82dc684d2f..64c2fedfc6 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -250,6 +250,9 @@ FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) : void FadeConfigureJob::configure(const Config& config) { assert(_parameters); _parameters->_editedCategory = config.editedCategory; + _parameters->_isManualThresholdEnabled = config.manualFade; + _parameters->_manualThreshold = config.manualThreshold; + for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) { auto& configuration = _configurations[i]; @@ -267,6 +270,7 @@ void FadeConfigureJob::configure(const Config& config) { configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; configuration._innerEdgeColor = config.edgeInnerColor[i]; configuration._outerEdgeColor = config.edgeOuterColor[i]; + _parameters->_thresholdScale[i] = 1.f + 2.f*(configuration._edgeWidthInvWidth.x + std::max(0.f, (config.noiseLevel[i] + config.baseLevel[i])*0.5f-0.5f)); } _isBufferDirty = true; } @@ -276,7 +280,7 @@ void FadeConfigureJob::run(const render::RenderContextPointer& renderContext, co auto& configurations = output.edit1().edit(); std::copy(_configurations, _configurations + FadeJobConfig::EVENT_CATEGORY_COUNT, configurations.parameters); if (_parameters->_editedCategory == FadeJobConfig::USER_ENTER_LEAVE_DOMAIN) { - configurations.parameters[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._baseInvSizeAndLevel.y = 2.f / input.getDimensions().y; + configurations.parameters[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._baseInvSizeAndLevel.y = 1.0f / input.getDimensions().y; } _isBufferDirty = false; } @@ -314,10 +318,10 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const // Update interactive edit effect if (_parameters->_isEditEnabled) { - updateFadeEdit(inItems.front()); + updateFadeEdit(renderContext, inItems.front()); } else { - _editStartTime = 0; + _editPreviousTime = 0; } // Setup camera, projection and viewport for all items @@ -362,9 +366,10 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const } } -float FadeRenderJob::computeElementEnterThreshold(double time) const { +float FadeRenderJob::computeElementEnterThreshold(double time, const double period) const { + assert(period > 0.0); float fadeAlpha = 1.0f; - const double INV_FADE_PERIOD = 1.0 / (double)(_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]); + const double INV_FADE_PERIOD = 1.0 / period; double fraction = time * INV_FADE_PERIOD; fraction = std::max(fraction, 0.0); if (fraction < 1.0) { @@ -376,31 +381,35 @@ float FadeRenderJob::computeElementEnterThreshold(double time) const { float FadeRenderJob::computeFadePercent(quint64 startTime) { const double time = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) / (double)(USECS_PER_SECOND); assert(_currentInstance); - return _currentInstance->computeElementEnterThreshold(time); + return _currentInstance->computeElementEnterThreshold(time, _currentInstance->_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]); } -void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) { - if (_editStartTime == 0) { - _editStartTime = usecTimestampNow(); +void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderContext, const render::ItemBound& itemBounds) { + if (_editPreviousTime == 0) { + _editPreviousTime = usecTimestampNow(); + _editTime = 0.0; } - const double time = (int64_t(usecTimestampNow()) - int64_t(_editStartTime)) / double(USECS_PER_SECOND); + uint64_t now = usecTimestampNow(); + const double deltaTime = (int64_t(now) - int64_t(_editPreviousTime)) / double(USECS_PER_SECOND); const float eventDuration = _parameters->_durations[_parameters->_editedCategory]; + const double waitTime = 0.5; // Wait between fade in and out + double cycleTime = fmod(_editTime, (eventDuration + waitTime) * 2.0); + + _editTime += deltaTime; + _editPreviousTime = now; switch (_parameters->_editedCategory) { case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: { - const double waitTime = 0.5; // Wait between fade in and out - double cycleTime = fmod(time, (eventDuration+waitTime) * 2.0); - if (cycleTime < eventDuration) { - _editThreshold = 1.f-computeElementEnterThreshold(cycleTime); + _editThreshold = 1.f-computeElementEnterThreshold(cycleTime, eventDuration); } else if (cycleTime < (eventDuration + waitTime)) { _editThreshold = 0.f; } else if (cycleTime < (2 * eventDuration + waitTime)) { - _editThreshold = computeElementEnterThreshold(cycleTime- (eventDuration + waitTime)); + _editThreshold = computeElementEnterThreshold(cycleTime- (eventDuration + waitTime), eventDuration); } else { _editThreshold = 1.f; @@ -416,28 +425,21 @@ void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) { case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: { - const double waitTime = 0.5; // Wait between fade in and out - double cycleTime = fmod(time, (eventDuration + waitTime) * 2.0); - - _editNoiseOffset.x = time*0.5; + _editNoiseOffset.x = _editTime*0.5; _editNoiseOffset.y = 0.f; - _editNoiseOffset.z = time*0.75; + _editNoiseOffset.z = _editTime*0.75; - _editBaseOffset.x = 0.f; - _editBaseOffset.y = -itemBounds.bound.getDimensions().y; - _editBaseOffset.z = 0.f; - { - - } + _editBaseOffset = itemBounds.bound.calcCenter(); + _editBaseOffset.y -= itemBounds.bound.getDimensions().y/2.f; if (cycleTime < eventDuration) { - _editThreshold = 1.f - computeElementEnterThreshold(cycleTime); + _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration); } else if (cycleTime < (eventDuration + waitTime)) { _editThreshold = 0.f; } else if (cycleTime < (2 * eventDuration + waitTime)) { - _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime)); + _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration); } else { _editThreshold = 1.f; @@ -451,6 +453,10 @@ void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) { default: assert(false); } + + if (_parameters->_isManualThresholdEnabled) { + _editThreshold = _parameters->_manualThreshold; + } } void FadeRenderJob::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation) { @@ -496,9 +502,12 @@ bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline eventCategory = _currentInstance->_parameters->_editedCategory; threshold = _currentInstance->_editThreshold; noiseOffset += _currentInstance->_editNoiseOffset; - baseOffset += _currentInstance->_editBaseOffset; + // This works supposing offset is the world position of the object that is fading. + baseOffset = _currentInstance->_editBaseOffset - offset; } + threshold = (threshold-0.5f)*_currentInstance->_parameters->_thresholdScale[eventCategory] + 0.5f; + batch._glUniform1i(fadeCategoryLocation, eventCategory); batch._glUniform1f(fadeThresholdLocation, threshold); // This is really temporary diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index dce5687151..a441ce831d 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -52,6 +52,8 @@ class FadeJobConfig : public render::Job::Config { Q_PROPERTY(float edgeOuterColorG READ getEdgeOuterColorG WRITE setEdgeOuterColorG NOTIFY dirty) Q_PROPERTY(float edgeOuterColorB READ getEdgeOuterColorB WRITE setEdgeOuterColorB NOTIFY dirty) Q_PROPERTY(float edgeOuterIntensity READ getEdgeOuterIntensity WRITE setEdgeOuterIntensity NOTIFY dirty) + Q_PROPERTY(bool manualFade MEMBER manualFade NOTIFY dirty) + Q_PROPERTY(float manualThreshold MEMBER manualThreshold NOTIFY dirty) public: @@ -124,10 +126,12 @@ public: void setEdgeOuterIntensity(float value); float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } - + + bool manualFade{ false }; + float manualThreshold{ 0.f }; int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ - { 1.f, 1.f, 1.f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.75f, 0.75f, 0.75f }, // ELEMENT_ENTER_LEAVE_DOMAIN { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN @@ -201,6 +205,9 @@ struct FadeCommonParameters using Pointer = std::shared_ptr; bool _isEditEnabled{ false }; + bool _isManualThresholdEnabled{ false }; + float _manualThreshold{ 0.f }; + float _thresholdScale[FadeJobConfig::EVENT_CATEGORY_COUNT]; int _editedCategory{ FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN }; float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]{ 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN @@ -312,15 +319,16 @@ private: render::ShapePlumberPointer _shapePlumber; FadeCommonParameters::Pointer _parameters; - float computeElementEnterThreshold(double time) const; + float computeElementEnterThreshold(double time, const double period) const; // Everything needed for interactive edition - uint64_t _editStartTime{ 0 }; + uint64_t _editPreviousTime{ 0 }; + double _editTime{ 0.0 }; float _editThreshold{ 0.f }; glm::vec3 _editNoiseOffset{ 0.f, 0.f, 0.f }; glm::vec3 _editBaseOffset{ 0.f, 0.f, 0.f }; - void updateFadeEdit(const render::ItemBound& itemBounds); + void updateFadeEdit(const render::RenderContextPointer& renderContext, const render::ItemBound& itemBounds); }; #endif // hifi_FadeEffect_h diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf index 7c70dabda2..d5f0c56b4b 100644 --- a/libraries/render-utils/src/model_normal_map_fade.slf +++ b/libraries/render-utils/src/model_normal_map_fade.slf @@ -66,7 +66,7 @@ void main(void) { albedo, roughness, getMaterialMetallic(mat), - emissive, + emissive+fadeEmissive, occlusionTex, scattering); } diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 9b6ef95837..8b3885d230 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -46,6 +46,25 @@ Column { } } } + Row { + CheckBox { + text: "Manual" + checked: root.config["manualFade"] + onCheckedChanged: { + root.config["manualFade"] = checked; + } + } + ConfigSlider { + label: "Threshold" + integral: false + config: root.config + property: "manualThreshold" + max: 1.0 + min: 0.0 + width: 400 + } + } + Component { id: paramWidgets From 3fddac9f6e6b4b4f3d715f5463f7661c48f8d260 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 3 Jul 2017 16:12:23 +0200 Subject: [PATCH 26/38] Fixed compilation errors with array initializations --- libraries/render-utils/src/FadeEffect.cpp | 80 +++++++++++++++++++++ libraries/render-utils/src/FadeEffect.h | 84 ++++------------------- 2 files changed, 94 insertions(+), 70 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 64c2fedfc6..ab104bc531 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -102,6 +102,86 @@ void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext } } +FadeCommonParameters::FadeCommonParameters() : + _durations{ + 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.0f, // BUBBLE_ISECT_OWNER + 0.0f, // BUBBLE_ISECT_TRESPASSER + 3.0f, // USER_ENTER_LEAVE_DOMAIN + 3.0f, // AVATAR_CHANGE + } +{ + +} + +FadeJobConfig::FadeJobConfig() : + noiseSize{ + { 0.75f, 0.75f, 0.75f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER + { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE + }, + noiseLevel{ + 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 1.0f, // BUBBLE_ISECT_OWNER + 1.0f, // BUBBLE_ISECT_TRESPASSER + 0.70f, // USER_ENTER_LEAVE_DOMAIN + 1.0f, // AVATAR_CHANGE + }, + baseSize{ + { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER + { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER + { 10000.f, 1.0f, 10000.0f }, // USER_ENTER_LEAVE_DOMAIN + { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE + }, + baseLevel{ + 0.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 1.0f, // BUBBLE_ISECT_OWNER + 1.0f, // BUBBLE_ISECT_TRESPASSER + 1.0f, // USER_ENTER_LEAVE_DOMAIN + 1.0f, // AVATAR_CHANGE + }, + baseInverted{ + false, // ELEMENT_ENTER_LEAVE_DOMAIN + false, // BUBBLE_ISECT_OWNER + false, // BUBBLE_ISECT_TRESPASSER + true, // USER_ENTER_LEAVE_DOMAIN + false, // AVATAR_CHANGE + }, + _duration{ + 4.0f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.0f, // BUBBLE_ISECT_OWNER + 0.0f, // BUBBLE_ISECT_TRESPASSER + 3.0f, // USER_ENTER_LEAVE_DOMAIN + 3.0f, // AVATAR_CHANGE + }, + edgeWidth{ + 0.10f, // ELEMENT_ENTER_LEAVE_DOMAIN + 0.10f, // BUBBLE_ISECT_OWNER + 0.10f, // BUBBLE_ISECT_TRESPASSER + 0.529f, // USER_ENTER_LEAVE_DOMAIN + 0.05f, // AVATAR_CHANGE + }, + edgeInnerColor{ + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }, // USER_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + }, + edgeOuterColor{ + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN + { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE + } +{ + +} + void FadeJobConfig::setEditedCategory(int value) { assert(value < EVENT_CATEGORY_COUNT); editedCategory = std::min(EVENT_CATEGORY_COUNT, value); diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index a441ce831d..c3a41187e1 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -68,6 +68,8 @@ public: EVENT_CATEGORY_COUNT }; + FadeJobConfig(); + void setEditedCategory(int value); void setDuration(float value); @@ -130,69 +132,15 @@ public: bool manualFade{ false }; float manualThreshold{ 0.f }; int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; - glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ - { 0.75f, 0.75f, 0.75f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER - { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE - }; - float noiseLevel[EVENT_CATEGORY_COUNT]{ - 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 1.0f, // BUBBLE_ISECT_OWNER - 1.0f, // BUBBLE_ISECT_TRESPASSER - 0.70f, // USER_ENTER_LEAVE_DOMAIN - 1.0f, // AVATAR_CHANGE - }; - glm::vec3 baseSize[EVENT_CATEGORY_COUNT]{ - { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER - { 10000.f, 1.0f, 10000.0f }, // USER_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE - }; - float baseLevel[EVENT_CATEGORY_COUNT]{ - 0.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 1.0f, // BUBBLE_ISECT_OWNER - 1.0f, // BUBBLE_ISECT_TRESPASSER - 1.0f, // USER_ENTER_LEAVE_DOMAIN - 1.0f, // AVATAR_CHANGE - }; - bool baseInverted[EVENT_CATEGORY_COUNT]{ - false, // ELEMENT_ENTER_LEAVE_DOMAIN - false, // BUBBLE_ISECT_OWNER - false, // BUBBLE_ISECT_TRESPASSER - true, // USER_ENTER_LEAVE_DOMAIN - false, // AVATAR_CHANGE - }; - float _duration[EVENT_CATEGORY_COUNT]{ - 4.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.0f, // BUBBLE_ISECT_OWNER - 0.0f, // BUBBLE_ISECT_TRESPASSER - 3.0f, // USER_ENTER_LEAVE_DOMAIN - 3.0f, // AVATAR_CHANGE - }; - float edgeWidth[EVENT_CATEGORY_COUNT]{ - 0.10f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.10f, // BUBBLE_ISECT_OWNER - 0.10f, // BUBBLE_ISECT_TRESPASSER - 0.529f, // USER_ENTER_LEAVE_DOMAIN - 0.05f, // AVATAR_CHANGE - }; - glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]{ - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }, // USER_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE - }; - glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]{ - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE - }; + glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]; + float noiseLevel[EVENT_CATEGORY_COUNT]; + glm::vec3 baseSize[EVENT_CATEGORY_COUNT]; + float baseLevel[EVENT_CATEGORY_COUNT]; + bool baseInverted[EVENT_CATEGORY_COUNT]; + float _duration[EVENT_CATEGORY_COUNT]; + float edgeWidth[EVENT_CATEGORY_COUNT]; + glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]; + glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]; signals: void dirty(); @@ -204,18 +152,14 @@ struct FadeCommonParameters { using Pointer = std::shared_ptr; + FadeCommonParameters(); + bool _isEditEnabled{ false }; bool _isManualThresholdEnabled{ false }; float _manualThreshold{ 0.f }; float _thresholdScale[FadeJobConfig::EVENT_CATEGORY_COUNT]; int _editedCategory{ FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN }; - float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]{ - 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.0f, // BUBBLE_ISECT_OWNER - 0.0f, // BUBBLE_ISECT_TRESPASSER - 3.0f, // USER_ENTER_LEAVE_DOMAIN - 3.0f, // AVATAR_CHANGE - }; + float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]; }; class FadeSwitchJob { From 0d1d262db45be23f3d0888d5a8913eeb54e79442 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 3 Jul 2017 16:28:00 +0200 Subject: [PATCH 27/38] Working on bubble intersections --- libraries/render-utils/src/Fade.slh | 2 +- libraries/render-utils/src/FadeEffect.cpp | 80 +++++++++++------------ 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index cc79c26f07..f539d90217 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -73,7 +73,7 @@ float evalFadeNoiseGradient(vec3 position) { float evalFadeBaseGradient(vec3 position) { float gradient = length((position - fadeBaseOffset) * fadeParameters[fadeCategory]._baseInvSizeAndLevel.xyz); - gradient = mod(gradient, 1.0)-0.5; // Center on value 0.5 + gradient = gradient-0.5; // Center on value 0.5 gradient *= fadeParameters[fadeCategory]._baseInvSizeAndLevel.w; return gradient; } diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index ab104bc531..5e95297644 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -65,10 +65,10 @@ const render::Item* FadeSwitchJob::findNearestItem(const render::RenderContextPo glm::vec3 normal; float isectDistance; const render::Item* nearestItem = nullptr; - const float minDistance = 5.f; + const float minDistance = 2.f; for (const auto& itemBound : inputItems) { - if (itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { + if (!itemBound.bound.contains(rayOrigin) && itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { if (isectDistance>minDistance && isectDistance < minIsectDistance) { auto& item = scene->getItem(itemBound.id); nearestItem = &item; @@ -117,7 +117,7 @@ FadeCommonParameters::FadeCommonParameters() : FadeJobConfig::FadeJobConfig() : noiseSize{ { 0.75f, 0.75f, 0.75f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f/15.f, 1.0f }, // BUBBLE_ISECT_OWNER { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE @@ -131,8 +131,8 @@ FadeJobConfig::FadeJobConfig() : }, baseSize{ { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER + { 2.0f, 2.0f, 2.0f }, // BUBBLE_ISECT_OWNER + { 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER { 10000.f, 1.0f, 10000.0f }, // USER_ENTER_LEAVE_DOMAIN { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE }, @@ -159,22 +159,22 @@ FadeJobConfig::FadeJobConfig() : }, edgeWidth{ 0.10f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.10f, // BUBBLE_ISECT_OWNER - 0.10f, // BUBBLE_ISECT_TRESPASSER + 0.08f, // BUBBLE_ISECT_OWNER + 0.08f, // BUBBLE_ISECT_TRESPASSER 0.529f, // USER_ENTER_LEAVE_DOMAIN 0.05f, // AVATAR_CHANGE }, edgeInnerColor{ { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_TRESPASSER { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }, // USER_ENTER_LEAVE_DOMAIN { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE }, edgeOuterColor{ { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }, // BUBBLE_ISECT_OWNER + { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }, // BUBBLE_ISECT_TRESPASSER { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE } @@ -479,51 +479,47 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon _editTime += deltaTime; _editPreviousTime = now; + if (cycleTime < eventDuration) { + _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration); + } + else if (cycleTime < (eventDuration + waitTime)) { + _editThreshold = 0.f; + } + else if (cycleTime < (2 * eventDuration + waitTime)) { + _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration); + } + else { + _editThreshold = 1.f; + } + switch (_parameters->_editedCategory) { case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: - { - if (cycleTime < eventDuration) { - _editThreshold = 1.f-computeElementEnterThreshold(cycleTime, eventDuration); - } - else if (cycleTime < (eventDuration + waitTime)) { - _editThreshold = 0.f; - } - else if (cycleTime < (2 * eventDuration + waitTime)) { - _editThreshold = computeElementEnterThreshold(cycleTime- (eventDuration + waitTime), eventDuration); - } - else { - _editThreshold = 1.f; - } - } - break; + break; case FadeJobConfig::BUBBLE_ISECT_OWNER: - break; + { + const glm::vec3 cameraPos = renderContext->args->getViewFrustum().getPosition(); + const glm::vec3 delta = itemBounds.bound.calcCenter() - cameraPos; + + _editNoiseOffset.x = _editTime*0.1f; + _editNoiseOffset.y = _editTime*2.5f; + _editNoiseOffset.z = _editTime*0.1f; + + _editBaseOffset = cameraPos + delta*_editThreshold; + _editThreshold = 0.33f; + } + break; case FadeJobConfig::BUBBLE_ISECT_TRESPASSER: break; case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: { - _editNoiseOffset.x = _editTime*0.5; + _editNoiseOffset.x = _editTime*0.5f; _editNoiseOffset.y = 0.f; - _editNoiseOffset.z = _editTime*0.75; + _editNoiseOffset.z = _editTime*0.75f; _editBaseOffset = itemBounds.bound.calcCenter(); - _editBaseOffset.y -= itemBounds.bound.getDimensions().y/2.f; - - if (cycleTime < eventDuration) { - _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration); - } - else if (cycleTime < (eventDuration + waitTime)) { - _editThreshold = 0.f; - } - else if (cycleTime < (2 * eventDuration + waitTime)) { - _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration); - } - else { - _editThreshold = 1.f; - } } break; From ec1cf9dc5068e22918db26e23e8deb73e4bfeac5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 3 Jul 2017 16:42:27 +0200 Subject: [PATCH 28/38] Changed array initialization to old style C --- libraries/render-utils/src/FadeEffect.cpp | 132 ++++++++++------------ 1 file changed, 59 insertions(+), 73 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index ab104bc531..836c56079c 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -102,84 +102,70 @@ void FadeSwitchJob::distribute(const render::RenderContextPointer& renderContext } } -FadeCommonParameters::FadeCommonParameters() : - _durations{ - 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.0f, // BUBBLE_ISECT_OWNER - 0.0f, // BUBBLE_ISECT_TRESPASSER - 3.0f, // USER_ENTER_LEAVE_DOMAIN - 3.0f, // AVATAR_CHANGE - } +FadeCommonParameters::FadeCommonParameters() { - + _durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.f; + _durations[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.f; + _durations[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.f; + _durations[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.f; + _durations[FadeJobConfig::AVATAR_CHANGE] = 0.f; } -FadeJobConfig::FadeJobConfig() : - noiseSize{ - { 0.75f, 0.75f, 0.75f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER - { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE - }, - noiseLevel{ - 1.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 1.0f, // BUBBLE_ISECT_OWNER - 1.0f, // BUBBLE_ISECT_TRESPASSER - 0.70f, // USER_ENTER_LEAVE_DOMAIN - 1.0f, // AVATAR_CHANGE - }, - baseSize{ - { 1.0f, 1.0f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER - { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER - { 10000.f, 1.0f, 10000.0f }, // USER_ENTER_LEAVE_DOMAIN - { 0.4f, 0.4f, 0.4f }, // AVATAR_CHANGE - }, - baseLevel{ - 0.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 1.0f, // BUBBLE_ISECT_OWNER - 1.0f, // BUBBLE_ISECT_TRESPASSER - 1.0f, // USER_ENTER_LEAVE_DOMAIN - 1.0f, // AVATAR_CHANGE - }, - baseInverted{ - false, // ELEMENT_ENTER_LEAVE_DOMAIN - false, // BUBBLE_ISECT_OWNER - false, // BUBBLE_ISECT_TRESPASSER - true, // USER_ENTER_LEAVE_DOMAIN - false, // AVATAR_CHANGE - }, - _duration{ - 4.0f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.0f, // BUBBLE_ISECT_OWNER - 0.0f, // BUBBLE_ISECT_TRESPASSER - 3.0f, // USER_ENTER_LEAVE_DOMAIN - 3.0f, // AVATAR_CHANGE - }, - edgeWidth{ - 0.10f, // ELEMENT_ENTER_LEAVE_DOMAIN - 0.10f, // BUBBLE_ISECT_OWNER - 0.10f, // BUBBLE_ISECT_TRESPASSER - 0.529f, // USER_ENTER_LEAVE_DOMAIN - 0.05f, // AVATAR_CHANGE - }, - edgeInnerColor{ - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }, // USER_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE - }, - edgeOuterColor{ - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // ELEMENT_ENTER_LEAVE_DOMAIN - { 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }, // BUBBLE_ISECT_OWNER - { 1.0f, 1.0f, 1.0f, 1.0f }, // BUBBLE_ISECT_TRESPASSER - { 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }, // USER_ENTER_LEAVE_DOMAIN - { 1.0f, 1.0f, 1.0f, 1.0f }, // AVATAR_CHANGE - } +FadeJobConfig::FadeJobConfig() { + noiseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.75f, 0.75f, 0.75f }; + noiseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + noiseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + noiseSize[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 10.f, 0.01f, 10.0f }; + noiseSize[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + noiseLevel[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 1.f; + noiseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 1.f; + noiseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 1.f; + noiseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.7f; + noiseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; + + baseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 1.0f, 1.0f, 1.0f }; + baseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 2.0f, 2.0f, 2.0f }; + baseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 2.0f, 2.0f, 2.0f }; + baseSize[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 10000.f, 1.0f, 10000.0f }; + baseSize[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + + baseLevel[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.f; + baseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 1.f; + baseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 1.f; + baseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 1.f; + baseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; + + baseInverted[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = false; + baseInverted[FadeJobConfig::BUBBLE_ISECT_OWNER] = false; + baseInverted[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = false; + baseInverted[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = true; + baseInverted[FadeJobConfig::AVATAR_CHANGE] = false; + + _duration[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 4.f; + _duration[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.f; + _duration[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.f; + _duration[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 3.f; + _duration[FadeJobConfig::AVATAR_CHANGE] = 3.f; + + edgeWidth[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.1f; + edgeWidth[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.08f; + edgeWidth[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.08f; + edgeWidth[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.329f; + edgeWidth[FadeJobConfig::AVATAR_CHANGE] = 0.05f; + + edgeInnerColor[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }; + edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; + edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; + edgeInnerColor[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }; + edgeInnerColor[FadeJobConfig::AVATAR_CHANGE] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; + + edgeOuterColor[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; + edgeOuterColor[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }; + edgeOuterColor[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }; + edgeOuterColor[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; + edgeOuterColor[FadeJobConfig::AVATAR_CHANGE] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; } void FadeJobConfig::setEditedCategory(int value) { From 972db8f54c04312eceee9cbe778c654b1358fbff Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 3 Jul 2017 17:17:37 +0200 Subject: [PATCH 29/38] Fixed compilation error on Mac and Linux --- libraries/render/src/task/Varying.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/task/Varying.h b/libraries/render/src/task/Varying.h index c9eb78fd71..0144801701 100644 --- a/libraries/render/src/task/Varying.h +++ b/libraries/render/src/task/Varying.h @@ -286,7 +286,7 @@ public: VaryingArray(std::initializer_list list) { assert(list.size() == NUM); - std::copy(list.begin(), list.end(), begin()); + std::copy(list.begin(), list.end(), std::array::begin()); } }; } From 57b2bdf7090ec12604095a176c5124704c8ae641 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 09:14:08 +0200 Subject: [PATCH 30/38] Working bubble isect owner POV --- libraries/render-utils/src/FadeEffect.cpp | 53 +++++++++++-------- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderForwardTask.cpp | 12 ++--- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index dd59e729a3..20931e3a67 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -10,11 +10,11 @@ #define FADE_MAX_SCALE 10000.0 inline float parameterToValuePow(float parameter, const double minValue, const double maxOverMinValue) { - return (float)(minValue * pow(maxOverMinValue, parameter)); + return (float)(minValue * pow(maxOverMinValue, double(parameter))); } inline float valueToParameterPow(float value, const double minValue, const double maxOverMinValue) { - return (float)(log(value / minValue) / log(maxOverMinValue)); + return (float)(log(double(value) / minValue) / log(maxOverMinValue)); } void FadeSwitchJob::configure(const Config& config) { @@ -71,8 +71,11 @@ const render::Item* FadeSwitchJob::findNearestItem(const render::RenderContextPo if (!itemBound.bound.contains(rayOrigin) && itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { if (isectDistance>minDistance && isectDistance < minIsectDistance) { auto& item = scene->getItem(itemBound.id); - nearestItem = &item; - minIsectDistance = isectDistance; + + if (item.getKey().isShape() && !item.getKey().isMeta()) { + nearestItem = &item; + minIsectDistance = isectDistance; + } } } } @@ -114,13 +117,13 @@ FadeCommonParameters::FadeCommonParameters() FadeJobConfig::FadeJobConfig() { noiseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.75f, 0.75f, 0.75f }; - noiseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + noiseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 1.0f, 1.0f/15.f, 1.0f }; noiseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 0.4f, 0.4f, 0.4f }; noiseSize[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 10.f, 0.01f, 10.0f }; noiseSize[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.4f, 0.4f, 0.4f }; noiseLevel[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 1.f; - noiseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 1.f; + noiseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.37f; noiseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 1.f; noiseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.7f; noiseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; @@ -144,8 +147,8 @@ FadeJobConfig::FadeJobConfig() baseInverted[FadeJobConfig::AVATAR_CHANGE] = false; _duration[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 4.f; - _duration[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.f; - _duration[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.f; + _duration[FadeJobConfig::BUBBLE_ISECT_OWNER] = 4.f; + _duration[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 4.f; _duration[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 3.f; _duration[FadeJobConfig::AVATAR_CHANGE] = 3.f; @@ -458,24 +461,29 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon uint64_t now = usecTimestampNow(); const double deltaTime = (int64_t(now) - int64_t(_editPreviousTime)) / double(USECS_PER_SECOND); - const float eventDuration = _parameters->_durations[_parameters->_editedCategory]; + const double eventDuration = (double)_parameters->_durations[_parameters->_editedCategory]; const double waitTime = 0.5; // Wait between fade in and out double cycleTime = fmod(_editTime, (eventDuration + waitTime) * 2.0); _editTime += deltaTime; _editPreviousTime = now; - if (cycleTime < eventDuration) { - _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration); - } - else if (cycleTime < (eventDuration + waitTime)) { - _editThreshold = 0.f; - } - else if (cycleTime < (2 * eventDuration + waitTime)) { - _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration); + if (_parameters->_isManualThresholdEnabled) { + _editThreshold = _parameters->_manualThreshold; } else { - _editThreshold = 1.f; + if (cycleTime < eventDuration) { + _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration); + } + else if (cycleTime < (eventDuration + waitTime)) { + _editThreshold = 0.f; + } + else if (cycleTime < (2 * eventDuration + waitTime)) { + _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration); + } + else { + _editThreshold = 1.f; + } } switch (_parameters->_editedCategory) { @@ -485,8 +493,10 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon case FadeJobConfig::BUBBLE_ISECT_OWNER: { const glm::vec3 cameraPos = renderContext->args->getViewFrustum().getPosition(); - const glm::vec3 delta = itemBounds.bound.calcCenter() - cameraPos; + glm::vec3 delta = itemBounds.bound.calcCenter() - cameraPos; + float distance = glm::length(delta); + delta = glm::normalize(delta) * std::max(0.f, distance - 0.5f); _editNoiseOffset.x = _editTime*0.1f; _editNoiseOffset.y = _editTime*2.5f; _editNoiseOffset.z = _editTime*0.1f; @@ -506,6 +516,7 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon _editNoiseOffset.z = _editTime*0.75f; _editBaseOffset = itemBounds.bound.calcCenter(); + _editBaseOffset.y -= itemBounds.bound.getDimensions().y / 2.f; } break; @@ -515,10 +526,6 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon default: assert(false); } - - if (_parameters->_isManualThresholdEnabled) { - _editThreshold = _parameters->_manualThreshold; - } } void FadeRenderJob::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation) { diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index d717d45b76..92f23751f4 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -73,7 +73,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto& metas = items.get0()[RenderFetchCullSortTask::META]; const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; - const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND]; + //const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND]; const auto& spatialSelection = items[1]; // Filter the non antialiaased overlays diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index ef9cfe8613..296eea1da8 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -37,13 +37,13 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // Extract opaques / transparents / lights / metas / overlays / background const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE]; - const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; - const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT]; - const auto& metas = items.get0()[RenderFetchCullSortTask::META]; - const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; - const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; +// const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; +// const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT]; +// const auto& metas = items.get0()[RenderFetchCullSortTask::META]; +// const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; +// const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND]; - const auto& spatialSelection = items[1]; +// const auto& spatialSelection = items[1]; const auto framebuffer = task.addJob("PrepareFramebuffer"); From 0244dd6325b2c5306086a2223e56b1cede969edd Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 09:47:23 +0200 Subject: [PATCH 31/38] Working bubble isect trespasser POV --- libraries/render-utils/src/FadeEffect.cpp | 33 +++++++++++++++-------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 20931e3a67..faca326171 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -117,8 +117,8 @@ FadeCommonParameters::FadeCommonParameters() FadeJobConfig::FadeJobConfig() { noiseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.75f, 0.75f, 0.75f }; - noiseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 1.0f, 1.0f/15.f, 1.0f }; - noiseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + noiseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 1.5f, 1.0f/25.f, 0.5f }; + noiseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 0.5f, 1.0f / 25.f, 0.5f }; noiseSize[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 10.f, 0.01f, 10.0f }; noiseSize[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.4f, 0.4f, 0.4f }; @@ -136,7 +136,7 @@ FadeJobConfig::FadeJobConfig() baseLevel[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.f; baseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 1.f; - baseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 1.f; + baseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.f; baseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 1.f; baseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; @@ -153,14 +153,14 @@ FadeJobConfig::FadeJobConfig() _duration[FadeJobConfig::AVATAR_CHANGE] = 3.f; edgeWidth[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.1f; - edgeWidth[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.08f; - edgeWidth[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.08f; + edgeWidth[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.02f; + edgeWidth[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.025f; edgeWidth[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.329f; edgeWidth[FadeJobConfig::AVATAR_CHANGE] = 0.05f; edgeInnerColor[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }; edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; - edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; + edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; edgeInnerColor[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }; edgeInnerColor[FadeJobConfig::AVATAR_CHANGE] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; @@ -497,9 +497,9 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon float distance = glm::length(delta); delta = glm::normalize(delta) * std::max(0.f, distance - 0.5f); - _editNoiseOffset.x = _editTime*0.1f; - _editNoiseOffset.y = _editTime*2.5f; - _editNoiseOffset.z = _editTime*0.1f; + _editNoiseOffset.x = _editTime*2.1f; + _editNoiseOffset.y = _editTime*1.0f; + _editNoiseOffset.z = _editTime*2.1f; _editBaseOffset = cameraPos + delta*_editThreshold; _editThreshold = 0.33f; @@ -507,6 +507,13 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon break; case FadeJobConfig::BUBBLE_ISECT_TRESPASSER: + { + _editNoiseOffset.x = _editTime*2.1f; + _editNoiseOffset.y = _editTime*1.0f; + _editNoiseOffset.z = _editTime*2.1f; + + _editBaseOffset = glm::vec3{ 0.f, 0.f, 0.f }; + } break; case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: @@ -572,10 +579,14 @@ bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline threshold = _currentInstance->_editThreshold; noiseOffset += _currentInstance->_editNoiseOffset; // This works supposing offset is the world position of the object that is fading. - baseOffset = _currentInstance->_editBaseOffset - offset; + if (eventCategory != FadeJobConfig::BUBBLE_ISECT_TRESPASSER) { + baseOffset = _currentInstance->_editBaseOffset - offset; + } } - threshold = (threshold-0.5f)*_currentInstance->_parameters->_thresholdScale[eventCategory] + 0.5f; + if (eventCategory != FadeJobConfig::BUBBLE_ISECT_OWNER) { + threshold = (threshold - 0.5f)*_currentInstance->_parameters->_thresholdScale[eventCategory] + 0.5f; + } batch._glUniform1i(fadeCategoryLocation, eventCategory); batch._glUniform1f(fadeThresholdLocation, threshold); From 7d851c1cbdd9c66d0db30dd37f33fd0ee4c20fb5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 12:01:28 +0200 Subject: [PATCH 32/38] Added timing parameters and visual debug of threshold --- libraries/render-utils/src/Fade.slh | 4 +- libraries/render-utils/src/FadeEffect.cpp | 115 +++-- libraries/render-utils/src/FadeEffect.h | 59 ++- .../render/configSlider/ConfigSlider.qml | 4 +- .../developer/utilities/render/debugFade.js | 4 +- scripts/developer/utilities/render/fade.qml | 468 ++++++++++-------- 6 files changed, 418 insertions(+), 236 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index f539d90217..5828c815e7 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -25,7 +25,7 @@ struct FadeParameters vec4 _innerEdgeColor; vec4 _outerEdgeColor; vec2 _edgeWidthInvWidth; - int _invertBase; + int _isInverted; float _padding; }; @@ -102,7 +102,7 @@ void applyFadeClip(vec3 position) { void applyFade(vec3 position, out vec3 emissive) { float alpha = evalFadeAlpha(position); - if (fadeParameters[fadeCategory]._invertBase!=0) { + if (fadeParameters[fadeCategory]._isInverted!=0) { alpha = -alpha; } diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index faca326171..b4f66e36ce 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -8,6 +8,7 @@ #define FADE_MIN_SCALE 0.001 #define FADE_MAX_SCALE 10000.0 +#define FADE_MAX_SPEED 50.f inline float parameterToValuePow(float parameter, const double minValue, const double maxOverMinValue) { return (float)(minValue * pow(maxOverMinValue, double(parameter))); @@ -128,6 +129,18 @@ FadeJobConfig::FadeJobConfig() noiseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.7f; noiseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; + noiseSpeed[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.0f, 0.0f, 0.0f }; + noiseSpeed[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 1.0f, 0.2f, 1.0f }; + noiseSpeed[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 1.0f, 0.2f, 1.0f }; + noiseSpeed[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.0f, -0.5f, 0.0f }; + noiseSpeed[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.0f, 0.0f, 0.0f }; + + timing[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = FadeJobConfig::LINEAR; + timing[FadeJobConfig::BUBBLE_ISECT_OWNER] = FadeJobConfig::LINEAR; + timing[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = FadeJobConfig::LINEAR; + timing[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = FadeJobConfig::LINEAR; + timing[FadeJobConfig::AVATAR_CHANGE] = FadeJobConfig::LINEAR; + baseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 1.0f, 1.0f, 1.0f }; baseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 2.0f, 2.0f, 2.0f }; baseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 2.0f, 2.0f, 2.0f }; @@ -140,11 +153,11 @@ FadeJobConfig::FadeJobConfig() baseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 1.f; baseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; - baseInverted[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = false; - baseInverted[FadeJobConfig::BUBBLE_ISECT_OWNER] = false; - baseInverted[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = false; - baseInverted[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = true; - baseInverted[FadeJobConfig::AVATAR_CHANGE] = false; + _isInverted[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = false; + _isInverted[FadeJobConfig::BUBBLE_ISECT_OWNER] = false; + _isInverted[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = false; + _isInverted[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = true; + _isInverted[FadeJobConfig::AVATAR_CHANGE] = false; _duration[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 4.f; _duration[FadeJobConfig::BUBBLE_ISECT_OWNER] = 4.f; @@ -219,13 +232,13 @@ void FadeJobConfig::setBaseLevel(float value) { emit dirty(); } -void FadeJobConfig::setBaseInverted(bool value) { - baseInverted[editedCategory] = value; +void FadeJobConfig::setInverted(bool value) { + _isInverted[editedCategory] = value; emit dirty(); } -bool FadeJobConfig::isBaseInverted() const { - return baseInverted[editedCategory]; +bool FadeJobConfig::isInverted() const { + return _isInverted[editedCategory]; } void FadeJobConfig::setNoiseSizeX(float value) { @@ -260,6 +273,33 @@ void FadeJobConfig::setNoiseLevel(float value) { emit dirty(); } +void FadeJobConfig::setNoiseSpeedX(float value) { + noiseSpeed[editedCategory].x = powf(value, 3.f)*FADE_MAX_SPEED; + emit dirty(); +} + +float FadeJobConfig::getNoiseSpeedX() const { + return powf(noiseSpeed[editedCategory].x / FADE_MAX_SPEED, 1.f/3.f); +} + +void FadeJobConfig::setNoiseSpeedY(float value) { + noiseSpeed[editedCategory].y = powf(value, 3.f)*FADE_MAX_SPEED; + emit dirty(); +} + +float FadeJobConfig::getNoiseSpeedY() const { + return powf(noiseSpeed[editedCategory].y / FADE_MAX_SPEED, 1.f / 3.f); +} + +void FadeJobConfig::setNoiseSpeedZ(float value) { + noiseSpeed[editedCategory].z = powf(value, 3.f)*FADE_MAX_SPEED; + emit dirty(); +} + +float FadeJobConfig::getNoiseSpeedZ() const { + return powf(noiseSpeed[editedCategory].z / FADE_MAX_SPEED, 1.f / 3.f); +} + void FadeJobConfig::setEdgeWidth(float value) { edgeWidth[editedCategory] = value * value; emit dirty(); @@ -309,6 +349,12 @@ void FadeJobConfig::setEdgeOuterIntensity(float value) { emit dirty(); } +void FadeJobConfig::setTiming(int value) { + assert(value < TIMING_COUNT); + timing[editedCategory] = value; + emit dirty(); +} + FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) : _parameters{ commonParams } { @@ -334,12 +380,14 @@ void FadeConfigureJob::configure(const Config& config) { configuration._noiseInvSizeAndLevel.y = 1.f / config.noiseSize[i].y; configuration._noiseInvSizeAndLevel.z = 1.f / config.noiseSize[i].z; configuration._noiseInvSizeAndLevel.w = config.noiseLevel[i]; - configuration._invertBase = config.baseInverted[i] & 1; + configuration._isInverted = config._isInverted[i] & 1; configuration._edgeWidthInvWidth.x = config.edgeWidth[i]; configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; configuration._innerEdgeColor = config.edgeInnerColor[i]; configuration._outerEdgeColor = config.edgeOuterColor[i]; _parameters->_thresholdScale[i] = 1.f + 2.f*(configuration._edgeWidthInvWidth.x + std::max(0.f, (config.noiseLevel[i] + config.baseLevel[i])*0.5f-0.5f)); + _parameters->_noiseSpeed[i] = config.noiseSpeed[i]; + _parameters->_timing[i] = (FadeJobConfig::Timing) config.timing[i]; } _isBufferDirty = true; } @@ -435,14 +483,28 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const } } -float FadeRenderJob::computeElementEnterThreshold(double time, const double period) const { +float FadeRenderJob::computeElementEnterThreshold(double time, const double period, FadeJobConfig::Timing timing) const { assert(period > 0.0); float fadeAlpha = 1.0f; const double INV_FADE_PERIOD = 1.0 / period; double fraction = time * INV_FADE_PERIOD; fraction = std::max(fraction, 0.0); if (fraction < 1.0) { - fadeAlpha = Interpolate::easeInOutQuad(fraction); + switch (timing) { + default: + fadeAlpha = fraction; + break; + case FadeJobConfig::EASE_IN: + fadeAlpha = fraction*fraction; + break; + case FadeJobConfig::EASE_OUT: + fadeAlpha = 1.f - fraction; + fadeAlpha = 1.f- fadeAlpha*fadeAlpha; + break; + case FadeJobConfig::EASE_IN_OUT: + fadeAlpha = fraction*fraction*(3 - 2 * fraction); + break; + } } return fadeAlpha; } @@ -450,7 +512,9 @@ float FadeRenderJob::computeElementEnterThreshold(double time, const double peri float FadeRenderJob::computeFadePercent(quint64 startTime) { const double time = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) / (double)(USECS_PER_SECOND); assert(_currentInstance); - return _currentInstance->computeElementEnterThreshold(time, _currentInstance->_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]); + return _currentInstance->computeElementEnterThreshold(time, + _currentInstance->_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN], + _currentInstance->_parameters->_timing[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]); } void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderContext, const render::ItemBound& itemBounds) { @@ -461,7 +525,9 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon uint64_t now = usecTimestampNow(); const double deltaTime = (int64_t(now) - int64_t(_editPreviousTime)) / double(USECS_PER_SECOND); - const double eventDuration = (double)_parameters->_durations[_parameters->_editedCategory]; + const int editedCategory = _parameters->_editedCategory; + const double eventDuration = (double)_parameters->_durations[editedCategory]; + const FadeJobConfig::Timing timing = _parameters->_timing[editedCategory]; const double waitTime = 0.5; // Wait between fade in and out double cycleTime = fmod(_editTime, (eventDuration + waitTime) * 2.0); @@ -473,20 +539,24 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon } else { if (cycleTime < eventDuration) { - _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration); + _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration, timing); } else if (cycleTime < (eventDuration + waitTime)) { _editThreshold = 0.f; } else if (cycleTime < (2 * eventDuration + waitTime)) { - _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration); + _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration, timing); } else { _editThreshold = 1.f; } } - switch (_parameters->_editedCategory) { + renderContext->jobConfig->setProperty("threshold", _editThreshold); + + _editNoiseOffset = _parameters->_noiseSpeed[editedCategory] * (float)_editTime; + + switch (editedCategory) { case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: break; @@ -497,9 +567,6 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon float distance = glm::length(delta); delta = glm::normalize(delta) * std::max(0.f, distance - 0.5f); - _editNoiseOffset.x = _editTime*2.1f; - _editNoiseOffset.y = _editTime*1.0f; - _editNoiseOffset.z = _editTime*2.1f; _editBaseOffset = cameraPos + delta*_editThreshold; _editThreshold = 0.33f; @@ -508,20 +575,12 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon case FadeJobConfig::BUBBLE_ISECT_TRESPASSER: { - _editNoiseOffset.x = _editTime*2.1f; - _editNoiseOffset.y = _editTime*1.0f; - _editNoiseOffset.z = _editTime*2.1f; - _editBaseOffset = glm::vec3{ 0.f, 0.f, 0.f }; } break; case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: { - _editNoiseOffset.x = _editTime*0.5f; - _editNoiseOffset.y = 0.f; - _editNoiseOffset.z = _editTime*0.75f; - _editBaseOffset = itemBounds.bound.calcCenter(); _editBaseOffset.y -= itemBounds.bound.getDimensions().y / 2.f; } diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index c3a41187e1..b29495cea0 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -38,7 +38,7 @@ class FadeJobConfig : public render::Job::Config { Q_PROPERTY(float baseSizeY READ getBaseSizeY WRITE setBaseSizeY NOTIFY dirty) Q_PROPERTY(float baseSizeZ READ getBaseSizeZ WRITE setBaseSizeZ NOTIFY dirty) Q_PROPERTY(float baseLevel READ getBaseLevel WRITE setBaseLevel NOTIFY dirty) - Q_PROPERTY(bool baseInverted READ isBaseInverted WRITE setBaseInverted NOTIFY dirty) + Q_PROPERTY(bool _isInverted READ isInverted WRITE setInverted NOTIFY dirty) Q_PROPERTY(float noiseSizeX READ getNoiseSizeX WRITE setNoiseSizeX NOTIFY dirty) Q_PROPERTY(float noiseSizeY READ getNoiseSizeY WRITE setNoiseSizeY NOTIFY dirty) Q_PROPERTY(float noiseSizeZ READ getNoiseSizeZ WRITE setNoiseSizeZ NOTIFY dirty) @@ -54,6 +54,10 @@ class FadeJobConfig : public render::Job::Config { Q_PROPERTY(float edgeOuterIntensity READ getEdgeOuterIntensity WRITE setEdgeOuterIntensity NOTIFY dirty) Q_PROPERTY(bool manualFade MEMBER manualFade NOTIFY dirty) Q_PROPERTY(float manualThreshold MEMBER manualThreshold NOTIFY dirty) + Q_PROPERTY(int timing READ getTiming WRITE setTiming NOTIFY dirty) + Q_PROPERTY(float noiseSpeedX READ getNoiseSpeedX WRITE setNoiseSpeedX NOTIFY dirty) + Q_PROPERTY(float noiseSpeedY READ getNoiseSpeedY WRITE setNoiseSpeedY NOTIFY dirty) + Q_PROPERTY(float noiseSpeedZ READ getNoiseSpeedZ WRITE setNoiseSpeedZ NOTIFY dirty) public: @@ -68,6 +72,15 @@ public: EVENT_CATEGORY_COUNT }; + enum Timing { + LINEAR, + EASE_IN, + EASE_OUT, + EASE_IN_OUT, + + TIMING_COUNT + }; + FadeJobConfig(); void setEditedCategory(int value); @@ -87,8 +100,8 @@ public: void setBaseLevel(float value); float getBaseLevel() const { return baseLevel[editedCategory]; } - void setBaseInverted(bool value); - bool isBaseInverted() const; + void setInverted(bool value); + bool isInverted() const; void setNoiseSizeX(float value); float getNoiseSizeX() const; @@ -102,6 +115,15 @@ public: void setNoiseLevel(float value); float getNoiseLevel() const { return noiseLevel[editedCategory]; } + void setNoiseSpeedX(float value); + float getNoiseSpeedX() const; + + void setNoiseSpeedY(float value); + float getNoiseSpeedY() const; + + void setNoiseSpeedZ(float value); + float getNoiseSpeedZ() const; + void setEdgeWidth(float value); float getEdgeWidth() const; @@ -128,19 +150,24 @@ public: void setEdgeOuterIntensity(float value); float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } + + void setTiming(int value); + int getTiming() const { return timing[editedCategory]; } bool manualFade{ false }; float manualThreshold{ 0.f }; int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]; + glm::vec3 noiseSpeed[EVENT_CATEGORY_COUNT]; float noiseLevel[EVENT_CATEGORY_COUNT]; glm::vec3 baseSize[EVENT_CATEGORY_COUNT]; float baseLevel[EVENT_CATEGORY_COUNT]; - bool baseInverted[EVENT_CATEGORY_COUNT]; + bool _isInverted[EVENT_CATEGORY_COUNT]; float _duration[EVENT_CATEGORY_COUNT]; float edgeWidth[EVENT_CATEGORY_COUNT]; glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]; glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]; + int timing[EVENT_CATEGORY_COUNT]; signals: void dirty(); @@ -160,6 +187,8 @@ struct FadeCommonParameters float _thresholdScale[FadeJobConfig::EVENT_CATEGORY_COUNT]; int _editedCategory{ FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN }; float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]; + glm::vec3 _noiseSpeed[FadeJobConfig::EVENT_CATEGORY_COUNT]; + FadeJobConfig::Timing _timing[FadeJobConfig::EVENT_CATEGORY_COUNT]; }; class FadeSwitchJob { @@ -200,7 +229,7 @@ struct FadeParameters glm::vec4 _innerEdgeColor; glm::vec4 _outerEdgeColor; glm::vec2 _edgeWidthInvWidth; - glm::int32 _invertBase; + glm::int32 _isInverted; glm::float32 _padding; }; @@ -234,15 +263,31 @@ private: FadeParameters _configurations[FadeJobConfig::EVENT_CATEGORY_COUNT]; }; + +class FadeRenderJobConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) + +public: + + float threshold{ 0.f }; + +signals: + void dirty(); + +}; + class FadeRenderJob { public: + using Config = FadeRenderJobConfig; using Input = render::VaryingSet3; - using JobModel = render::Job::ModelI; + using JobModel = render::Job::ModelI; FadeRenderJob(FadeCommonParameters::Pointer commonParams, render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber }, _parameters{ commonParams } {} + void configure(const Config& config) {} void run(const render::RenderContextPointer& renderContext, const Input& inputs); static void bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation); @@ -263,7 +308,7 @@ private: render::ShapePlumberPointer _shapePlumber; FadeCommonParameters::Pointer _parameters; - float computeElementEnterThreshold(double time, const double period) const; + float computeElementEnterThreshold(double time, const double period, FadeJobConfig::Timing timing) const; // Everything needed for interactive edition uint64_t _editPreviousTime{ 0 }; diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index c1a6d6b7f3..021365686a 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -43,7 +43,7 @@ Item { anchors.left: root.left anchors.leftMargin: 200 anchors.top: root.top - anchors.topMargin: 7 + anchors.topMargin: 15 } Binding { @@ -57,7 +57,7 @@ Item { Slider { id: sliderControl stepSize: root.integral ? 1.0 : 0.0 - width: 150 + width: root.width-130 height: 20 anchors.right: root.right anchors.rightMargin: 8 diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js index 6632cd8094..b01c4b5e1f 100644 --- a/scripts/developer/utilities/render/debugFade.js +++ b/scripts/developer/utilities/render/debugFade.js @@ -14,8 +14,8 @@ var qml = Script.resolvePath('fade.qml'); var window = new OverlayWindow({ title: 'Fade', source: qml, - width: 500, - height: 900, + width: 910, + height: 610, }); window.setPosition(50, 50); window.closed.connect(function() { Script.stop(); }); diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index 8b3885d230..da180aaefe 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -11,6 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "configSlider" +import "../lib/plotperf" Column { id: root @@ -47,6 +48,8 @@ Column { } } Row { + spacing: 8 + CheckBox { text: "Manual" checked: root.config["manualFade"] @@ -72,209 +75,284 @@ Column { Column { spacing: 8 - ConfigSlider { - label: "Duration" - integral: false - config: root.config - property: "duration" - max: 10.0 - min: 0.1 - width: 400 + CheckBox { + text: "Invert" + checked: root.config["isInverted"] + onCheckedChanged: { root.config["isInverted"] = checked } } - GroupBox { - title: "Base Gradient" - width: 500 - Column { - spacing: 8 + Row { + spacing: 8 + + GroupBox { + title: "Base Gradient" + width: 450 + Column { + spacing: 8 - ConfigSlider { - label: "Size X" - integral: false - config: root.config - property: "baseSizeX" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Y" - integral: false - config: root.config - property: "baseSizeY" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Z" - integral: false - config: root.config - property: "baseSizeZ" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Level" - integral: false - config: root.config - property: "baseLevel" - max: 1.0 - min: 0.0 - width: 400 - } - CheckBox { - text: "Invert" - checked: root.config["baseInverted"] - onCheckedChanged: { root.config["baseInverted"] = checked } - } - } - } - GroupBox { - title: "Noise Gradient" - width: 500 - Column { - spacing: 8 - - ConfigSlider { - label: "Size X" - integral: false - config: root.config - property: "noiseSizeX" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Y" - integral: false - config: root.config - property: "noiseSizeY" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Size Z" - integral: false - config: root.config - property: "noiseSizeZ" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Level" - integral: false - config: root.config - property: "noiseLevel" - max: 1.0 - min: 0.0 - width: 400 - } - } - } - GroupBox { - title: "Edge" - width: 500 - Column { - spacing: 8 - - ConfigSlider { - label: "Width" - integral: false - config: root.config - property: "edgeWidth" - max: 1.0 - min: 0.0 - width: 400 - } - GroupBox { - title: "Inner color" - Column { - spacing: 8 - ConfigSlider { - label: "Color R" - integral: false - config: root.config - property: "edgeInnerColorR" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color G" - integral: false - config: root.config - property: "edgeInnerColorG" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color B" - integral: false - config: root.config - property: "edgeInnerColorB" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color intensity" - integral: false - config: root.config - property: "edgeInnerIntensity" - max: 5.0 - min: 0.0 - width: 400 - } + ConfigSlider { + label: "Size X" + integral: false + config: root.config + property: "baseSizeX" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Y" + integral: false + config: root.config + property: "baseSizeY" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Z" + integral: false + config: root.config + property: "baseSizeZ" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Level" + integral: false + config: root.config + property: "baseLevel" + max: 1.0 + min: 0.0 + width: 400 } } - GroupBox { - title: "Outer color" - Column { - spacing: 8 - ConfigSlider { - label: "Color R" - integral: false - config: root.config - property: "edgeOuterColorR" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color G" - integral: false - config: root.config - property: "edgeOuterColorG" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color B" - integral: false - config: root.config - property: "edgeOuterColorB" - max: 1.0 - min: 0.0 - width: 400 - } - ConfigSlider { - label: "Color intensity" - integral: false - config: root.config - property: "edgeOuterIntensity" - max: 5.0 - min: 0.0 - width: 400 - } + } + GroupBox { + title: "Noise Gradient" + width: 450 + Column { + spacing: 8 + + ConfigSlider { + label: "Size X" + integral: false + config: root.config + property: "noiseSizeX" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Y" + integral: false + config: root.config + property: "noiseSizeY" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Size Z" + integral: false + config: root.config + property: "noiseSizeZ" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Level" + integral: false + config: root.config + property: "noiseLevel" + max: 1.0 + min: 0.0 + width: 400 } } } } + Row { + spacing: 8 + + GroupBox { + title: "Edge" + width: 450 + Column { + spacing: 8 + + ConfigSlider { + label: "Width" + integral: false + config: root.config + property: "edgeWidth" + max: 1.0 + min: 0.0 + width: 400 + } + GroupBox { + title: "Inner color" + Column { + spacing: 8 + ConfigSlider { + label: "Color R" + integral: false + config: root.config + property: "edgeInnerColorR" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color G" + integral: false + config: root.config + property: "edgeInnerColorG" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color B" + integral: false + config: root.config + property: "edgeInnerColorB" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color intensity" + integral: false + config: root.config + property: "edgeInnerIntensity" + max: 5.0 + min: 0.0 + width: 400 + } + } + } + GroupBox { + title: "Outer color" + Column { + spacing: 8 + ConfigSlider { + label: "Color R" + integral: false + config: root.config + property: "edgeOuterColorR" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color G" + integral: false + config: root.config + property: "edgeOuterColorG" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color B" + integral: false + config: root.config + property: "edgeOuterColorB" + max: 1.0 + min: 0.0 + width: 400 + } + ConfigSlider { + label: "Color intensity" + integral: false + config: root.config + property: "edgeOuterIntensity" + max: 5.0 + min: 0.0 + width: 400 + } + } + } + } + } + + GroupBox { + title: "Timing" + width: 450 + Column { + spacing: 8 + + ConfigSlider { + label: "Duration" + integral: false + config: root.config + property: "duration" + max: 10.0 + min: 0.1 + width: 400 + } + ComboBox { + width: 400 + model: ["Linear", "Ease In", "Ease Out", "Ease In / Out"] + onCurrentIndexChanged: { + root.config["timing"] = currentIndex; + } + } + GroupBox { + title: "Noise Animation" + Column { + spacing: 8 + ConfigSlider { + label: "Speed X" + integral: false + config: root.config + property: "noiseSpeedX" + max: 1.0 + min: -1.0 + width: 400 + } + ConfigSlider { + label: "Speed Y" + integral: false + config: root.config + property: "noiseSpeedY" + max: 1.0 + min: -1.0 + width: 400 + } + ConfigSlider { + label: "Speed Z" + integral: false + config: root.config + property: "noiseSpeedZ" + max: 1.0 + min: -1.0 + width: 400 + } + } + } + + PlotPerf { + title: "Threshold" + height: parent.evalEvenHeight() + object: Render.getConfig("RenderMainView.DrawFadeOpaque") + valueUnit: "%" + valueScale: 0.01 + valueNumDigits: "1" + plots: [ + { + prop: "threshold", + label: "Threshold", + color: "#FFBB77" + } + ] + } + + } + } + + } } } From 98d915cf0f12a37ac4bb09cf83a36e6694d9355f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 14:35:43 +0200 Subject: [PATCH 33/38] Smoother ease in / out functions --- libraries/render-utils/src/Fade.slh | 5 ++--- libraries/render-utils/src/FadeEffect.cpp | 14 +++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 5828c815e7..d3ab532650 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -45,7 +45,8 @@ vec2 hash2D(vec3 position) { } float noise3D(vec3 position) { - return textureLod(fadeMaskMap, hash2D(position), 0).r; + float n = textureLod(fadeMaskMap, hash2D(position), 0).r; + return pow(n, 1.0/2.2); // Need to fix this later directly in the texture } float evalFadeNoiseGradient(vec3 position) { @@ -87,8 +88,6 @@ float evalFadeGradient(vec3 position) { } float evalFadeAlpha(vec3 position) { - //float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; - //float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold); float cutoff = fadeThreshold; return evalFadeGradient(position)-cutoff; diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index b4f66e36ce..6152bc213b 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -385,7 +385,7 @@ void FadeConfigureJob::configure(const Config& config) { configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; configuration._innerEdgeColor = config.edgeInnerColor[i]; configuration._outerEdgeColor = config.edgeOuterColor[i]; - _parameters->_thresholdScale[i] = 1.f + 2.f*(configuration._edgeWidthInvWidth.x + std::max(0.f, (config.noiseLevel[i] + config.baseLevel[i])*0.5f-0.5f)); + _parameters->_thresholdScale[i] = 1.f + (configuration._edgeWidthInvWidth.x + std::max(0.f, (config.noiseLevel[i] + config.baseLevel[i])*0.5f-0.5f)); _parameters->_noiseSpeed[i] = config.noiseSpeed[i]; _parameters->_timing[i] = (FadeJobConfig::Timing) config.timing[i]; } @@ -495,14 +495,14 @@ float FadeRenderJob::computeElementEnterThreshold(double time, const double peri fadeAlpha = fraction; break; case FadeJobConfig::EASE_IN: - fadeAlpha = fraction*fraction; + fadeAlpha = fraction*fraction*fraction; break; case FadeJobConfig::EASE_OUT: fadeAlpha = 1.f - fraction; - fadeAlpha = 1.f- fadeAlpha*fadeAlpha; + fadeAlpha = 1.f- fadeAlpha*fadeAlpha*fadeAlpha; break; case FadeJobConfig::EASE_IN_OUT: - fadeAlpha = fraction*fraction*(3 - 2 * fraction); + fadeAlpha = fraction*fraction*fraction*(fraction*(fraction * 6 - 15) + 10); break; } } @@ -552,7 +552,11 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon } } - renderContext->jobConfig->setProperty("threshold", _editThreshold); + float threshold = _editThreshold; + if (editedCategory != FadeJobConfig::BUBBLE_ISECT_OWNER) { + threshold = (threshold - 0.5f)*_parameters->_thresholdScale[editedCategory] + 0.5f; + } + renderContext->jobConfig->setProperty("threshold", threshold); _editNoiseOffset = _parameters->_noiseSpeed[editedCategory] * (float)_editTime; From 2525fe5869716b240146f3770def4dc12a867841 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 17:31:24 +0200 Subject: [PATCH 34/38] Working save and load --- libraries/render-utils/src/FadeEffect.cpp | 431 +++++++++++++++----- libraries/render-utils/src/FadeEffect.h | 54 ++- scripts/developer/utilities/render/fade.qml | 168 +++++--- 3 files changed, 452 insertions(+), 201 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 6152bc213b..dec67dac85 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -6,6 +6,8 @@ #include #include +#include + #define FADE_MIN_SCALE 0.001 #define FADE_MAX_SCALE 10000.0 #define FADE_MAX_SPEED 50.f @@ -117,71 +119,65 @@ FadeCommonParameters::FadeCommonParameters() FadeJobConfig::FadeJobConfig() { - noiseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.75f, 0.75f, 0.75f }; - noiseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 1.5f, 1.0f/25.f, 0.5f }; - noiseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 0.5f, 1.0f / 25.f, 0.5f }; - noiseSize[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 10.f, 0.01f, 10.0f }; - noiseSize[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.4f, 0.4f, 0.4f }; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].noiseSize = glm::vec3{ 0.75f, 0.75f, 0.75f }; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].noiseLevel = 1.f; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].noiseSpeed = glm::vec3{ 0.0f, 0.0f, 0.0f }; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].timing = FadeJobConfig::LINEAR; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].baseSize = glm::vec3{ 1.0f, 1.0f, 1.0f }; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].baseLevel = 0.f; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]._isInverted = false; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]._duration = 4.f; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].edgeWidth = 0.1f; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].edgeInnerColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }; + events[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN].edgeOuterColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; - noiseLevel[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 1.f; - noiseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.37f; - noiseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 1.f; - noiseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.7f; - noiseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].noiseSize = glm::vec3{ 1.5f, 1.0f/25.f, 0.5f }; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].noiseLevel = 0.37f; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].noiseSpeed = glm::vec3{ 1.0f, 0.2f, 1.0f }; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].timing = FadeJobConfig::LINEAR; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].baseSize = glm::vec3{ 2.0f, 2.0f, 2.0f }; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].baseLevel = 1.f; + events[FadeJobConfig::BUBBLE_ISECT_OWNER]._isInverted = false; + events[FadeJobConfig::BUBBLE_ISECT_OWNER]._duration = 4.f; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].edgeWidth = 0.02f; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].edgeInnerColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; + events[FadeJobConfig::BUBBLE_ISECT_OWNER].edgeOuterColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }; - noiseSpeed[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.0f, 0.0f, 0.0f }; - noiseSpeed[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 1.0f, 0.2f, 1.0f }; - noiseSpeed[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 1.0f, 0.2f, 1.0f }; - noiseSpeed[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 0.0f, -0.5f, 0.0f }; - noiseSpeed[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.0f, 0.0f, 0.0f }; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].noiseSize = glm::vec3{ 0.5f, 1.0f / 25.f, 0.5f }; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].noiseLevel = 1.f; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].noiseSpeed = glm::vec3{ 1.0f, 0.2f, 1.0f }; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].timing = FadeJobConfig::LINEAR; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].baseSize = glm::vec3{ 2.0f, 2.0f, 2.0f }; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].baseLevel = 0.f; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER]._isInverted = false; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER]._duration = 4.f; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].edgeWidth = 0.025f; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].edgeInnerColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; + events[FadeJobConfig::BUBBLE_ISECT_TRESPASSER].edgeOuterColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }; - timing[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = FadeJobConfig::LINEAR; - timing[FadeJobConfig::BUBBLE_ISECT_OWNER] = FadeJobConfig::LINEAR; - timing[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = FadeJobConfig::LINEAR; - timing[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = FadeJobConfig::LINEAR; - timing[FadeJobConfig::AVATAR_CHANGE] = FadeJobConfig::LINEAR; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseSize = glm::vec3{ 10.f, 0.01f, 10.0f }; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseLevel = 0.7f; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseSpeed = glm::vec3{ 1.0f, -0.5f, 50.0f }; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].timing = FadeJobConfig::LINEAR; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].baseSize = glm::vec3{ 10000.f, 1.0f, 10000.0f }; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].baseLevel = 1.f; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._isInverted = true; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._duration = 3.f; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeWidth = 0.329f; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeInnerColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeOuterColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; - baseSize[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec3{ 1.0f, 1.0f, 1.0f }; - baseSize[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec3{ 2.0f, 2.0f, 2.0f }; - baseSize[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec3{ 2.0f, 2.0f, 2.0f }; - baseSize[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec3{ 10000.f, 1.0f, 10000.0f }; - baseSize[FadeJobConfig::AVATAR_CHANGE] = glm::vec3{ 0.4f, 0.4f, 0.4f }; - - baseLevel[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.f; - baseLevel[FadeJobConfig::BUBBLE_ISECT_OWNER] = 1.f; - baseLevel[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.f; - baseLevel[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 1.f; - baseLevel[FadeJobConfig::AVATAR_CHANGE] = 1.f; - - _isInverted[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = false; - _isInverted[FadeJobConfig::BUBBLE_ISECT_OWNER] = false; - _isInverted[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = false; - _isInverted[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = true; - _isInverted[FadeJobConfig::AVATAR_CHANGE] = false; - - _duration[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 4.f; - _duration[FadeJobConfig::BUBBLE_ISECT_OWNER] = 4.f; - _duration[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 4.f; - _duration[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 3.f; - _duration[FadeJobConfig::AVATAR_CHANGE] = 3.f; - - edgeWidth[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = 0.1f; - edgeWidth[FadeJobConfig::BUBBLE_ISECT_OWNER] = 0.02f; - edgeWidth[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = 0.025f; - edgeWidth[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = 0.329f; - edgeWidth[FadeJobConfig::AVATAR_CHANGE] = 0.05f; - - edgeInnerColor[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f }; - edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; - edgeInnerColor[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f }; - edgeInnerColor[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }; - edgeInnerColor[FadeJobConfig::AVATAR_CHANGE] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; - - edgeOuterColor[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; - edgeOuterColor[FadeJobConfig::BUBBLE_ISECT_OWNER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }; - edgeOuterColor[FadeJobConfig::BUBBLE_ISECT_TRESPASSER] = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f }; - edgeOuterColor[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN] = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; - edgeOuterColor[FadeJobConfig::AVATAR_CHANGE] = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; + events[FadeJobConfig::AVATAR_CHANGE].noiseSize = glm::vec3{ 0.4f, 0.4f, 0.4f }; + events[FadeJobConfig::AVATAR_CHANGE].noiseLevel = 1.f; + events[FadeJobConfig::AVATAR_CHANGE].noiseSpeed = glm::vec3{ 0.0f, 0.0f, 0.0f }; + events[FadeJobConfig::AVATAR_CHANGE].timing = FadeJobConfig::LINEAR; + events[FadeJobConfig::AVATAR_CHANGE].baseSize = glm::vec3{ 0.4f, 0.4f, 0.4f }; + events[FadeJobConfig::AVATAR_CHANGE].baseLevel = 1.f; + events[FadeJobConfig::AVATAR_CHANGE]._isInverted = false; + events[FadeJobConfig::AVATAR_CHANGE]._duration = 3.f; + events[FadeJobConfig::AVATAR_CHANGE].edgeWidth = 0.05f; + events[FadeJobConfig::AVATAR_CHANGE].edgeInnerColor = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; + events[FadeJobConfig::AVATAR_CHANGE].edgeOuterColor = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }; } void FadeJobConfig::setEditedCategory(int value) { @@ -192,169 +188,373 @@ void FadeJobConfig::setEditedCategory(int value) { } void FadeJobConfig::setDuration(float value) { - _duration[editedCategory] = value; + events[editedCategory]._duration = value; emit dirty(); } float FadeJobConfig::getDuration() const { - return _duration[editedCategory]; + return events[editedCategory]._duration; } void FadeJobConfig::setBaseSizeX(float value) { - baseSize[editedCategory].x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE); + events[editedCategory].baseSize.x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getBaseSizeX() const { - return valueToParameterPow(baseSize[editedCategory].x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(events[editedCategory].baseSize.x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setBaseSizeY(float value) { - baseSize[editedCategory].y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + events[editedCategory].baseSize.y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getBaseSizeY() const { - return valueToParameterPow(baseSize[editedCategory].y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(events[editedCategory].baseSize.y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setBaseSizeZ(float value) { - baseSize[editedCategory].z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + events[editedCategory].baseSize.z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getBaseSizeZ() const { - return valueToParameterPow(baseSize[editedCategory].z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(events[editedCategory].baseSize.z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setBaseLevel(float value) { - baseLevel[editedCategory] = value; + events[editedCategory].baseLevel = value; emit dirty(); } void FadeJobConfig::setInverted(bool value) { - _isInverted[editedCategory] = value; + events[editedCategory]._isInverted = value; emit dirty(); } bool FadeJobConfig::isInverted() const { - return _isInverted[editedCategory]; + return events[editedCategory]._isInverted; } void FadeJobConfig::setNoiseSizeX(float value) { - noiseSize[editedCategory].x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + events[editedCategory].noiseSize.x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getNoiseSizeX() const { - return valueToParameterPow(noiseSize[editedCategory].x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(events[editedCategory].noiseSize.x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setNoiseSizeY(float value) { - noiseSize[editedCategory].y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + events[editedCategory].noiseSize.y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getNoiseSizeY() const { - return valueToParameterPow(noiseSize[editedCategory].y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(events[editedCategory].noiseSize.y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setNoiseSizeZ(float value) { - noiseSize[editedCategory].z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + events[editedCategory].noiseSize.z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); emit dirty(); } float FadeJobConfig::getNoiseSizeZ() const { - return valueToParameterPow(noiseSize[editedCategory].z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); + return valueToParameterPow(events[editedCategory].noiseSize.z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE); } void FadeJobConfig::setNoiseLevel(float value) { - noiseLevel[editedCategory] = value; + events[editedCategory].noiseLevel = value; emit dirty(); } void FadeJobConfig::setNoiseSpeedX(float value) { - noiseSpeed[editedCategory].x = powf(value, 3.f)*FADE_MAX_SPEED; + events[editedCategory].noiseSpeed.x = powf(value, 3.f)*FADE_MAX_SPEED; emit dirty(); } float FadeJobConfig::getNoiseSpeedX() const { - return powf(noiseSpeed[editedCategory].x / FADE_MAX_SPEED, 1.f/3.f); + return powf(events[editedCategory].noiseSpeed.x / FADE_MAX_SPEED, 1.f / 3.f); } void FadeJobConfig::setNoiseSpeedY(float value) { - noiseSpeed[editedCategory].y = powf(value, 3.f)*FADE_MAX_SPEED; + events[editedCategory].noiseSpeed.y = powf(value, 3.f)*FADE_MAX_SPEED; emit dirty(); } float FadeJobConfig::getNoiseSpeedY() const { - return powf(noiseSpeed[editedCategory].y / FADE_MAX_SPEED, 1.f / 3.f); + return powf(events[editedCategory].noiseSpeed.y / FADE_MAX_SPEED, 1.f / 3.f); } void FadeJobConfig::setNoiseSpeedZ(float value) { - noiseSpeed[editedCategory].z = powf(value, 3.f)*FADE_MAX_SPEED; + events[editedCategory].noiseSpeed.z = powf(value, 3.f)*FADE_MAX_SPEED; emit dirty(); } float FadeJobConfig::getNoiseSpeedZ() const { - return powf(noiseSpeed[editedCategory].z / FADE_MAX_SPEED, 1.f / 3.f); + return powf(events[editedCategory].noiseSpeed.z / FADE_MAX_SPEED, 1.f / 3.f); } void FadeJobConfig::setEdgeWidth(float value) { - edgeWidth[editedCategory] = value * value; + events[editedCategory].edgeWidth = value * value; emit dirty(); } float FadeJobConfig::getEdgeWidth() const { - return sqrtf(edgeWidth[editedCategory]); + return sqrtf(events[editedCategory].edgeWidth); } void FadeJobConfig::setEdgeInnerColorR(float value) { - edgeInnerColor[editedCategory].r = value; + events[editedCategory].edgeInnerColor.r = value; emit dirty(); } void FadeJobConfig::setEdgeInnerColorG(float value) { - edgeInnerColor[editedCategory].g = value; + events[editedCategory].edgeInnerColor.g = value; emit dirty(); } void FadeJobConfig::setEdgeInnerColorB(float value) { - edgeInnerColor[editedCategory].b = value; + events[editedCategory].edgeInnerColor.b = value; emit dirty(); } void FadeJobConfig::setEdgeInnerIntensity(float value) { - edgeInnerColor[editedCategory].a = value; + events[editedCategory].edgeInnerColor.a = value; emit dirty(); } void FadeJobConfig::setEdgeOuterColorR(float value) { - edgeOuterColor[editedCategory].r = value; + events[editedCategory].edgeOuterColor.r = value; emit dirty(); } void FadeJobConfig::setEdgeOuterColorG(float value) { - edgeOuterColor[editedCategory].g = value; + events[editedCategory].edgeOuterColor.g = value; emit dirty(); } void FadeJobConfig::setEdgeOuterColorB(float value) { - edgeOuterColor[editedCategory].b = value; + events[editedCategory].edgeOuterColor.b = value; emit dirty(); } void FadeJobConfig::setEdgeOuterIntensity(float value) { - edgeOuterColor[editedCategory].a = value; + events[editedCategory].edgeOuterColor.a = value; emit dirty(); } void FadeJobConfig::setTiming(int value) { assert(value < TIMING_COUNT); - timing[editedCategory] = value; + events[editedCategory].timing = value; emit dirty(); } +QString FadeJobConfig::eventNames[EVENT_CATEGORY_COUNT] = { + "element_enter_leave_domain", + "bubble_isect_owner", + "bubble_isect_trespasser", + "user_enter_leave_domain", + "avatar_change", +}; + +void FadeJobConfig::save() const { + assert(category < EVENT_CATEGORY_COUNT); + QJsonObject lProperties; + const QString configFile = "config/" + eventNames[editedCategory] + ".json"; + QUrl path(PathUtils::resourcesPath() + configFile); + QFile file(path.toString()); + if (!file.open(QFile::WriteOnly | QFile::Text)) { + qWarning() << "Fade event configuration file " << path << " cannot be opened"; + } + else { + const auto& event = events[editedCategory]; + + lProperties["edgeInnerColor"] = QJsonArray{ event.edgeInnerColor.r, event.edgeInnerColor.g, event.edgeInnerColor.b, event.edgeInnerColor.a }; + lProperties["edgeOuterColor"] = QJsonArray{ event.edgeOuterColor.r, event.edgeOuterColor.g, event.edgeOuterColor.b, event.edgeOuterColor.a }; + lProperties["noiseSize"] = QJsonArray{ event.noiseSize.x, event.noiseSize.y, event.noiseSize.z }; + lProperties["noiseSpeed"] = QJsonArray{ event.noiseSpeed.x, event.noiseSpeed.y, event.noiseSpeed.z }; + lProperties["baseSize"] = QJsonArray{ event.baseSize.x, event.baseSize.y, event.baseSize.z }; + lProperties["noiseLevel"] = event.noiseLevel; + lProperties["baseLevel"] = event.baseLevel; + lProperties["duration"] = event._duration; + lProperties["edgeWidth"] = event.edgeWidth; + lProperties["timing"] = event.timing; + lProperties["isInverted"] = event._isInverted; + + file.write( QJsonDocument(lProperties).toJson() ); + file.close(); + } +} + +void FadeJobConfig::load() { + const QString configFile = "config/" + eventNames[editedCategory] + ".json"; + + QUrl path(PathUtils::resourcesPath() + configFile); + QFile file(path.toString()); + if (!file.exists()) { + qWarning() << "Fade event configuration file " << path << " does not exist"; + } + else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Fade event configuration file " << path << " cannot be opened"; + } + else { + QString fileData = file.readAll(); + file.close(); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(fileData.toUtf8(), &error); + if (error.error == error.NoError) { + QJsonObject jsonObject = doc.object(); + QJsonValue value; + auto& event = events[editedCategory]; + + qCDebug(renderlogging) << "Fade event configuration file" << path << "loaded"; + + value = jsonObject["edgeInnerColor"]; + if (value.isArray()) { + QJsonArray data = value.toArray(); + + if (data.size() < 4) { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeInnerColor' field. Expected array of size 4"; + } + else { + event.edgeInnerColor.r = (float)data.at(0).toDouble(); + event.edgeInnerColor.g = (float)data.at(1).toDouble(); + event.edgeInnerColor.b = (float)data.at(2).toDouble(); + event.edgeInnerColor.a = (float)data.at(3).toDouble(); + } + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeInnerColor' field. Expected array of size 4"; + } + + value = jsonObject["edgeOuterColor"]; + if (value.isArray()) { + QJsonArray data = value.toArray(); + + if (data.size() < 4) { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeOuterColor' field. Expected array of size 4"; + } + else { + event.edgeOuterColor.r = (float)data.at(0).toDouble(); + event.edgeOuterColor.g = (float)data.at(1).toDouble(); + event.edgeOuterColor.b = (float)data.at(2).toDouble(); + event.edgeOuterColor.a = (float)data.at(3).toDouble(); + } + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeOuterColor' field. Expected array of size 4"; + } + + value = jsonObject["noiseSize"]; + if (value.isArray()) { + QJsonArray data = value.toArray(); + + if (data.size() < 3) { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSize' field. Expected array of size 3"; + } + else { + event.noiseSize.x = (float)data.at(0).toDouble(); + event.noiseSize.y = (float)data.at(1).toDouble(); + event.noiseSize.z = (float)data.at(2).toDouble(); + } + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSize' field. Expected array of size 3"; + } + + value = jsonObject["noiseSpeed"]; + if (value.isArray()) { + QJsonArray data = value.toArray(); + + if (data.size() < 3) { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSpeed' field. Expected array of size 3"; + } + else { + event.noiseSpeed.x = (float)data.at(0).toDouble(); + event.noiseSpeed.y = (float)data.at(1).toDouble(); + event.noiseSpeed.z = (float)data.at(2).toDouble(); + } + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSpeed' field. Expected array of size 3"; + } + + value = jsonObject["baseSize"]; + if (value.isArray()) { + QJsonArray data = value.toArray(); + + if (data.size() < 3) { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'baseSize' field. Expected array of size 3"; + } + else { + event.baseSize.x = (float)data.at(0).toDouble(); + event.baseSize.y = (float)data.at(1).toDouble(); + event.baseSize.z = (float)data.at(2).toDouble(); + } + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'baseSize' field. Expected array of size 3"; + } + + value = jsonObject["noiseLevel"]; + if (value.isDouble()) { + event.noiseLevel = (float)value.toDouble(); + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseLevel' field. Expected float value"; + } + + value = jsonObject["baseLevel"]; + if (value.isDouble()) { + event.baseLevel = (float)value.toDouble(); + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'baseLevel' field. Expected float value"; + } + + value = jsonObject["duration"]; + if (value.isDouble()) { + event._duration = (float)value.toDouble(); + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'duration' field. Expected float value"; + } + + value = jsonObject["edgeWidth"]; + if (value.isDouble()) { + event.edgeWidth = std::min(1.f, std::max(0.f, (float)value.toDouble())); + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeWidth' field. Expected float value"; + } + + value = jsonObject["timing"]; + if (value.isDouble()) { + event.timing = std::max(0, std::min(TIMING_COUNT - 1, value.toInt())); + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'timing' field. Expected integer value"; + } + + value = jsonObject["isInverted"]; + if (value.isBool()) { + event._isInverted = value.toBool(); + } + else { + qWarning() << "Fade event configuration file " << path << " contains an invalid 'isInverted' field. Expected boolean value"; + } + + emit dirty(); + } + else { + qWarning() << "Fade event configuration file" << path << "failed to load:" << + error.errorString() << "at offset" << error.offset; + } + } +} + FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) : _parameters{ commonParams } { @@ -370,24 +570,25 @@ void FadeConfigureJob::configure(const Config& config) { for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) { auto& configuration = _configurations[i]; + const auto& eventConfig = config.events[i]; - _parameters->_durations[i] = config._duration[i]; - configuration._baseInvSizeAndLevel.x = 1.f / config.baseSize[i].x; - configuration._baseInvSizeAndLevel.y = 1.f / config.baseSize[i].y; - configuration._baseInvSizeAndLevel.z = 1.f / config.baseSize[i].z; - configuration._baseInvSizeAndLevel.w = config.baseLevel[i]; - configuration._noiseInvSizeAndLevel.x = 1.f / config.noiseSize[i].x; - configuration._noiseInvSizeAndLevel.y = 1.f / config.noiseSize[i].y; - configuration._noiseInvSizeAndLevel.z = 1.f / config.noiseSize[i].z; - configuration._noiseInvSizeAndLevel.w = config.noiseLevel[i]; - configuration._isInverted = config._isInverted[i] & 1; - configuration._edgeWidthInvWidth.x = config.edgeWidth[i]; + _parameters->_durations[i] = eventConfig._duration; + configuration._baseInvSizeAndLevel.x = 1.f / eventConfig.baseSize.x; + configuration._baseInvSizeAndLevel.y = 1.f / eventConfig.baseSize.y; + configuration._baseInvSizeAndLevel.z = 1.f / eventConfig.baseSize.z; + configuration._baseInvSizeAndLevel.w = eventConfig.baseLevel; + configuration._noiseInvSizeAndLevel.x = 1.f / eventConfig.noiseSize.x; + configuration._noiseInvSizeAndLevel.y = 1.f / eventConfig.noiseSize.y; + configuration._noiseInvSizeAndLevel.z = 1.f / eventConfig.noiseSize.z; + configuration._noiseInvSizeAndLevel.w = eventConfig.noiseLevel; + configuration._isInverted = eventConfig._isInverted & 1; + configuration._edgeWidthInvWidth.x = eventConfig.edgeWidth; configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; - configuration._innerEdgeColor = config.edgeInnerColor[i]; - configuration._outerEdgeColor = config.edgeOuterColor[i]; - _parameters->_thresholdScale[i] = 1.f + (configuration._edgeWidthInvWidth.x + std::max(0.f, (config.noiseLevel[i] + config.baseLevel[i])*0.5f-0.5f)); - _parameters->_noiseSpeed[i] = config.noiseSpeed[i]; - _parameters->_timing[i] = (FadeJobConfig::Timing) config.timing[i]; + configuration._innerEdgeColor = eventConfig.edgeInnerColor; + configuration._outerEdgeColor = eventConfig.edgeOuterColor; + _parameters->_thresholdScale[i] = 1.f + (configuration._edgeWidthInvWidth.x + std::max(0.f, (eventConfig.noiseLevel + eventConfig.baseLevel)*0.5f-0.5f)); + _parameters->_noiseSpeed[i] = eventConfig.noiseSpeed; + _parameters->_timing[i] = (FadeJobConfig::Timing) eventConfig.timing; } _isBufferDirty = true; } @@ -530,6 +731,7 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon const FadeJobConfig::Timing timing = _parameters->_timing[editedCategory]; const double waitTime = 0.5; // Wait between fade in and out double cycleTime = fmod(_editTime, (eventDuration + waitTime) * 2.0); + bool inverseTime = false; _editTime += deltaTime; _editPreviousTime = now; @@ -546,9 +748,11 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon } else if (cycleTime < (2 * eventDuration + waitTime)) { _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration, timing); + inverseTime = true; } else { _editThreshold = 1.f; + inverseTime = true; } } @@ -559,6 +763,9 @@ void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderCon renderContext->jobConfig->setProperty("threshold", threshold); _editNoiseOffset = _parameters->_noiseSpeed[editedCategory] * (float)_editTime; + if (inverseTime) { + _editNoiseOffset = -_editNoiseOffset; + } switch (editedCategory) { case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index b29495cea0..157b4aebac 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -98,7 +98,7 @@ public: float getBaseSizeZ() const; void setBaseLevel(float value); - float getBaseLevel() const { return baseLevel[editedCategory]; } + float getBaseLevel() const { return events[editedCategory].baseLevel; } void setInverted(bool value); bool isInverted() const; @@ -113,7 +113,7 @@ public: float getNoiseSizeZ() const; void setNoiseLevel(float value); - float getNoiseLevel() const { return noiseLevel[editedCategory]; } + float getNoiseLevel() const { return events[editedCategory].noiseLevel; } void setNoiseSpeedX(float value); float getNoiseSpeedX() const; @@ -128,46 +128,56 @@ public: float getEdgeWidth() const; void setEdgeInnerColorR(float value); - float getEdgeInnerColorR() const { return edgeInnerColor[editedCategory].r; } + float getEdgeInnerColorR() const { return events[editedCategory].edgeInnerColor.r; } void setEdgeInnerColorG(float value); - float getEdgeInnerColorG() const { return edgeInnerColor[editedCategory].g; } + float getEdgeInnerColorG() const { return events[editedCategory].edgeInnerColor.g; } void setEdgeInnerColorB(float value); - float getEdgeInnerColorB() const { return edgeInnerColor[editedCategory].b; } + float getEdgeInnerColorB() const { return events[editedCategory].edgeInnerColor.b; } void setEdgeInnerIntensity(float value); - float getEdgeInnerIntensity() const { return edgeInnerColor[editedCategory].a; } + float getEdgeInnerIntensity() const { return events[editedCategory].edgeInnerColor.a; } void setEdgeOuterColorR(float value); - float getEdgeOuterColorR() const { return edgeOuterColor[editedCategory].r; } + float getEdgeOuterColorR() const { return events[editedCategory].edgeOuterColor.r; } void setEdgeOuterColorG(float value); - float getEdgeOuterColorG() const { return edgeOuterColor[editedCategory].g; } + float getEdgeOuterColorG() const { return events[editedCategory].edgeOuterColor.g; } void setEdgeOuterColorB(float value); - float getEdgeOuterColorB() const { return edgeOuterColor[editedCategory].b; } + float getEdgeOuterColorB() const { return events[editedCategory].edgeOuterColor.b; } void setEdgeOuterIntensity(float value); - float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } + float getEdgeOuterIntensity() const { return events[editedCategory].edgeOuterColor.a; } void setTiming(int value); - int getTiming() const { return timing[editedCategory]; } + int getTiming() const { return events[editedCategory].timing; } bool manualFade{ false }; float manualThreshold{ 0.f }; int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; - glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]; - glm::vec3 noiseSpeed[EVENT_CATEGORY_COUNT]; - float noiseLevel[EVENT_CATEGORY_COUNT]; - glm::vec3 baseSize[EVENT_CATEGORY_COUNT]; - float baseLevel[EVENT_CATEGORY_COUNT]; - bool _isInverted[EVENT_CATEGORY_COUNT]; - float _duration[EVENT_CATEGORY_COUNT]; - float edgeWidth[EVENT_CATEGORY_COUNT]; - glm::vec4 edgeInnerColor[EVENT_CATEGORY_COUNT]; - glm::vec4 edgeOuterColor[EVENT_CATEGORY_COUNT]; - int timing[EVENT_CATEGORY_COUNT]; + + struct Event { + glm::vec4 edgeInnerColor; + glm::vec4 edgeOuterColor; + glm::vec3 noiseSize; + glm::vec3 noiseSpeed; + glm::vec3 baseSize; + float noiseLevel; + float baseLevel; + float _duration; + float edgeWidth; + int timing; + bool _isInverted; + }; + + Event events[EVENT_CATEGORY_COUNT]; + + Q_INVOKABLE void save() const; + Q_INVOKABLE void load(); + + static QString eventNames[EVENT_CATEGORY_COUNT]; signals: void dirty(); diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml index da180aaefe..698b2384da 100644 --- a/scripts/developer/utilities/render/fade.qml +++ b/scripts/developer/utilities/render/fade.qml @@ -18,6 +18,7 @@ Column { property var config: Render.getConfig("RenderMainView.FadeConfigure"); property var switchConfig: Render.getConfig("RenderMainView.FadeSwitch"); spacing: 8 + Row { spacing: 8 @@ -43,6 +44,7 @@ Column { // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component // by setting the loader source to Null and then recreate it 100ms later paramWidgetLoader.sourceComponent = undefined; + postpone.interval = 100 postpone.start() } } @@ -68,6 +70,25 @@ Column { } } + Action { + id: saveAction + text: "Save" + onTriggered: { + root.config.save() + } + } + Action { + id: loadAction + text: "Load" + onTriggered: { + root.config.load() + // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component + // by setting the loader source to Null and then recreate it 500ms later + paramWidgetLoader.sourceComponent = undefined; + postpone.interval = 500 + postpone.start() + } + } Component { id: paramWidgets @@ -277,81 +298,94 @@ Column { } } - GroupBox { - title: "Timing" - width: 450 - Column { - spacing: 8 + Column { + GroupBox { + title: "Timing" + width: 450 + Column { + spacing: 8 - ConfigSlider { - label: "Duration" - integral: false - config: root.config - property: "duration" - max: 10.0 - min: 0.1 - width: 400 - } - ComboBox { - width: 400 - model: ["Linear", "Ease In", "Ease Out", "Ease In / Out"] - onCurrentIndexChanged: { - root.config["timing"] = currentIndex; + ConfigSlider { + label: "Duration" + integral: false + config: root.config + property: "duration" + max: 10.0 + min: 0.1 + width: 400 } - } - GroupBox { - title: "Noise Animation" - Column { - spacing: 8 - ConfigSlider { - label: "Speed X" - integral: false - config: root.config - property: "noiseSpeedX" - max: 1.0 - min: -1.0 - width: 400 - } - ConfigSlider { - label: "Speed Y" - integral: false - config: root.config - property: "noiseSpeedY" - max: 1.0 - min: -1.0 - width: 400 - } - ConfigSlider { - label: "Speed Z" - integral: false - config: root.config - property: "noiseSpeedZ" - max: 1.0 - min: -1.0 - width: 400 + ComboBox { + width: 400 + model: ["Linear", "Ease In", "Ease Out", "Ease In / Out"] + currentIndex: root.config["timing"] + onCurrentIndexChanged: { + root.config["timing"] = currentIndex; } } - } - - PlotPerf { - title: "Threshold" - height: parent.evalEvenHeight() - object: Render.getConfig("RenderMainView.DrawFadeOpaque") - valueUnit: "%" - valueScale: 0.01 - valueNumDigits: "1" - plots: [ - { - prop: "threshold", - label: "Threshold", - color: "#FFBB77" + GroupBox { + title: "Noise Animation" + Column { + spacing: 8 + ConfigSlider { + label: "Speed X" + integral: false + config: root.config + property: "noiseSpeedX" + max: 1.0 + min: -1.0 + width: 400 + } + ConfigSlider { + label: "Speed Y" + integral: false + config: root.config + property: "noiseSpeedY" + max: 1.0 + min: -1.0 + width: 400 + } + ConfigSlider { + label: "Speed Z" + integral: false + config: root.config + property: "noiseSpeedZ" + max: 1.0 + min: -1.0 + width: 400 + } } - ] - } + } + PlotPerf { + title: "Threshold" + height: parent.evalEvenHeight() + object: Render.getConfig("RenderMainView.DrawFadeOpaque") + valueUnit: "%" + valueScale: 0.01 + valueNumDigits: "1" + plots: [ + { + prop: "threshold", + label: "Threshold", + color: "#FFBB77" + } + ] + } + + } } - } + Row { + spacing: 8 + Button { + action: saveAction + } + Button { + action: loadAction + } + } + + } } } } From 704effc0a6a75b3873c693d22ec826aeba8654d5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 17:38:45 +0200 Subject: [PATCH 35/38] Added cubic interpolation in noise for rounder effect --- libraries/render-utils/src/Fade.slh | 3 +++ libraries/render-utils/src/FadeEffect.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index d3ab532650..28fe718942 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -54,6 +54,9 @@ float evalFadeNoiseGradient(vec3 position) { vec3 noisePosition = position * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.xyz + fadeNoiseOffset; vec3 noisePositionFloored = floor(noisePosition); vec3 noisePositionFraction = fract(noisePosition); + + noisePositionFraction = noisePositionFraction*noisePositionFraction*(3 - 2*noisePositionFraction); + float noiseLowXLowYLowZ = noise3D(noisePositionFloored); float noiseLowXHighYLowZ = noise3D(noisePositionFloored+vec3(0,1,0)); float noiseHighXLowYLowZ = noise3D(noisePositionFloored+vec3(1,0,0)); diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index dec67dac85..f1abca434a 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -157,13 +157,13 @@ FadeJobConfig::FadeJobConfig() events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseSize = glm::vec3{ 10.f, 0.01f, 10.0f }; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseLevel = 0.7f; - events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseSpeed = glm::vec3{ 1.0f, -0.5f, 50.0f }; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].noiseSpeed = glm::vec3{ 0.0f, -0.5f, 0.0f }; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].timing = FadeJobConfig::LINEAR; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].baseSize = glm::vec3{ 10000.f, 1.0f, 10000.0f }; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].baseLevel = 1.f; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._isInverted = true; - events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._duration = 3.f; - events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeWidth = 0.329f; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._duration = 5.f; + events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeWidth = 0.229f; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeInnerColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.25f }; events[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN].edgeOuterColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f }; From 45342a00fd248d26573b78e5967624071508e562 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 17:45:32 +0200 Subject: [PATCH 36/38] Forced faded objects to double sided (without correct lighting for the moment) --- libraries/render-utils/src/FadeEffect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index f1abca434a..bb5e5799f6 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -625,6 +625,7 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const render::ShapeKey::Builder defaultKeyBuilder; defaultKeyBuilder.withFade(); + defaultKeyBuilder.withoutCullFace(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; From 23bfc2c13d9b87848c056f5e41de474d061840bf Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 4 Jul 2017 18:36:54 +0200 Subject: [PATCH 37/38] Fixed compilation on mac and linux --- libraries/render-utils/src/FadeEffect.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index bb5e5799f6..fcc6a52b8c 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -1,5 +1,6 @@ #include "FadeEffect.h" #include "TextureCache.h" +#include "Logging.h" #include #include @@ -694,17 +695,17 @@ float FadeRenderJob::computeElementEnterThreshold(double time, const double peri if (fraction < 1.0) { switch (timing) { default: - fadeAlpha = fraction; + fadeAlpha = (float)fraction; break; case FadeJobConfig::EASE_IN: - fadeAlpha = fraction*fraction*fraction; + fadeAlpha = (float)(fraction*fraction*fraction); break; case FadeJobConfig::EASE_OUT: - fadeAlpha = 1.f - fraction; + fadeAlpha = 1.f - (float)fraction; fadeAlpha = 1.f- fadeAlpha*fadeAlpha*fadeAlpha; break; case FadeJobConfig::EASE_IN_OUT: - fadeAlpha = fraction*fraction*fraction*(fraction*(fraction * 6 - 15) + 10); + fadeAlpha = (float)(fraction*fraction*fraction*(fraction*(fraction * 6 - 15) + 10)); break; } } From b1b11ec756ccdc75b6bfde884de66394f24c110c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 5 Jul 2017 09:08:51 +0200 Subject: [PATCH 38/38] Correct fix for mac and linux due to multiple Logging.h files --- libraries/render-utils/src/FadeEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index fcc6a52b8c..3ffb54f2a2 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -1,6 +1,6 @@ #include "FadeEffect.h" #include "TextureCache.h" -#include "Logging.h" +#include "render/Logging.h" #include #include