Disable normal raycaster for LOD generation by default

Normal raycaster makes LOD generation process >2x slower and often
generates normals that look significantly worse compared to what the
simplifier comes up with by default. This was likely different before
last meshoptimizer upgrade, as the attribute metric was not functioning
properly, but now it looks like it's doing more harm than good.

This change makes it disabled by default but keeps an easy option to
re-enable it per mesh using LOD parameters for now until we get more
confidence and can remove the code outright.

Because the long term plan would be to disable this feature entirely,
the scripting API isn't changed, and it's just off-by-default there with
no way to re-enable.
This commit is contained in:
Arseny Kapoulkine 2024-06-28 18:32:59 -07:00
parent cae2f853dc
commit a13a64eacd
3 changed files with 31 additions and 12 deletions

View file

@ -2009,6 +2009,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_split_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), 25.0f));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_merge_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), 60.0f));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "lods/raycast_normals", PROPERTY_HINT_NONE, ""), false));
} break;
case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "use_external/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
@ -2436,6 +2437,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
bool generate_lods = p_generate_lods;
float split_angle = 25.0f;
float merge_angle = 60.0f;
bool raycast_normals = false;
bool create_shadow_meshes = p_create_shadow_meshes;
bool bake_lightmaps = p_light_bake_mode == LIGHT_BAKE_STATIC_LIGHTMAPS;
String save_to_file;
@ -2490,6 +2492,10 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
merge_angle = mesh_settings["lods/normal_merge_angle"];
}
if (mesh_settings.has("lods/raycast_normals")) {
raycast_normals = mesh_settings["lods/raycast_normals"];
}
if (bool(mesh_settings.get("save_to_file/enabled", false))) {
save_to_file = mesh_settings.get("save_to_file/path", String());
if (!save_to_file.is_resource_file()) {
@ -2536,7 +2542,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
if (generate_lods) {
Array skin_pose_transform_array = _get_skinned_pose_transforms(src_mesh_node);
src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle, skin_pose_transform_array);
src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle, skin_pose_transform_array, raycast_normals);
}
if (create_shadow_meshes) {

View file

@ -269,7 +269,7 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma
} \
write_array[vert_idx] = transformed_vert;
void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array) {
void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array, bool p_raycast_normals) {
if (!SurfaceTool::simplify_scale_func) {
return;
}
@ -429,6 +429,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
unsigned int index_target = 12; // Start with the smallest target, 4 triangles
unsigned int last_index_count = 0;
// Only used for normal raycasting
int split_vertex_count = vertex_count;
LocalVector<Vector3> split_vertex_normals;
LocalVector<int> split_vertex_indices;
@ -438,7 +439,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
RandomPCG pcg;
pcg.seed(123456789); // Keep seed constant across imports
Ref<StaticRaycaster> raycaster = StaticRaycaster::create();
Ref<StaticRaycaster> raycaster = p_raycast_normals ? StaticRaycaster::create() : Ref<StaticRaycaster>();
if (raycaster.is_valid()) {
raycaster->add_mesh(vertices, indices, 0);
raycaster->commit();
@ -485,19 +486,22 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
new_indices.resize(new_index_count);
LocalVector<LocalVector<int>> vertex_corners;
vertex_corners.resize(vertex_count);
{
int *ptrw = new_indices.ptrw();
for (unsigned int j = 0; j < new_index_count; j++) {
const int &remapped = vertex_inverse_remap[ptrw[j]];
vertex_corners[remapped].push_back(j);
ptrw[j] = remapped;
ptrw[j] = vertex_inverse_remap[ptrw[j]];
}
}
if (raycaster.is_valid()) {
LocalVector<LocalVector<int>> vertex_corners;
vertex_corners.resize(vertex_count);
int *ptrw = new_indices.ptrw();
for (unsigned int j = 0; j < new_index_count; j++) {
vertex_corners[ptrw[j]].push_back(j);
}
float error_factor = 1.0f / (scale * MAX(mesh_error, 0.15));
const float ray_bias = 0.05;
float ray_length = ray_bias + mesh_error * scale * 3.0f;
@ -668,7 +672,10 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
if (raycaster.is_valid()) {
surfaces.write[i].split_normals(split_vertex_indices, split_vertex_normals);
}
surfaces.write[i].lods.sort_custom<Surface::LODComparator>();
for (int j = 0; j < surfaces.write[i].lods.size(); j++) {
@ -679,6 +686,10 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
void ImporterMesh::_generate_lods_bind(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array) {
generate_lods(p_normal_merge_angle, p_normal_split_angle, p_skin_pose_transform_array);
}
bool ImporterMesh::has_mesh() const {
return mesh.is_valid();
}
@ -1364,7 +1375,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::generate_lods);
ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::_generate_lods_bind);
ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);

View file

@ -86,6 +86,8 @@ protected:
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
void _generate_lods_bind(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
static void _bind_methods();
public:
@ -112,7 +114,7 @@ public:
void set_surface_material(int p_surface, const Ref<Material> &p_material);
void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array, bool p_raycast_normals = false);
void create_shadow_mesh();
Ref<ImporterMesh> get_shadow_mesh() const;