Skip to content

Commit

Permalink
Separate code for client and server side occlusion culling
Browse files Browse the repository at this point in the history
  • Loading branch information
lhofhansl committed Jan 4, 2024
1 parent 9065734 commit 06cfa81
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 14 deletions.
56 changes: 56 additions & 0 deletions src/client/clientmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,62 @@ void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
p_nodes_max.Z / MAP_BLOCKSIZE + 1);
}

bool ClientMap::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
{
// Check occlusion for center and all 8 corners of the mapblock
// Overshoot a little for less flickering
static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
static const v3s16 dir9[9] = {
v3s16( 0, 0, 0),
v3s16( 1, 1, 1) * bs2,
v3s16( 1, 1, -1) * bs2,
v3s16( 1, -1, 1) * bs2,
v3s16( 1, -1, -1) * bs2,
v3s16(-1, 1, 1) * bs2,
v3s16(-1, 1, -1) * bs2,
v3s16(-1, -1, 1) * bs2,
v3s16(-1, -1, -1) * bs2,
};

v3s16 pos_relative = block->getPosRelative();
v3s16 pos_blockcenter = pos_relative + (MAP_BLOCKSIZE / 2);

// Starting step size, value between 1m and sqrt(3)m
float step = BS * 1.2f;
// Multiply step by each iteraction by 'stepfac' to reduce checks in distance
float stepfac = 1.05f;

float start_offset = BS * 1.0f;

// The occlusion search of 'isOccluded()' must stop short of the target
// point by distance 'end_offset' to not enter the target mapblock.
// For the 8 mapblock corners 'end_offset' must therefore be the maximum
// diagonal of a mapblock, because we must consider all view angles.
// sqrt(1^2 + 1^2 + 1^2) = 1.732
float end_offset = -BS * MAP_BLOCKSIZE * 1.732f;

// to reduce the likelihood of falsely occluded blocks
// require at least two solid blocks
// 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))
return false;
}
return true;
}

class MapBlockFlags
{
public:
Expand Down
2 changes: 2 additions & 0 deletions src/client/clientmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class ClientMap : public Map, public scene::ISceneNode

void onSettingChanged(const std::string &name);

bool isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes);

protected:
void reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks) override;
private:
Expand Down
2 changes: 1 addition & 1 deletion src/clientiface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ void RemoteClient::GetNextBlocks (
Note that we do this even before the block is loaded as this does not depend on its contents.
*/
if (m_occ_cull &&
env->getMap().isBlockOccluded(p * MAP_BLOCKSIZE, cam_pos_nodes, d)) {
env->getServerMap().isBlockOccluded(p * MAP_BLOCKSIZE, cam_pos_nodes, d)) {
m_blocks_occ.insert(p);
continue;
}
Expand Down
14 changes: 8 additions & 6 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ bool Map::determineAdditionalOcclusionCheck(const v3s16 &pos_camera,
}

bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
float step, float stepfac, float offset, float end_offset)
float step, float stepfac, float offset, float end_offset, u32 needed_count)
{
v3f direction = intToFloat(pos_target - pos_camera, BS);
float distance = direction.getLength();
Expand All @@ -1134,6 +1134,7 @@ bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
direction /= distance;

v3f pos_origin_f = intToFloat(pos_camera, BS);
u32 count = 0;
bool is_valid_position;

for (; offset < distance + end_offset; offset += step) {
Expand All @@ -1145,16 +1146,17 @@ bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target,
if (is_valid_position &&
!m_nodedef->getLightingFlags(node).light_propagates) {
// Cannot see through light-blocking nodes --> occluded
return true;
count++;
if (count >= needed_count)
return true;
}
step *= stepfac;
}
return false;
}

bool Map::isBlockOccluded(v3s16 pos_relative, v3s16 cam_pos_nodes, s16 d)
bool ServerMap::isBlockOccluded(v3s16 pos_relative, v3s16 cam_pos_nodes, s16 d)
{
// Check occlusion for center and all 8 corners of the mapblock
// Overshoot a little for less flickering
static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1;

Expand Down Expand Up @@ -1184,14 +1186,14 @@ bool Map::isBlockOccluded(v3s16 pos_relative, v3s16 cam_pos_nodes, s16 d)
if (determineAdditionalOcclusionCheck(cam_pos_nodes, MapBlock::getBox(pos_relative), 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))
-1.0f, 2))
return false;
}
}

for (int i=0; i<rounds; i++) {
if (!isOccluded(cam_pos_nodes, pos_blockcenter + v3s16(myrand_range(-bs2, bs2), myrand_range(-bs2, bs2), myrand_range(-bs2, bs2)), step, stepfac,
start_offset, end_offset))
start_offset, end_offset, 1))
return false;
}
return true;
Expand Down
11 changes: 4 additions & 7 deletions src/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,6 @@ class Map /*: public NodeContainer*/
}
}

bool isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes)
{
return isBlockOccluded(block->getPosRelative(), cam_pos_nodes);
}
bool isBlockOccluded(v3s16 pos_relative, v3s16 cam_pos_nodes, s16 d = 0);

protected:
IGameDef *m_gamedef;

Expand All @@ -331,7 +325,8 @@ class Map /*: public NodeContainer*/
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);
float step, float stepfac, float start_offset, float end_offset,
u32 needed_count);
};

/*
Expand Down Expand Up @@ -449,6 +444,8 @@ class ServerMap : public Map

void transforming_liquid_add(v3s16 p);

bool isBlockOccluded(v3s16 pos_relative, v3s16 cam_pos_nodes, s16 d);

MapSettingsManager settings_mgr;

protected:
Expand Down

0 comments on commit 06cfa81

Please sign in to comment.