Mesh optimizations

This commit is contained in:
2024-10-17 01:03:15 +03:00
parent b2fe7d7e46
commit 997b66b7f9
9 changed files with 230 additions and 21 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
+1
View File
@@ -12,6 +12,7 @@ module_obj = []
SConscript("buildings/SCsub")
env_stream.Prepend(CPPPATH=["../../meshoptimizer/src"])
env_stream.add_source_files(module_obj, "*.cpp")
env_stream.add_source_files(module_obj, "flecs/*.c")
env.modules_sources += module_obj
+1
View File
@@ -15,3 +15,4 @@ env.add_source_files(env.stream_building_sources, "*.cpp")
lib = env.add_library("buildings", env.stream_building_sources)
env.Prepend(LIBS=[lib])
env.Prepend(CPPPATH=[".."])
env.Prepend(CPPPATH=["../../../meshoptimizer/src"])
@@ -18,6 +18,12 @@
#include <scene/gui/menu_button.h>
#include <editor/editor_node.h>
#include <flecs/flecs.h>
namespace meshoptimizer
{
#define MESHOPTIMIZER_API static
#include <meshoptimizer.h>
#include <simplifier.cpp>
}
#include "editor_event.h"
#include "element_data.h"
#include "building_layout_editor.h"
@@ -1148,8 +1154,8 @@ Ref<Mesh> BuildingLayoutEditor::get_element_mesh(const String &element) const
assert(ret.is_valid());
return ret;
}
Ref<Mesh>
BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout) const
Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
int lod) const
{
Ref<ArrayMesh> ret;
ret.instance();
@@ -1228,6 +1234,165 @@ BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout) const
}
Array arr = sf.commit_to_arrays();
print_line("optimizing for lod: " + itos(lod));
if (lod > 0) {
const PoolVector<Vector2> &uvs = arr[Mesh::ARRAY_TEX_UV];
const PoolVector<int> &index_array = arr[Mesh::ARRAY_INDEX];
LocalVector<Color> colors;
colors.resize(uvs.size());
{
Ref<SpatialMaterial> spmat = mat;
assert(spmat.is_valid());
Ref<Texture> albedo_texture = spmat->get_texture(
SpatialMaterial::TEXTURE_ALBEDO);
assert(albedo_texture.is_valid());
Ref<Image> img_data = albedo_texture->get_data();
assert(img_data.is_valid());
img_data->lock();
for (i = 0; i < uvs.size(); i++)
colors[i] = img_data->get_pixelv(
uvs[i] * img_data->get_size());
img_data->unlock();
}
HashMap<Color, int> map_colors;
HashMap<int, int[3]> base_uvs;
Set<Color> seen_colors;
for (i = 0; i < colors.size(); i++) {
int j;
Color base = colors[i];
if (seen_colors.has(base))
continue;
map_colors[base] = i;
base_uvs[i][0] = i;
for (j = 0; j < colors.size(); j++) {
if (i == j)
continue;
if (base.is_equal_approx(colors[j])) {
const Vector2 &w = uvs[base_uvs[i][0]];
if (w.x > uvs[j].x && w.y > uvs[j].y)
base_uvs[i][0] = j;
}
}
base_uvs[i][1] = i;
for (j = 0; j < colors.size(); j++) {
if (i == j)
continue;
if (base.is_equal_approx(colors[j])) {
const Vector2 &w = uvs[base_uvs[i][1]];
if (w.x < uvs[j].x && w.y > uvs[j].y)
base_uvs[i][1] = j;
}
}
base_uvs[i][2] = i;
for (j = 0; j < colors.size(); j++) {
if (i == j)
continue;
if (base.is_equal_approx(colors[j])) {
const Vector2 &w = uvs[base_uvs[i][2]];
if (w.x < uvs[j].x && w.y < uvs[j].y)
base_uvs[i][2] = j;
}
}
seen_colors.insert(base);
}
List<int> keys;
base_uvs.get_key_list(&keys);
List<int>::Element *e = keys.front();
while (e) {
print_line(
"color: " +
(colors[e->get()].operator String()) + " " +
(uvs[base_uvs[e->get()][0]].operator String()) +
" " +
(uvs[base_uvs[e->get()][1]].operator String()) +
" " +
(uvs[base_uvs[e->get()][2]].operator String()));
e = e->next();
}
PoolVector<Vector2> uv_remap;
uv_remap.resize(uvs.size());
for (i = 0; i < index_array.size(); i++) {
int idx = index_array[i];
int state = i % 3;
int c = map_colors[colors[idx]];
int uv_idx = base_uvs[c][state];
uv_remap.write()[idx] = uvs[uv_idx];
}
arr[Mesh::ARRAY_TEX_UV] = uv_remap;
PoolVector<int> lodv;
LocalVector<float> vertices;
const PoolVector<Vector3> &vertex_array =
arr[Mesh::ARRAY_VERTEX];
lodv.resize(index_array.size());
vertices.resize(vertex_array.size() * 3);
for (i = 0; i < vertex_array.size(); i++) {
vertices[i * 3 + 0] = vertex_array[i].x;
vertices[i * 3 + 1] = vertex_array[i].y;
vertices[i * 3 + 2] = vertex_array[i].z;
}
float error = 0.f;
const int simplify_options = 1; /* lock border */
float threshold = 1.0f;
float target_error = 0.01f;
bool sloppy = false;
switch (lod) {
case 1:
threshold = 0.6f;
target_error = 0.01f;
sloppy = false;
break;
case 2:
threshold = 0.3f;
target_error = 0.01f;
sloppy = false;
break;
default:
threshold = 1.0f / (float(lod + 1));
target_error = 0.01;
sloppy = true;
break;
}
int target_index_count = index_array.size() * threshold;
print_line("meshopt for lod: " + itos(lod));
print_line("output size: " + itos(lodv.size()));
print_line("index size: " + itos(index_array.size()));
print_line("vertex count: " + itos(vertex_array.size()));
print_line("vertex buffer size: " + itos(vertices.size()));
int index_count = 0;
if (!sloppy)
index_count = meshoptimizer::meshopt_simplify(
(unsigned int *)lodv.write().ptr(),
(const unsigned int *)index_array.read().ptr(),
(size_t)index_array.size(), vertices.ptr(),
(size_t)vertex_array.size(),
(size_t)(sizeof(float) * 3),
(size_t)target_index_count, target_error,
simplify_options, &error);
else
index_count = meshoptimizer::meshopt_simplifySloppy(
(unsigned int *)lodv.write().ptr(),
(const unsigned int *)index_array.read().ptr(),
(size_t)index_array.size(), vertices.ptr(),
(size_t)vertex_array.size(),
(size_t)(sizeof(float) * 3),
(size_t)target_index_count, target_error,
&error);
assert(index_count > 0);
lodv.resize(index_count);
#if 0
meshopt_optimizeVertexCache(lodv.write().ptr(),
lodv.read().ptr(), index_count,
vertex_array.size());
meshopt_optimizeOverdraw(lodv.write().ptr(), lodv.read().ptr(),
index_count, vertices.ptr(),
vertex_array.size(),
(size_t)(sizeof(float) * 3), 1.05f);
#endif
arr[Mesh::ARRAY_INDEX] = lodv;
print_line("final output size: " + itos(lodv.size()));
}
print_line("optimizing for lod: " + itos(lod) + " done");
ret->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, Array(),
Mesh::ARRAY_COMPRESS_DEFAULT);
ret->surface_set_material(0, mat);
@@ -1266,23 +1431,26 @@ void BuildingLayoutEditor::update_layout_meshes()
int lod = 0;
while (e) {
print_line("update_layout_meshes: " + e->get());
String item_name = e->get() + "_lod" + itos(lod);
int id = ml->get_last_unused_item_id();
ml->create_item(id);
Ref<Mesh> mesh = get_layout_exterior_mesh(e->get());
assert(mesh.is_valid());
Ref<Shape> shape = mesh->create_trimesh_shape();
assert(shape.is_valid());
ml->set_item_name(id, item_name);
ml->set_item_mesh(id, mesh);
Vector<MeshLibrary::ShapeData> shapes;
MeshLibrary::ShapeData shape_data;
shape_data.shape = shape;
shape_data.local_transform = Transform();
shapes.push_back(shape_data);
ml->set_item_shapes(id, shapes);
for_previews.push_back(mesh);
for_previews_xform.push_back(Transform());
for (lod = 0; lod < 4; lod++) {
String item_name = e->get() + "_lod" + itos(lod);
int id = ml->get_last_unused_item_id();
ml->create_item(id);
Ref<Mesh> mesh =
get_layout_exterior_mesh(e->get(), lod);
assert(mesh.is_valid());
Ref<Shape> shape = mesh->create_trimesh_shape();
assert(shape.is_valid());
ml->set_item_name(id, item_name);
ml->set_item_mesh(id, mesh);
Vector<MeshLibrary::ShapeData> shapes;
MeshLibrary::ShapeData shape_data;
shape_data.shape = shape;
shape_data.local_transform = Transform();
shapes.push_back(shape_data);
ml->set_item_shapes(id, shapes);
for_previews.push_back(mesh);
for_previews_xform.push_back(Transform());
}
e = e->next();
}
Vector<Ref<Texture> > previews =
@@ -30,7 +30,7 @@ public:
const String &test_element);
void visualize_element_at(const String &element, Spatial *node) const;
Ref<Mesh> get_element_mesh(const String &element) const;
Ref<Mesh> get_layout_exterior_mesh(const String &layout) const;
Ref<Mesh> get_layout_exterior_mesh(const String &layout, int lod) const;
void update_element_meshes();
void update_layout_meshes();