mirror of
https://github.com/minetest/minetest.git
synced 2024-11-30 11:33:44 +01:00
Order drawlist by distance to the camera when rendering (#11651)
This commit is contained in:
parent
d51d0f3a5a
commit
f5040707fe
@ -73,7 +73,8 @@ ClientMap::ClientMap(
|
|||||||
rendering_engine->get_scene_manager(), id),
|
rendering_engine->get_scene_manager(), id),
|
||||||
m_client(client),
|
m_client(client),
|
||||||
m_rendering_engine(rendering_engine),
|
m_rendering_engine(rendering_engine),
|
||||||
m_control(control)
|
m_control(control),
|
||||||
|
m_drawlist(MapBlockComparer(v3s16(0,0,0)))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -164,6 +165,8 @@ void ClientMap::updateDrawList()
|
|||||||
{
|
{
|
||||||
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
|
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
|
||||||
|
|
||||||
|
m_needs_update_drawlist = false;
|
||||||
|
|
||||||
for (auto &i : m_drawlist) {
|
for (auto &i : m_drawlist) {
|
||||||
MapBlock *block = i.second;
|
MapBlock *block = i.second;
|
||||||
block->refDrop();
|
block->refDrop();
|
||||||
@ -178,6 +181,7 @@ void ClientMap::updateDrawList()
|
|||||||
const f32 camera_fov = m_camera_fov * 1.1f;
|
const f32 camera_fov = m_camera_fov * 1.1f;
|
||||||
|
|
||||||
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
|
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
|
||||||
|
|
||||||
v3s16 p_blocks_min;
|
v3s16 p_blocks_min;
|
||||||
v3s16 p_blocks_max;
|
v3s16 p_blocks_max;
|
||||||
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
|
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
|
||||||
@ -202,6 +206,8 @@ void ClientMap::updateDrawList()
|
|||||||
occlusion_culling_enabled = false;
|
occlusion_culling_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v3s16 camera_block = getContainerPos(cam_pos_nodes, MAP_BLOCKSIZE);
|
||||||
|
m_drawlist = std::map<v3s16, MapBlock*, MapBlockComparer>(MapBlockComparer(camera_block));
|
||||||
|
|
||||||
// Uncomment to debug occluded blocks in the wireframe mode
|
// Uncomment to debug occluded blocks in the wireframe mode
|
||||||
// TODO: Include this as a flag for an extended debugging setting
|
// TODO: Include this as a flag for an extended debugging setting
|
||||||
@ -321,7 +327,20 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
Draw the selected MapBlocks
|
Draw the selected MapBlocks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MeshBufListList drawbufs;
|
MeshBufListList grouped_buffers;
|
||||||
|
|
||||||
|
struct DrawDescriptor {
|
||||||
|
v3s16 m_pos;
|
||||||
|
scene::IMeshBuffer *m_buffer;
|
||||||
|
bool m_reuse_material;
|
||||||
|
|
||||||
|
DrawDescriptor(const v3s16 &pos, scene::IMeshBuffer *buffer, bool reuse_material) :
|
||||||
|
m_pos(pos), m_buffer(buffer), m_reuse_material(reuse_material)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<DrawDescriptor> draw_order;
|
||||||
|
video::SMaterial previous_material;
|
||||||
|
|
||||||
for (auto &i : m_drawlist) {
|
for (auto &i : m_drawlist) {
|
||||||
v3s16 block_pos = i.first;
|
v3s16 block_pos = i.first;
|
||||||
@ -386,21 +405,46 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
material.setFlag(video::EMF_WIREFRAME,
|
material.setFlag(video::EMF_WIREFRAME,
|
||||||
m_control.show_wireframe);
|
m_control.show_wireframe);
|
||||||
|
|
||||||
drawbufs.add(buf, block_pos, layer);
|
if (is_transparent_pass) {
|
||||||
|
// Same comparison as in MeshBufListList
|
||||||
|
bool new_material = material.getTexture(0) != previous_material.getTexture(0) ||
|
||||||
|
material != previous_material;
|
||||||
|
|
||||||
|
draw_order.emplace_back(block_pos, buf, !new_material);
|
||||||
|
|
||||||
|
if (new_material)
|
||||||
|
previous_material = material;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
grouped_buffers.add(buf, block_pos, layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture draw order for all solid meshes
|
||||||
|
for (auto &lists : grouped_buffers.lists) {
|
||||||
|
for (MeshBufList &list : lists) {
|
||||||
|
// iterate in reverse to draw closest blocks first
|
||||||
|
for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) {
|
||||||
|
draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TimeTaker draw("Drawing mesh buffers");
|
TimeTaker draw("Drawing mesh buffers");
|
||||||
|
|
||||||
core::matrix4 m; // Model matrix
|
core::matrix4 m; // Model matrix
|
||||||
v3f offset = intToFloat(m_camera_offset, BS);
|
v3f offset = intToFloat(m_camera_offset, BS);
|
||||||
|
u32 material_swaps = 0;
|
||||||
|
|
||||||
|
// Render all mesh buffers in order
|
||||||
|
drawcall_count += draw_order.size();
|
||||||
|
for (auto &descriptor : draw_order) {
|
||||||
|
scene::IMeshBuffer *buf = descriptor.m_buffer;
|
||||||
|
|
||||||
// Render all layers in order
|
|
||||||
for (auto &lists : drawbufs.lists) {
|
|
||||||
for (MeshBufList &list : lists) {
|
|
||||||
// Check and abort if the machine is swapping a lot
|
// Check and abort if the machine is swapping a lot
|
||||||
if (draw.getTimerTime() > 2000) {
|
if (draw.getTimerTime() > 2000) {
|
||||||
infostream << "ClientMap::renderMap(): Rendering took >2s, " <<
|
infostream << "ClientMap::renderMap(): Rendering took >2s, " <<
|
||||||
@ -408,31 +452,29 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!descriptor.m_reuse_material) {
|
||||||
|
auto &material = buf->getMaterial();
|
||||||
// pass the shadow map texture to the buffer texture
|
// pass the shadow map texture to the buffer texture
|
||||||
ShadowRenderer *shadow = m_rendering_engine->get_shadow_renderer();
|
ShadowRenderer *shadow = m_rendering_engine->get_shadow_renderer();
|
||||||
if (shadow && shadow->is_active()) {
|
if (shadow && shadow->is_active()) {
|
||||||
auto &layer = list.m.TextureLayer[3];
|
auto &layer = material.TextureLayer[3];
|
||||||
layer.Texture = shadow->get_texture();
|
layer.Texture = shadow->get_texture();
|
||||||
layer.TextureWrapU = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
|
layer.TextureWrapU = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
|
||||||
layer.TextureWrapV = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
|
layer.TextureWrapV = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
|
||||||
layer.TrilinearFilter = true;
|
layer.TrilinearFilter = true;
|
||||||
}
|
}
|
||||||
|
driver->setMaterial(material);
|
||||||
|
++material_swaps;
|
||||||
|
}
|
||||||
|
|
||||||
driver->setMaterial(list.m);
|
v3f block_wpos = intToFloat(descriptor.m_pos * MAP_BLOCKSIZE, BS);
|
||||||
|
|
||||||
drawcall_count += list.bufs.size();
|
|
||||||
for (auto &pair : list.bufs) {
|
|
||||||
scene::IMeshBuffer *buf = pair.second;
|
|
||||||
|
|
||||||
v3f block_wpos = intToFloat(pair.first * MAP_BLOCKSIZE, BS);
|
|
||||||
m.setTranslation(block_wpos - offset);
|
m.setTranslation(block_wpos - offset);
|
||||||
|
|
||||||
driver->setTransform(video::ETS_WORLD, m);
|
driver->setTransform(video::ETS_WORLD, m);
|
||||||
driver->drawMeshBuffer(buf);
|
driver->drawMeshBuffer(buf);
|
||||||
vertex_count += buf->getVertexCount();
|
vertex_count += buf->getVertexCount();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
|
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
|
||||||
|
|
||||||
// Log only on solid pass because values are the same
|
// Log only on solid pass because values are the same
|
||||||
@ -440,8 +482,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
|
g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pass == scene::ESNRP_TRANSPARENT) {
|
||||||
|
g_profiler->avg("renderMap(): transparent buffers [#]", draw_order.size());
|
||||||
|
}
|
||||||
|
|
||||||
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
|
||||||
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
|
||||||
|
g_profiler->avg(prefix + "material swaps [#]", material_swaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
|
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
|
||||||
|
@ -87,10 +87,18 @@ public:
|
|||||||
|
|
||||||
void updateCamera(const v3f &pos, const v3f &dir, f32 fov, const v3s16 &offset)
|
void updateCamera(const v3f &pos, const v3f &dir, f32 fov, const v3s16 &offset)
|
||||||
{
|
{
|
||||||
|
v3s16 previous_block = getContainerPos(floatToInt(m_camera_position, BS) + m_camera_offset, MAP_BLOCKSIZE);
|
||||||
|
|
||||||
m_camera_position = pos;
|
m_camera_position = pos;
|
||||||
m_camera_direction = dir;
|
m_camera_direction = dir;
|
||||||
m_camera_fov = fov;
|
m_camera_fov = fov;
|
||||||
m_camera_offset = offset;
|
m_camera_offset = offset;
|
||||||
|
|
||||||
|
v3s16 current_block = getContainerPos(floatToInt(m_camera_position, BS) + m_camera_offset, MAP_BLOCKSIZE);
|
||||||
|
|
||||||
|
// reorder the blocks when camera crosses block boundary
|
||||||
|
if (previous_block != current_block)
|
||||||
|
m_needs_update_drawlist = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -122,6 +130,8 @@ public:
|
|||||||
v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range=-1.0f);
|
v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range=-1.0f);
|
||||||
void updateDrawList();
|
void updateDrawList();
|
||||||
void updateDrawListShadow(const v3f &shadow_light_pos, const v3f &shadow_light_dir, float shadow_range);
|
void updateDrawListShadow(const v3f &shadow_light_pos, const v3f &shadow_light_dir, float shadow_range);
|
||||||
|
// Returns true if draw list needs updating before drawing the next frame.
|
||||||
|
bool needsUpdateDrawList() { return m_needs_update_drawlist; }
|
||||||
void renderMap(video::IVideoDriver* driver, s32 pass);
|
void renderMap(video::IVideoDriver* driver, s32 pass);
|
||||||
|
|
||||||
void renderMapShadows(video::IVideoDriver *driver,
|
void renderMapShadows(video::IVideoDriver *driver,
|
||||||
@ -140,6 +150,23 @@ public:
|
|||||||
f32 getCameraFov() const { return m_camera_fov; }
|
f32 getCameraFov() const { return m_camera_fov; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Orders blocks by distance to the camera
|
||||||
|
class MapBlockComparer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapBlockComparer(const v3s16 &camera_block) : m_camera_block(camera_block) {}
|
||||||
|
|
||||||
|
bool operator() (const v3s16 &left, const v3s16 &right) const
|
||||||
|
{
|
||||||
|
auto distance_left = left.getDistanceFromSQ(m_camera_block);
|
||||||
|
auto distance_right = right.getDistanceFromSQ(m_camera_block);
|
||||||
|
return distance_left > distance_right || (distance_left == distance_right && left > right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
v3s16 m_camera_block;
|
||||||
|
};
|
||||||
|
|
||||||
Client *m_client;
|
Client *m_client;
|
||||||
RenderingEngine *m_rendering_engine;
|
RenderingEngine *m_rendering_engine;
|
||||||
|
|
||||||
@ -153,8 +180,9 @@ private:
|
|||||||
f32 m_camera_fov = M_PI;
|
f32 m_camera_fov = M_PI;
|
||||||
v3s16 m_camera_offset;
|
v3s16 m_camera_offset;
|
||||||
|
|
||||||
std::map<v3s16, MapBlock*> m_drawlist;
|
std::map<v3s16, MapBlock*, MapBlockComparer> m_drawlist;
|
||||||
std::map<v3s16, MapBlock*> m_drawlist_shadow;
|
std::map<v3s16, MapBlock*> m_drawlist_shadow;
|
||||||
|
bool m_needs_update_drawlist;
|
||||||
|
|
||||||
std::set<v2s16> m_last_drawn_sectors;
|
std::set<v2s16> m_last_drawn_sectors;
|
||||||
|
|
||||||
|
@ -3897,8 +3897,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
v3f camera_direction = camera->getDirection();
|
v3f camera_direction = camera->getDirection();
|
||||||
if (runData.update_draw_list_timer >= update_draw_list_delta
|
if (runData.update_draw_list_timer >= update_draw_list_delta
|
||||||
|| runData.update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
|
|| runData.update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
|
||||||
|| m_camera_offset_changed) {
|
|| m_camera_offset_changed
|
||||||
|
|| client->getEnv().getClientMap().needsUpdateDrawList()) {
|
||||||
runData.update_draw_list_timer = 0;
|
runData.update_draw_list_timer = 0;
|
||||||
client->getEnv().getClientMap().updateDrawList();
|
client->getEnv().getClientMap().updateDrawList();
|
||||||
runData.update_draw_list_last_cam_dir = camera_direction;
|
runData.update_draw_list_last_cam_dir = camera_direction;
|
||||||
|
Loading…
Reference in New Issue
Block a user