diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 55ebf03adc0da347d2c852f162ad78dcd1b63bcd..5b614a2ce0bdf6a8ec02314181dd56adfe666c88 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -51,7 +51,7 @@ LLDrawPoolSky::LLDrawPoolSky()
 void LLDrawPoolSky::prerender()
 {
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT); 
-    if (gSky.mVOSkyp->mDrawable)
+    if (gSky.mVOSkyp && gSky.mVOSkyp->mDrawable)
     {
         gSky.mVOSkyp->updateGeometry(gSky.mVOSkyp->mDrawable);
     }
diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp
index b07efff82791144ef1011901e0ad92138e4823f9..89f14c6cfa411cb7dd9987c0d2b54f08284ce701 100644
--- a/indra/newview/lllocalgltfmaterials.cpp
+++ b/indra/newview/lllocalgltfmaterials.cpp
@@ -93,27 +93,27 @@ LLLocalGLTFMaterial::~LLLocalGLTFMaterial()
 }
 
 /* accessors */
-std::string LLLocalGLTFMaterial::getFilename()
+std::string LLLocalGLTFMaterial::getFilename() const
 {
     return mFilename;
 }
 
-std::string LLLocalGLTFMaterial::getShortName()
+std::string LLLocalGLTFMaterial::getShortName() const
 {
     return mShortName;
 }
 
-LLUUID LLLocalGLTFMaterial::getTrackingID()
+LLUUID LLLocalGLTFMaterial::getTrackingID() const
 {
     return mTrackingID;
 }
 
-LLUUID LLLocalGLTFMaterial::getWorldID()
+LLUUID LLLocalGLTFMaterial::getWorldID() const
 {
     return mWorldID;
 }
 
-S32 LLLocalGLTFMaterial::getIndexInFile()
+S32 LLLocalGLTFMaterial::getIndexInFile() const
 {
     return mMaterialIndex;
 }
diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h
index 3bdccbbf3de9bcc016b4b44af8321f6a60f8e249..6919b9b4b25d25f386ad99b8549c985571d96d7d 100644
--- a/indra/newview/lllocalgltfmaterials.h
+++ b/indra/newview/lllocalgltfmaterials.h
@@ -42,11 +42,11 @@ class LLLocalGLTFMaterial : public LLFetchedGLTFMaterial
     virtual ~LLLocalGLTFMaterial();
 
 public: /* accessors */
-    std::string	getFilename();
-    std::string	getShortName();
-    LLUUID		getTrackingID();
-    LLUUID		getWorldID();
-    S32			getIndexInFile();
+    std::string	getFilename() const;
+    std::string	getShortName() const;
+    LLUUID		getTrackingID() const;
+    LLUUID		getWorldID() const;
+    S32			getIndexInFile() const;
 
 public:
     bool updateSelf();
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index d5339777c4748bc6740cb97432565dbb68078e36..fe674abeee22db19b42c300df7de44a88375cc8c 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -46,6 +46,7 @@
 #include "llsdutil.h"
 #include "llselectmgr.h"
 #include "llstatusbar.h"	// can_afford_transaction()
+#include "lltoolpie.h"
 #include "llviewerinventory.h"
 #include "llinventory.h"
 #include "llviewerregion.h"
@@ -322,9 +323,17 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index)
                 mLocalMaterial = local_mat;
             }
             mMaterial = tep->getGLTFRenderMaterial();
+
+            if (mMaterial.isNull())
+            {
+                // Shouldn't be possible?
+                LL_WARNS("MaterialEditor") << "Object has material id, but no material" << LL_ENDL;
+                mMaterial = gGLTFMaterialList.getMaterial(mat_id);
+            }
         }
+        return true;
     }
-    return true;
+    return false;
 }
 
 ///----------------------------------------------------------------------------
@@ -1816,58 +1825,95 @@ void LLMaterialEditor::loadLive()
 
 void LLMaterialEditor::saveObjectsMaterialAs()
 {
-
-    // Find an applicable material.
-    // Do this before showing message, because
-    // message is going to drop selection.
     LLSelectedTEGetMatData func(false);
     LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/);
+    saveMaterialAs(func.mMaterial, func.mLocalMaterial);
+}
+void LLMaterialEditor::savePickedMaterialAs()
+{
+    LLPickInfo pick = LLToolPie::getInstance()->getPick();
+    if (pick.mPickType != LLPickInfo::PICK_OBJECT || !pick.getObject())
+    {
+        return;
+    }
+
+    LLPointer<LLGLTFMaterial> render_material;
+    LLPointer<LLLocalGLTFMaterial> local_material;
 
-    if (func.mLocalMaterial.notNull())
+    LLViewerObject *objectp = pick.getObject();
+    LLUUID mat_id = objectp->getRenderMaterialID(pick.mObjectFace);
+    if (mat_id.notNull() && objectp->permCopy())
+    {
+        // Try a face user picked first
+        // (likely the only method we need, but in such case
+        // enable_object_save_gltf_material will need to check this)
+        LLTextureEntry *tep = objectp->getTE(pick.mObjectFace);
+        LLGLTFMaterial *mat = tep->getGLTFMaterial();
+        LLLocalGLTFMaterial *local_mat = dynamic_cast<LLLocalGLTFMaterial*>(mat);
+
+        if (local_mat)
+        {
+            local_material = local_mat;
+        }
+        render_material = tep->getGLTFRenderMaterial();
+    }
+    else
+    {
+        // Find an applicable material.
+        // Do this before showing message, because
+        // message is going to drop selection.
+        LLSelectedTEGetMatData func(false);
+        LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/);
+        local_material = func.mLocalMaterial;
+        render_material = func.mMaterial;
+    }
+
+    saveMaterialAs(render_material, local_material);
+}
+
+void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, const LLLocalGLTFMaterial *local_material)
+{
+    if (local_material)
     {
         // This is a local material, reload it from file
         // so that user won't end up with grey textures
         // on next login.
-        LLMaterialEditor::loadMaterialFromFile(func.mLocalMaterial->getFilename(), func.mLocalMaterial->getIndexInFile());
+        LLMaterialEditor::loadMaterialFromFile(local_material->getFilename(), local_material->getIndexInFile());
 
         LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor");
         if (me)
         {
-            // apply differences on top
-            LLGLTFMaterial* local_mat = func.mLocalMaterial.get();
-            // don't use override mat here, it has 'hacked ids'
-            // and values, use end result.
-            LLGLTFMaterial* cmp_mat = func.mMaterial.get();
-
-            me->setBaseColor(cmp_mat->mBaseColor);
-            me->setMetalnessFactor(cmp_mat->mMetallicFactor);
-            me->setRoughnessFactor(cmp_mat->mRoughnessFactor);
-            me->setEmissiveColor(cmp_mat->mEmissiveColor);
-            me->setDoubleSided(cmp_mat->mDoubleSided);
-            me->setAlphaMode(cmp_mat->getAlphaMode());
-            me->setAlphaCutoff(cmp_mat->mAlphaCutoff);
+            // don't use override material here, it has 'hacked ids'
+            // and values, use end result, apply it on top of local.
+            me->setBaseColor(render_material->mBaseColor);
+            me->setMetalnessFactor(render_material->mMetallicFactor);
+            me->setRoughnessFactor(render_material->mRoughnessFactor);
+            me->setEmissiveColor(render_material->mEmissiveColor);
+            me->setDoubleSided(render_material->mDoubleSided);
+            me->setAlphaMode(render_material->getAlphaMode());
+            me->setAlphaCutoff(render_material->mAlphaCutoff);
 
             // most things like colors we can apply without verifying
             // but texture ids are going to be different from both, base and override
             // so only apply override id if there is actually a difference
-            if (local_mat->mBaseColorId != cmp_mat->mBaseColorId)
+            if (local_material->mBaseColorId != render_material->mBaseColorId)
             {
-                me->setBaseColorId(cmp_mat->mBaseColorId);
+                me->setBaseColorId(render_material->mBaseColorId);
                 me->childSetValue("base_color_upload_fee", me->getString("no_upload_fee_string"));
             }
-            if (local_mat->mNormalId != cmp_mat->mNormalId)
+            if (local_material->mNormalId != render_material->mNormalId)
             {
-                me->setNormalId(cmp_mat->mNormalId);
+                me->setNormalId(render_material->mNormalId);
                 me->childSetValue("normal_upload_fee", me->getString("no_upload_fee_string"));
             }
-            if (local_mat->mMetallicRoughnessId != cmp_mat->mMetallicRoughnessId)
+            if (local_material->mMetallicRoughnessId != render_material->mMetallicRoughnessId)
             {
-                me->setMetallicRoughnessId(cmp_mat->mMetallicRoughnessId);
+                me->setMetallicRoughnessId(render_material->mMetallicRoughnessId);
                 me->childSetValue("metallic_upload_fee", me->getString("no_upload_fee_string"));
             }
-            if (local_mat->mEmissiveId != cmp_mat->mEmissiveId)
+            if (local_material->mEmissiveId != render_material->mEmissiveId)
             {
-                me->setEmissiveId(cmp_mat->mEmissiveId);
+                me->setEmissiveId(render_material->mEmissiveId);
                 me->childSetValue("emissive_upload_fee", me->getString("no_upload_fee_string"));
             }
 
@@ -1879,9 +1925,9 @@ void LLMaterialEditor::saveObjectsMaterialAs()
     }
 
     LLSD payload;
-    if (func.mMaterial.notNull())
+    if (render_material)
     {
-        payload["data"] = func.mMaterial->asJSON();
+        payload["data"] = render_material->asJSON();
     }
     else
     {
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 23d5434ff7163a3a7de986efde13084eb2fc7d51..6deda5df50743332b58c56cd3e2426497575e6ad 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -35,6 +35,7 @@ class LLButton;
 class LLColorSwatchCtrl;
 class LLComboBox;
 class LLGLTFMaterial;
+class LLLocalGLTFMaterial;
 class LLTextureCtrl;
 class LLTextBox;
 
@@ -111,6 +112,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
     static void loadLive();
 
     static void saveObjectsMaterialAs();
+    static void savePickedMaterialAs();
     static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response);
 
     static void loadFromGLTFMaterial(LLUUID &asset_id);
@@ -232,6 +234,8 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
     static bool capabilitiesAvailable();
 
 private:
+    static void saveMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material);
+
     static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id);
     static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc);
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index c67d76100a350cb09601c088b484cbdc11049b5e..8d0dd505bf0785d230119368d9b3c1eccaebcd5d 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -2962,7 +2962,7 @@ void handle_object_edit_gltf_material()
 
 void handle_object_save_gltf_material()
 {
-    LLMaterialEditor::saveObjectsMaterialAs();
+    LLMaterialEditor::savePickedMaterialAs();
 }
 
 void handle_attachment_edit(const LLUUID& inv_item_id)
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 0673652e61a7b28fb5e3df9b3ad219efc61cf1b6..7142763451a2bf02baba752fa0ae80ef933d9803 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -135,7 +135,6 @@ bool anyone_copy_selection(LLSelectNode* nodep);
 // *TODO: Move to separate file
 bool for_sale_selection(LLSelectNode* nodep);
 
-void handle_save_snapshot(void *);
 void handle_toggle_flycam();
 
 void handle_object_sit_or_stand();