mirror of
https://github.com/minetest/minetest.git
synced 2024-11-30 11:33:44 +01:00
Allow server side occlusion culling.
This commit is contained in:
parent
6738c7e9a3
commit
ba4b704ebf
@ -864,6 +864,12 @@ liquid_update (Liquid update tick) float 1.0
|
|||||||
# Stated in mapblocks (16 nodes)
|
# Stated in mapblocks (16 nodes)
|
||||||
block_send_optimize_distance (block send optimize distance) int 4 2
|
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]
|
[*Mapgen]
|
||||||
|
|
||||||
# Name of map generator to be used when creating a new world.
|
# Name of map generator to be used when creating a new world.
|
||||||
|
@ -1056,6 +1056,12 @@
|
|||||||
# type: int min: 2
|
# type: int min: 2
|
||||||
# block_send_optimize_distance = 4
|
# 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
|
## Mapgen
|
||||||
|
|
||||||
# Name of map generator to be used when creating a new world.
|
# Name of map generator to be used when creating a new world.
|
||||||
|
@ -197,6 +197,9 @@ void RemoteClient::GetNextBlocks (
|
|||||||
s32 nearest_sent_d = -1;
|
s32 nearest_sent_d = -1;
|
||||||
//bool queue_is_full = false;
|
//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;
|
s16 d;
|
||||||
for(d = d_start; d <= d_max; d++) {
|
for(d = d_start; d <= d_max; d++) {
|
||||||
/*
|
/*
|
||||||
@ -298,6 +301,11 @@ void RemoteClient::GetNextBlocks (
|
|||||||
if(block->getDayNightDiff() == false)
|
if(block->getDayNightDiff() == false)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (occ_cull && !block_is_invalid &&
|
||||||
|
env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -109,35 +109,6 @@ void ClientMap::OnRegisterSceneNode()
|
|||||||
ISceneNode::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,
|
void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
|
||||||
v3s16 *p_blocks_min, v3s16 *p_blocks_max)
|
v3s16 *p_blocks_min, v3s16 *p_blocks_max)
|
||||||
{
|
{
|
||||||
@ -273,43 +244,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
|
|||||||
/*
|
/*
|
||||||
Occlusion culling
|
Occlusion culling
|
||||||
*/
|
*/
|
||||||
v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
|
if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
|
||||||
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)) {
|
|
||||||
blocks_occlusion_culled++;
|
blocks_occlusion_culled++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -282,6 +282,7 @@ void set_default_settings(Settings *settings)
|
|||||||
// This causes frametime jitter on client side, or does it?
|
// This causes frametime jitter on client side, or does it?
|
||||||
settings->setDefault("max_block_send_distance", "9");
|
settings->setDefault("max_block_send_distance", "9");
|
||||||
settings->setDefault("block_send_optimize_distance", "4");
|
settings->setDefault("block_send_optimize_distance", "4");
|
||||||
|
settings->setDefault("server_side_occlusion_culling", "false");
|
||||||
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
|
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
|
||||||
settings->setDefault("time_speed", "72");
|
settings->setDefault("time_speed", "72");
|
||||||
settings->setDefault("server_unload_unused_data_timeout", "29");
|
settings->setDefault("server_unload_unused_data_timeout", "29");
|
||||||
|
66
src/map.cpp
66
src/map.cpp
@ -1157,6 +1157,72 @@ void Map::removeNodeTimer(v3s16 p)
|
|||||||
block->m_node_timers.remove(p_rel);
|
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
|
ServerMap
|
||||||
*/
|
*/
|
||||||
|
@ -314,6 +314,7 @@ public:
|
|||||||
void transforming_liquid_add(v3s16 p);
|
void transforming_liquid_add(v3s16 p);
|
||||||
s32 transforming_liquid_size();
|
s32 transforming_liquid_size();
|
||||||
|
|
||||||
|
bool isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes);
|
||||||
protected:
|
protected:
|
||||||
friend class LuaVoxelManip;
|
friend class LuaVoxelManip;
|
||||||
|
|
||||||
@ -335,6 +336,9 @@ protected:
|
|||||||
// This stores the properties of the nodes on the map.
|
// This stores the properties of the nodes on the map.
|
||||||
INodeDefManager *m_nodedef;
|
INodeDefManager *m_nodedef;
|
||||||
|
|
||||||
|
bool isOccluded(v3s16 p0, v3s16 p1, float step, float stepfac,
|
||||||
|
float start_off, float end_off, u32 needed_count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
f32 m_transforming_liquid_loop_count_multiplier;
|
f32 m_transforming_liquid_loop_count_multiplier;
|
||||||
u32 m_unprocessed_count;
|
u32 m_unprocessed_count;
|
||||||
|
Loading…
Reference in New Issue
Block a user