aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/clientmap.cpp5
-rw-r--r--src/map.cpp84
-rw-r--r--src/map.h5
3 files changed, 60 insertions, 34 deletions
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index f2db94296..3e4ab2e94 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -151,6 +151,11 @@ void ClientMap::updateDrawList()
occlusion_culling_enabled = false;
}
+ // Uncomment to debug occluded blocks in the wireframe mode
+ // TODO: Include this as a flag for an extended debugging setting
+ //if (occlusion_culling_enabled && m_control.show_wireframe)
+ // occlusion_culling_enabled = porting::getTimeS() & 1;
+
for (const auto &sector_it : m_sectors) {
MapSector *sector = sector_it.second;
v2s16 sp = sector->getPos();
diff --git a/src/map.cpp b/src/map.cpp
index 3b57a9493..6b027d34b 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1032,21 +1032,46 @@ void Map::removeNodeTimer(v3s16 p)
block->m_node_timers.remove(p_rel);
}
-bool Map::isOccluded(v3s16 pos_origin, v3s16 pos_blockcenter, float step,
- float stepfac, float offset, float end_offset, u32 needed_count)
+bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
+ const core::aabbox3d<s16> &block_bounds, float step, float stepfac, float offset,
+ u32 needed_count)
{
- float distance = BS * pos_origin.getDistanceFrom(pos_blockcenter);
- v3f direction = intToFloat(pos_blockcenter - pos_origin, BS);
- direction.normalize();
- v3f pos_origin_f = intToFloat(pos_origin, BS);
+ // Worst-case safety distance to keep to the target position
+ // Anything smaller than the mapblock diagonal could result in in self-occlusion
+ // Diagonal = sqrt(1*1 + 1*1 + 1*1)
+ const static float BLOCK_DIAGONAL = BS * MAP_BLOCKSIZE * 1.732f;
+ v3f direction = intToFloat(pos_target - pos_camera, BS);
+ float distance = direction.getLength();
+
+ // Disable occlusion culling for near mapblocks in underground
+ if (distance < BLOCK_DIAGONAL)
+ return false;
+
+ // Normalize direction vector
+ if (distance > 0.0f)
+ direction /= distance;
+
+ v3f pos_origin_f = intToFloat(pos_camera, BS);
u32 count = 0;
- for (; offset < distance + end_offset; offset += step){
- v3f pf = pos_origin_f + direction * offset;
- v3s16 pos_node = floatToInt(pf, BS);
- MapNode node = getNode(pos_node);
- if (m_nodedef->get(node).drawtype == NDT_NORMAL) {
- // not transparent, see ContentFeature::updateTextures
+ bool is_valid_position;
+
+ for (; offset < distance; offset += step) {
+ v3f pos_node_f = pos_origin_f + direction * offset;
+ v3s16 pos_node = floatToInt(pos_node_f, BS);
+
+ if (offset > distance - BLOCK_DIAGONAL) {
+ // Do accurate position checks:
+ // Check whether the node is inside the current mapblock
+ if (block_bounds.isPointInside(pos_node))
+ return false;
+ }
+
+ MapNode node = getNode(pos_node, &is_valid_position);
+
+ if (is_valid_position &&
+ !m_nodedef->get(node).light_propagates) {
+ // Cannot see through light-blocking nodes --> occluded
count++;
if (count >= needed_count)
return true;
@@ -1058,8 +1083,11 @@ bool Map::isOccluded(v3s16 pos_origin, v3s16 pos_blockcenter, float step,
bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
{
+ // Check occlusion for center and all 8 corners of the mapblock
+ // Overshoot a little for less flickering
static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
- static const v3s16 dir8[8] = {
+ static const v3s16 dir9[9] = {
+ v3s16( 0, 0, 0),
v3s16( 1, 1, 1) * bs2,
v3s16( 1, 1, -1) * bs2,
v3s16( 1, -1, 1) * bs2,
@@ -1070,34 +1098,26 @@ bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
v3s16(-1, -1, -1) * bs2,
};
- v3s16 pos_blockcenter = block->getPos() * MAP_BLOCKSIZE;
- pos_blockcenter += v3s16(MAP_BLOCKSIZE) / 2;
+ // Minimal and maximal positions in the mapblock
+ core::aabbox3d<s16> block_bounds = block->getBox();
- float step = BS * 1;
+ v3s16 pos_blockcenter = block_bounds.MinEdge + (MAP_BLOCKSIZE / 2);
+
+ // Starting step size, value between 1m and sqrt(3)m
+ float step = BS * 1.2f;
// Multiply step by each iteraction by 'stepfac' to reduce checks in distance
- float stepfac = 1.1;
+ float stepfac = 1.05f;
- float start_offset = BS * 1;
- // The occlusion search of 'isOccluded()' must stop short of the target
- // point by distance 'end_offset' (end offset) to not enter the target mapblock.
- // For the 8 mapblock corners 'end_offset' must therefore be the maximum diagonal
- // of a mapblock, because we must consider all view angles.
- // sqrt(1^2 + 1^2 + 1^2) = 1.732
- float end_offset = -BS * MAP_BLOCKSIZE * 1.7321;
+ float start_offset = BS * 1.0f;
// to reduce the likelihood of falsely occluded blocks
// require at least two solid blocks
// this is a HACK, we should think of a more precise algorithm
u32 needed_count = 2;
- // For the central point of the mapblock 'end_offset' can be halved
- if (!isOccluded(cam_pos_nodes, pos_blockcenter,
- step, stepfac, start_offset, end_offset / 2.0f, needed_count))
- return false;
-
- for (const v3s16 &dir : dir8) {
- if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir,
- step, stepfac, start_offset, end_offset, needed_count))
+ for (const v3s16 &dir : dir9) {
+ if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, block_bounds,
+ step, stepfac, start_offset, needed_count))
return false;
}
return true;
diff --git a/src/map.h b/src/map.h
index d26da37a6..232a25ac7 100644
--- a/src/map.h
+++ b/src/map.h
@@ -310,8 +310,9 @@ protected:
// This stores the properties of the nodes on the map.
const NodeDefManager *m_nodedef;
- bool isOccluded(v3s16 pos_origin, v3s16 pos_blockcenter, float step,
- float stepfac, float start_offset, float end_offset, u32 needed_count);
+ bool isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
+ const core::aabbox3d<s16> &block_bounds, float step, float stepfac,
+ float offset, u32 needed_count);
private:
f32 m_transforming_liquid_loop_count_multiplier = 1.0f;