Forráskód Böngészése

Feature: Minor improvements to precision with reconstruction of world position from depth

BearishSun 8 éve
szülő
commit
703f01e652

+ 3 - 1
Data/Raw/Engine/Includes/PerCameraData.bslinc

@@ -42,12 +42,14 @@ mixin PerCameraData
 		/** Converts Z value in range [0,1] into Z value in view space. */
 		/** Converts Z value in range [0,1] into Z value in view space. */
 		float convertFromDeviceZ(float deviceZ)
 		float convertFromDeviceZ(float deviceZ)
 		{
 		{
-			return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;
+			// Note: Convert to MAD form
+			return gDeviceZToWorldZ.x / (deviceZ + gDeviceZToWorldZ.y);
 		}
 		}
 		
 		
 		/** Converts Z value in range [0,1] into Z value in view space. */
 		/** Converts Z value in range [0,1] into Z value in view space. */
 		float4 convertFromDeviceZ(float4 deviceZ)
 		float4 convertFromDeviceZ(float4 deviceZ)
 		{
 		{
+			// Note: Convert to MAD form
 			return gDeviceZToWorldZ.x / (deviceZ + gDeviceZToWorldZ.y);
 			return gDeviceZToWorldZ.x / (deviceZ + gDeviceZToWorldZ.y);
 		}		
 		}		
 		
 		

+ 34 - 3
Source/RenderBeast/BsRendererView.cpp

@@ -411,16 +411,47 @@ namespace bs { namespace ct
 		return ndcZToDeviceZ;
 		return ndcZToDeviceZ;
 	}
 	}
 
 
+	Matrix4 invertProjectionMatrix(const Matrix4& mat)
+	{
+		// Try to solve the most common case using high percision calculations, in order to reduce depth error
+		if(mat[0][1] == 0.0f && mat[0][3] == 0.0f &&
+		   mat[1][0] == 0.0f && mat[1][3] == 0.0f &&
+		   mat[2][0] == 0.0f && mat[2][1] == 0.0f &&
+		   mat[3][0] == 0.0f && mat[3][1] == 0.0f &&
+		   mat[3][2] == -1.0f && mat[3][3] == 0.0f)
+		{
+			double a = mat[0][0];
+			double b = mat[1][1];
+			double c = mat[2][2];
+			double d = mat[2][3];
+			double s = mat[0][2];
+			double t = mat[1][2];
+
+			return Matrix4(
+				(float)(1.0/a), 0.0f, 0.0f, (float)(-s/a),
+				0.0f, (float)(1.0/b), 0.0f, (float)(-t/b),
+				0.0f, 0.0f, 0.0f, -1.0f,
+				0.0f, 0.0f, (float)(1.0/d), (float)(c/d)
+				);
+		}
+		else
+		{
+			return mat.inverse();
+		}
+	}
+
 	void RendererView::updatePerViewBuffer()
 	void RendererView::updatePerViewBuffer()
 	{
 	{
 		Matrix4 viewProj = mProperties.projTransform * mProperties.viewTransform;
 		Matrix4 viewProj = mProperties.projTransform * mProperties.viewTransform;
-		Matrix4 invViewProj = viewProj.inverse();
+		Matrix4 invProj = invertProjectionMatrix(mProperties.projTransform);
+		Matrix4 invView = mProperties.viewTransform.inverseAffine();
+		Matrix4 invViewProj = invView * invProj;
 
 
 		gPerCameraParamDef.gMatProj.set(mParamBuffer, mProperties.projTransform);
 		gPerCameraParamDef.gMatProj.set(mParamBuffer, mProperties.projTransform);
 		gPerCameraParamDef.gMatView.set(mParamBuffer, mProperties.viewTransform);
 		gPerCameraParamDef.gMatView.set(mParamBuffer, mProperties.viewTransform);
 		gPerCameraParamDef.gMatViewProj.set(mParamBuffer, viewProj);
 		gPerCameraParamDef.gMatViewProj.set(mParamBuffer, viewProj);
-		gPerCameraParamDef.gMatInvViewProj.set(mParamBuffer, invViewProj); // Note: Calculate inverses separately (better precision possibly)
-		gPerCameraParamDef.gMatInvProj.set(mParamBuffer, mProperties.projTransform.inverse());
+		gPerCameraParamDef.gMatInvViewProj.set(mParamBuffer, invViewProj);
+		gPerCameraParamDef.gMatInvProj.set(mParamBuffer, invProj);
 
 
 		// Construct a special inverse view-projection matrix that had projection entries that effect z and w eliminated.
 		// Construct a special inverse view-projection matrix that had projection entries that effect z and w eliminated.
 		// Used to transform a vector(clip_x, clip_y, view_z, view_w), where clip_x/clip_y are in clip space, and 
 		// Used to transform a vector(clip_x, clip_y, view_z, view_w), where clip_x/clip_y are in clip space, and