diff --git a/aegisub/src/gl_wrap.cpp b/aegisub/src/gl_wrap.cpp
index 03949b4df94613609438f067f5037ec2ffd90fa1..61b7f640412c4acc39317f917296792a9008517a 100644
--- a/aegisub/src/gl_wrap.cpp
+++ b/aegisub/src/gl_wrap.cpp
@@ -415,6 +415,17 @@ void OpenGLWrapper::SetRotation(float x, float y, float z) {
 	glRotatef(z, 0.f, 0.f, -1.f);
 }
 
+void OpenGLWrapper::SetShear(float x, float y) {
+	PrepareTransform();
+	float matrix[16] = {
+		1, y, 0, 0,
+		x, 1, 0, 0,
+		0, 0, 1, 0,
+		0, 0, 0, 1
+	};
+	glMultMatrixf(matrix);
+}
+
 void OpenGLWrapper::PrepareTransform() {
 	if (!transform_pushed) {
 		glMatrixMode(GL_MODELVIEW);
diff --git a/aegisub/src/gl_wrap.h b/aegisub/src/gl_wrap.h
index 772acd1c64f5be5138cedf9307978d1a992149bd..4e3cd34e94f99760a7bf4a2a560af2125c90cd9b 100644
--- a/aegisub/src/gl_wrap.h
+++ b/aegisub/src/gl_wrap.h
@@ -49,6 +49,7 @@ public:
 	void SetScale(Vector2D scale);
 	void SetOrigin(Vector2D origin);
 	void SetRotation(float x, float y, float z);
+	void SetShear(float x, float y);
 	void ResetTransform();
 
 	void DrawLine(Vector2D p1, Vector2D p2) const;
diff --git a/aegisub/src/visual_tool.cpp b/aegisub/src/visual_tool.cpp
index c32a40a1d9246e212e2a804c3a1351f1579faffd..c1977252a363a95b6c02112d871f46a395ee256b 100644
--- a/aegisub/src/visual_tool.cpp
+++ b/aegisub/src/visual_tool.cpp
@@ -445,6 +445,17 @@ void VisualToolBase::GetLineRotation(AssDialogue *diag, float &rx, float &ry, fl
 		rz = tag->front().Get(rz);
 }
 
+void VisualToolBase::GetLineShear(AssDialogue *diag, float& fax, float& fay) {
+	fax = fay = 0.f;
+
+	boost::ptr_vector<AssDialogueBlock> blocks(diag->ParseTags());
+
+	if (param_vec tag = find_tag(blocks, "\\fax"))
+		fax = tag->front().Get(fax);
+	if (param_vec tag = find_tag(blocks, "\\fay"))
+		fay = tag->front().Get(fay);
+}
+
 void VisualToolBase::GetLineScale(AssDialogue *diag, Vector2D &scale) {
 	float x = 100.f, y = 100.f;
 
diff --git a/aegisub/src/visual_tool.h b/aegisub/src/visual_tool.h
index 1d4b14abc7ba549ae3ad60fd2c94fd2e93713068..f5122e555536ef276add2c3f814febb05fca10ea 100644
--- a/aegisub/src/visual_tool.h
+++ b/aegisub/src/visual_tool.h
@@ -122,6 +122,7 @@ protected:
 	Vector2D GetLineOrigin(AssDialogue *diag);
 	bool GetLineMove(AssDialogue *diag, Vector2D &p1, Vector2D &p2, int &t1, int &t2);
 	void GetLineRotation(AssDialogue *diag, float &rx, float &ry, float &rz);
+	void GetLineShear(AssDialogue *diag, float& fax, float& fay);
 	void GetLineScale(AssDialogue *diag, Vector2D &scale);
 	void GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse);
 	std::string GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse);
diff --git a/aegisub/src/visual_tool_rotatexy.cpp b/aegisub/src/visual_tool_rotatexy.cpp
index f7f95bc6fedabd2530c1b074293e7ff908d79912..ae1c47b7dc4b07d988af7f841eb8a93371a79792 100644
--- a/aegisub/src/visual_tool_rotatexy.cpp
+++ b/aegisub/src/visual_tool_rotatexy.cpp
@@ -41,6 +41,7 @@ void VisualToolRotateXY::Draw() {
 	// Transform grid
 	gl.SetOrigin(org->pos);
 	gl.SetRotation(angle_x, angle_y, angle_z);
+	gl.SetShear(fax, fay);
 
 	// Draw grid
 	gl.SetLineColour(colour[0], 0.5f, 2);
@@ -178,4 +179,5 @@ void VisualToolRotateXY::DoRefresh() {
 	org->pos = FromScriptCoords(org->pos);
 
 	GetLineRotation(active_line, angle_x, angle_y, angle_z);
+	GetLineShear(active_line, fax, fay);
 }
diff --git a/aegisub/src/visual_tool_rotatexy.h b/aegisub/src/visual_tool_rotatexy.h
index 9379ba8af2020e39f6a8920b87038d76fa346648..36be33120e7d463589dc0f120441e6b94d389563 100644
--- a/aegisub/src/visual_tool_rotatexy.h
+++ b/aegisub/src/visual_tool_rotatexy.h
@@ -27,6 +27,9 @@ class VisualToolRotateXY : public VisualTool<VisualDraggableFeature> {
 	float angle_y = 0.f; /// Current y rotation
 	float angle_z = 0.f; /// Current z rotation
 
+	float fax = 0.f;
+	float fay = 0.f;
+
 	float orig_x = 0.f; ///< x rotation at the beginning of the current hold
 	float orig_y = 0.f; ///< y rotation at the beginning of the current hold