From dbf0b64dfbc2ce7c34adc7b34bf2d8d08387db13 Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Tue, 18 Jul 2017 12:49:34 +0200
Subject: [PATCH] Refactored Fade.slh to take into account differences between
 instanced draw and normal draw

---
 .../src/RenderablePolyVoxEntityItem.cpp       |   4 +-
 .../src/RenderableShapeEntityItem.cpp         |  26 +++-
 .../entities-renderer/src/polyvox_fade.slf    |   5 +-
 libraries/render-utils/src/Fade.slh           | 115 +++++++++++++----
 libraries/render-utils/src/FadeEffect.cpp     |  72 ++++++++---
 libraries/render-utils/src/FadeEffect.h       |  20 ++-
 libraries/render-utils/src/GeometryCache.cpp  | 119 ++++++++++++++++--
 libraries/render-utils/src/GeometryCache.h    |  12 ++
 .../render-utils/src/RenderDeferredTask.cpp   |   2 +-
 libraries/render-utils/src/model_fade.slf     |   4 +-
 .../render-utils/src/model_lightmap_fade.slf  |   4 +-
 .../src/model_lightmap_normal_map_fade.slf    |   4 +-
 ...odel_lightmap_normal_specular_map_fade.slf |   4 +-
 .../src/model_lightmap_specular_map_fade.slf  |   4 +-
 .../src/model_normal_map_fade.slf             |   4 +-
 .../src/model_normal_specular_map_fade.slf    |   4 +-
 .../render-utils/src/model_shadow_fade.slf    |   5 +-
 .../src/model_specular_map_fade.slf           |   4 +-
 .../src/model_translucent_fade.slf            |   4 +-
 .../src/model_translucent_unlit_fade.slf      |   4 +-
 .../render-utils/src/model_unlit_fade.slf     |   4 +-
 libraries/render-utils/src/simple_fade.slf    |   6 +-
 libraries/render-utils/src/simple_fade.slv    |   4 +
 .../render-utils/src/simple_textured_fade.slf |   6 +-
 .../src/simple_textured_unlit_fade.slf        |   6 +-
 .../src/simple_transparent_textured_fade.slf  |   6 +-
 ...simple_transparent_textured_unlit_fade.slf |   6 +-
 .../src/skin_model_shadow_fade.slf            |   5 +-
 28 files changed, 378 insertions(+), 85 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index a717005f97..602f09b466 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -865,10 +865,10 @@ render::ShapePipelinePointer PolyVoxPayload::shapePipelineFactory(const render::
     if (key.isFaded()) {
         const auto& fadeEffect = DependencyManager::get<FadeEffect>();
         if (key.isWireframe()) {
-            return std::make_shared<render::ShapePipeline>(_wireframePipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemSetter());
+            return std::make_shared<render::ShapePipeline>(_wireframePipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
         }
         else {
-            return std::make_shared<render::ShapePipeline>(_pipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemSetter());
+            return std::make_shared<render::ShapePipeline>(_pipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
         }
     }
     else {
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index 7462d45968..4424d3aa17 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -19,6 +19,7 @@
 
 #include <render-utils/simple_vert.h>
 #include <render-utils/simple_frag.h>
+#include <FadeEffect.h>
 
 // Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1 
 // is a half unit sphere.  However, the geometry cache renders a UNIT sphere, so we need to scale down.
@@ -160,10 +161,29 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
         
         assert(args->_shapePipeline != nullptr);
 
-        if (shapeKey.isWireframe()) {
-            geometryCache->renderWireShapeInstance(args, batch, MAPPING[_shape], color, args->_shapePipeline);
+        if (shapeKey.isFaded()) {
+            auto fadeEffect = DependencyManager::get<FadeEffect>();
+            auto fadeCategory = fadeEffect->getLastCategory();
+            auto fadeThreshold = fadeEffect->getLastThreshold();
+            auto fadeNoiseOffset = fadeEffect->getLastNoiseOffset();
+            auto fadeBaseOffset = fadeEffect->getLastBaseOffset();
+            auto fadeBaseInvSize = fadeEffect->getLastBaseInvSize();
+
+            if (shapeKey.isWireframe()) {
+                geometryCache->renderWireFadeShapeInstance(args, batch, MAPPING[_shape], color, fadeCategory, fadeThreshold,
+                    fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, args->_shapePipeline);
+            }
+            else {
+                geometryCache->renderSolidFadeShapeInstance(args, batch, MAPPING[_shape], color, fadeCategory, fadeThreshold,
+                    fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, args->_shapePipeline);
+            }
         } else {
-            geometryCache->renderSolidShapeInstance(args, batch, MAPPING[_shape], color, args->_shapePipeline);
+            if (shapeKey.isWireframe()) {
+                geometryCache->renderWireShapeInstance(args, batch, MAPPING[_shape], color, args->_shapePipeline);
+            }
+            else {
+                geometryCache->renderSolidShapeInstance(args, batch, MAPPING[_shape], color, args->_shapePipeline);
+            }
         }
     }
 
diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf
index 7aac6049e3..ad4950f64c 100644
--- a/libraries/entities-renderer/src/polyvox_fade.slf
+++ b/libraries/entities-renderer/src/polyvox_fade.slf
@@ -30,7 +30,10 @@ uniform vec3 voxelVolumeSize;
 
 void main(void) {
     vec3    emissive;
-    applyFade(_worldPosition.xyz, emissive);
+    FadeObjectParams fadeParams;
+
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, emissive);
 
     vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
     worldNormal = normalize(worldNormal);
diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh
index 488964f843..6b801d0746 100644
--- a/libraries/render-utils/src/Fade.slh
+++ b/libraries/render-utils/src/Fade.slh
@@ -9,7 +9,7 @@
 <@if not FADE_SLH@>
 <@def FADE_SLH@>
 
-<@func declareFadeFragment()@>
+<@func declareFadeFragmentCommon()@>
 
 
 #define CATEGORY_COUNT    5
@@ -19,25 +19,28 @@
 uniform fadeParametersBuffer {
     FadeParameters fadeParameters[CATEGORY_COUNT];
 };
-uniform int fadeCategory;
-uniform vec3 fadeNoiseOffset;
-uniform vec3 fadeBaseOffset;
-uniform vec3 fadeBaseInvSize;
-uniform float fadeThreshold;
 uniform sampler2D fadeMaskMap;
 
+struct FadeObjectParams {
+    int category;
+    float threshold;
+    vec3 noiseOffset;
+    vec3 baseOffset;
+    vec3 baseInvSize;
+};
+
 vec2 hash2D(vec3 position) {
     return position.xy* vec2(0.1677,  0.221765) + position.z*0.561;
 }
 
 float noise3D(vec3 position) {
     float n = textureLod(fadeMaskMap, hash2D(position), 0).r;
-    return pow(n, 1.0/2.2); // Need to fix this later directly in the texture
+    return pow(n, 1.0/2.2); // Remove sRGB. Need to fix this later directly in the texture
 }
 
-float evalFadeNoiseGradient(vec3 position) {
+float evalFadeNoiseGradient(FadeObjectParams params, vec3 position) {
     // Do tri-linear interpolation
-    vec3    noisePosition = position * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.xyz + fadeNoiseOffset;
+    vec3    noisePosition = position * fadeParameters[params.category]._noiseInvSizeAndLevel.xyz + params.noiseOffset;
     vec3    noisePositionFloored = floor(noisePosition);
     vec3    noisePositionFraction = fract(noisePosition);
 
@@ -58,39 +61,37 @@ float evalFadeNoiseGradient(vec3 position) {
 
     float noise = mix(maskY.x, maskY.y, noisePositionFraction.y);
     noise -= 0.5;   // Center on value 0
-    return noise * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.w;
+    return noise * fadeParameters[params.category]._noiseInvSizeAndLevel.w;
 }
 
-float evalFadeBaseGradient(vec3 position) {
-    float gradient = length((position - fadeBaseOffset) * fadeBaseInvSize.xyz);
+float evalFadeBaseGradient(FadeObjectParams params, vec3 position) {
+    float gradient = length((position - params.baseOffset) * params.baseInvSize.xyz);
     gradient = gradient-0.5;  // Center on value 0.5
-    gradient *= fadeParameters[fadeCategory]._baseLevel;
+    gradient *= fadeParameters[params.category]._baseLevel;
     return gradient;
 }
 
-float evalFadeGradient(vec3 position) {
-    float baseGradient = evalFadeBaseGradient(position);
-    float noiseGradient = evalFadeNoiseGradient(position);
+float evalFadeGradient(FadeObjectParams params, vec3 position) {
+    float baseGradient = evalFadeBaseGradient(params, position);
+    float noiseGradient = evalFadeNoiseGradient(params, position);
     float gradient = noiseGradient+baseGradient+0.5;
 
     return gradient;
 }
 
-float evalFadeAlpha(vec3 position) {
-    float  cutoff = fadeThreshold;
-
-    return evalFadeGradient(position)-cutoff;
+float evalFadeAlpha(FadeObjectParams params, vec3 position) {
+    return evalFadeGradient(params, position)-params.threshold;
 }
 
-void applyFadeClip(vec3 position) {
-    if (evalFadeAlpha(position) < 0) {
+void applyFadeClip(FadeObjectParams params, vec3 position) {
+    if (evalFadeAlpha(params, position) < 0) {
         discard;
     }
 }
 
-void applyFade(vec3 position, out vec3 emissive) {
-    float alpha = evalFadeAlpha(position);
-    if (fadeParameters[fadeCategory]._isInverted!=0) {
+void applyFade(FadeObjectParams params, vec3 position, out vec3 emissive) {
+    float alpha = evalFadeAlpha(params, position);
+    if (fadeParameters[params.category]._isInverted!=0) {
         alpha = -alpha;
     }
 
@@ -98,15 +99,75 @@ void applyFade(vec3 position, out vec3 emissive) {
         discard;
     }
     
-    float edgeMask = alpha * fadeParameters[fadeCategory]._edgeWidthInvWidth.y;
+    float edgeMask = alpha * fadeParameters[params.category]._edgeWidthInvWidth.y;
     float edgeAlpha = 1.0-clamp(edgeMask, 0, 1);
 
     edgeMask = step(edgeMask, 1.f);
     edgeAlpha *= edgeAlpha; // Square to have a nice ease out
-    vec4 color = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha);
+    vec4 color = mix(fadeParameters[params.category]._innerEdgeColor, fadeParameters[params.category]._outerEdgeColor, edgeAlpha);
     emissive = color.rgb * edgeMask * color.a;
 }
 
 <@endfunc@>
 
+<@func declareFadeFragmentUniform()@>
+
+uniform int fadeCategory;
+uniform vec3 fadeNoiseOffset;
+uniform vec3 fadeBaseOffset;
+uniform vec3 fadeBaseInvSize;
+uniform float fadeThreshold;
+
+<@endfunc@>
+
+<@func fetchFadeObjectParams(fadeParams)@>
+    <$fadeParams$>.category = fadeCategory;
+    <$fadeParams$>.threshold = fadeThreshold;
+    <$fadeParams$>.noiseOffset = fadeNoiseOffset;
+    <$fadeParams$>.baseOffset = fadeBaseOffset;
+    <$fadeParams$>.baseInvSize = fadeBaseInvSize;
+<@endfunc@>
+
+<@func declareFadeFragmentVertexInput()@>
+
+in vec4 _fadeData1;
+in vec4 _fadeData2;
+in vec4 _fadeData3;
+
+<@endfunc@>
+
+<@func fetchFadeObjectParamsInstanced(fadeParams)@>
+    <$fadeParams$>.category = int(_fadeData1.w);
+    <$fadeParams$>.threshold = _fadeData2.w;
+    <$fadeParams$>.noiseOffset = _fadeData1.xyz;
+    <$fadeParams$>.baseOffset = _fadeData2.xyz;
+    <$fadeParams$>.baseInvSize = _fadeData3.xyz;
+<@endfunc@>
+
+<@func declareFadeFragment()@>
+<$declareFadeFragmentCommon()$>
+<$declareFadeFragmentUniform()$>
+<@endfunc@>
+
+<@func declareFadeFragmentInstanced()@>
+<$declareFadeFragmentCommon()$>
+<$declareFadeFragmentVertexInput()$>
+<@endfunc@>
+
+<@func declareFadeVertexInstanced()@>
+in vec4 _texCoord2;
+in vec4 _texCoord3;
+in vec4 _texCoord4;
+
+out vec4 _fadeData1;
+out vec4 _fadeData2;
+out vec4 _fadeData3;
+<@endfunc@>
+
+<@func passThroughFadeObjectParams()@>
+    _fadeData1 = _texCoord2;
+    _fadeData2 = _texCoord3;
+    _fadeData3 = _texCoord4;    
+<@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 aec19ce32f..d8e7b5c9b1 100644
--- a/libraries/render-utils/src/FadeEffect.cpp
+++ b/libraries/render-utils/src/FadeEffect.cpp
@@ -39,35 +39,67 @@ render::ShapePipeline::BatchSetter FadeEffect::getBatchSetter() const {
     };
 }
 
-render::ShapePipeline::ItemSetter FadeEffect::getItemSetter() const {
+render::ShapePipeline::ItemSetter FadeEffect::getItemUniformSetter() const {
     return [](const render::ShapePipeline& shapePipeline, render::Args* args, const render::Item& item) {
         if (!render::TransitionStage::isIndexInvalid(item.getTransitionId())) {
             auto scene = args->_scene;
             auto batch = args->_batch;
             auto transitionStage = scene->getStage<render::TransitionStage>(render::TransitionStage::getName());
             auto& transitionState = transitionStage->getTransition(item.getTransitionId());
-            render::ShapeKey shapeKey(args->_globalShapeKey);
+            auto program = shapePipeline.pipeline->getProgram();
+            auto& uniforms = program->getUniforms();
+            auto fadeNoiseOffsetLocation = uniforms.findLocation("fadeNoiseOffset");
+            auto fadeBaseOffsetLocation = uniforms.findLocation("fadeBaseOffset");
+            auto fadeBaseInvSizeLocation = uniforms.findLocation("fadeBaseInvSize");
+            auto fadeThresholdLocation = uniforms.findLocation("fadeThreshold");
+            auto fadeCategoryLocation = uniforms.findLocation("fadeCategory");
 
-            // This is the normal case where we need to push the parameters in uniforms
-            {
-                auto program = shapePipeline.pipeline->getProgram();
-                auto& uniforms = program->getUniforms();
-                auto fadeNoiseOffsetLocation = uniforms.findLocation("fadeNoiseOffset");
-                auto fadeBaseOffsetLocation = uniforms.findLocation("fadeBaseOffset");
-                auto fadeBaseInvSizeLocation = uniforms.findLocation("fadeBaseInvSize");
-                auto fadeThresholdLocation = uniforms.findLocation("fadeThreshold");
-                auto fadeCategoryLocation = uniforms.findLocation("fadeCategory");
+            if (fadeNoiseOffsetLocation >= 0 || fadeBaseInvSizeLocation >= 0 || fadeBaseOffsetLocation >= 0 || fadeThresholdLocation >= 0 || fadeCategoryLocation >= 0) {
+                const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
 
-                if (fadeNoiseOffsetLocation >= 0 || fadeBaseInvSizeLocation >= 0 || fadeBaseOffsetLocation >= 0 || fadeThresholdLocation >= 0 || fadeCategoryLocation >= 0) {
-                    const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
-
-                    batch->_glUniform1i(fadeCategoryLocation, fadeCategory);
-                    batch->_glUniform1f(fadeThresholdLocation, transitionState.threshold);
-                    batch->_glUniform3f(fadeNoiseOffsetLocation, transitionState.noiseOffset.x, transitionState.noiseOffset.y, transitionState.noiseOffset.z);
-                    batch->_glUniform3f(fadeBaseOffsetLocation, transitionState.baseOffset.x, transitionState.baseOffset.y, transitionState.baseOffset.z);
-                    batch->_glUniform3f(fadeBaseInvSizeLocation, transitionState.baseInvSize.x, transitionState.baseInvSize.y, transitionState.baseInvSize.z);
-                }
+                batch->_glUniform1i(fadeCategoryLocation, fadeCategory);
+                batch->_glUniform1f(fadeThresholdLocation, transitionState.threshold);
+                batch->_glUniform3f(fadeNoiseOffsetLocation, transitionState.noiseOffset.x, transitionState.noiseOffset.y, transitionState.noiseOffset.z);
+                batch->_glUniform3f(fadeBaseOffsetLocation, transitionState.baseOffset.x, transitionState.baseOffset.y, transitionState.baseOffset.z);
+                batch->_glUniform3f(fadeBaseInvSizeLocation, transitionState.baseInvSize.x, transitionState.baseInvSize.y, transitionState.baseInvSize.z);
             }
         }
     };
 }
+
+render::ShapePipeline::ItemSetter FadeEffect::getItemStoredSetter() {
+    return [this](const render::ShapePipeline& shapePipeline, render::Args* args, const render::Item& item) {
+        if (!render::TransitionStage::isIndexInvalid(item.getTransitionId())) {
+            auto scene = args->_scene;
+            auto batch = args->_batch;
+            auto transitionStage = scene->getStage<render::TransitionStage>(render::TransitionStage::getName());
+            auto& transitionState = transitionStage->getTransition(item.getTransitionId());
+            const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
+
+            _lastCategory = fadeCategory;
+            _lastThreshold = transitionState.threshold;
+            _lastNoiseOffset = transitionState.noiseOffset;
+            _lastBaseOffset = transitionState.baseOffset;
+            _lastBaseInvSize = transitionState.baseInvSize;
+        }
+    };
+}
+
+void FadeEffect::packToAttributes(const int category, const float threshold, const glm::vec3& noiseOffset,
+    const glm::vec3& baseOffset, const glm::vec3& baseInvSize,
+    glm::vec4& packedData1, glm::vec4& packedData2, glm::vec4& packedData3) {
+    packedData1.x = noiseOffset.x;
+    packedData1.y = noiseOffset.y;
+    packedData1.z = noiseOffset.z;
+    packedData1.w = (float)category;
+
+    packedData2.x = baseOffset.x;
+    packedData2.y = baseOffset.y;
+    packedData2.z = baseOffset.z;
+    packedData2.w = threshold;
+
+    packedData3.x = baseInvSize.x;
+    packedData3.y = baseInvSize.y;
+    packedData3.z = baseInvSize.z;
+    packedData3.w = 0.f;
+}
diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h
index 8677609892..4b4e401332 100644
--- a/libraries/render-utils/src/FadeEffect.h
+++ b/libraries/render-utils/src/FadeEffect.h
@@ -22,13 +22,31 @@ public:
     void build(render::Task::TaskConcept& task, const task::Varying& editableItems);
 
     render::ShapePipeline::BatchSetter getBatchSetter() const;
-    render::ShapePipeline::ItemSetter getItemSetter() const;
+    render::ShapePipeline::ItemSetter getItemUniformSetter() const;
+    render::ShapePipeline::ItemSetter getItemStoredSetter();
+
+    int getLastCategory() const { return _lastCategory; }
+    float getLastThreshold() const { return _lastThreshold; }
+    const glm::vec3& getLastNoiseOffset() const { return _lastNoiseOffset; }
+    const glm::vec3& getLastBaseOffset() const { return _lastBaseOffset; }
+    const glm::vec3& getLastBaseInvSize() const { return _lastBaseInvSize; }
+
+    static void packToAttributes(const int category, const float threshold, const glm::vec3& noiseOffset,
+        const glm::vec3& baseOffset, const glm::vec3& baseInvSize,
+        glm::vec4& packedData1, glm::vec4& packedData2, glm::vec4& packedData3);
 
 private:
 
     gpu::BufferView _configurations;
     gpu::TexturePointer _maskMap;
 
+    // The last fade set through the stored item setter
+    int _lastCategory { 0 };
+    float _lastThreshold { 0.f };
+    glm::vec3 _lastNoiseOffset { 0.f, 0.f, 0.f };
+    glm::vec3 _lastBaseOffset { 0.f, 0.f, 0.f };
+    glm::vec3 _lastBaseInvSize { 1.f, 1.f, 1.f };
+
 	explicit FadeEffect();
 	virtual ~FadeEffect() { }
 
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index 9e97540d53..7a68baa978 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -60,9 +60,11 @@ static const int VERTICES_PER_TRIANGLE = 3;
 static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
 static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
 static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
+static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::HALF, gpu::XYZW };
 
 static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
 static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
+static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
 
 static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
 static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
@@ -451,6 +453,19 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
     return INSTANCED_SOLID_STREAM_FORMAT;
 }
 
+gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
+    if (!INSTANCED_SOLID_FADE_STREAM_FORMAT) {
+        INSTANCED_SOLID_FADE_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
+        INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
+        INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
+        INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
+        INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD2, gpu::Stream::TEXCOORD2, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
+        INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD3, gpu::Stream::TEXCOORD3, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
+        INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD4, gpu::Stream::TEXCOORD4, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
+    }
+    return INSTANCED_SOLID_FADE_STREAM_FORMAT;
+}
+
 QHash<SimpleProgramKey, gpu::PipelinePointer> GeometryCache::_simplePrograms;
 
 gpu::ShaderPointer GeometryCache::_simpleShader;
@@ -535,11 +550,6 @@ void GeometryCache::releaseID(int id) {
     _registeredGridBuffers.remove(id);
 }
 
-void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) {
-    gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
-    batch.setInputBuffer(gpu::Stream::COLOR, colorView);
-}
-
 void GeometryCache::initializeShapePipelines() {
     if (!_simpleOpaquePipeline) {
         _simpleOpaquePipeline = getShapePipeline(false, false, true, false);
@@ -564,7 +574,7 @@ render::ShapePipelinePointer GeometryCache::getFadingShapePipeline(bool textured
     bool unlit, bool depthBias) {
     auto fadeEffect = DependencyManager::get<FadeEffect>();
     auto fadeBatchSetter = fadeEffect->getBatchSetter();
-    auto fadeItemSetter = fadeEffect->getItemSetter();
+    auto fadeItemSetter = fadeEffect->getItemStoredSetter();
     return std::make_shared<render::ShapePipeline>(getSimplePipeline(textured, transparent, culled, unlit, depthBias, true), nullptr,
         [fadeBatchSetter, fadeItemSetter](const render::ShapePipeline& shapePipeline, gpu::Batch& batch, render::Args* args) {
             batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get<TextureCache>()->getWhiteTexture());
@@ -592,6 +602,11 @@ void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) {
     _shapes[shape].drawWire(batch);
 }
 
+void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) {
+    gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
+    batch.setInputBuffer(gpu::Stream::COLOR, colorView);
+}
+
 void GeometryCache::renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer) {
     batch.setInputFormat(getInstancedSolidStreamFormat());
     setupBatchInstance(batch, colorBuffer);
@@ -604,6 +619,32 @@ void GeometryCache::renderWireShapeInstances(gpu::Batch& batch, Shape shape, siz
     _shapes[shape].drawWireInstances(batch, count);
 }
 
+void setupBatchFadeInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer, 
+    gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3) {
+    gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
+    gpu::BufferView texCoord2View(fadeBuffer1, TEXCOORD4_ELEMENT);
+    gpu::BufferView texCoord3View(fadeBuffer2, TEXCOORD4_ELEMENT);
+    gpu::BufferView texCoord4View(fadeBuffer3, TEXCOORD4_ELEMENT);
+    batch.setInputBuffer(gpu::Stream::COLOR, colorView);
+    batch.setInputBuffer(gpu::Stream::TEXCOORD2, texCoord2View);
+    batch.setInputBuffer(gpu::Stream::TEXCOORD3, texCoord3View);
+    batch.setInputBuffer(gpu::Stream::TEXCOORD4, texCoord4View);
+}
+
+void GeometryCache::renderFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
+    gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3) {
+    batch.setInputFormat(getInstancedSolidFadeStreamFormat());
+    setupBatchFadeInstance(batch, colorBuffer, fadeBuffer1, fadeBuffer2, fadeBuffer3);
+    _shapes[shape].drawInstances(batch, count);
+}
+
+void GeometryCache::renderWireFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
+    gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3) {
+    batch.setInputFormat(getInstancedSolidFadeStreamFormat());
+    setupBatchFadeInstance(batch, colorBuffer, fadeBuffer1, fadeBuffer2, fadeBuffer3);
+    _shapes[shape].drawWireInstances(batch, count);
+}
+
 void GeometryCache::renderCube(gpu::Batch& batch) {
     renderShape(batch, Cube);
 }
@@ -2046,12 +2087,62 @@ void renderInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color
 
         if (isWire) {
             DependencyManager::get<GeometryCache>()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]);
-        } else {
+        }
+        else {
             DependencyManager::get<GeometryCache>()->renderShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]);
         }
     });
 }
 
+static const size_t INSTANCE_FADE_BUFFER1 = 1;
+static const size_t INSTANCE_FADE_BUFFER2 = 2;
+static const size_t INSTANCE_FADE_BUFFER3 = 3;
+
+void renderFadeInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, int fadeCategory, float fadeThreshold,
+    const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize, bool isWire,
+    const render::ShapePipelinePointer& pipeline, GeometryCache::Shape shape) {
+    // Add pipeline to name
+    std::string instanceName = (isWire ? "wire_fade_shapes_" : "solid_fade_shapes_") + std::to_string(shape) + "_" + std::to_string(std::hash<render::ShapePipelinePointer>()(pipeline));
+
+    // Add color to named buffer
+    {
+        gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(instanceName, INSTANCE_COLOR_BUFFER);
+        auto compactColor = toCompactColor(color);
+        instanceColorBuffer->append(compactColor);
+    }
+    // Add fade parameters to named buffers
+    {
+        gpu::BufferPointer fadeBuffer1 = batch.getNamedBuffer(instanceName, INSTANCE_FADE_BUFFER1);
+        gpu::BufferPointer fadeBuffer2 = batch.getNamedBuffer(instanceName, INSTANCE_FADE_BUFFER2);
+        gpu::BufferPointer fadeBuffer3 = batch.getNamedBuffer(instanceName, INSTANCE_FADE_BUFFER3);
+        // Pack parameters in 3 vec4s
+        glm::vec4 fadeData1;
+        glm::vec4 fadeData2;
+        glm::vec4 fadeData3;
+        FadeEffect::packToAttributes(fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize,
+            fadeData1, fadeData2, fadeData3);
+        fadeBuffer1->append(fadeData1);
+        fadeBuffer2->append(fadeData2);
+        fadeBuffer3->append(fadeData3);
+    }
+
+    // Add call to named buffer
+    batch.setupNamedCalls(instanceName, [args, isWire, pipeline, shape](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
+        auto& buffers = data.buffers;
+        batch.setPipeline(pipeline->pipeline);
+        pipeline->prepare(batch, args);
+
+        if (isWire) {
+            DependencyManager::get<GeometryCache>()->renderWireFadeShapeInstances(batch, shape, data.count(), 
+                buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]);
+        }
+        else {
+            DependencyManager::get<GeometryCache>()->renderFadeShapeInstances(batch, shape, data.count(), 
+                buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]);
+        }
+    });
+}
+
 void GeometryCache::renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
     assert(pipeline != nullptr);
     renderInstances(args, batch, color, false, pipeline, shape);
@@ -2062,6 +2153,20 @@ void GeometryCache::renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch,
     renderInstances(args, batch, color, true, pipeline, shape);
 }
 
+void GeometryCache::renderSolidFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, 
+    int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize, 
+    const render::ShapePipelinePointer& pipeline) {
+    assert(pipeline != nullptr);
+    renderFadeInstances(args, batch, color, fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, false, pipeline, shape);
+}
+
+void GeometryCache::renderWireFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, 
+    int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize, 
+    const render::ShapePipelinePointer& pipeline) {
+    assert(pipeline != nullptr);
+    renderFadeInstances(args, batch, color, fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, true, pipeline, shape);
+}
+
 void GeometryCache::renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
     assert(pipeline != nullptr);
     renderInstances(args, batch, color, false, pipeline, GeometryCache::Sphere);
diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h
index 46d74a9bb4..40aa829444 100644
--- a/libraries/render-utils/src/GeometryCache.h
+++ b/libraries/render-utils/src/GeometryCache.h
@@ -187,6 +187,11 @@ public:
     void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
     void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
 
+    void renderFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
+        gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3);
+    void renderWireFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
+        gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3);
+
     void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
                                     const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
     void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec3& color,
@@ -201,6 +206,13 @@ public:
         renderWireShapeInstance(args, batch, shape, glm::vec4(color, 1.0f), pipeline);
     }
 
+    void renderSolidFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color, int fadeCategory, float fadeThreshold,
+        const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
+        const render::ShapePipelinePointer& pipeline);
+    void renderWireFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color, int fadeCategory, float fadeThreshold,
+        const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
+        const render::ShapePipelinePointer& pipeline);
+
     void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color,
                                     const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
     void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color,
diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp
index 32903ad0d2..3ce2f01705 100644
--- a/libraries/render-utils/src/RenderDeferredTask.cpp
+++ b/libraries/render-utils/src/RenderDeferredTask.cpp
@@ -62,7 +62,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
 
     // Prepare the ShapePipelines
     ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
-    initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemSetter());
+    initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
 
     // Extract opaques / transparents / lights / metas / overlays / background
     const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE];
diff --git a/libraries/render-utils/src/model_fade.slf b/libraries/render-utils/src/model_fade.slf
index 172d7ddbee..d232667660 100644
--- a/libraries/render-utils/src/model_fade.slf
+++ b/libraries/render-utils/src/model_fade.slf
@@ -31,8 +31,10 @@ in vec2 _texCoord1;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     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
index 7ca5fc0a22..92d00a2046 100644
--- a/libraries/render-utils/src/model_lightmap_fade.slf
+++ b/libraries/render-utils/src/model_lightmap_fade.slf
@@ -32,8 +32,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
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 82c5a11529..825e84d666 100644
--- a/libraries/render-utils/src/model_lightmap_normal_map_fade.slf
+++ b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf
@@ -33,8 +33,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
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 7314753ae6..791d5bf552 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
@@ -33,8 +33,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
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 e17512fe7f..e82018eefb 100644
--- a/libraries/render-utils/src/model_lightmap_specular_map_fade.slf
+++ b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf
@@ -32,8 +32,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf
index 6134e871da..d8b864260c 100644
--- a/libraries/render-utils/src/model_normal_map_fade.slf
+++ b/libraries/render-utils/src/model_normal_map_fade.slf
@@ -32,8 +32,10 @@ in vec3 _color;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.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 59ee0e9927..5492b24763 100644
--- a/libraries/render-utils/src/model_normal_specular_map_fade.slf
+++ b/libraries/render-utils/src/model_normal_specular_map_fade.slf
@@ -32,8 +32,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
diff --git a/libraries/render-utils/src/model_shadow_fade.slf b/libraries/render-utils/src/model_shadow_fade.slf
index a697ba4f12..c00eed622c 100644
--- a/libraries/render-utils/src/model_shadow_fade.slf
+++ b/libraries/render-utils/src/model_shadow_fade.slf
@@ -20,7 +20,10 @@ layout(location = 0) out vec4 _fragColor;
 in vec4 _worldPosition;
 
 void main(void) {
-    applyFadeClip(_worldPosition.xyz);
+    FadeObjectParams fadeParams;
+
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFadeClip(fadeParams, _worldPosition.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 a43027a034..6eb56c0929 100644
--- a/libraries/render-utils/src/model_specular_map_fade.slf
+++ b/libraries/render-utils/src/model_specular_map_fade.slf
@@ -31,8 +31,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf
index cc4611586d..c46b396ebc 100644
--- a/libraries/render-utils/src/model_translucent_fade.slf
+++ b/libraries/render-utils/src/model_translucent_fade.slf
@@ -39,8 +39,10 @@ out vec4 _fragColor;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
diff --git a/libraries/render-utils/src/model_translucent_unlit_fade.slf b/libraries/render-utils/src/model_translucent_unlit_fade.slf
index cb7739d1b7..6a77efe4ca 100644
--- a/libraries/render-utils/src/model_translucent_unlit_fade.slf
+++ b/libraries/render-utils/src/model_translucent_unlit_fade.slf
@@ -30,8 +30,10 @@ out vec4 _fragColor;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
diff --git a/libraries/render-utils/src/model_unlit_fade.slf b/libraries/render-utils/src/model_unlit_fade.slf
index 179b16a3b1..0fe9f2ebac 100644
--- a/libraries/render-utils/src/model_unlit_fade.slf
+++ b/libraries/render-utils/src/model_unlit_fade.slf
@@ -30,8 +30,10 @@ in vec4 _worldPosition;
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material mat = getMaterial();
     int matKey = getMaterialKey(mat);
diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf
index 3424af15f5..245d32e81e 100644
--- a/libraries/render-utils/src/simple_fade.slf
+++ b/libraries/render-utils/src/simple_fade.slf
@@ -16,7 +16,7 @@
 <@include model/Material.slh@>
 
 <@include Fade.slh@>
-<$declareFadeFragment()$>
+<$declareFadeFragmentInstanced()$>
 
 // the interpolated normal
 in vec3 _normal;
@@ -34,8 +34,10 @@ in vec4 _worldPosition;
 #line 2030
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParamsInstanced(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     Material material = getMaterial();
     vec3 normal = normalize(_normal.xyz); 
diff --git a/libraries/render-utils/src/simple_fade.slv b/libraries/render-utils/src/simple_fade.slv
index 02f69677d3..3d9eb2c812 100644
--- a/libraries/render-utils/src/simple_fade.slv
+++ b/libraries/render-utils/src/simple_fade.slv
@@ -17,6 +17,9 @@
 <@include gpu/Transform.slh@>
 <$declareStandardTransform()$>
 
+<@include Fade.slh@>
+<$declareFadeVertexInstanced()$>
+
 // the interpolated normal
 out vec3 _normal;
 out vec3 _modelNormal;
@@ -37,4 +40,5 @@ void main(void) {
     <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
     <$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
     <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
+    <$passThroughFadeObjectParams()$>
 }
\ 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
index 659280f88b..025fe5fca6 100644
--- a/libraries/render-utils/src/simple_textured_fade.slf
+++ b/libraries/render-utils/src/simple_textured_fade.slf
@@ -28,12 +28,14 @@ in vec2 _texCoord0;
 in vec4 _worldPosition;
 
 // Declare after all samplers to prevent sampler location mix up with originalTexture
-<$declareFadeFragment()$>
+<$declareFadeFragmentInstanced()$>
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParamsInstanced(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     vec4 texel = texture(originalTexture, _texCoord0);
     float colorAlpha = _color.a;
diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf
index f3c50bef9b..6f03c6746f 100644
--- a/libraries/render-utils/src/simple_textured_unlit_fade.slf
+++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf
@@ -27,12 +27,14 @@ in vec2 _texCoord0;
 in vec4 _worldPosition;
 
 // Declare after all samplers to prevent sampler location mix up with originalTexture
-<$declareFadeFragment()$>
+<$declareFadeFragmentInstanced()$>
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParamsInstanced(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     vec4 texel = texture(originalTexture, _texCoord0.st);
     float colorAlpha = _color.a;
diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf
index 31dc6f166a..20c7907bbe 100644
--- a/libraries/render-utils/src/simple_transparent_textured_fade.slf
+++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf
@@ -34,12 +34,14 @@ in vec2 _texCoord0;
 in vec4 _worldPosition;
 
 // Declare after all samplers to prevent sampler location mix up with originalTexture
-<$declareFadeFragment()$>
+<$declareFadeFragmentInstanced()$>
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParamsInstanced(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     vec4 texel = texture(originalTexture, _texCoord0.st);
     float opacity = _color.a;
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 bd403b0634..1c42a1f724 100644
--- a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf
+++ b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf
@@ -28,12 +28,14 @@ in vec4 _worldPosition;
 layout(location = 0) out vec4 _fragColor0;
 
 // Declare after all samplers to prevent sampler location mix up with originalTexture
-<$declareFadeFragment()$>
+<$declareFadeFragmentInstanced()$>
 
 void main(void) {
     vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
 
-    applyFade(_worldPosition.xyz, fadeEmissive);
+    <$fetchFadeObjectParamsInstanced(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
 
     vec4 texel = texture(originalTexture, _texCoord0.st);
     float colorAlpha = _color.a;
diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slf b/libraries/render-utils/src/skin_model_shadow_fade.slf
index 9d720c7bee..aaf29076b8 100644
--- a/libraries/render-utils/src/skin_model_shadow_fade.slf
+++ b/libraries/render-utils/src/skin_model_shadow_fade.slf
@@ -20,7 +20,10 @@ in vec4 _worldPosition;
 layout(location = 0) out vec4 _fragColor;
 
 void main(void) {
-    applyFadeClip(_worldPosition.xyz);
+    FadeObjectParams fadeParams;
+
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFadeClip(fadeParams, _worldPosition.xyz);
 
     // pass-through to set z-buffer
     _fragColor = vec4(1.0, 1.0, 1.0, 0.0);