Improve occlusion culling in corridors with additional check

pull/10/head
sfan5 2019-08-23 00:14:45 +02:00
parent e8716ffede
commit efbac7e446
2 changed files with 75 additions and 0 deletions

View File

@ -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))

View File

@ -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);