mirror of
https://github.com/luanti-org/luanti.git
synced 2026-10-11 22:09:57 +00:00
Optimize isBlockInSight (#17471)
* Reduce algebraic operations in isBlockInSight * Pre-compute camera related constants
This commit is contained in:
@@ -242,6 +242,11 @@ void RemoteClient::GetNextBlocks (
|
||||
|
||||
const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
|
||||
|
||||
// Calculate FOV attributes here, once per call
|
||||
// see numeric.h for details
|
||||
const f32 target_cos_sq = getFovCosSq(camera_fov);
|
||||
const f32 adjdist = getFovAdj(camera_fov);
|
||||
|
||||
s16 d;
|
||||
for (d = d_start; d <= d_max; d++) {
|
||||
/*
|
||||
@@ -284,7 +289,7 @@ void RemoteClient::GetNextBlocks (
|
||||
(0.1 is about 5 degrees)
|
||||
*/
|
||||
f32 dist;
|
||||
if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
|
||||
if (!(isBlockInSightEx(p, camera_pos, camera_dir, target_cos_sq, adjdist,
|
||||
d_blocks_in_sight, &dist) ||
|
||||
(playerspeed.getLength() > 1.0f * BS &&
|
||||
isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
|
||||
|
||||
+41
-34
@@ -86,57 +86,64 @@ u64 murmur_hash_64_ua(const void *key, size_t len, unsigned int seed)
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
||||
f32 camera_fov, f32 range, f32 *distance_ptr)
|
||||
bool isBlockInSight(const v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
||||
const f32 camera_fov, const f32 range, f32 *distance_ptr)
|
||||
{
|
||||
v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
|
||||
return isBlockInSightEx(blockpos_b, camera_pos, camera_dir, getFovCosSq(camera_fov), getFovAdj(camera_fov), range, distance_ptr);
|
||||
}
|
||||
|
||||
// Block center position
|
||||
v3f blockpos = v3f::from(blockpos_nodes + MAP_BLOCKSIZE / 2) * BS;
|
||||
bool isBlockInSightEx(const v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
||||
const f32 target_cos_sq, const f32 adjdist, f32 range, f32 *distance_ptr)
|
||||
{
|
||||
// Block center position relative to camera
|
||||
const v3f blockpos_relative =
|
||||
intToFloat(blockpos_b * MAP_BLOCKSIZE + v3s16(MAP_BLOCKSIZE / 2), BS) -
|
||||
camera_pos;
|
||||
|
||||
// Block position relative to camera
|
||||
v3f blockpos_relative = blockpos - camera_pos;
|
||||
if (distance_ptr) {
|
||||
*distance_ptr = 0.0f;
|
||||
}
|
||||
|
||||
// Total distance
|
||||
f32 d = std::max(0.0f, blockpos_relative.getLength() - BLOCK_MAX_RADIUS);
|
||||
|
||||
if (distance_ptr)
|
||||
*distance_ptr = d;
|
||||
// Square distance
|
||||
const f32 len_sq = blockpos_relative.getLengthSQ();
|
||||
|
||||
// If block is far away, it's not in sight
|
||||
if (d > range)
|
||||
const f32 max_reach = range + BLOCK_MAX_RADIUS;
|
||||
if (len_sq > max_reach * max_reach)
|
||||
return false;
|
||||
|
||||
// If block is (nearly) touching the camera, don't
|
||||
// bother validating further (that is, render it anyway)
|
||||
if (d == 0)
|
||||
if (len_sq <= BLOCK_MAX_RADIUS * BLOCK_MAX_RADIUS) {
|
||||
// this means distance in blocks is 0
|
||||
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 position
|
||||
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);
|
||||
|
||||
const f32 dot = blockpos_relative.dotProduct(camera_dir);
|
||||
// Distance in camera direction (+=front, -=back)
|
||||
f32 dforward = blockpos_adj.dotProduct(camera_dir);
|
||||
const f32 dforward = dot + adjdist;
|
||||
|
||||
// Cosine of the angle between the camera direction
|
||||
// and the block direction (camera_dir is an unit vector)
|
||||
f32 cosangle = dforward / blockpos_adj.getLength();
|
||||
|
||||
// If block is not in the field of view, skip it
|
||||
// HOTFIX: use slightly increased angle (+10%) to fix too aggressive
|
||||
// culling. Somebody has to find out what's wrong with the math here.
|
||||
// Previous value: camera_fov / 2
|
||||
if (cosangle < std::cos(camera_fov * 0.55f))
|
||||
// If the block is behind the adjusted camera position, cull it instantly
|
||||
if (dforward <= 0.0f)
|
||||
return false;
|
||||
|
||||
// |A+B|^2 = |A|^2 + 2(A dot B) + |B|^2
|
||||
const f32 len_adj_sq = len_sq + 2.0f * adjdist * dot + adjdist * adjdist;
|
||||
|
||||
// do angle check with squared values
|
||||
// This is a transformation of the previous
|
||||
// dForward/blockpos_adj.getLength() < target_cos
|
||||
// This is safe because of the (dforward <= 0.0f) check above
|
||||
// (and the fact that fov <= 160 degrees)
|
||||
if (dforward * dforward < target_cos_sq * len_adj_sq)
|
||||
return false;
|
||||
|
||||
// calculate the actual distance only if the block is visible
|
||||
if (distance_ptr) {
|
||||
*distance_ptr = std::max(0.0f, std::sqrt(len_sq) - BLOCK_MAX_RADIUS);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+35
-2
@@ -313,14 +313,47 @@ u64 murmur_hash_64_ua(const void *key, size_t len, unsigned int seed);
|
||||
* @param blockpos_b position of block in block coordinates
|
||||
* @param camera_pos position of camera in nodes
|
||||
* @param camera_dir an unit vector pointing to camera direction
|
||||
* @param camera_fov in rad
|
||||
* @param range viewing range
|
||||
* @param distance_ptr return location for distance from the camera
|
||||
*/
|
||||
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
||||
f32 camera_fov, f32 range, f32 *distance_ptr=nullptr);
|
||||
bool isBlockInSight(const v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
||||
const f32 camera_fov, const f32 range, f32 *distance_ptr=nullptr);
|
||||
|
||||
/**
|
||||
* @param blockpos_b position of block in block coordinates
|
||||
* @param camera_pos position of camera in nodes
|
||||
* @param camera_dir an unit vector pointing to camera direction
|
||||
* @param target_cos_sq pre-computed adjusted cos^2(camera fov) (use getFovCosSq(...))
|
||||
* @param adjdist pre-computed camera distance adjustment (use getFovAdj(...))
|
||||
* @param range viewing range
|
||||
* @param distance_ptr return location for distance from the camera
|
||||
*/
|
||||
bool isBlockInSightEx(const v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
||||
const f32 target_cos_sq, const f32 adjdist, const f32 range, f32 *distance_ptr);
|
||||
|
||||
s16 adjustDist(s16 dist, float zoom_fov);
|
||||
|
||||
|
||||
inline f32 getFovAdj(f32 camera_fov)
|
||||
{
|
||||
// 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 position
|
||||
return BLOCK_MAX_RADIUS / std::sin(camera_fov * 0.5f);
|
||||
}
|
||||
|
||||
inline f32 getFovCosSq(f32 camera_fov)
|
||||
{
|
||||
// If block is not in the field of view, skip it
|
||||
// HOTFIX: use slightly increased angle (+10%) to fix too aggressive
|
||||
// culling. Somebody has to find out what's wrong with the math here.
|
||||
// Previous value: camera_fov / 2
|
||||
const f32 target_cos = std::cos(camera_fov * 0.55f);
|
||||
return target_cos * target_cos;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns nearest 32-bit integer for given floating point number.
|
||||
<cmath> and <math.h> in VC++ don't provide round().
|
||||
|
||||
Reference in New Issue
Block a user