diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp
index c127a92..ec259c0 100644
--- a/Src/Graphics/New3D/New3D.cpp
+++ b/Src/Graphics/New3D/New3D.cpp
@@ -309,8 +309,12 @@ void CNew3D::RenderFrame(void)
 		m_nfPairs[i].zFar  =  std::numeric_limits<float>::max();
 	}
 
-	for (int i = 0; i < 4; i++) {
-		m_lineOfSight[i] = 0;
+	{
+		std::lock_guard<std::mutex> guard(m_losMutex);
+		std::swap(m_losBack, m_losFront);
+		for (int i = 0; i < 4; i++) {
+			m_losBack->value[i] = 0;
+		}
 	}
 
 	// release any resources from last frame
@@ -1671,7 +1675,10 @@ void CNew3D::SetSignedShade(bool enable)
 
 float CNew3D::GetLosValue(int layer)
 {
-	return m_lineOfSight[layer];
+	// we always write to the 'back' buffer, and the software reads from the front
+	// then they get swapped
+	std::lock_guard<std::mutex> guard(m_losMutex);
+	return m_losFront->value[layer];
 }
 
 void CNew3D::TranslateLosPosition(int inX, int inY, int& outX, int& outY)
@@ -1705,7 +1712,7 @@ bool CNew3D::ProcessLos(int priority)
 				float zFar	= m_nfPairs[priority].zFar;
 				float zVal	= 2.0f * zNear * zFar / (zFar + zNear - depth * (zFar - zNear));
 
-				m_lineOfSight[priority] = zVal;
+				m_losBack->value[priority] = zVal;
 				return true;
 			}
 		}
diff --git a/Src/Graphics/New3D/New3D.h b/Src/Graphics/New3D/New3D.h
index 1901eda..5d6024b 100644
--- a/Src/Graphics/New3D/New3D.h
+++ b/Src/Graphics/New3D/New3D.h
@@ -43,6 +43,7 @@
 #include "R3DScrollFog.h"
 #include "PolyHeader.h"
 #include "R3DFrameBuffers.h"
+#include <mutex>
 
 namespace New3D {
 
@@ -262,7 +263,14 @@ private:
 	NodeAttributes	m_nodeAttribs;
 	Mat4			m_modelMat;				// current modelview matrix
 
-	float			m_lineOfSight[4];
+	struct LOS
+	{
+		float value[4] = { 0,0,0,0 };		// line of sight value for each priority layer
+	} m_los[2];
+
+	LOS* m_losFront = &m_los[0];			// we need to double buffer this because 3d works in separate thread
+	LOS* m_losBack = &m_los[1];
+	std::mutex m_losMutex;
 
 	Vertex			m_prev[4];				// these are class variables because sega bass fishing starts meshes with shared vertices from the previous one
 	UINT16			m_prevTexCoords[4][2];	// basically relying on undefined behavour