summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Hofhansl <larsh@apache.org>2017-02-27 23:06:15 -0800
committerAuke Kok <sofar+github@foo-projects.org>2017-03-11 18:11:19 -0800
commitba4b704ebf24952ab9a84c914b8ad6c45dabfaba (patch)
treed0e8d00948e40dbf20c9f3eb009ba494fb551648
parent6738c7e9a310514fca7d4ddb685800391756626b (diff)
downloadminetest-ba4b704ebf24952ab9a84c914b8ad6c45dabfaba.tar.gz
minetest-ba4b704ebf24952ab9a84c914b8ad6c45dabfaba.tar.bz2
minetest-ba4b704ebf24952ab9a84c914b8ad6c45dabfaba.zip
Allow server side occlusion culling.
-rw-r--r--builtin/settingtypes.txt6
-rw-r--r--minetest.conf.example6
-rw-r--r--src/clientiface.cpp8
-rw-r--r--src/clientmap.cpp67
-rw-r--r--src/defaultsettings.cpp1
-rw-r--r--src/map.cpp66
-rw-r--r--src/map.h4
7 files changed, 92 insertions, 66 deletions
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index 4e800e25b..ffd872c20 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -864,6 +864,12 @@ liquid_update (Liquid update tick) float 1.0
# Stated in mapblocks (16 nodes)
block_send_optimize_distance (block send optimize distance) int 4 2
+# If enabled the server will perform map block occlusion culling based on
+# on the eye position of the player. This can reduce the number of blocks
+# sent to the client 50-80%. The client will not longer receive most invisible
+# so that the utility of noclip mode is reduced.
+server_side_occlusion_culling (Server side occlusion culling) bool false
+
[*Mapgen]
# Name of map generator to be used when creating a new world.
diff --git a/minetest.conf.example b/minetest.conf.example
index d53a00fd9..08d00d62a 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -1056,6 +1056,12 @@
# type: int min: 2
# block_send_optimize_distance = 4
+# If enabled the server will perform map block occlusion culling based on
+# on the eye position of the player. This can reduce the number of blocks
+# sent to the client 50-80%. The client will not longer receive most invisible
+# so that the utility of noclip mode is reduced.
+server_side_occlusion_culling = false
+
## Mapgen
# Name of map generator to be used when creating a new world.
diff --git a/src/clientiface.cpp b/src/clientiface.cpp
index 0eb68c9c1..76a34c392 100644
--- a/src/clientiface.cpp
+++ b/src/clientiface.cpp
@@ -197,6 +197,9 @@ void RemoteClient::GetNextBlocks (
s32 nearest_sent_d = -1;
//bool queue_is_full = false;
+ const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
+ const bool occ_cull = g_settings->getBool("server_side_occlusion_culling");
+
s16 d;
for(d = d_start; d <= d_max; d++) {
/*
@@ -298,6 +301,11 @@ void RemoteClient::GetNextBlocks (
if(block->getDayNightDiff() == false)
continue;
}
+
+ if (occ_cull && !block_is_invalid &&
+ env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
+ continue;
+ }
}
/*
diff --git a/src/clientmap.cpp b/src/clientmap.cpp
index fb70a97e9..4cae03bf2 100644
--- a/src/clientmap.cpp
+++ b/src/clientmap.cpp
@@ -109,35 +109,6 @@ void ClientMap::OnRegisterSceneNode()
ISceneNode::OnRegisterSceneNode();
}
-static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
- float start_off, float end_off, u32 needed_count, INodeDefManager *nodemgr)
-{
- float d0 = (float)BS * p0.getDistanceFrom(p1);
- v3s16 u0 = p1 - p0;
- v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
- uf.normalize();
- v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
- u32 count = 0;
- for(float s=start_off; s<d0+end_off; s+=step){
- v3f pf = p0f + uf * s;
- v3s16 p = floatToInt(pf, BS);
- MapNode n = map->getNodeNoEx(p);
- bool is_transparent = false;
- const ContentFeatures &f = nodemgr->get(n);
- if(f.solidness == 0)
- is_transparent = (f.visual_solidness != 2);
- else
- is_transparent = (f.solidness != 2);
- if(!is_transparent){
- count++;
- if(count >= needed_count)
- return true;
- }
- step *= stepfac;
- }
- return false;
-}
-
void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
v3s16 *p_blocks_min, v3s16 *p_blocks_max)
{
@@ -273,43 +244,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
/*
Occlusion culling
*/
- v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
- cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
- float step = BS * 1;
- float stepfac = 1.1;
- float startoff = BS * 1;
- // The occlusion search of 'isOccluded()' must stop short of the target
- // point by distance 'endoff' (end offset) to not enter the target mapblock.
- // For the 8 mapblock corners 'endoff' 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 endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
- v3s16 spn = cam_pos_nodes;
- s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
- // 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;
- if (occlusion_culling_enabled &&
- // For the central point of the mapblock 'endoff' can be halved
- isOccluded(this, spn, cpn,
- step, stepfac, startoff, endoff / 2.0f, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, m_nodedef)) {
+ if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
blocks_occlusion_culled++;
continue;
}
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index e9ee1135f..483c9cff6 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -282,6 +282,7 @@ void set_default_settings(Settings *settings)
// This causes frametime jitter on client side, or does it?
settings->setDefault("max_block_send_distance", "9");
settings->setDefault("block_send_optimize_distance", "4");
+ settings->setDefault("server_side_occlusion_culling", "false");
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
settings->setDefault("time_speed", "72");
settings->setDefault("server_unload_unused_data_timeout", "29");
diff --git a/src/map.cpp b/src/map.cpp
index a1502befa..43a49dc2f 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1157,6 +1157,72 @@ void Map::removeNodeTimer(v3s16 p)
block->m_node_timers.remove(p_rel);
}
+bool Map::isOccluded(v3s16 p0, v3s16 p1, float step, float stepfac,
+ float start_off, float end_off, u32 needed_count)
+{
+ float d0 = (float)BS * p0.getDistanceFrom(p1);
+ v3s16 u0 = p1 - p0;
+ v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
+ uf.normalize();
+ v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
+ u32 count = 0;
+ for(float s=start_off; s<d0+end_off; s+=step){
+ v3f pf = p0f + uf * s;
+ v3s16 p = floatToInt(pf, BS);
+ MapNode n = getNodeNoEx(p);
+ const ContentFeatures &f = m_nodedef->get(n);
+ if(f.drawtype == NDT_NORMAL){
+ // not transparent, see ContentFeature::updateTextures
+ count++;
+ if(count >= needed_count)
+ return true;
+ }
+ step *= stepfac;
+ }
+ return false;
+}
+
+bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes) {
+ v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
+ cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
+ float step = BS * 1;
+ float stepfac = 1.1;
+ float startoff = BS * 1;
+ // The occlusion search of 'isOccluded()' must stop short of the target
+ // point by distance 'endoff' (end offset) to not enter the target mapblock.
+ // For the 8 mapblock corners 'endoff' 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 endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
+ v3s16 spn = cam_pos_nodes;
+ s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
+ // 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;
+
+ return (
+ // For the central point of the mapblock 'endoff' can be halved
+ isOccluded(spn, cpn,
+ step, stepfac, startoff, endoff / 2.0f, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,-bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,-bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,-bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,-bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count));
+}
+
/*
ServerMap
*/
diff --git a/src/map.h b/src/map.h
index c4181a49f..aeb05c704 100644
--- a/src/map.h
+++ b/src/map.h
@@ -314,6 +314,7 @@ public:
void transforming_liquid_add(v3s16 p);
s32 transforming_liquid_size();
+ bool isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes);
protected:
friend class LuaVoxelManip;
@@ -335,6 +336,9 @@ protected:
// This stores the properties of the nodes on the map.
INodeDefManager *m_nodedef;
+ bool isOccluded(v3s16 p0, v3s16 p1, float step, float stepfac,
+ float start_off, float end_off, u32 needed_count);
+
private:
f32 m_transforming_liquid_loop_count_multiplier;
u32 m_unprocessed_count;