diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 6fbcf50482577df90f6420d297b4bf8b700eb97b..e8e4b62934d79916d3430664cd88919d0cf0cf38 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -61,6 +61,11 @@ LLMatrix3 LLGLTFMaterial::TextureTransform::asMatrix()
     return offset * rotation * scale;
 }
 
+bool LLGLTFMaterial::TextureTransform::operator==(const TextureTransform& other) const
+{
+    return mOffset == other.mOffset && mScale == other.mScale && mRotation == other.mRotation;
+}
+
 LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs)
 {
     *this = rhs;
@@ -268,16 +273,14 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
 
     tinygltf::Material& material_out = model.materials[mat_index];
 
-    constexpr bool is_override = false;
-
     // set base color texture
-    writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId, is_override, LLUUID());
+    writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId);
     // set normal texture
-    writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId, is_override, LLUUID());
+    writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId);
     // set metallic-roughness texture
-    writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId, is_override, LLUUID());
+    writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId);
     // set emissive texture
-    writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId, is_override, LLUUID());
+    writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId);
 
     material_out.alphaMode = getAlphaMode();
     material_out.alphaCutoff = mAlphaCutoff;
@@ -338,10 +341,11 @@ void gltf_allocate_texture_image(tinygltf::Model& model, T& texture_info, const
 }
 
 template<typename T>
-void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id, bool is_override, const LLUUID& base_texture_id) const
+void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id) const
 {
     LL_PROFILE_ZONE_SCOPED;
-    if (texture_id.isNull() || (is_override && texture_id == base_texture_id))
+    const TextureTransform& transform = mTextureTransform[texture_info_id];
+    if (texture_id.isNull() && transform == sDefault.mTextureTransform[0])
     {
         return;
     }
@@ -349,7 +353,6 @@ void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, Tex
     gltf_allocate_texture_image(model, texture_info, texture_id.asString());
 
     tinygltf::Value::Object transform_map;
-    const TextureTransform& transform = mTextureTransform[texture_info_id];
     transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({
         tinygltf::Value(transform.mOffset.mV[VX]),
         tinygltf::Value(transform.mOffset.mV[VY])
diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h
index 60116fd423a17b1e7b62fd68e11bed27de37b3b3..aa49a58f0c333b371dd2757b795f7bcb8fde6cff 100644
--- a/indra/llprimitive/llgltfmaterial.h
+++ b/indra/llprimitive/llgltfmaterial.h
@@ -56,6 +56,8 @@ class LLGLTFMaterial : public LLRefCount
         F32 mRotation = 0.f;
 
         LLMatrix3 asMatrix();
+
+        bool operator==(const TextureTransform& other) const;
     };
 
     enum AlphaMode
@@ -149,14 +151,14 @@ class LLGLTFMaterial : public LLRefCount
     static LLVector2 getDefaultTextureScale();
     static F32 getDefaultTextureRotation();
 
-    
+
     static void hackOverrideUUID(LLUUID& id);
     static void applyOverrideUUID(LLUUID& dst_id, const LLUUID& override_id);
 
     // set mAlphaMode from string.
     // Anything otherthan "MASK" or "BLEND" sets mAlphaMode to ALPHA_MODE_OPAQUE
     void setAlphaMode(const std::string& mode, bool for_override = false);
-   
+
     const char* getAlphaMode() const;
     
     // set the contents of this LLGLTFMaterial from the given json
@@ -185,6 +187,6 @@ class LLGLTFMaterial : public LLRefCount
     void setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id, LLUUID& texture_id_out);
 
     template<typename T>
-    void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id, bool is_override, const LLUUID& base_texture_id) const;
+    void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id) const;
 };
 
diff --git a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl
index 9172789b38d228dd541d7e667f405289e6944122..d48aeb98b6bb74bb118f72a5173aa043aa63f9ae 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl
@@ -44,8 +44,10 @@ VARYING vec3 camera_ray;
 
 uniform sampler2D depthMap;
 uniform sampler2D normalMap;
+uniform sampler2D specularRect;
 uniform sampler2D sceneMap;
 uniform sampler2D diffuseRect;
+uniform sampler2D diffuseMap;
 
 vec3 getNorm(vec2 screenpos);
 float getDepth(vec2 pos_screen);
@@ -54,45 +56,63 @@ float linearDepth01(float d, float znear, float zfar);
 
 vec4 getPositionWithDepth(vec2 pos_screen, float depth);
 vec4 getPosition(vec2 pos_screen);
-
-bool traceScreenRay(vec3 position, vec3 reflection, out vec3 hitColor, out float hitDepth, float depth, sampler2D textureFrame);
+vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
+bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame);
 float random (vec2 uv);
 void main() {
     vec2  tc = vary_fragcoord.xy;
     float depth = linearDepth01(getDepth(tc), zNear, zFar);
+    vec3 n = vec3(0, 0, 1);
+    float envIntensity;
+    vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG()
     vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz;
+    vec4 spec    = texture2D(specularRect, tc);
     vec3 viewPos = camera_ray * depth;
-    vec3 rayDirection = normalize(reflect(normalize(viewPos), getNorm(tc))) * -viewPos.z;
+    vec3 rayDirection = normalize(reflect(normalize(viewPos), n)) * -viewPos.z;
     vec2 hitpixel;
-    vec3 hitpoint;
+    vec4 hitpoint;
+    vec4 diffuse = texture2D(diffuseRect, tc);
+    vec3 specCol = spec.rgb;
+
+    if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) {
+        vec3 orm = specCol.rgb;
+        float perceptualRoughness = orm.g;
+        float metallic = orm.b;
+        vec3 f0 = vec3(0.04);
+        vec3 baseColor = diffuse.rgb;
+        
+        vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
+
+        specCol = mix(f0, baseColor.rgb, metallic);
+    }
 
 	vec2 uv2 = tc * screen_res;
 	float c = (uv2.x + uv2.y) * 0.125;
 	float jitter = mod( c, 1.0);
 
-    vec3 firstBasis = normalize(cross(vec3(0.f, 0.f, 1.f), rayDirection));
+    vec3 firstBasis = normalize(cross(vec3(1.f, 1.f, 1.f), rayDirection));
 	vec3 secondBasis = normalize(cross(rayDirection, firstBasis));
     
-    frag_color.rgb = texture(diffuseRect, tc).rgb;
+    frag_color = texture(diffuseMap, tc);
     vec4 collectedColor;
-    for (int i = 0; i < 1; i++) {
-		vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0))) * 0.25;
+    
+    vec2 screenpos = 1 - abs(tc * 2 - 1);
+    float vignette = clamp((screenpos.x * screenpos.y) * 16,0, 1);
+    vignette *= clamp((dot(normalize(viewPos), n) * 0.5 + 0.5 - 0.2) * 8, 0, 1);
+    vignette *= min(linearDepth(getDepth(tc), zNear, zFar) / zFar, 1);
+    int totalSamples = 4;
+    for (int i = 0; i < totalSamples; i++) {
+		vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0)));
 		vec3 reflectionDirectionRandomized = rayDirection + firstBasis * coeffs.x + secondBasis * coeffs.y;
 
-        bool hit = traceScreenRay(pos, reflectionDirectionRandomized, hitpoint, depth, depth, diffuseRect);
+        bool hit = traceScreenRay(pos, reflectionDirectionRandomized, hitpoint, depth, depth, diffuseMap);
         if (hit) {
-            vec2 screenpos = tc * 2 - 1;
-            float vignette = 1;// clamp((1 - dot(screenpos, screenpos)) * 4,0, 1);
-            vignette *= dot(normalize(viewPos), getNorm(tc)) * 0.5 + 0.5;
-            vignette *= min(linearDepth(getDepth(tc), zNear, zFar) / (zFar * 0.0125), 1);
-            collectedColor.rgb = hitpoint * vignette * 0.25;
-            frag_color.rgb = hitpoint;
+            collectedColor += hitpoint;
+            collectedColor.rgb *= specCol.rgb;
         }
 	}
 
-    //frag_color.rgb = collectedColor.rgb;
-
-
+    collectedColor *= vignette;
 
-    frag_color.a = 1.0;
+    frag_color += collectedColor;
 }
diff --git a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl
index 5eefd99d001977f49d4259373892b4de7c4586b9..f8c6e5701af678360f209c39b1ced4edc7884a7c 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl
@@ -52,28 +52,28 @@ vec2 generateProjectedPosition(vec3 pos){
 
 bool isBinarySearchEnabled = true;
 bool isAdaptiveStepEnabled = true;
-bool isExponentialStepEnabled = false;
+bool isExponentialStepEnabled = true;
 bool debugDraw = false;
-int iterationCount = 100;
-float rayStep = 0.2;
-float distanceBias = 0.05;
+int iterationCount = 40;
+float rayStep = 0.1;
+float distanceBias = 0.02;
 float depthRejectBias = 0.001;
 float epsilon = 0.1;
 
-bool traceScreenRay(vec3 position, vec3 reflection, out vec3 hitColor, out float hitDepth, float depth, sampler2D textureFrame) {
+bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame) {
 	vec3 step = rayStep * reflection;
 	vec3 marchingPosition = position + step;
 	float delta;
 	float depthFromScreen;
 	vec2 screenPosition;
     bool hit = false;
-    hitColor = vec3(0);
+    hitColor = vec4(0);
 	
 	int i = 0;
 	if (depth > depthRejectBias) {
 		for (; i < iterationCount && !hit; i++) {
 			screenPosition = generateProjectedPosition(marchingPosition);
-			depthFromScreen = abs(getPositionWithDepth(screenPosition, linearDepth(getDepth(screenPosition), zNear, zFar)).z);
+				depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar);
 			delta = abs(marchingPosition.z) - depthFromScreen;
 			
 			if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) {
@@ -81,10 +81,10 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec3 hitColor, out float
 			}
 
 			if (abs(delta) < distanceBias) {
-				vec3 color = vec3(1);
+				vec4 color = vec4(1);
 				if(debugDraw)
-					color = vec3( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2);
-				hitColor = texture(textureFrame, screenPosition).xyz * color;
+					color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
+				hitColor = texture(textureFrame, screenPosition) * color;
 				hitDepth = depthFromScreen;
 				hit = true;
 				break;
@@ -114,7 +114,7 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec3 hitColor, out float
 				marchingPosition = marchingPosition - step * sign(delta);
 				
 				screenPosition = generateProjectedPosition(marchingPosition);
-				depthFromScreen = abs(getPositionWithDepth(screenPosition, getDepth(screenPosition)).z);
+				depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar);
 				delta = abs(marchingPosition.z) - depthFromScreen;
 
 				if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) {
@@ -122,10 +122,10 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec3 hitColor, out float
 				}
 
 				if (abs(delta) < distanceBias && depthFromScreen != (depth - distanceBias)) {
-					vec3 color = vec3(1);
+					vec4 color = vec4(1);
 					if(debugDraw)
-						color = vec3( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2);
-					hitColor = texture(textureFrame, screenPosition).xyz * color;
+						color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
+					hitColor = texture(textureFrame, screenPosition) * color;
 					hitDepth = depthFromScreen;
 					hit = true;
 					break;
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index 19cef5dffd6da0c3ba1efab0b7e2e256eba522c4..d37cf3b6181265f1d47d3a9aacb8527e192aaa8e 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -27,6 +27,7 @@
 
 #include "llgltfmateriallist.h"
 
+#include "llagent.h"
 #include "llassetstorage.h"
 #include "lldispatcher.h"
 #include "llfetchedgltfmaterial.h"
@@ -37,9 +38,11 @@
 #include "llviewercontrol.h"
 #include "llviewergenericmessage.h"
 #include "llviewerobjectlist.h"
+#include "llviewerregion.h"
 #include "llviewerstats.h"
 #include "llcorehttputil.h"
 #include "llagent.h"
+#include "llworld.h"
 
 #include "tinygltf/tiny_gltf.h"
 #include <strstream>
@@ -163,8 +166,14 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
             {
                 LL_WARNS() << "LLGLTFMaterialOverrideDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
             }
+            LLGLTFMaterialList::writeCacheOverrides(message, llsdRaw);
         }
-        
+        else
+        {
+            // malformed message, nothing we can do to handle it
+            return false;
+        }
+
         LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
         LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General");
 
@@ -676,3 +685,33 @@ void LLGLTFMaterialList::modifyMaterialCoro(std::string cap_url, LLSD overrides,
         done_callback(success);
     }
 }
+
+void LLGLTFMaterialList::writeCacheOverrides(LLSD const & message, std::string const & llsdRaw)
+{
+    LL_DEBUGS() << "material overrides cache" << LL_ENDL;
+
+    // default to main region if message doesn't specify
+    LLViewerRegion * region = gAgent.getRegion();;
+
+    if (message.has("region_handle_low") && message.has("region_handle_high"))
+    {
+        // TODO start requiring this once server sends this for all messages
+        U64 region_handle_low = message["region_handle_low"].asInteger();
+        U64 region_handle_high = message["region_handle_high"].asInteger();
+        U64 region_handle = (region_handle_low & 0x00000000ffffffffUL) || (region_handle_high << 32);
+        region = LLWorld::instance().getRegionFromHandle(region_handle);
+    }
+
+    if (region) {
+        region->cacheFullUpdateExtras(message, llsdRaw);
+    } else {
+        LL_WARNS() << "could not access region for material overrides message cache, region_handle: " << LL_ENDL;
+    }
+}
+
+void LLGLTFMaterialList::loadCacheOverrides(std::string const & message)
+{
+    std::vector<std::string> strings(1, message);
+
+    handle_gltf_override_message(nullptr, "", LLUUID::null, strings);
+}
diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h
index c4eabc8ef7bbe1d866018fe8a7308cbd26711598..805b47724847cba5965376fd138da72f6ac03f3a 100644
--- a/indra/newview/llgltfmateriallist.h
+++ b/indra/newview/llgltfmateriallist.h
@@ -89,6 +89,11 @@ class LLGLTFMaterialList
     // any override data that arrived before the object was ready to receive it
     void applyQueuedOverrides(LLViewerObject* obj);
 
+    // takes both the parsed message and its raw text to avoid unnecessary re serialization
+    static void writeCacheOverrides(LLSD const & message, std::string const & llsdRaw);
+
+    static void loadCacheOverrides(std::string const & message_raw);
+
 private:
     friend class LLGLTFMaterialOverrideDispatchHandler;
     // save an override update that we got from the simulator for later (for example, if an override arrived for an unknown object)
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 0cadfb3eee9293f8f3dd82c709fa897b123f9da6..9d720b1523a62cc60c21bffe52f5af638858cf1d 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -108,9 +108,11 @@ const S32 MATTYPE_SPECULAR = 2;		// Specular map
 const S32 ALPHAMODE_MASK = 2;		// Alpha masking mode
 const S32 BUMPY_TEXTURE = 18;		// use supplied normal map
 const S32 SHINY_TEXTURE = 4;		// use supplied specular map
-const S32 PBRTYPE_BASE_COLOR = 0;		// PBR Base Color
-const S32 PBRTYPE_NORMAL = 1;		// PBR Normal
-const S32 PBRTYPE_METALLIC = 2;		// PBR Metallic
+const S32 PBRTYPE_RENDER_MATERIAL_ID = 0;  // Render Material ID
+const S32 PBRTYPE_BASE_COLOR = 1;   // PBR Base Color
+const S32 PBRTYPE_NORMAL = 2;       // PBR Normal
+const S32 PBRTYPE_METALLIC_ROUGHNESS = 3; // PBR Metallic
+const S32 PBRTYPE_EMISSIVE = 4;     // PBR Emissive
 
 BOOST_STATIC_ASSERT(MATTYPE_DIFFUSE == LLRender::DIFFUSE_MAP && MATTYPE_NORMAL == LLRender::NORMAL_MAP && MATTYPE_SPECULAR == LLRender::SPECULAR_MAP);
 
@@ -199,6 +201,12 @@ BOOL	LLPanelFace::postBuild()
     childSetCommitCallback("add_media", &LLPanelFace::onClickBtnAddMedia, this);
     childSetCommitCallback("delete_media", &LLPanelFace::onClickBtnDeleteMedia, this);
 
+    childSetCommitCallback("gltfTextureScaleU", &LLPanelFace::onCommitGLTFTextureScaleU, this);
+    childSetCommitCallback("gltfTextureScaleV", &LLPanelFace::onCommitGLTFTextureScaleV, this);
+    childSetCommitCallback("gltfRotation", &LLPanelFace::onCommitGLTFRotation, this);
+    childSetCommitCallback("gltfTextureTranslationU", &LLPanelFace::onCommitGLTFTextureTranslationU, this);
+    childSetCommitCallback("gltfTextureTranslationV", &LLPanelFace::onCommitGLTFTextureTranslationV, this);
+
 	childSetAction("button align",&LLPanelFace::onClickAutoFix,this);
 	childSetAction("button align textures", &LLPanelFace::onAlignTexture, this);
     childSetAction("pbr_from_inventory", &LLPanelFace::onClickBtnLoadInvPBR, this);
@@ -363,7 +371,7 @@ BOOL	LLPanelFace::postBuild()
     if (radio_pbr_type)
     {
         radio_pbr_type->setCommitCallback(LLPanelFace::onCommitPbrType, this);
-        radio_pbr_type->selectNthItem(PBRTYPE_BASE_COLOR);
+        radio_pbr_type->selectNthItem(PBRTYPE_RENDER_MATERIAL_ID);
     }
 
 	mCtrlGlow = getChild<LLSpinCtrl>("glow");
@@ -537,41 +545,21 @@ struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor
 		BOOL valid;
 		F32 value;
         std::string prefix;
-        U32 materials_media = mPanel->getChild<LLComboBox>("combobox matmedia")->getCurrentIndex();
 
-        if (MATMEDIA_PBR == materials_media)
+        // Effectively the same as MATMEDIA_PBR sans using different radio,
+        // separate for the sake of clarity
+        LLRadioGroup * radio_mat_type = mPanel->getChild<LLRadioGroup>("radio_material_type");
+        switch (radio_mat_type->getSelectedIndex())
         {
-            LLRadioGroup * radio_pbr_type = mPanel->getChild<LLRadioGroup>("radio_pbr_type");
-            switch (radio_pbr_type->getSelectedIndex())
-            {
-            case PBRTYPE_BASE_COLOR:
-                prefix = "Tex";
-                break;
-            case PBRTYPE_NORMAL:
-                prefix = "bumpy";
-                break;
-            case PBRTYPE_METALLIC:
-                prefix = "shiny";
-                break;
-            }
-        }
-        else
-        {
-            // Effectively the same as MATMEDIA_PBR sans using different radio,
-            // separate for the sake of clarity
-            LLRadioGroup * radio_mat_type = mPanel->getChild<LLRadioGroup>("radio_material_type");
-            switch (radio_mat_type->getSelectedIndex())
-            {
-            case MATTYPE_DIFFUSE:
-                prefix = "Tex";
-                break;
-            case MATTYPE_NORMAL:
-                prefix = "bumpy";
-                break;
-            case MATTYPE_SPECULAR:
-                prefix = "shiny";
-                break;
-            }
+        case MATTYPE_DIFFUSE:
+            prefix = "Tex";
+            break;
+        case MATTYPE_NORMAL:
+            prefix = "bumpy";
+            break;
+        case MATTYPE_SPECULAR:
+            prefix = "shiny";
+            break;
         }
         
         LLSpinCtrl * ctrlTexScaleS = mPanel->getChild<LLSpinCtrl>(prefix + "ScaleU");
@@ -921,6 +909,11 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 	{
 		BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced();
 
+        bool has_pbr_material;
+        updateUIGLTF(objectp, has_pbr_material, force_set_values);
+
+        const bool has_material = !has_pbr_material;
+
 		// only turn on auto-adjust button if there is a media renderer and the media is loaded
         childSetEnabled("button align", editable);
 		
@@ -938,40 +931,25 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
         radio_mat_type->setEnabled(editable);
 
         LLRadioGroup* radio_pbr_type = getChild<LLRadioGroup>("radio_pbr_type");
-        if (radio_pbr_type->getSelectedIndex() < PBRTYPE_BASE_COLOR)
+        if (radio_pbr_type->getSelectedIndex() < PBRTYPE_RENDER_MATERIAL_ID)
         {
-            radio_pbr_type->selectNthItem(PBRTYPE_BASE_COLOR);
+            radio_pbr_type->selectNthItem(PBRTYPE_RENDER_MATERIAL_ID);
         }
         radio_pbr_type->setEnabled(editable);
 
 		getChildView("checkbox_sync_settings")->setEnabled(editable);
 		childSetValue("checkbox_sync_settings", gSavedSettings.getBOOL("SyncMaterialSettings"));
+
 		updateVisibility();
 
+        // *NOTE: The "identical" variable is currently only used to decide if
+        // the texgen control should be tentative - this is not used by GLTF
+        // materials. -Cosmic;2022-11-09
 		bool identical				= true;	// true because it is anded below
         bool identical_diffuse	= false;
         bool identical_norm		= false;
         bool identical_spec		= false;
 
-        // pbr material
-        bool has_pbr_material = false;
-        LLTextureCtrl*	pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
-        if (pbr_ctrl)
-        {
-            LLUUID pbr_id;
-            bool identical_pbr;
-            LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr);
-            identical &= identical_pbr;
-
-            pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE);
-            pbr_ctrl->setEnabled(editable);
-            pbr_ctrl->setImageAssetID(pbr_id);
-            has_pbr_material = pbr_id.notNull();
-        }
-        getChildView("pbr_from_inventory")->setEnabled(editable);
-        getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material);
-        getChildView("save_selected_pbr")->setEnabled(objectp->permCopy() && has_pbr_material);
-
 		LLTextureCtrl*	texture_ctrl = getChild<LLTextureCtrl>("texture control");
 		LLTextureCtrl*	shinytexture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
 		LLTextureCtrl*	bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
@@ -982,7 +960,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		
 		// Color swatch
 		{
-			getChildView("color label")->setEnabled(editable && !has_pbr_material);
+			getChildView("color label")->setEnabled(editable);
 		}
 		LLColorSwatchCtrl*	color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
 
@@ -1003,11 +981,11 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		}
 
 		// Color transparency
-		getChildView("color trans")->setEnabled(editable && !has_pbr_material);
+		getChildView("color trans")->setEnabled(editable);
 
 		F32 transparency = (1.f - color.mV[VALPHA]) * 100.f;
 		getChild<LLUICtrl>("ColorTrans")->setValue(editable ? transparency : 0);
-		getChildView("ColorTrans")->setEnabled(editable && !has_pbr_material);
+		getChildView("ColorTrans")->setEnabled(editable);
 
 		// Specular map
 		LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec);
@@ -1266,18 +1244,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			getChild<LLUICtrl>("shinyScaleU")->setValue(spec_scale_s);
 			getChild<LLUICtrl>("bumpyScaleU")->setValue(norm_scale_s);
 
-            if (mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR)
-            {
-                getChildView("TexScaleU")->setEnabled(editable && has_pbr_material);
-                getChildView("shinyScaleU")->setEnabled(editable && has_pbr_material);
-                getChildView("bumpyScaleU")->setEnabled(editable && has_pbr_material);
-            }
-            else
-            {
-                getChildView("TexScaleU")->setEnabled(editable);
-                getChildView("shinyScaleU")->setEnabled(editable && specmap_id.notNull());
-                getChildView("bumpyScaleU")->setEnabled(editable && normmap_id.notNull());
-            }
+            getChildView("TexScaleU")->setEnabled(editable && has_material);
+            getChildView("shinyScaleU")->setEnabled(editable && has_material && specmap_id.notNull());
+            getChildView("bumpyScaleU")->setEnabled(editable && has_material && normmap_id.notNull());
 
 			BOOL diff_scale_tentative = !(identical && identical_diff_scale_s);
 			BOOL norm_scale_tentative = !(identical && identical_norm_scale_s);
@@ -1314,18 +1283,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			BOOL norm_scale_tentative = !identical_norm_scale_t;
 			BOOL spec_scale_tentative = !identical_spec_scale_t;
 
-            if (mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR)
-            {
-                getChildView("TexScaleV")->setEnabled(editable && has_pbr_material);
-                getChildView("shinyScaleV")->setEnabled(editable && has_pbr_material);
-                getChildView("bumpyScaleV")->setEnabled(editable && has_pbr_material);
-            }
-            else
-            {
-                getChildView("TexScaleV")->setEnabled(editable);
-                getChildView("shinyScaleV")->setEnabled(editable && specmap_id.notNull());
-                getChildView("bumpyScaleV")->setEnabled(editable && normmap_id.notNull());
-            }
+            getChildView("TexScaleV")->setEnabled(editable && has_material);
+            getChildView("shinyScaleV")->setEnabled(editable && has_material && specmap_id.notNull());
+            getChildView("bumpyScaleV")->setEnabled(editable && has_material && normmap_id.notNull());
 
 			if (force_set_values)
 			{
@@ -1369,18 +1329,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			getChild<LLUICtrl>("shinyOffsetU")->setTentative(LLSD(norm_offset_u_tentative));
 			getChild<LLUICtrl>("bumpyOffsetU")->setTentative(LLSD(spec_offset_u_tentative));
 
-            if (mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR)
-            {
-                getChildView("TexOffsetU")->setEnabled(editable && has_pbr_material);
-                getChildView("shinyOffsetU")->setEnabled(editable && has_pbr_material);
-                getChildView("bumpyOffsetU")->setEnabled(editable && has_pbr_material);
-            }
-            else
-            {
-                getChildView("TexOffsetU")->setEnabled(editable);
-                getChildView("shinyOffsetU")->setEnabled(editable && specmap_id.notNull());
-                getChildView("bumpyOffsetU")->setEnabled(editable && normmap_id.notNull());
-            }
+            getChildView("TexOffsetU")->setEnabled(editable && has_material);
+            getChildView("shinyOffsetU")->setEnabled(editable && has_material && specmap_id.notNull());
+            getChildView("bumpyOffsetU")->setEnabled(editable && has_material && normmap_id.notNull());
 		}
 
 		{
@@ -1408,18 +1359,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			getChild<LLUICtrl>("shinyOffsetV")->setTentative(LLSD(norm_offset_v_tentative));
 			getChild<LLUICtrl>("bumpyOffsetV")->setTentative(LLSD(spec_offset_v_tentative));
 
-            if (mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR)
-            {
-                getChildView("TexOffsetV")->setEnabled(editable && has_pbr_material);
-                getChildView("shinyOffsetV")->setEnabled(editable && has_pbr_material);
-                getChildView("bumpyOffsetV")->setEnabled(editable && has_pbr_material);
-            }
-            else
-            {
-                getChildView("TexOffsetV")->setEnabled(editable);
-                getChildView("shinyOffsetV")->setEnabled(editable && specmap_id.notNull());
-                getChildView("bumpyOffsetV")->setEnabled(editable && normmap_id.notNull());
-            }
+            getChildView("TexOffsetV")->setEnabled(editable && has_material);
+            getChildView("shinyOffsetV")->setEnabled(editable && has_material && specmap_id.notNull());
+            getChildView("bumpyOffsetV")->setEnabled(editable && has_material && normmap_id.notNull());
 		}
 
 		// Texture rotation
@@ -1444,18 +1386,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			F32 norm_rot_deg = norm_rotation * RAD_TO_DEG;
 			F32 spec_rot_deg = spec_rotation * RAD_TO_DEG;
 
-            if (mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR)
-            {
-                getChildView("TexRot")->setEnabled(editable && has_pbr_material);
-                getChildView("shinyRot")->setEnabled(editable && has_pbr_material);
-                getChildView("bumpyRot")->setEnabled(editable && has_pbr_material);
-            }
-            else
-            {
-                getChildView("TexRot")->setEnabled(editable);
-                getChildView("shinyRot")->setEnabled(editable && specmap_id.notNull());
-                getChildView("bumpyRot")->setEnabled(editable && normmap_id.notNull());
-            }
+            getChildView("TexRot")->setEnabled(editable && has_material);
+            getChildView("shinyRot")->setEnabled(editable && has_material && specmap_id.notNull());
+            getChildView("bumpyRot")->setEnabled(editable && has_material && normmap_id.notNull());
 
 			getChild<LLUICtrl>("TexRot")->setTentative(diff_rot_tentative);
 			getChild<LLUICtrl>("shinyRot")->setTentative(LLSD(norm_rot_tentative));
@@ -1579,7 +1512,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 				BOOL repeats_tentative = !identical_repeats;
 
-				getChildView("rptctrl")->setEnabled(identical_planar_texgen ? FALSE : enabled);
 				LLSpinCtrl* rpt_ctrl = getChild<LLSpinCtrl>("rptctrl");
 				if (force_set_values)
 				{
@@ -1591,6 +1523,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					rpt_ctrl->setValue(editable ? repeats : 1.0f);
 				}
 				rpt_ctrl->setTentative(LLSD(repeats_tentative));
+                rpt_ctrl->setEnabled(has_material && !identical_planar_texgen && enabled);
 			}
 		}
 
@@ -1767,6 +1700,57 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 	}
 }
 
+void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool force_set_values)
+{
+    has_pbr_material = false;
+
+    BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced();
+
+    // pbr material
+    LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
+    if (pbr_ctrl)
+    {
+        LLUUID pbr_id;
+        bool identical_pbr;
+        LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr);
+
+        pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE);
+        pbr_ctrl->setEnabled(editable);
+        pbr_ctrl->setImageAssetID(pbr_id);
+        has_pbr_material = pbr_id.notNull();
+    }
+    getChildView("pbr_from_inventory")->setEnabled(editable);
+    getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material);
+    getChildView("save_selected_pbr")->setEnabled(objectp->permCopy() && has_pbr_material);
+}
+
+void LLPanelFace::updateVisibilityGLTF()
+{
+    const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();
+
+    LLRadioGroup* radio_pbr_type = findChild<LLRadioGroup>("radio_pbr_type");
+    radio_pbr_type->setVisible(show_pbr);
+
+    const U32 pbr_type = radio_pbr_type->getSelectedIndex();
+    const bool show_pbr_render_material_id = show_pbr && (pbr_type == PBRTYPE_RENDER_MATERIAL_ID);
+    const bool show_pbr_base_color = show_pbr && (pbr_type == PBRTYPE_BASE_COLOR);
+    const bool show_pbr_normal = show_pbr && (pbr_type == PBRTYPE_NORMAL);
+    const bool show_pbr_metallic_roughness = show_pbr && (pbr_type == PBRTYPE_METALLIC_ROUGHNESS);
+    const bool show_pbr_emissive = show_pbr && (pbr_type == PBRTYPE_EMISSIVE);
+    const bool show_pbr_transform = show_pbr_base_color || show_pbr_normal || show_pbr_metallic_roughness || show_pbr_emissive;
+
+    getChildView("pbr_control")->setVisible(show_pbr_render_material_id);
+
+    getChildView("pbr_from_inventory")->setVisible(show_pbr_render_material_id);
+    getChildView("edit_selected_pbr")->setVisible(show_pbr_render_material_id);
+    getChildView("save_selected_pbr")->setVisible(show_pbr_render_material_id);
+
+    getChildView("gltfTextureScaleU")->setVisible(show_pbr_transform);
+    getChildView("gltfTextureScaleV")->setVisible(show_pbr_transform);
+    getChildView("gltfTextureRotation")->setVisible(show_pbr_transform);
+    getChildView("gltfTextureTranslationU")->setVisible(show_pbr_transform);
+    getChildView("gltfTextureTranslationV")->setVisible(show_pbr_transform);
+}
 
 void LLPanelFace::updateCopyTexButton()
 {
@@ -2608,19 +2592,19 @@ void LLPanelFace::updateVisibility()
 	}
 	U32 materials_media = mComboMatMedia->getCurrentIndex();
 	U32 material_type = radio_mat_type->getSelectedIndex();
-    U32 pbr_type = radio_pbr_type->getSelectedIndex();
 	bool show_media = (materials_media == MATMEDIA_MEDIA) && mComboMatMedia->getEnabled();
     bool show_material = materials_media == MATMEDIA_MATERIAL;
-    bool show_pbr = materials_media == MATMEDIA_PBR;
 	bool show_texture = (show_media || (show_material && (material_type == MATTYPE_DIFFUSE) && mComboMatMedia->getEnabled()));
 	bool show_bumpiness = show_material && (material_type == MATTYPE_NORMAL) && mComboMatMedia->getEnabled();
 	bool show_shininess = show_material && (material_type == MATTYPE_SPECULAR) && mComboMatMedia->getEnabled();
-    bool show_pbr_base_color = show_pbr && (pbr_type == PBRTYPE_BASE_COLOR) && mComboMatMedia->getEnabled();
-    bool show_pbr_normal = show_pbr && (pbr_type == PBRTYPE_NORMAL) && mComboMatMedia->getEnabled();
-    bool show_pbr_metallic = show_pbr && (pbr_type == PBRTYPE_METALLIC) && mComboMatMedia->getEnabled();
 
     radio_mat_type->setVisible(show_material);
-    radio_pbr_type->setVisible(show_pbr);
+
+    // Shared material controls
+    getChildView("checkbox_sync_settings")->setVisible(show_material || show_media);
+    getChildView("tex gen")->setVisible(show_material || show_media);
+    getChildView("combobox texgen")->setVisible(show_material || show_media);
+    getChildView("button align textures")->setVisible(show_material || show_media);
 
 	// Media controls
     mTitleMediaText->setVisible(show_media);
@@ -2634,16 +2618,16 @@ void LLPanelFace::updateVisibility()
 	getChildView("combobox alphamode")->setVisible(show_texture && show_material);
 	getChildView("label maskcutoff")->setVisible(false);
 	getChildView("maskcutoff")->setVisible(false);
-	if ((show_texture && show_material) || show_pbr)
+	if (show_texture && show_material)
 	{
 		updateAlphaControls();
 	}
-    // texture scale and position controls are shared between bpr and non-pbr textures
-	getChildView("TexScaleU")->setVisible(show_texture || show_pbr_base_color);
-	getChildView("TexScaleV")->setVisible(show_texture || show_pbr_base_color);
-	getChildView("TexRot")->setVisible(show_texture || show_pbr_base_color);
-	getChildView("TexOffsetU")->setVisible(show_texture || show_pbr_base_color);
-	getChildView("TexOffsetV")->setVisible(show_texture || show_pbr_base_color);
+    // texture scale and position controls
+	getChildView("TexScaleU")->setVisible(show_texture);
+	getChildView("TexScaleV")->setVisible(show_texture);
+	getChildView("TexRot")->setVisible(show_texture);
+	getChildView("TexOffsetU")->setVisible(show_texture);
+	getChildView("TexOffsetV")->setVisible(show_texture);
 
 	// Specular map controls
 	getChildView("shinytexture control")->setVisible(show_shininess);
@@ -2659,11 +2643,11 @@ void LLPanelFace::updateVisibility()
 	{
 		updateShinyControls();
 	}
-	getChildView("shinyScaleU")->setVisible(show_shininess || show_pbr_metallic);
-	getChildView("shinyScaleV")->setVisible(show_shininess || show_pbr_metallic);
-	getChildView("shinyRot")->setVisible(show_shininess || show_pbr_metallic);
-	getChildView("shinyOffsetU")->setVisible(show_shininess || show_pbr_metallic);
-	getChildView("shinyOffsetV")->setVisible(show_shininess || show_pbr_metallic);
+	getChildView("shinyScaleU")->setVisible(show_shininess);
+	getChildView("shinyScaleV")->setVisible(show_shininess);
+	getChildView("shinyRot")->setVisible(show_shininess);
+	getChildView("shinyOffsetU")->setVisible(show_shininess);
+	getChildView("shinyOffsetV")->setVisible(show_shininess);
 
 	// Normal map controls
 	if (show_bumpiness)
@@ -2673,17 +2657,16 @@ void LLPanelFace::updateVisibility()
 	getChildView("bumpytexture control")->setVisible(show_bumpiness);
 	getChildView("combobox bumpiness")->setVisible(show_bumpiness);
 	getChildView("label bumpiness")->setVisible(show_bumpiness);
-	getChildView("bumpyScaleU")->setVisible(show_bumpiness || show_pbr_normal);
-	getChildView("bumpyScaleV")->setVisible(show_bumpiness || show_pbr_normal);
-	getChildView("bumpyRot")->setVisible(show_bumpiness || show_pbr_normal);
-	getChildView("bumpyOffsetU")->setVisible(show_bumpiness || show_pbr_normal);
-	getChildView("bumpyOffsetV")->setVisible(show_bumpiness || show_pbr_normal);
+	getChildView("bumpyScaleU")->setVisible(show_bumpiness);
+	getChildView("bumpyScaleV")->setVisible(show_bumpiness);
+	getChildView("bumpyRot")->setVisible(show_bumpiness);
+	getChildView("bumpyOffsetU")->setVisible(show_bumpiness);
+	getChildView("bumpyOffsetV")->setVisible(show_bumpiness);
+
+    getChild<LLSpinCtrl>("rptctrl")->setVisible(show_material || show_media);
 
     // PBR controls
-    getChildView("pbr_control")->setVisible(show_pbr);
-    getChildView("pbr_from_inventory")->setVisible(show_pbr);
-    getChildView("edit_selected_pbr")->setVisible(show_pbr);
-    getChildView("save_selected_pbr")->setVisible(show_pbr);
+    updateVisibilityGLTF();
 }
 
 // static
@@ -4555,6 +4538,56 @@ void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
 	self->sendTextureInfo();
 }
 
+// static
+void LLPanelFace::onCommitGLTFTextureScaleU(LLUICtrl* ctrl, void* userdata)
+{
+#if 0
+	LLPanelFace* self = (LLPanelFace*)userdata;
+    LL_WARNS() << ctrl->getValue().asReal() << LL_ENDL; // TODO: Remove
+    // TODO
+#endif
+}
+
+// static
+void LLPanelFace::onCommitGLTFTextureScaleV(LLUICtrl* ctrl, void* userdata)
+{
+#if 0
+	LLPanelFace* self = (LLPanelFace*)userdata;
+    LL_WARNS() << ctrl->getValue().asReal() << LL_ENDL; // TODO: Remove
+    // TODO
+#endif
+}
+
+// static
+void LLPanelFace::onCommitGLTFRotation(LLUICtrl* ctrl, void* userdata)
+{
+#if 0
+	LLPanelFace* self = (LLPanelFace*)userdata;
+    LL_WARNS() << ctrl->getValue().asReal() << LL_ENDL; // TODO: Remove
+    // TODO
+#endif
+}
+
+// static
+void LLPanelFace::onCommitGLTFTextureTranslationU(LLUICtrl* ctrl, void* userdata)
+{
+#if 0
+	LLPanelFace* self = (LLPanelFace*)userdata;
+    LL_WARNS() << ctrl->getValue().asReal() << LL_ENDL; // TODO: Remove
+    // TODO
+#endif
+}
+
+// static
+void LLPanelFace::onCommitGLTFTextureTranslationV(LLUICtrl* ctrl, void* userdata)
+{
+#if 0
+	LLPanelFace* self = (LLPanelFace*)userdata;
+    LL_WARNS() << ctrl->getValue().asReal() << LL_ENDL; // TODO: Remove
+    // TODO
+#endif
+}
+
 void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp)
 {
 	LL_DEBUGS("Materials") << "item asset " << itemp->getAssetUUID() << LL_ENDL;
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 27c1bb5f337bbc0e724ac60138ddffb093a74aa9..0d8a86069d0378d3fb05424ca1e3180a71dd103d 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -102,6 +102,8 @@ class LLPanelFace : public LLPanel
     void			refreshMedia();
     void			unloadMedia();
 
+    static void onGLTFMaterialUpdate(const LLUUID& object_id, S32 side);
+
     /*virtual*/ void draw();
 
 	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
@@ -174,6 +176,7 @@ class LLPanelFace : public LLPanel
 	//
 	// @param force_set_values forces spinners to set value even if they are focused
 	void updateUI(bool force_set_values = false);
+    void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool force_set_values);
 
 	// Convenience func to determine if all faces in selection have
 	// identical planar texgen settings during edits
@@ -226,6 +229,11 @@ class LLPanelFace : public LLPanel
 	static void    onCommitGlow(				LLUICtrl* ctrl, void *userdata);
 	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
 	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
+    static void     onCommitGLTFTextureScaleU(LLUICtrl* ctrl, void* userinfo);
+    static void     onCommitGLTFTextureScaleV(LLUICtrl* ctrl, void* userinfo);
+    static void     onCommitGLTFRotation(LLUICtrl* ctrl, void* userinfo);
+    static void     onCommitGLTFTextureTranslationU(LLUICtrl* ctrl, void* userinfo);
+    static void     onCommitGLTFTextureTranslationV(LLUICtrl* ctrl, void* userinfo);
 	static void		onClickAutoFix(void*);
     static void		onAlignTexture(void*);
     static void 	onClickBtnLoadInvPBR(void* userdata);
@@ -283,6 +291,7 @@ class LLPanelFace : public LLPanel
 	// Do NOT call updateUI from within this function.
 	//
 	void updateVisibility();
+    void updateVisibilityGLTF();
 
 	// Hey look everyone, a type-safe alternative to copy and paste! :)
 	//
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 36d8fffa7c6688a844127b76f7eb56d9da3e1758..0e7fd63c7fa2b418b87406cb548e05448856b40f 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -53,6 +53,7 @@
 #include "llfloatergodtools.h"
 #include "llfloaterreporter.h"
 #include "llfloaterregioninfo.h"
+#include "llgltfmateriallist.h"
 #include "llhttpnode.h"
 #include "llregioninfomodel.h"
 #include "llsdutil.h"
@@ -214,6 +215,7 @@ class LLViewerRegionImpl
 	LLVOCacheEntry::vocache_entry_set_t   mVisibleEntries; //must-be-created visible entries wait for objects creation.	
 	LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation.
 	std::set<U32>                          mNonCacheableCreatedList; //list of local ids of all non-cacheable objects
+    LLVOCacheEntry::vocache_extras_entry_map_t mCacheExtraJson; // for materials
 
 	// time?
 	// LRU info?
@@ -782,7 +784,10 @@ void LLViewerRegion::loadObjectCache()
 
 	if(LLVOCache::instanceExists())
 	{
-		LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ;
+        LLVOCache & vocache = LLVOCache::instance();
+		vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap)  ;
+        vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheExtraJson);
+
 		if (mImpl->mCacheMap.empty())
 		{
 			mCacheDirty = TRUE;
@@ -807,8 +812,10 @@ void LLViewerRegion::saveObjectCache()
 	{
 		const F32 start_time_threshold = 600.0f; //seconds
 		bool removal_enabled = sVOCacheCullingEnabled && (mRegionTimer.getElapsedTimeF32() > start_time_threshold); //allow to remove invalid objects from object cache file.
-		
-		LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled) ;
+
+        LLVOCache & instance = LLVOCache::instance();
+		instance.writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled)  ;
+        instance.writeGenericExtrasToCache(mHandle, mImpl->mCacheID, mImpl->mCacheExtraJson, mCacheDirty, removal_enabled);
 		mCacheDirty = FALSE;
 	}
 
@@ -1823,7 +1830,7 @@ LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry)
 
 	LLViewerObject* obj = NULL;
 	if(!entry->getEntry()->hasDrawable()) //not added to the rendering pipeline yet
-	{
+	{ 
 		//add the object
 		obj = gObjectList.processObjectUpdateFromCache(entry, this);
 		if(obj)
@@ -2598,7 +2605,7 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB
             LL_DEBUGS("AnimatedObjects") << " got update for local_id " << local_id << LL_ENDL;
             dumpStack("AnimatedObjectsStack");
 
-			// Update the cache entry
+			// Update the cache entry 
 			entry->updateEntry(crc, dp);
 
 			decodeBoundingInfo(entry);
@@ -2615,7 +2622,7 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB
 		// Create new entry and add to map
 		result = CACHE_UPDATE_ADDED;
 		entry = new LLVOCacheEntry(local_id, crc, dp);
-		record(LLStatViewer::OBJECT_CACHE_HIT_RATE, LLUnits::Ratio::fromValue(0));
+		record(LLStatViewer::OBJECT_CACHE_HIT_RATE, LLUnits::Ratio::fromValue(0)); 
 		
 		mImpl->mCacheMap[local_id] = entry;
 		
@@ -2633,6 +2640,22 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 	return result;
 }
 
+void LLViewerRegion::cacheFullUpdateExtras(LLSD const & extras, std::string const & extras_raw)
+{
+    LLUUID object_id = extras["object_id"].asUUID();
+    LLViewerObject * obj = gObjectList.findObject(object_id);
+    if (obj != nullptr)
+    {
+        U32 local_id = obj->getLocalID();
+
+        mImpl->mCacheExtraJson[local_id] = LLVOCacheEntry::ExtrasEntry{extras, extras_raw};
+    }
+    else
+    {
+        LL_WARNS() << "got material override for unknown object_id, cannot cache it" << LL_ENDL;
+    }
+}
+
 LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id)
 {
 	if(!sVOCacheCullingEnabled)
@@ -2657,7 +2680,7 @@ LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id, bool valid)
 		}
 	}
 	return NULL;
-	}
+}
 
 void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type)
 {
@@ -2731,6 +2754,9 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss
 
 			entry->setValid();
 			decodeBoundingInfo(entry);
+
+            loadCacheMiscExtras(local_id, entry, crc);
+
 			return true;
 		}
 		else
@@ -3514,3 +3540,11 @@ std::string LLViewerRegion::getSimHostName()
 	return std::string("...");
 }
 
+void LLViewerRegion::loadCacheMiscExtras(U32 local_id, LLVOCacheEntry * entry, U32 crc)
+{
+    auto iter = mImpl->mCacheExtraJson.find(local_id);
+    if (iter != mImpl->mCacheExtraJson.end())
+    {
+        LLGLTFMaterialList::loadCacheOverrides(iter->second.extras_raw);
+    }
+}
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 8b27004f1d03ccf8d7e45cdb2461ac5630373e8f..85f5b48b4806f61cf119940920e77c3c29357c65 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -348,7 +348,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 
 	// handle a full update message
 	eCacheUpdateResult cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags);
-	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags);	
+	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags);
+    void cacheFullUpdateExtras(LLSD const & extras, std::string const & extras_raw);
+
 	LLVOCacheEntry* getCacheEntryForOctree(U32 local_id);
 	LLVOCacheEntry* getCacheEntry(U32 local_id, bool valid = true);
 	bool probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type);
@@ -419,6 +421,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	void decodeBoundingInfo(LLVOCacheEntry* entry);
 	bool isNonCacheableObjectCreated(U32 local_id);	
 
+    void loadCacheMiscExtras(U32 local_id, LLVOCacheEntry * entry, U32 crc);
+    
 public:
 	struct CompareDistance
 	{
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 55fc66349632ada8eb9f22fe2d4bb71cf6b11fe5..2b93460d25762724b920cb401d01a244d894c0af 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -170,7 +170,7 @@ LLVOCacheEntry::~LLVOCacheEntry()
 }
 
 void LLVOCacheEntry::updateEntry(U32 crc, LLDataPackerBinaryBuffer &dp)
-{
+{ 
 	if(mCRC != crc)
 	{
 		mCRC = crc;
@@ -1435,7 +1435,12 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 
 	return ;
 }
-	
+
+void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map)
+{
+    LL_DEBUGS() << "TODO" << LL_ENDL;
+}
+
 void LLVOCache::purgeEntries(U32 size)
 {
 	while(mHeaderEntryQueue.size() > size)
@@ -1572,3 +1577,7 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 
 	return ;
 }
+
+void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled)
+{
+}
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 55a13d934dd01f4652c6943be6047250bb5f179b..33c1dfef8d42df37c5ca7fb73804ad3d002e05b4 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -33,6 +33,8 @@
 #include "llvieweroctree.h"
 #include "llapr.h"
 
+#include <unordered_map>
+
 //---------------------------------------------------------------------------
 // Cache entries
 class LLCamera;
@@ -79,6 +81,13 @@ class LLVOCacheEntry
 			}			
 		}
 	};
+
+    struct ExtrasEntry
+    {
+        LLSD extras;
+        std::string extras_raw;
+    };
+
 protected:
 	~LLVOCacheEntry();
 public:
@@ -142,7 +151,8 @@ class LLVOCacheEntry
 public:
 	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	   vocache_entry_map_t;
 	typedef std::set<LLVOCacheEntry*>                      vocache_entry_set_t;
-	typedef std::set<LLVOCacheEntry*, CompareVOCacheEntry> vocache_entry_priority_list_t;	
+	typedef std::set<LLVOCacheEntry*, CompareVOCacheEntry> vocache_entry_priority_list_t;
+    typedef std::unordered_map<U32, ExtrasEntry>  vocache_extras_entry_map_t;
 
 	S32                         mLastCameraUpdated;
 protected:
@@ -265,7 +275,10 @@ class LLVOCache : public LLParamSingleton<LLVOCache>
 	void removeCache(ELLPath location, bool started = false) ;
 
 	void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
+    void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map);
+
 	void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled);
+    void writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled);
 	void removeEntry(U64 handle) ;
 
 	U32 getCacheEntries() { return mNumEntries; }
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d2c079baa6ec49f95b0d179ba47a1535574596bc..a2e01eec3f2c99035a7fd94944e2210b30035aa8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -7616,7 +7616,7 @@ void LLPipeline::renderFinalize()
             LLRenderTarget *screen_target = &mRT->screen;
 
             screen_target->bindTarget();
-            S32 channel = gPostScreenSpaceReflectionProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage());
+            S32 channel = gPostScreenSpaceReflectionProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP, screen_target->getUsage());
             if (channel > -1)
             {
                 screen_target->bindTexture(0, channel, LLTexUnit::TFO_POINT);
@@ -7624,8 +7624,9 @@ void LLPipeline::renderFinalize()
             }
 
             {
-                LLGLDisable   blend(GL_BLEND);
+                LLGLDisable blend(GL_BLEND);
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+
                 stop_glerror();
                 mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
                 stop_glerror();
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index da74b65848aacb80c493391e51be92605d0aeb3f..91cd28d80a385e7db3aa5ecded6406cc5504b1b4 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -153,7 +153,7 @@
                  value="Media" />
             </combo_box>
             <radio_group
-            height="50"
+            height="84"
             layout="topleft"
             left_pad="5"
             top_delta="-10"
@@ -183,7 +183,7 @@
                 value="2"/>
             </radio_group>
             <radio_group
-            height="50"
+            height="84"
             layout="topleft"
             left_delta="0"
             top_delta="0"
@@ -191,26 +191,40 @@
             visible = "false"
             name="radio_pbr_type">
                 <radio_item
-                label="Color/emissive"
-                name="Color/emissive"
-                top="0" 
+                label="Complete material"
+                name="Complete material"
+                top="0"
                 layout="topleft"
-                height="16" 
+                height="16"
                 value="0"/>
                 <radio_item
+                label="Base color"
+                name="Base color"
+                layout="topleft"
+                top_pad="1" 
+                height="16" 
+                value="1"/>
+                <radio_item
                 label="Normal"
                 layout="topleft"
                 top_pad="1" 
                 height="16" 
                 name="Normal"
-                value="1"/>
+                value="2"/>
                 <radio_item
                 label="Metallic/roughness"
                 name="Metallic/roughness"
                 height="16"
                 layout="topleft"
                 top_pad="1"
-                value="2"/>
+                value="3"/>
+                <radio_item
+                label="Emissive"
+                name="Emissive"
+                layout="topleft"
+                top_pad="1" 
+                height="16" 
+                value="4"/>
             </radio_group>
             <menu_button
                 menu_filename="menu_copy_paste_texture.xml"
@@ -228,7 +242,7 @@
             <check_box
              control_name="SyncMaterialSettings"
              follows="top|left"
-             height="20"
+             height="47"
              initial_value="false"
              label="Lock repeat"
              layout="topleft"
@@ -877,6 +891,59 @@
              max_val="1"
              name="shinyOffsetV"
              width="265" />
+            <!-- BEGIN PBR Material texture transform parameters -->
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="1"
+             label="ScaleU"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             name="gltfTextureScaleU"
+             top_delta="-115"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="1"
+             label="ScaleV"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             name="gltfTextureScaleV"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Rotation"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             name="gltfTextureRotation"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="TranslationU"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             name="gltfTextureTranslationU"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="TranslationV"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             name="gltfTextureTranslationV"
+             width="265" />
+            <!-- END PBR Material texture transform parameters -->
             <check_box
              follows="top|left"
              height="16"
@@ -889,10 +956,10 @@
              top_delta="16"
              width="260" />
 			<button
-       follows="left|top"
-       layout="topleft"
+             follows="left|top"
+             layout="topleft"
 			 left="9"
-			 top="204"
+			 top="231"
 			 height="20"
 			 label="Align"
 			 label_selected="Align current texture layers"