mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
VBO-related optimizations and improvements (#14395)
This commit is contained in:
parent
d85c842ce9
commit
bb7f57b095
22 changed files with 439 additions and 322 deletions
|
@ -18,10 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
*/
|
||||
|
||||
#include "client/renderingengine.h"
|
||||
#include "client/shader.h"
|
||||
#include "clouds.h"
|
||||
#include "noise.h"
|
||||
#include "constants.h"
|
||||
#include "debug.h"
|
||||
#include "irrlicht_changes/printing.h"
|
||||
#include "noise.h"
|
||||
#include "profiler.h"
|
||||
#include "settings.h"
|
||||
#include <cmath>
|
||||
|
@ -40,35 +42,38 @@ static void cloud_3d_setting_changed(const std::string &settingname, void *data)
|
|||
((Clouds *)data)->readSettings();
|
||||
}
|
||||
|
||||
Clouds::Clouds(scene::ISceneManager* mgr,
|
||||
Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc,
|
||||
s32 id,
|
||||
u32 seed
|
||||
):
|
||||
scene::ISceneNode(mgr->getRootSceneNode(), mgr, id),
|
||||
m_seed(seed)
|
||||
{
|
||||
m_enable_shaders = g_settings->getBool("enable_shaders");
|
||||
// menu clouds use shader-less clouds for simplicity (ssrc == NULL)
|
||||
m_enable_shaders = m_enable_shaders && ssrc;
|
||||
|
||||
m_material.Lighting = false;
|
||||
m_material.BackfaceCulling = true;
|
||||
m_material.FogEnable = true;
|
||||
m_material.AntiAliasing = video::EAAM_SIMPLE;
|
||||
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
m_material.forEachTexture([] (auto &tex) {
|
||||
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
|
||||
tex.MagFilter = video::ETMAGF_NEAREST;
|
||||
});
|
||||
if (m_enable_shaders) {
|
||||
auto sid = ssrc->getShader("cloud_shader", TILE_MATERIAL_ALPHA);
|
||||
m_material.MaterialType = ssrc->getShaderInfo(sid).material;
|
||||
} else {
|
||||
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
}
|
||||
|
||||
m_params.height = 120;
|
||||
m_params.density = 0.4f;
|
||||
m_params.thickness = 16.0f;
|
||||
m_params.color_bright = video::SColor(229, 240, 240, 255);
|
||||
m_params.color_ambient = video::SColor(255, 0, 0, 0);
|
||||
m_params.speed = v2f(0.0f, -2.0f);
|
||||
m_params = SkyboxDefaults::getCloudDefaults();
|
||||
|
||||
readSettings();
|
||||
g_settings->registerChangedCallback("enable_3d_clouds",
|
||||
&cloud_3d_setting_changed, this);
|
||||
|
||||
updateBox();
|
||||
|
||||
m_meshbuffer.reset(new scene::SMeshBuffer());
|
||||
m_meshbuffer->setHardwareMappingHint(scene::EHM_DYNAMIC);
|
||||
}
|
||||
|
||||
Clouds::~Clouds()
|
||||
|
@ -82,38 +87,14 @@ void Clouds::OnRegisterSceneNode()
|
|||
if(IsVisible)
|
||||
{
|
||||
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
|
||||
//SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
|
||||
}
|
||||
|
||||
ISceneNode::OnRegisterSceneNode();
|
||||
}
|
||||
|
||||
void Clouds::render()
|
||||
void Clouds::updateMesh()
|
||||
{
|
||||
|
||||
if (m_params.density <= 0.0f)
|
||||
return; // no need to do anything
|
||||
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
|
||||
if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
|
||||
//if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
|
||||
return;
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Clouds::render()", SPT_AVG);
|
||||
|
||||
int num_faces_to_draw = m_enable_3d ? 6 : 1;
|
||||
|
||||
m_material.BackfaceCulling = m_enable_3d;
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
driver->setMaterial(m_material);
|
||||
|
||||
/*
|
||||
Clouds move from Z+ towards Z-
|
||||
*/
|
||||
|
||||
const float cloud_full_radius = cloud_size * m_cloud_radius_i;
|
||||
// Clouds move from Z+ towards Z-
|
||||
|
||||
v2f camera_pos_2d(m_camera_pos.X, m_camera_pos.Z);
|
||||
// Position of cloud noise origin from the camera
|
||||
|
@ -126,56 +107,61 @@ void Clouds::render()
|
|||
std::floor(center_of_drawing_in_noise_f.Y / cloud_size)
|
||||
);
|
||||
|
||||
// Only update mesh if it has moved enough, this saves lots of GPU buffer uploads.
|
||||
constexpr float max_d = 5 * BS;
|
||||
|
||||
if (!m_mesh_valid) {
|
||||
// mesh was never created or invalidated
|
||||
} else if (m_mesh_origin.getDistanceFrom(m_origin) >= max_d) {
|
||||
// clouds moved
|
||||
} else if (center_of_drawing_in_noise_i != m_last_noise_center) {
|
||||
// noise offset changed
|
||||
// I think in practice this never happens due to the camera offset
|
||||
// being smaller than the cloud size.(?)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Clouds::updateMesh()", SPT_AVG);
|
||||
m_mesh_origin = m_origin;
|
||||
m_last_noise_center = center_of_drawing_in_noise_i;
|
||||
m_mesh_valid = true;
|
||||
|
||||
const u32 num_faces_to_draw = m_enable_3d ? 6 : 1;
|
||||
|
||||
// The world position of the integer center point of drawing in the noise
|
||||
v2f world_center_of_drawing_in_noise_f = v2f(
|
||||
center_of_drawing_in_noise_i.X * cloud_size,
|
||||
center_of_drawing_in_noise_i.Y * cloud_size
|
||||
) + m_origin;
|
||||
|
||||
/*video::SColor c_top(128,b*240,b*240,b*255);
|
||||
video::SColor c_side_1(128,b*230,b*230,b*255);
|
||||
video::SColor c_side_2(128,b*220,b*220,b*245);
|
||||
video::SColor c_bottom(128,b*205,b*205,b*230);*/
|
||||
// Colors with primitive shading
|
||||
|
||||
video::SColorf c_top_f(m_color);
|
||||
video::SColorf c_side_1_f(m_color);
|
||||
video::SColorf c_side_2_f(m_color);
|
||||
video::SColorf c_bottom_f(m_color);
|
||||
c_side_1_f.r *= 0.95;
|
||||
c_side_1_f.g *= 0.95;
|
||||
c_side_1_f.b *= 0.95;
|
||||
c_side_2_f.r *= 0.90;
|
||||
c_side_2_f.g *= 0.90;
|
||||
c_side_2_f.b *= 0.90;
|
||||
c_bottom_f.r *= 0.80;
|
||||
c_bottom_f.g *= 0.80;
|
||||
c_bottom_f.b *= 0.80;
|
||||
if (m_enable_shaders) {
|
||||
// shader mixes the base color, set via EmissiveColor
|
||||
c_top_f = c_side_1_f = c_side_2_f = c_bottom_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
c_side_1_f.r *= 0.95f;
|
||||
c_side_1_f.g *= 0.95f;
|
||||
c_side_1_f.b *= 0.95f;
|
||||
c_side_2_f.r *= 0.90f;
|
||||
c_side_2_f.g *= 0.90f;
|
||||
c_side_2_f.b *= 0.90f;
|
||||
c_bottom_f.r *= 0.80f;
|
||||
c_bottom_f.g *= 0.80f;
|
||||
c_bottom_f.b *= 0.80f;
|
||||
video::SColor c_top = c_top_f.toSColor();
|
||||
video::SColor c_side_1 = c_side_1_f.toSColor();
|
||||
video::SColor c_side_2 = c_side_2_f.toSColor();
|
||||
video::SColor c_bottom = c_bottom_f.toSColor();
|
||||
|
||||
// Get fog parameters for setting them back later
|
||||
video::SColor fog_color(0,0,0,0);
|
||||
video::E_FOG_TYPE fog_type = video::EFT_FOG_LINEAR;
|
||||
f32 fog_start = 0;
|
||||
f32 fog_end = 0;
|
||||
f32 fog_density = 0;
|
||||
bool fog_pixelfog = false;
|
||||
bool fog_rangefog = false;
|
||||
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||
fog_pixelfog, fog_rangefog);
|
||||
|
||||
// Set our own fog, unless it was already disabled
|
||||
if (fog_start < FOG_RANGE_ALL) {
|
||||
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
|
||||
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
||||
}
|
||||
|
||||
// Read noise
|
||||
|
||||
std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
|
||||
std::vector<video::S3DVertex> vertices;
|
||||
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);
|
||||
|
||||
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
|
||||
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
|
||||
|
@ -190,10 +176,23 @@ void Clouds::render()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
auto *mb = m_meshbuffer.get();
|
||||
{
|
||||
const u32 vertex_count = num_faces_to_draw * 16 * m_cloud_radius_i * m_cloud_radius_i;
|
||||
const u32 quad_count = vertex_count / 4;
|
||||
const u32 index_count = quad_count * 6;
|
||||
|
||||
// reserve memory
|
||||
mb->Vertices.reallocate(vertex_count);
|
||||
mb->Indices.reallocate(index_count);
|
||||
}
|
||||
|
||||
#define GETINDEX(x, z, radius) (((z)+(radius))*(radius)*2 + (x)+(radius))
|
||||
#define INAREA(x, z, radius) \
|
||||
((x) >= -(radius) && (x) < (radius) && (z) >= -(radius) && (z) < (radius))
|
||||
|
||||
mb->Vertices.set_used(0);
|
||||
for (s16 zi0= -m_cloud_radius_i; zi0 < m_cloud_radius_i; zi0++)
|
||||
for (s16 xi0= -m_cloud_radius_i; xi0 < m_cloud_radius_i; xi0++)
|
||||
{
|
||||
|
@ -224,7 +223,7 @@ void Clouds::render()
|
|||
const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
|
||||
const f32 rz = cloud_size / 2;
|
||||
|
||||
for(int i=0; i<num_faces_to_draw; i++)
|
||||
for(u32 i = 0; i < num_faces_to_draw; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
|
@ -310,27 +309,87 @@ void Clouds::render()
|
|||
}
|
||||
|
||||
v3f pos(p0.X, m_params.height * BS, p0.Y);
|
||||
pos -= intToFloat(m_camera_offset, BS);
|
||||
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Pos += pos;
|
||||
vertices.push_back(vertex);
|
||||
mb->Vertices.push_back(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
int quad_count = vertices.size() / 4;
|
||||
std::vector<u16> indices;
|
||||
indices.reserve(quad_count * 6);
|
||||
for (int k = 0; k < quad_count; k++) {
|
||||
indices.push_back(4 * k + 0);
|
||||
indices.push_back(4 * k + 1);
|
||||
indices.push_back(4 * k + 2);
|
||||
indices.push_back(4 * k + 2);
|
||||
indices.push_back(4 * k + 3);
|
||||
indices.push_back(4 * k + 0);
|
||||
mb->setDirty(scene::EBT_VERTEX);
|
||||
|
||||
const u32 quad_count = mb->getVertexCount() / 4;
|
||||
const u32 index_count = quad_count * 6;
|
||||
// rewrite index array as needed
|
||||
if (mb->getIndexCount() > index_count) {
|
||||
mb->Indices.set_used(index_count);
|
||||
mb->setDirty(scene::EBT_INDEX);
|
||||
} else if (mb->getIndexCount() < index_count) {
|
||||
const u32 start = mb->getIndexCount() / 6;
|
||||
assert(start * 6 == mb->getIndexCount());
|
||||
for (u32 k = start; k < quad_count; k++) {
|
||||
mb->Indices.push_back(4 * k + 0);
|
||||
mb->Indices.push_back(4 * k + 1);
|
||||
mb->Indices.push_back(4 * k + 2);
|
||||
mb->Indices.push_back(4 * k + 2);
|
||||
mb->Indices.push_back(4 * k + 3);
|
||||
mb->Indices.push_back(4 * k + 0);
|
||||
}
|
||||
mb->setDirty(scene::EBT_INDEX);
|
||||
}
|
||||
driver->drawVertexPrimitiveList(vertices.data(), vertices.size(), indices.data(), 2 * quad_count,
|
||||
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
|
||||
|
||||
tracestream << "Cloud::updateMesh(): " << mb->getVertexCount() << " vertices"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void Clouds::render()
|
||||
{
|
||||
if (m_params.density <= 0.0f)
|
||||
return; // no need to do anything
|
||||
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
|
||||
if (SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
|
||||
return;
|
||||
|
||||
updateMesh();
|
||||
|
||||
// Update position
|
||||
{
|
||||
v2f off_origin = m_origin - m_mesh_origin;
|
||||
v3f rel(off_origin.X, 0, off_origin.Y);
|
||||
rel -= intToFloat(m_camera_offset, BS);
|
||||
setPosition(rel);
|
||||
updateAbsolutePosition();
|
||||
}
|
||||
|
||||
m_material.BackfaceCulling = m_enable_3d;
|
||||
if (m_enable_shaders)
|
||||
m_material.EmissiveColor = m_color.toSColor();
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
driver->setMaterial(m_material);
|
||||
|
||||
const float cloud_full_radius = cloud_size * m_cloud_radius_i;
|
||||
|
||||
// Get fog parameters for setting them back later
|
||||
video::SColor fog_color(0,0,0,0);
|
||||
video::E_FOG_TYPE fog_type = video::EFT_FOG_LINEAR;
|
||||
f32 fog_start = 0;
|
||||
f32 fog_end = 0;
|
||||
f32 fog_density = 0;
|
||||
bool fog_pixelfog = false;
|
||||
bool fog_rangefog = false;
|
||||
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||
fog_pixelfog, fog_rangefog);
|
||||
|
||||
// Set our own fog, unless it was already disabled
|
||||
if (fog_start < FOG_RANGE_ALL) {
|
||||
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
|
||||
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
||||
}
|
||||
|
||||
driver->drawMeshBuffer(m_meshbuffer.get());
|
||||
|
||||
// Restore fog settings
|
||||
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||
|
@ -346,13 +405,13 @@ void Clouds::update(const v3f &camera_p, const video::SColorf &color_diffuse)
|
|||
{
|
||||
video::SColorf ambient(m_params.color_ambient);
|
||||
video::SColorf bright(m_params.color_bright);
|
||||
m_camera_pos = camera_p;
|
||||
m_color.r = core::clamp(color_diffuse.r * bright.r, ambient.r, 1.0f);
|
||||
m_color.g = core::clamp(color_diffuse.g * bright.g, ambient.g, 1.0f);
|
||||
m_color.b = core::clamp(color_diffuse.b * bright.b, ambient.b, 1.0f);
|
||||
m_color.a = bright.a;
|
||||
|
||||
// is the camera inside the cloud mesh?
|
||||
m_camera_pos = camera_p;
|
||||
m_camera_inside_cloud = false; // default
|
||||
if (m_enable_3d) {
|
||||
float camera_height = camera_p.Y - BS * m_camera_offset.Y;
|
||||
|
@ -369,9 +428,14 @@ void Clouds::update(const v3f &camera_p, const video::SColorf &color_diffuse)
|
|||
|
||||
void Clouds::readSettings()
|
||||
{
|
||||
// Upper limit was chosen due to posible render bugs
|
||||
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, 62);
|
||||
// The code isn't designed to go over 64k vertices so the upper limits were
|
||||
// chosen to avoid exactly that.
|
||||
// refer to vertex_count in updateMesh()
|
||||
m_enable_3d = g_settings->getBool("enable_3d_clouds");
|
||||
const u16 maximum = m_enable_3d ? 62 : 25;
|
||||
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum);
|
||||
|
||||
invalidateMesh();
|
||||
}
|
||||
|
||||
bool Clouds::gridFilled(int x, int y) const
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue