Skip to content
Permalink
Browse files

Improve occlusion culling in corridors with additional check

  • Loading branch information...
sfan5 committed Aug 22, 2019
1 parent e8716ff commit efbac7e4466ebc576b2cc64b5b782c61136cde66
Showing with 75 additions and 0 deletions.
  1. +73 −0 src/map.cpp
  2. +2 −0 src/map.h
@@ -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 @@ class Map /*: public NodeContainer*/
// 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);

0 comments on commit efbac7e

Please sign in to comment.
You can’t perform that action at this time.