|
|
|
|
@@ -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 =
|
|
|
|
|
|