diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16174087a9..f6c137b4ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -189,6 +189,7 @@
     Bug #8064: Lua move360 script doesn't respect the enableZoom/disableZoom Camera interface setting
     Feature #1415: Infinite fall failsafe
     Feature #2566: Handle NAM9 records for manual cell references
+    Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
     Feature #3537: Shader-based water ripples
     Feature #5173: Support for NiFogProperty
     Feature #5492: Let rain and snow collide with statics
diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp
index ba3a544f36..7b3b827583 100644
--- a/apps/opencs/model/prefs/state.cpp
+++ b/apps/opencs/model/prefs/state.cpp
@@ -376,6 +376,13 @@ void CSMPrefs::State::declare()
     declareShortcut(mValues->mKeyBindings.mSceneSave8, "Save Group 8");
     declareShortcut(mValues->mKeyBindings.mSceneGroup9, "Selection Group 9");
     declareShortcut(mValues->mKeyBindings.mSceneSave9, "Save Group 9");
+    declareShortcut(mValues->mKeyBindings.mSceneAxisX, "X Axis Movement Lock");
+    declareShortcut(mValues->mKeyBindings.mSceneAxisY, "Y Axis Movement Lock");
+    declareShortcut(mValues->mKeyBindings.mSceneAxisZ, "Z Axis Movement Lock");
+    declareShortcut(mValues->mKeyBindings.mSceneMoveSubmode, "Move Object Submode");
+    declareShortcut(mValues->mKeyBindings.mSceneScaleSubmode, "Scale Object Submode");
+    declareShortcut(mValues->mKeyBindings.mSceneRotateSubmode, "Rotate Object Submode");
+    declareShortcut(mValues->mKeyBindings.mSceneCameraCycle, "Cycle Camera Mode");
 
     declareSubcategory("1st/Free Camera");
     declareShortcut(mValues->mKeyBindings.mFreeForward, "Forward");
diff --git a/apps/opencs/model/prefs/values.hpp b/apps/opencs/model/prefs/values.hpp
index b2bf87d753..c4b7010aaf 100644
--- a/apps/opencs/model/prefs/values.hpp
+++ b/apps/opencs/model/prefs/values.hpp
@@ -436,19 +436,19 @@ namespace CSMPrefs
         Settings::SettingValue<std::string> mReporttableRemove{ mIndex, sName, "reporttable-remove", "Delete" };
         Settings::SettingValue<std::string> mReporttableReplace{ mIndex, sName, "reporttable-replace", "" };
         Settings::SettingValue<std::string> mReporttableRefresh{ mIndex, sName, "reporttable-refresh", "" };
-        Settings::SettingValue<std::string> mSceneNaviPrimary{ mIndex, sName, "scene-navi-primary", "LMB" };
-        Settings::SettingValue<std::string> mSceneNaviSecondary{ mIndex, sName, "scene-navi-secondary", "Ctrl+LMB" };
-        Settings::SettingValue<std::string> mSceneOpenPrimary{ mIndex, sName, "scene-open-primary", "Shift+LMB" };
+        Settings::SettingValue<std::string> mSceneNaviPrimary{ mIndex, sName, "scene-navi-primary", "MMB" };
+        Settings::SettingValue<std::string> mSceneNaviSecondary{ mIndex, sName, "scene-navi-secondary", "Ctrl+MMB" };
+        Settings::SettingValue<std::string> mSceneOpenPrimary{ mIndex, sName, "scene-open-primary", "Shift+RMB" };
         Settings::SettingValue<std::string> mSceneEditPrimary{ mIndex, sName, "scene-edit-primary", "RMB" };
         Settings::SettingValue<std::string> mSceneEditSecondary{ mIndex, sName, "scene-edit-secondary", "Ctrl+RMB" };
-        Settings::SettingValue<std::string> mSceneSelectPrimary{ mIndex, sName, "scene-select-primary", "MMB" };
+        Settings::SettingValue<std::string> mSceneSelectPrimary{ mIndex, sName, "scene-select-primary", "LMB" };
         Settings::SettingValue<std::string> mSceneSelectSecondary{ mIndex, sName, "scene-select-secondary",
-            "Ctrl+MMB" };
-        Settings::SettingValue<std::string> mSceneSelectTertiary{ mIndex, sName, "scene-select-tertiary", "Shift+MMB" };
+            "Ctrl+LMB" };
+        Settings::SettingValue<std::string> mSceneSelectTertiary{ mIndex, sName, "scene-select-tertiary", "Shift+LMB" };
         Settings::SettingValue<std::string> mSceneSpeedModifier{ mIndex, sName, "scene-speed-modifier", "Shift" };
         Settings::SettingValue<std::string> mSceneDelete{ mIndex, sName, "scene-delete", "Delete" };
         Settings::SettingValue<std::string> mSceneInstanceDropTerrain{ mIndex, sName, "scene-instance-drop-terrain",
-            "G" };
+            "B" };
         Settings::SettingValue<std::string> mSceneInstanceDropCollision{ mIndex, sName, "scene-instance-drop-collision",
             "H" };
         Settings::SettingValue<std::string> mSceneInstanceDropTerrainSeparately{ mIndex, sName,
@@ -491,6 +491,14 @@ namespace CSMPrefs
         Settings::SettingValue<std::string> mSceneSave8{ mIndex, sName, "scene-save-8", "Ctrl+8" };
         Settings::SettingValue<std::string> mSceneGroup9{ mIndex, sName, "scene-group-9", "9" };
         Settings::SettingValue<std::string> mSceneSave9{ mIndex, sName, "scene-save-9", "Ctrl+9" };
+        Settings::SettingValue<std::string> mSceneAxisX{ mIndex, sName, "scene-axis-x", "X" };
+        Settings::SettingValue<std::string> mSceneAxisY{ mIndex, sName, "scene-axis-y", "Y" };
+        Settings::SettingValue<std::string> mSceneAxisZ{ mIndex, sName, "scene-axis-z", "Z" };
+        Settings::SettingValue<std::string> mSceneMoveSubmode{ mIndex, sName, "scene-submode-move", "G" };
+        Settings::SettingValue<std::string> mSceneScaleSubmode{ mIndex, sName, "scene-submode-scale", "V" };
+        Settings::SettingValue<std::string> mSceneRotateSubmode{ mIndex, sName, "scene-submode-rotate", "R" };
+        Settings::SettingValue<std::string> mSceneCameraCycle{ mIndex, sName, "scene-cam-cycle", "Tab" };
+        Settings::SettingValue<std::string> mSceneToggleMarkers{ mIndex, sName, "scene-toggle-markers", "F4" };
         Settings::SettingValue<std::string> mFreeForward{ mIndex, sName, "free-forward", "W" };
         Settings::SettingValue<std::string> mFreeBackward{ mIndex, sName, "free-backward", "S" };
         Settings::SettingValue<std::string> mFreeLeft{ mIndex, sName, "free-left", "A" };
diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp
index bc821ee25a..5851311035 100644
--- a/apps/opencs/view/render/instancemode.cpp
+++ b/apps/opencs/view/render/instancemode.cpp
@@ -252,6 +252,48 @@ void CSVRender::InstanceMode::getSelectionGroup(const int group)
     getWorldspaceWidget().selectGroup(targets);
 }
 
+void CSVRender::InstanceMode::setDragAxis(const char axis)
+{
+    int newDragAxis;
+
+    const std::vector<osg::ref_ptr<TagBase>> selection = getWorldspaceWidget().getSelection(Mask_Reference);
+
+    if (selection.empty())
+        return;
+
+    switch (axis)
+    {
+        case 'x':
+            newDragAxis = 0;
+            break;
+        case 'y':
+            newDragAxis = 1;
+            break;
+        case 'z':
+            newDragAxis = 2;
+            break;
+        default:
+            return;
+    }
+
+    if (newDragAxis == mDragAxis)
+        newDragAxis = -1;
+
+    if (mSubModeId == "move")
+    {
+        mObjectsAtDragStart.clear();
+
+        for (const auto& object : selection)
+            if (CSVRender::ObjectTag* objectTag = dynamic_cast<CSVRender::ObjectTag*>(object.get()))
+            {
+                const osg::Vec3f thisPoint = objectTag->mObject->getPosition().asVec3();
+                mDragStart = thisPoint;
+                mObjectsAtDragStart.emplace_back(thisPoint);
+            }
+    }
+    mDragAxis = newDragAxis;
+}
+
 CSVRender::InstanceMode::InstanceMode(
     WorldspaceWidget* worldspaceWidget, osg::ref_ptr<osg::Group> parentNode, QWidget* parent)
     : EditMode(worldspaceWidget, Misc::ScalableIcon::load(":scenetoolbar/editing-instance"),
@@ -306,6 +348,19 @@ CSVRender::InstanceMode::InstanceMode(
         connect(new CSMPrefs::Shortcut("scene-save-" + std::to_string(i), worldspaceWidget),
             qOverload<>(&CSMPrefs::Shortcut::activated), this, [this, i] { this->saveSelectionGroup(i); });
     }
+
+    connect(new CSMPrefs::Shortcut("scene-submode-move", worldspaceWidget), qOverload<>(&CSMPrefs::Shortcut::activated),
+        this, [this] { mSubMode->setButton("move"); });
+
+    connect(new CSMPrefs::Shortcut("scene-submode-scale", worldspaceWidget),
+        qOverload<>(&CSMPrefs::Shortcut::activated), this, [this] { mSubMode->setButton("scale"); });
+
+    connect(new CSMPrefs::Shortcut("scene-submode-rotate", worldspaceWidget),
+        qOverload<>(&CSMPrefs::Shortcut::activated), this, [this] { mSubMode->setButton("rotate"); });
+
+    for (const char axis : "xyz")
+        connect(new CSMPrefs::Shortcut(std::string("scene-axis-") + axis, worldspaceWidget),
+            qOverload<>(&CSMPrefs::Shortcut::activated), this, [this, axis] { this->setDragAxis(axis); });
 }
 
 void CSVRender::InstanceMode::activate(CSVWidget::SceneToolbar* toolbar)
diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp
index 9267823e22..45d7c2b6fd 100644
--- a/apps/opencs/view/render/instancemode.hpp
+++ b/apps/opencs/view/render/instancemode.hpp
@@ -133,6 +133,7 @@ namespace CSVRender
 
     private slots:
 
+        void setDragAxis(const char axis);
         void subModeChanged(const std::string& id);
         void deleteSelectedInstances();
         void cloneSelectedInstances();
diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp
index 089cb01f07..0a02ae456b 100644
--- a/apps/opencs/view/render/worldspacewidget.cpp
+++ b/apps/opencs/view/render/worldspacewidget.cpp
@@ -75,6 +75,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget(CSMDoc::Document& document, QWidge
     , mShowToolTips(false)
     , mToolTipDelay(0)
     , mInConstructor(true)
+    , mSelectedNavigationMode(0)
 {
     setAcceptDrops(true);
 
@@ -146,6 +147,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget(CSMDoc::Document& document, QWidge
     connect(new CSMPrefs::Shortcut("scene-clear-selection", this), qOverload<>(&CSMPrefs::Shortcut::activated), this,
         [this] { this->clearSelection(Mask_Reference); });
 
+    CSMPrefs::Shortcut* switchPerspectiveShortcut = new CSMPrefs::Shortcut("scene-cam-cycle", this);
+    connect(switchPerspectiveShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this,
+        &WorldspaceWidget::cycleNavigationMode);
+
     mInConstructor = false;
 }
 
@@ -235,9 +240,11 @@ CSVWidget::SceneToolMode* CSVRender::WorldspaceWidget::makeNavigationSelector(CS
             tool),
         "orbit");
 
-    connect(tool, &CSVWidget::SceneToolMode::modeChanged, this, &WorldspaceWidget::selectNavigationMode);
+    mCameraMode = tool;
 
-    return tool;
+    connect(mCameraMode, &CSVWidget::SceneToolMode::modeChanged, this, &WorldspaceWidget::selectNavigationMode);
+
+    return mCameraMode;
 }
 
 CSVWidget::SceneToolToggle2* CSVRender::WorldspaceWidget::makeSceneVisibilitySelector(CSVWidget::SceneToolbar* parent)
@@ -769,6 +776,26 @@ void CSVRender::WorldspaceWidget::toggleHiddenInstances()
             objectTag->mObject->getRootNode()->setNodeMask(firstMask);
 }
 
+void CSVRender::WorldspaceWidget::cycleNavigationMode()
+{
+    switch (++mSelectedNavigationMode)
+    {
+        case (CameraMode::FirstPerson):
+            mCameraMode->setButton("1st");
+            break;
+        case (CameraMode::Orbit):
+            mCameraMode->setButton("orbit");
+            break;
+        case (CameraMode::Free):
+            mCameraMode->setButton("free");
+            break;
+        default:
+            mCameraMode->setButton("1st");
+            mSelectedNavigationMode = 0;
+            break;
+    }
+}
+
 void CSVRender::WorldspaceWidget::handleInteraction(InteractionType type, bool activate)
 {
     if (activate)
diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp
index 06470d2883..9a7df38620 100644
--- a/apps/opencs/view/render/worldspacewidget.hpp
+++ b/apps/opencs/view/render/worldspacewidget.hpp
@@ -75,6 +75,7 @@ namespace CSVRender
         CSMDoc::Document& mDocument;
         unsigned int mInteractionMask;
         CSVWidget::SceneToolMode* mEditMode;
+        CSVWidget::SceneToolMode* mCameraMode;
         bool mLocked;
         int mDragMode;
         bool mDragging;
@@ -89,6 +90,7 @@ namespace CSVRender
         bool mShowToolTips;
         int mToolTipDelay;
         bool mInConstructor;
+        int mSelectedNavigationMode;
 
     public:
         enum DropType
@@ -225,6 +227,13 @@ namespace CSVRender
             Button_Terrain = 0x8
         };
 
+        enum CameraMode
+        {
+            FirstPerson,
+            Orbit,
+            Free
+        };
+
         virtual void addVisibilitySelectorButtons(CSVWidget::SceneToolToggle2* tool);
 
         virtual void addEditModeSelectorButtons(CSVWidget::SceneToolMode* tool);
@@ -240,6 +249,8 @@ namespace CSVRender
 
         bool getSpeedMode();
 
+        void cycleNavigationMode();
+
     private:
         void dragEnterEvent(QDragEnterEvent* event) override;