diff options
author | sfan5 <sfan5@live.de> | 2019-08-23 00:14:45 +0200 |
---|---|---|
committer | sfan5 <sfan5@live.de> | 2019-08-24 18:37:25 +0200 |
commit | efbac7e4466ebc576b2cc64b5b782c61136cde66 (patch) | |
tree | c8e515c853ed758db26cdf2dfcc73c6e25617cde | |
parent | e8716ffede885b3041a5fc97557b336d6699abc5 (diff) | |
download | minetest-efbac7e4466ebc576b2cc64b5b782c61136cde66.tar.gz minetest-efbac7e4466ebc576b2cc64b5b782c61136cde66.tar.bz2 minetest-efbac7e4466ebc576b2cc64b5b782c61136cde66.zip |
Improve occlusion culling in corridors with additional check
-rw-r--r-- | src/map.cpp | 73 | ||||
-rw-r--r-- | src/map.h | 2 |
2 files changed, 75 insertions, 0 deletions
diff --git a/src/map.cpp b/src/map.cpp index fba970823..022eb9f19 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1032,6 +1032,70 @@ void Map::removeNodeTimer(v3s16 p) block->m_node_timers.remove(p_rel); } +bool Map::determineAdditionalOcclusionCheck(const v3s16 &pos_camera, + const core::aabbox3d<s16> &block_bounds, v3s16 &check) +{ + /* + This functions determines the node inside the target block that is + closest to the camera position. This increases the occlusion culling + accuracy in straight and diagonal corridors. + The returned position will be occlusion checked first in addition to the + others (8 corners + center). + No position is returned if + - the closest node is a corner, corners are checked anyway. + - the camera is inside the target block, it will never be occluded. + */ +#define CLOSEST_EDGE(pos, bounds, axis) \ + ((pos).axis <= (bounds).MinEdge.axis) ? (bounds).MinEdge.axis : \ + (bounds).MaxEdge.axis + + bool x_inside = (block_bounds.MinEdge.X <= pos_camera.X) && + (pos_camera.X <= block_bounds.MaxEdge.X); + bool y_inside = (block_bounds.MinEdge.Y <= pos_camera.Y) && + (pos_camera.Y <= block_bounds.MaxEdge.Y); + bool z_inside = (block_bounds.MinEdge.Z <= pos_camera.Z) && + (pos_camera.Z <= block_bounds.MaxEdge.Z); + + if (x_inside && y_inside && z_inside) + return false; // Camera inside target mapblock + + // straight + if (x_inside && y_inside) { + check = v3s16(pos_camera.X, pos_camera.Y, 0); + check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z); + return true; + } else if (y_inside && z_inside) { + check = v3s16(0, pos_camera.Y, pos_camera.Z); + check.X = CLOSEST_EDGE(pos_camera, block_bounds, X); + return true; + } else if (x_inside && z_inside) { + check = v3s16(pos_camera.X, 0, pos_camera.Z); + check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y); + return true; + } + + // diagonal + if (x_inside) { + check = v3s16(pos_camera.X, 0, 0); + check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y); + check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z); + return true; + } else if (y_inside) { + check = v3s16(0, pos_camera.Y, 0); + check.X = CLOSEST_EDGE(pos_camera, block_bounds, X); + check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z); + return true; + } else if (z_inside) { + check = v3s16(0, 0, pos_camera.Z); + check.X = CLOSEST_EDGE(pos_camera, block_bounds, X); + check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y); + return true; + } + + // Closest node would be a corner, none returned + return false; +} + bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target, float step, float stepfac, float offset, float end_offset, u32 needed_count) { @@ -1102,6 +1166,15 @@ bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes) // this is a HACK, we should think of a more precise algorithm u32 needed_count = 2; + // Additional occlusion check, see comments in that function + v3s16 check; + if (determineAdditionalOcclusionCheck(cam_pos_nodes, block->getBox(), check)) { + // node is always on a side facing the camera, end_offset can be lower + if (!isOccluded(cam_pos_nodes, check, step, stepfac, start_offset, + -1.0f, needed_count)) + return false; + } + for (const v3s16 &dir : dir9) { if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, step, stepfac, start_offset, end_offset, needed_count)) @@ -310,6 +310,8 @@ protected: // This stores the properties of the nodes on the map. const NodeDefManager *m_nodedef; + bool determineAdditionalOcclusionCheck(const v3s16 &pos_camera, + const core::aabbox3d<s16> &block_bounds, v3s16 &check); bool isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target, float step, float stepfac, float start_offset, float end_offset, u32 needed_count); |