Fix math for isBlockInSight. Fixes #718 (client-side).
authorAaron Suen <warr1024@gmail.com>
Fri, 17 May 2013 21:10:39 +0000 (17:10 -0400)
committerPilzAdam <pilzadam@minetest.net>
Fri, 17 May 2013 22:13:01 +0000 (00:13 +0200)
src/camera.cpp
src/util/numeric.cpp

index 6224a2b8ec99b052f11b2919af7f653d21bebaa6..0dd0a767bce056cf37412ec169afc68dd674e62d 100644 (file)
@@ -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);
 
index ed83df7d7f768be0f4635820d8d0985cc409f4bd..0e2772c3214d5826bd56ae275834f6c17d76aa55 100644 (file)
@@ -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;