Index: Unreal/Plugins/NoesisGUI/Shaders/Private/NoesisVS.usf
===================================================================
--- Unreal/Plugins/NoesisGUI/Shaders/Private/NoesisVS.usf	(revision 13463)
+++ Unreal/Plugins/NoesisGUI/Shaders/Private/NoesisVS.usf	(revision 13464)
@@ -1,5 +1,6 @@
 #include "/Engine/Private/Common.ush"
 #include "/Engine/Private/GammaCorrectionCommon.ush"
+#include "/Engine/Private/InstancedStereo.ush"
 
 struct In
 {
@@ -85,7 +86,11 @@
 
 #if WITH_STEREO
 #if INSTANCED_STEREO
+#if MULTI_VIEW
     nointerpolation uint viewportIndex : SV_ViewPortArrayIndex;
+#else
+    float clipDistance : SV_ClipDistance;
+#endif
 #elif MOBILE_MULTI_VIEW
     nointerpolation uint viewId : VIEW_ID;
 #endif
@@ -97,11 +102,17 @@
 {
 #if WITH_STEREO
 #if INSTANCED_STEREO
+    o.position = mul(NoesisVSConstantsStereo.projectionMtx[i.instanceId], float4(i.position, 0, 1));
+#if MULTI_VIEW
     o.viewportIndex = i.instanceId;
-    o.position = mul(i.instanceId == 0 ? NoesisVSConstants.projectionMtx : NoesisVSConstantsRightEye.projectionMtx, float4(i.position, 0, 1));
+#else
+    o.clipDistance = dot(o.position, EyeClipEdge[i.instanceId]);
+    o.position.x *= 0.5/* * ResolvedView.HMDEyePaddingOffset*/;
+    o.position.x += (EyeOffsetScale[i.instanceId] * o.position.w) * (1.0f - 0.5/* * ResolvedView.HMDEyePaddingOffset*/);
+#endif
 #elif MOBILE_MULTI_VIEW
     o.viewId = i.viewId;
-    o.position = mul(i.viewId == 0 ? NoesisVSConstants.projectionMtx : NoesisVSConstantsRightEye.projectionMtx, float4(i.position, 0, 1));
+    o.position = mul(NoesisVSConstantsStereo.projectionMtx[i.viewId], float4(i.position, 0, 1));
 #else
     o.position = mul(NoesisVSConstants.projectionMtx, float4(i.position, 0, 1));
 #endif
Index: Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/NoesisInstance.cpp
===================================================================
--- Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/NoesisInstance.cpp	(revision 13463)
+++ Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/NoesisInstance.cpp	(revision 13464)
@@ -108,7 +108,7 @@
 // Only to be modified from the render thread. Enqueue any operation needed to the render thread.
 TArray<FNoesisSlateElement*> GNoesis3DSlateElements;
 
-Noesis::Matrix4 UnrealToNoesisViewProj(const FMatrix& UnrealViewProj, float Width, float Height)
+static Noesis::Matrix4 UnrealToNoesisViewProj(const FMatrix& UnrealViewProj, float Width, float Height)
 {
 	/// ViewProj = BaseChange * UnrealViewProj * Scale * Trans * Invert, where
 	/// BaseChange = Matrix4(
@@ -312,6 +312,9 @@
 	if ((View->bIsMobileMultiViewEnabled || View->bIsInstancedStereoEnabled) && (View == View->GetInstancedSceneView()))
 		return;
 
+	if (fabs(ViewProjectionMatrix.Determinant()) < FLT_EPSILON)
+		return;
+
 	const auto ViewFamily = View->Family;
 
 	ViewRect = View->ViewRect;
@@ -323,30 +326,55 @@
 	WorldTime = ViewFamily->Time;
 	IsMobileMultiView = View->bIsMobileMultiViewEnabled && View->StereoPass == EStereoscopicPass::eSSP_PRIMARY;
 	IsInstancedStereo = View->bIsInstancedStereoEnabled && View->StereoPass == EStereoscopicPass::eSSP_PRIMARY;
-	RHICmdList.SetViewport(Left, Top, 0.0f, Right, Bottom, 1.0f);
 	if (IsMobileMultiView || IsInstancedStereo)
 	{
-		ViewProj = UnrealToNoesisViewProj(ViewProjectionMatrix, Right - Left, Bottom - Top);
+#if UE_VERSION_OLDER_THAN(5, 1, 0)
+		if (!View->bIsMultiViewEnabled)
+		{
+			ViewProj = UnrealToNoesisViewProj(ViewProjectionMatrix, Right - Left, Bottom - Top);
 
-		auto LeftEyeViewProjectionMatrix = View->ViewMatrices.GetViewProjectionMatrix();
-		LeftEyeViewProj = UnrealToNoesisViewProj(LeftEyeViewProjectionMatrix, Right - Left, Bottom - Top);
+			auto LeftEyeViewProjectionMatrix = View->ViewMatrices.GetViewProjectionMatrix();
+			LeftEyeViewProj = UnrealToNoesisViewProj(LeftEyeViewProjectionMatrix, Right - Left, Bottom - Top);
 
-		auto InstancedView = (FViewInfo*)View->GetInstancedSceneView();
-		const auto& InstancedViewRect = InstancedView->ViewRect;
-		float InstancedLeft = InstancedViewRect.Min.X;
-		float InstancedTop = InstancedViewRect.Min.Y;
-		float InstancedRight = InstancedViewRect.Max.X;
-		float InstancedBottom = InstancedViewRect.Max.Y;
+			auto InstancedView = (FViewInfo*)View->GetInstancedSceneView();
+			const auto& InstancedViewRect = InstancedView->ViewRect;
+			float InstancedLeft = InstancedViewRect.Min.X;
+			float InstancedTop = InstancedViewRect.Min.Y;
+			float InstancedRight = InstancedViewRect.Max.X;
+			float InstancedBottom = InstancedViewRect.Max.Y;
 
-		auto RightEyeViewProjectionMatrix = InstancedView->ViewMatrices.GetViewProjectionMatrix();
-		RightEyeViewProj = UnrealToNoesisViewProj(RightEyeViewProjectionMatrix, InstancedRight - InstancedLeft, InstancedBottom - InstancedTop);
+			auto RightEyeViewProjectionMatrix = InstancedView->ViewMatrices.GetViewProjectionMatrix();
+			RightEyeViewProj = UnrealToNoesisViewProj(RightEyeViewProjectionMatrix, InstancedRight - InstancedLeft, InstancedBottom - InstancedTop);
 
-		RHICmdList.SetStereoViewport(Left, InstancedLeft, Top, InstancedTop, 0.0f, Right, InstancedRight, Bottom, InstancedBottom, 1.0f);
+			RHICmdList.SetViewport(Left, Top, 0.0f, View->InstancedStereoWidth, Bottom, 1.0f);
+		}
+		else
+#endif
+		{
+			ViewProj = UnrealToNoesisViewProj(ViewProjectionMatrix, Right - Left, Bottom - Top);
+
+			auto LeftEyeViewProjectionMatrix = View->ViewMatrices.GetViewProjectionMatrix();
+			LeftEyeViewProj = UnrealToNoesisViewProj(LeftEyeViewProjectionMatrix, Right - Left, Bottom - Top);
+
+			auto InstancedView = (FViewInfo*)View->GetInstancedSceneView();
+			const auto& InstancedViewRect = InstancedView->ViewRect;
+			float InstancedLeft = InstancedViewRect.Min.X;
+			float InstancedTop = InstancedViewRect.Min.Y;
+			float InstancedRight = InstancedViewRect.Max.X;
+			float InstancedBottom = InstancedViewRect.Max.Y;
+
+			auto RightEyeViewProjectionMatrix = InstancedView->ViewMatrices.GetViewProjectionMatrix();
+			RightEyeViewProj = UnrealToNoesisViewProj(RightEyeViewProjectionMatrix, InstancedRight - InstancedLeft, InstancedBottom - InstancedTop);
+
+			RHICmdList.SetStereoViewport(Left, InstancedLeft, Top, InstancedTop, 0.0f, Right, InstancedRight, Bottom, InstancedBottom, 1.0f);
+		}
 	}
 	else
 	{
 		auto MonoViewProjectionMatrix = View->ViewMatrices.GetViewProjectionMatrix();
 		ViewProj = UnrealToNoesisViewProj(MonoViewProjectionMatrix, Right - Left, Bottom - Top);
+
+		RHICmdList.SetViewport(Left, Top, 0.0f, Right, Bottom, 1.0f);
 	}
 	RenderOnscreen(RHICmdList, true);
 }
@@ -1831,7 +1859,10 @@
 
 	InitInstance();
 
-	PreTickDelegateHandle = FSlateApplication::Get().OnPreTick().AddUObject(this, &UNoesisInstance::PreTick);
+	if (!Is3DWidget)
+	{
+		PreTickDelegateHandle = FSlateApplication::Get().OnPreTick().AddUObject(this, &UNoesisInstance::PreTick);
+	}
 }
 
 void UNoesisInstance::NativeDestruct()
Index: Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisRenderDevice.cpp
===================================================================
--- Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisRenderDevice.cpp	(revision 13463)
+++ Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisRenderDevice.cpp	(revision 13464)
@@ -828,7 +828,7 @@
 	NOESIS_BIND_DEBUG_BUFFER_LABEL(DynamicIndexBuffer, IBName);
 
 	VSConstantBuffer = TUniformBufferRef<FNoesisVSConstants>::CreateUniformBufferImmediate(FNoesisVSConstants(), UniformBuffer_MultiFrame);
-	VSConstantBufferRightEye = TUniformBufferRef<FNoesisVSConstantsRightEye>::CreateUniformBufferImmediate(FNoesisVSConstantsRightEye(), UniformBuffer_MultiFrame);
+	VSConstantBufferStereo = TUniformBufferRef<FNoesisVSConstantsStereo>::CreateUniformBufferImmediate(FNoesisVSConstantsStereo(), UniformBuffer_MultiFrame);
 	TextureSizeBuffer = TUniformBufferRef<FNoesisTextureSize>::CreateUniformBufferImmediate(FNoesisTextureSize(), UniformBuffer_MultiFrame);
 	PSRgbaConstantBuffer = TUniformBufferRef<FNoesisPSRgbaConstants>::CreateUniformBufferImmediate(FNoesisPSRgbaConstants(), UniformBuffer_MultiFrame);
 	PSOpacityConstantBuffer = TUniformBufferRef<FNoesisPSOpacityConstants>::CreateUniformBufferImmediate(FNoesisPSOpacityConstants(), UniformBuffer_MultiFrame);
@@ -1488,7 +1488,7 @@
 	DynamicVertexBuffer.SafeRelease();
 	DynamicIndexBuffer.SafeRelease();
 	VSConstantBuffer.SafeRelease();
-	VSConstantBufferRightEye.SafeRelease();
+	VSConstantBufferStereo.SafeRelease();
 	TextureSizeBuffer.SafeRelease();
 	PSRgbaConstantBuffer.SafeRelease();
 	PSOpacityConstantBuffer.SafeRelease();
@@ -2510,28 +2510,15 @@
 			NumInstances = 2;
 		}
 
-		const Noesis::UniformData& UniformData = Batch.vertexUniforms[0];
-		if (BufferNeedsUpdate(VSConstantsHash, UniformData))
-		{
-			uint32 UniformDataSize = UniformData.numDwords * 4 / 2;
-			const uint8* UniformDataValues = (const uint8 *)UniformData.values;
-			UpdateUniformBuffer(RHICmdList, VSConstantBuffer, UniformDataSize, UniformDataValues);
-
-			UniformDataValues += UniformDataSize;
-			UpdateUniformBuffer(RHICmdList, VSConstantBufferRightEye, UniformDataSize, UniformDataValues);
-
-			VSConstantsHash = UniformData.hash;
-		}
-
-		VertexShader->SetVSConstantsRightEye(*RHICmdList, VSConstantBufferRightEye);
+		ConditionalUpdateUniformBuffer(RHICmdList, VSConstantBufferStereo, VSConstantsHash, Batch.vertexUniforms[0]);
+		VertexShader->SetVSConstantsStereo(*RHICmdList, VSConstantBufferStereo);
 	}
 	else
 	{
 		ConditionalUpdateUniformBuffer(RHICmdList, VSConstantBuffer, VSConstantsHash, Batch.vertexUniforms[0]);
+		VertexShader->SetVSConstants(*RHICmdList, VSConstantBuffer);
 	}
 
-	VertexShader->SetVSConstants(*RHICmdList, VSConstantBuffer);
-
 	ConditionalUpdateUniformBuffer(RHICmdList, TextureSizeBuffer, TextureSizeHash, Batch.vertexUniforms[1]);
 
 	ConditionalUpdateUniformBuffer(RHICmdList, PSUniformBuffer0, PSUniformBuffer0Hash, Batch.pixelUniforms[0]);
Index: Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisRenderDevice.h
===================================================================
--- Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisRenderDevice.h	(revision 13463)
+++ Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisRenderDevice.h	(revision 13464)
@@ -50,7 +50,7 @@
 	FBufferRHIRef DynamicIndexBuffer;
 #endif
 	FUniformBufferRHIRef VSConstantBuffer;
-	FUniformBufferRHIRef VSConstantBufferRightEye;
+	FUniformBufferRHIRef VSConstantBufferStereo;
 	FUniformBufferRHIRef TextureSizeBuffer;
 	FUniformBufferRHIRef PSRgbaConstantBuffer;
 	FUniformBufferRHIRef PSOpacityConstantBuffer;
Index: Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisShaders.cpp
===================================================================
--- Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisShaders.cpp	(revision 13463)
+++ Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisShaders.cpp	(revision 13464)
@@ -6,7 +6,7 @@
 #include "NoesisShaders.h"
 
 IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisVSConstants, "NoesisVSConstants");
-IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisVSConstantsRightEye, "NoesisVSConstantsRightEye");
+IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisVSConstantsStereo, "NoesisVSConstantsStereo");
 IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisTextureSize, "NoesisTextureSize");
 IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisPSRgbaConstants, "NoesisPSRgbaConstants");
 IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisPSOpacityConstants, "NoesisPSOpacityConstants");
Index: Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisShaders.h
===================================================================
--- Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisShaders.h	(revision 13463)
+++ Unreal/Plugins/NoesisGUI/Source/NoesisRuntime/Private/Render/NoesisShaders.h	(revision 13464)
@@ -135,8 +135,8 @@
 SHADER_PARAMETER(FMatrix44f, projectionMtx)
 END_GLOBAL_SHADER_PARAMETER_STRUCT()
 
-BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisVSConstantsRightEye, )
-SHADER_PARAMETER(FMatrix44f, projectionMtx)
+BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisVSConstantsStereo, )
+SHADER_PARAMETER_ARRAY(FMatrix44f, projectionMtx, [2])
 END_GLOBAL_SHADER_PARAMETER_STRUCT()
 
 BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FNoesisTextureSize, )
@@ -174,11 +174,11 @@
 	{
 #if UE_VERSION_OLDER_THAN(5, 3, 0)
 		VSConstantsBuffer.Bind(Initializer.ParameterMap, FNoesisVSConstants::StaticStructMetadata.GetShaderVariableName());
-		VSConstantsBufferRightEye.Bind(Initializer.ParameterMap, FNoesisVSConstantsRightEye::StaticStructMetadata.GetShaderVariableName());
+		VSConstantsBufferStereo.Bind(Initializer.ParameterMap, FNoesisVSConstantsStereo::StaticStructMetadata.GetShaderVariableName());
 		TextureSizeBuffer.Bind(Initializer.ParameterMap, FNoesisTextureSize::StaticStructMetadata.GetShaderVariableName());
 #else
 		VSConstantsBuffer.Bind(Initializer.ParameterMap, FNoesisVSConstants::GetStructMetadata()->GetShaderVariableName());
-		VSConstantsBufferRightEye.Bind(Initializer.ParameterMap, FNoesisVSConstantsRightEye::GetStructMetadata()->GetShaderVariableName());
+		VSConstantsBufferStereo.Bind(Initializer.ParameterMap, FNoesisVSConstantsStereo::GetStructMetadata()->GetShaderVariableName());
 		TextureSizeBuffer.Bind(Initializer.ParameterMap, FNoesisTextureSize::GetStructMetadata()->GetShaderVariableName());
 #endif
 	}
@@ -203,16 +203,16 @@
 #endif
 	}
 
-	void SetVSConstantsRightEye(FRHICommandList& RHICmdList, const FUniformBufferRHIRef& VSConstantsRightEye)
+	void SetVSConstantsStereo(FRHICommandList& RHICmdList, const FUniformBufferRHIRef& VSConstantsStereo)
 	{
 		FRHIVertexShader* ShaderRHI = RHICmdList.GetBoundVertexShader();
 
-		check(VSConstantsBufferRightEye.IsBound());
+		check(VSConstantsBufferStereo.IsBound());
 #if UE_VERSION_OLDER_THAN(5, 3, 0)
-		SetUniformBufferParameter(RHICmdList, ShaderRHI, VSConstantsBufferRightEye, VSConstantsRightEye);
+		SetUniformBufferParameter(RHICmdList, ShaderRHI, VSConstantsBufferStereo, VSConstantsStereo);
 #else
 		FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
-		BatchedParameters.SetShaderUniformBuffer(VSConstantsBufferRightEye.GetBaseIndex(), VSConstantsRightEye);
+		BatchedParameters.SetShaderUniformBuffer(VSConstantsBufferStereo.GetBaseIndex(), VSConstantsStereo);
 		RHICmdList.SetBatchedShaderParameters(ShaderRHI, BatchedParameters);
 #endif
 	}
@@ -232,7 +232,7 @@
 	}
 
 	LAYOUT_FIELD(FShaderUniformBufferParameter, VSConstantsBuffer);
-	LAYOUT_FIELD(FShaderUniformBufferParameter, VSConstantsBufferRightEye);
+	LAYOUT_FIELD(FShaderUniformBufferParameter, VSConstantsBufferStereo);
 	LAYOUT_FIELD(FShaderUniformBufferParameter, TextureSizeBuffer)
 };
 
