From 1369503aba1ae0c64e6c25b32cc5552bbdead8fb Mon Sep 17 00:00:00 2001
From: Aaron Suen <warr1024@gmail.com>
Date: Fri, 17 May 2013 17:10:39 -0400
Subject: [PATCH] Fix math for isBlockInSight.  Fixes #718 (client-side).

---
 src/camera.cpp       |  3 +--
 src/util/numeric.cpp | 33 +++++++++++++++++----------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/camera.cpp b/src/camera.cpp
index 6224a2b8e..0dd0a767b 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -342,8 +342,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
 	m_fov_y = fov_degrees * M_PI / 180.0;
 	// Increase vertical FOV on lower aspect ratios (<16:10)
 	m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect)));
-	// WTF is this? It can't be right
-	m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
+	m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y));
 	m_cameranode->setAspectRatio(m_aspect);
 	m_cameranode->setFOV(m_fov_y);
 
diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp
index ed83df7d7..0e2772c32 100644
--- a/src/util/numeric.cpp
+++ b/src/util/numeric.cpp
@@ -159,40 +159,41 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
 	// Block position relative to camera
 	v3f blockpos_relative = blockpos - camera_pos;
 
-	// Distance in camera direction (+=front, -=back)
-	f32 dforward = blockpos_relative.dotProduct(camera_dir);
-
 	// Total distance
 	f32 d = blockpos_relative.getLength();
 
 	if(distance_ptr)
 		*distance_ptr = d;
 	
-	// If block is very close, it is always in sight
-	if(d < 1.44*1.44*MAP_BLOCKSIZE*BS/2)
-		return true;
-
 	// If block is far away, it's not in sight
 	if(d > range)
 		return false;
 
-	// Maximum radius of a block
-	f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
+	// Maximum radius of a block.  The magic number is
+	// sqrt(3.0) / 2.0 in literal form.
+	f32 block_max_radius = 0.866025403784 * MAP_BLOCKSIZE * BS;
 	
 	// If block is (nearly) touching the camera, don't
 	// bother validating further (that is, render it anyway)
 	if(d < block_max_radius)
 		return true;
-	
+
+	// Adjust camera position, for purposes of computing the angle,
+	// such that a block that has any portion visible with the
+	// current camera position will have the center visible at the
+	// adjusted postion
+	f32 adjdist = block_max_radius / cos((M_PI - camera_fov) / 2);
+
+	// Block position relative to adjusted camera
+	v3f blockpos_adj = blockpos - (camera_pos - camera_dir * adjdist);
+
+	// Distance in camera direction (+=front, -=back)
+	f32 dforward = blockpos_adj.dotProduct(camera_dir);
+
 	// Cosine of the angle between the camera direction
 	// and the block direction (camera_dir is an unit vector)
-	f32 cosangle = dforward / d;
+	f32 cosangle = dforward / blockpos_adj.getLength();
 	
-	// Compensate for the size of the block
-	// (as the block has to be shown even if it's a bit off FOV)
-	// This is an estimate, plus an arbitary factor
-	cosangle += block_max_radius / d * 0.5;
-
 	// If block is not in the field of view, skip it
 	if(cosangle < cos(camera_fov / 2))
 		return false;
-- 
GitLab