From 0fde03c0e04fa7e056286eb3cf9a238213db3bfd Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Thu, 11 Jul 2024 15:44:30 -0700 Subject: [PATCH] Optimize base and shadow meshes for cache Previously, vertex cache optimization was ran for the LOD meshes, but was never ran for the base mesh or for the shadow meshes, including shadow LOD chain (shadow LOD chain would sometimes get implicitly optimized for vertex cache as a byproduct of base LOD optimization, but not always). This could significantly affect the rendering performance of geometry heavy scenes, especially for depth or shadow passes where the fragment load is light. --- editor/import/3d/resource_importer_scene.cpp | 2 ++ scene/resources/3d/importer_mesh.cpp | 35 ++++++++++++++++++++ scene/resources/3d/importer_mesh.h | 2 ++ 3 files changed, 39 insertions(+) diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 27b2af8f775..8ad8e6201ee 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -2544,6 +2544,8 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_ } } + src_mesh_node->get_mesh()->optimize_indices_for_cache(); + 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, raycast_normals); diff --git a/scene/resources/3d/importer_mesh.cpp b/scene/resources/3d/importer_mesh.cpp index 91531699b4a..e8aedabbb9a 100644 --- a/scene/resources/3d/importer_mesh.cpp +++ b/scene/resources/3d/importer_mesh.cpp @@ -256,6 +256,33 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref &p_ma mesh.unref(); } +void ImporterMesh::optimize_indices_for_cache() { + if (!SurfaceTool::optimize_vertex_cache_func) { + return; + } + + for (int i = 0; i < surfaces.size(); i++) { + if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) { + continue; + } + + Vector vertices = surfaces[i].arrays[RS::ARRAY_VERTEX]; + PackedInt32Array indices = surfaces[i].arrays[RS::ARRAY_INDEX]; + + unsigned int index_count = indices.size(); + unsigned int vertex_count = vertices.size(); + + if (index_count == 0) { + continue; + } + + int *indices_ptr = indices.ptrw(); + SurfaceTool::optimize_vertex_cache_func((unsigned int *)indices_ptr, (const unsigned int *)indices_ptr, index_count, vertex_count); + + surfaces.write[i].arrays[RS::ARRAY_INDEX] = indices; + } +} + #define VERTEX_SKIN_FUNC(bone_count, vert_idx, read_array, write_array, transform_array, bone_array, weight_array) \ Vector3 transformed_vert; \ for (unsigned int weight_idx = 0; weight_idx < bone_count; weight_idx++) { \ @@ -822,6 +849,10 @@ void ImporterMesh::create_shadow_mesh() { index_wptr[j] = vertex_remap[index]; } + if (SurfaceTool::optimize_vertex_cache_func) { + SurfaceTool::optimize_vertex_cache_func((unsigned int *)index_wptr, (const unsigned int *)index_wptr, index_count, new_vertices.size()); + } + new_surface[RS::ARRAY_INDEX] = new_indices; // Make sure the same LODs as the full version are used. @@ -840,6 +871,10 @@ void ImporterMesh::create_shadow_mesh() { index_wptr[k] = vertex_remap[index]; } + if (SurfaceTool::optimize_vertex_cache_func) { + SurfaceTool::optimize_vertex_cache_func((unsigned int *)index_wptr, (const unsigned int *)index_wptr, index_count, new_vertices.size()); + } + lods[surfaces[i].lods[j].distance] = new_indices; } } diff --git a/scene/resources/3d/importer_mesh.h b/scene/resources/3d/importer_mesh.h index 777f9360303..5eb4ee884e7 100644 --- a/scene/resources/3d/importer_mesh.h +++ b/scene/resources/3d/importer_mesh.h @@ -114,6 +114,8 @@ public: void set_surface_material(int p_surface, const Ref &p_material); + void optimize_indices_for_cache(); + 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();