@@ -1032,21 +1032,46 @@ void Map::removeNodeTimer(v3s16 p)
1032
1032
block->m_node_timers .remove (p_rel);
1033
1033
}
1034
1034
1035
- bool Map::isOccluded (v3s16 pos_origin, v3s16 pos_blockcenter, float step,
1036
- float stepfac, float offset, float end_offset, u32 needed_count)
1035
+ bool Map::isOccluded (const v3s16 &pos_camera, const v3s16 &pos_target,
1036
+ const core::aabbox3d<s16> &block_bounds, float step, float stepfac, float offset,
1037
+ u32 needed_count)
1037
1038
{
1038
- float distance = BS * pos_origin. getDistanceFrom (pos_blockcenter);
1039
- v3f direction = intToFloat (pos_blockcenter - pos_origin, BS);
1040
- direction. normalize ();
1041
- v3f pos_origin_f = intToFloat (pos_origin, BS) ;
1039
+ // Worst-case safety distance to keep to the target position
1040
+ // Anything smaller than the mapblock diagonal could result in in self-occlusion
1041
+ // Diagonal = sqrt(1*1 + 1*1 + 1*1)
1042
+ const static float BLOCK_DIAGONAL = BS * MAP_BLOCKSIZE * 1 . 732f ;
1042
1043
1044
+ v3f direction = intToFloat (pos_target - pos_camera, BS);
1045
+ float distance = direction.getLength ();
1046
+
1047
+ // Disable occlusion culling for near mapblocks in underground
1048
+ if (distance < BLOCK_DIAGONAL)
1049
+ return false ;
1050
+
1051
+ // Normalize direction vector
1052
+ if (distance > 0 .0f )
1053
+ direction /= distance;
1054
+
1055
+ v3f pos_origin_f = intToFloat (pos_camera, BS);
1043
1056
u32 count = 0 ;
1044
- for (; offset < distance + end_offset; offset += step){
1045
- v3f pf = pos_origin_f + direction * offset;
1046
- v3s16 pos_node = floatToInt (pf, BS);
1047
- MapNode node = getNode (pos_node);
1048
- if (m_nodedef->get (node).drawtype == NDT_NORMAL) {
1049
- // not transparent, see ContentFeature::updateTextures
1057
+ bool is_valid_position;
1058
+
1059
+ for (; offset < distance; offset += step) {
1060
+ v3f pos_node_f = pos_origin_f + direction * offset;
1061
+ v3s16 pos_node = floatToInt (pos_node_f, BS);
1062
+
1063
+ if (offset > distance - BLOCK_DIAGONAL) {
1064
+ // Do accurate position checks:
1065
+ // Check whether the node is inside the current mapblock
1066
+ if (block_bounds.isPointInside (pos_node))
1067
+ return false ;
1068
+ }
1069
+
1070
+ MapNode node = getNode (pos_node, &is_valid_position);
1071
+
1072
+ if (is_valid_position &&
1073
+ !m_nodedef->get (node).light_propagates ) {
1074
+ // Cannot see through light-blocking nodes --> occluded
1050
1075
count++;
1051
1076
if (count >= needed_count)
1052
1077
return true ;
@@ -1058,8 +1083,11 @@ bool Map::isOccluded(v3s16 pos_origin, v3s16 pos_blockcenter, float step,
1058
1083
1059
1084
bool Map::isBlockOccluded (MapBlock *block, v3s16 cam_pos_nodes)
1060
1085
{
1086
+ // Check occlusion for center and all 8 corners of the mapblock
1087
+ // Overshoot a little for less flickering
1061
1088
static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1 ;
1062
- static const v3s16 dir8[8 ] = {
1089
+ static const v3s16 dir9[9 ] = {
1090
+ v3s16 ( 0 , 0 , 0 ),
1063
1091
v3s16 ( 1 , 1 , 1 ) * bs2,
1064
1092
v3s16 ( 1 , 1 , -1 ) * bs2,
1065
1093
v3s16 ( 1 , -1 , 1 ) * bs2,
@@ -1070,34 +1098,26 @@ bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
1070
1098
v3s16 (-1 , -1 , -1 ) * bs2,
1071
1099
};
1072
1100
1073
- v3s16 pos_blockcenter = block-> getPos () * MAP_BLOCKSIZE;
1074
- pos_blockcenter += v3s16 (MAP_BLOCKSIZE) / 2 ;
1101
+ // Minimal and maximal positions in the mapblock
1102
+ core::aabbox3d<s16> block_bounds = block-> getBox () ;
1075
1103
1076
- float step = BS * 1 ;
1104
+ v3s16 pos_blockcenter = block_bounds.MinEdge + (MAP_BLOCKSIZE / 2 );
1105
+
1106
+ // Starting step size, value between 1m and sqrt(3)m
1107
+ float step = BS * 1 .2f ;
1077
1108
// Multiply step by each iteraction by 'stepfac' to reduce checks in distance
1078
- float stepfac = 1.1 ;
1109
+ float stepfac = 1 .05f ;
1079
1110
1080
- float start_offset = BS * 1 ;
1081
- // The occlusion search of 'isOccluded()' must stop short of the target
1082
- // point by distance 'end_offset' (end offset) to not enter the target mapblock.
1083
- // For the 8 mapblock corners 'end_offset' must therefore be the maximum diagonal
1084
- // of a mapblock, because we must consider all view angles.
1085
- // sqrt(1^2 + 1^2 + 1^2) = 1.732
1086
- float end_offset = -BS * MAP_BLOCKSIZE * 1.7321 ;
1111
+ float start_offset = BS * 1 .0f ;
1087
1112
1088
1113
// to reduce the likelihood of falsely occluded blocks
1089
1114
// require at least two solid blocks
1090
1115
// this is a HACK, we should think of a more precise algorithm
1091
1116
u32 needed_count = 2 ;
1092
1117
1093
- // For the central point of the mapblock 'end_offset' can be halved
1094
- if (!isOccluded (cam_pos_nodes, pos_blockcenter,
1095
- step, stepfac, start_offset, end_offset / 2 .0f , needed_count))
1096
- return false ;
1097
-
1098
- for (const v3s16 &dir : dir8) {
1099
- if (!isOccluded (cam_pos_nodes, pos_blockcenter + dir,
1100
- step, stepfac, start_offset, end_offset, needed_count))
1118
+ for (const v3s16 &dir : dir9) {
1119
+ if (!isOccluded (cam_pos_nodes, pos_blockcenter + dir, block_bounds,
1120
+ step, stepfac, start_offset, needed_count))
1101
1121
return false ;
1102
1122
}
1103
1123
return true ;
0 commit comments