Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Improve occlusion culling in corridors with additional check
  • Loading branch information
sfan5 committed Aug 24, 2019
1 parent e8716ff commit efbac7e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
73 changes: 73 additions & 0 deletions src/map.cpp
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 2 additions & 0 deletions src/map.h
Expand Up @@ -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);
Expand Down

0 comments on commit efbac7e

Please sign in to comment.