forked from Mirrorlandia_minetest/minetest
Improve occlusion culling in corridors with additional check
This commit is contained in:
parent
e8716ffede
commit
efbac7e446
73
src/map.cpp
73
src/map.cpp
@ -1032,6 +1032,70 @@ void Map::removeNodeTimer(v3s16 p)
|
|||||||
block->m_node_timers.remove(p_rel);
|
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,
|
bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
|
||||||
float step, float stepfac, float offset, float end_offset, u32 needed_count)
|
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
|
// this is a HACK, we should think of a more precise algorithm
|
||||||
u32 needed_count = 2;
|
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) {
|
for (const v3s16 &dir : dir9) {
|
||||||
if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, step, stepfac,
|
if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, step, stepfac,
|
||||||
start_offset, end_offset, needed_count))
|
start_offset, end_offset, needed_count))
|
||||||
|
@ -310,6 +310,8 @@ protected:
|
|||||||
// This stores the properties of the nodes on the map.
|
// This stores the properties of the nodes on the map.
|
||||||
const NodeDefManager *m_nodedef;
|
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,
|
bool isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
|
||||||
float step, float stepfac, float start_offset, float end_offset,
|
float step, float stepfac, float start_offset, float end_offset,
|
||||||
u32 needed_count);
|
u32 needed_count);
|
||||||
|
Loading…
Reference in New Issue
Block a user