From 51d8e32c937f9e0fd75ce86b0d48848255723bd4 Mon Sep 17 00:00:00 2001 From: reduz Date: Mon, 25 Jan 2021 12:20:11 -0300 Subject: Implement shadow meshes -When importing, a vertex-only version of the mesh is created. -This version is used when rendering shadows, and improves performance by reducing bandwidth -It's automatic, but can optionally be used by users, in case they want to make special versions of geometry for shadow casting. --- editor/import/resource_importer_scene.cpp | 12 +++- editor/import/resource_importer_scene.h | 2 +- editor/import/scene_importer_mesh.cpp | 102 ++++++++++++++++++++++++++++++ editor/import/scene_importer_mesh.h | 5 ++ 4 files changed, 117 insertions(+), 4 deletions(-) (limited to 'editor') diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index ead1f7c3e9..9944712931 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1129,6 +1129,7 @@ void ResourceImporterScene::get_import_options(List *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true)); @@ -1221,7 +1222,7 @@ Ref ResourceImporterScene::import_animation_from_other_importer(Edito return importer->import_animation(p_path, p_flags, p_bake_fps); } -void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods) { +void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes) { EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to(p_node); if (src_mesh_node) { //is mesh @@ -1237,8 +1238,12 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods) if (p_generate_lods) { src_mesh_node->get_mesh()->generate_lods(); } + if (p_create_shadow_meshes) { + src_mesh_node->get_mesh()->create_shadow_mesh(); + } } mesh = src_mesh_node->get_mesh()->get_mesh(); + if (mesh.is_valid()) { mesh_node->set_mesh(mesh); for (int i = 0; i < mesh->get_surface_count(); i++) { @@ -1252,7 +1257,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods) } for (int i = 0; i < p_node->get_child_count(); i++) { - _generate_meshes(p_node->get_child(i), p_generate_lods); + _generate_meshes(p_node->get_child(i), p_generate_lods, p_create_shadow_meshes); } } Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map &p_options, List *r_platform_variants, List *r_gen_files, Variant *r_metadata) { @@ -1348,8 +1353,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } bool gen_lods = bool(p_options["meshes/generate_lods"]); + bool create_shadow_meshes = bool(p_options["meshes/create_shadow_meshes"]); - _generate_meshes(scene, gen_lods); + _generate_meshes(scene, gen_lods, create_shadow_meshes); err = OK; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 66c317f858..aced0226ff 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -121,7 +121,7 @@ class ResourceImporterScene : public ResourceImporter { }; void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner); - void _generate_meshes(Node *p_node, bool p_generate_lods); + void _generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes); public: static ResourceImporterScene *get_singleton() { return singleton; } diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp index 620437af0e..78a7cd84f1 100644 --- a/editor/import/scene_importer_mesh.cpp +++ b/editor/import/scene_importer_mesh.cpp @@ -250,6 +250,11 @@ Ref EditorSceneImporterMesh::get_mesh() { mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name); } } + + if (shadow_mesh.is_valid()) { + Ref shadow = shadow_mesh->get_mesh(); + mesh->set_shadow_mesh(shadow); + } } return mesh; @@ -261,6 +266,103 @@ void EditorSceneImporterMesh::clear() { mesh.unref(); } +void EditorSceneImporterMesh::create_shadow_mesh() { + if (shadow_mesh.is_valid()) { + shadow_mesh.unref(); + } + + //no shadow mesh for blendshapes + if (blend_shapes.size() > 0) { + return; + } + //no shadow mesh for skeletons + for (int i = 0; i < surfaces.size(); i++) { + if (surfaces[i].arrays[RS::ARRAY_BONES].get_type() != Variant::NIL) { + return; + } + if (surfaces[i].arrays[RS::ARRAY_WEIGHTS].get_type() != Variant::NIL) { + return; + } + } + + shadow_mesh.instance(); + + for (int i = 0; i < surfaces.size(); i++) { + LocalVector vertex_remap; + Vector new_vertices; + Vector vertices = surfaces[i].arrays[RS::ARRAY_VERTEX]; + int vertex_count = vertices.size(); + { + Map unique_vertices; + const Vector3 *vptr = vertices.ptr(); + for (int j = 0; j < vertex_count; j++) { + Vector3 v = vptr[j]; + + Map::Element *E = unique_vertices.find(v); + + if (E) { + vertex_remap.push_back(E->get()); + } else { + int vcount = unique_vertices.size(); + unique_vertices[v] = vcount; + vertex_remap.push_back(vcount); + new_vertices.push_back(v); + } + } + } + + Array new_surface; + new_surface.resize(RS::ARRAY_MAX); + Dictionary lods; + + // print_line("original vertex count: " + itos(vertices.size()) + " new vertex count: " + itos(new_vertices.size())); + + new_surface[RS::ARRAY_VERTEX] = new_vertices; + + Vector indices = surfaces[i].arrays[RS::ARRAY_INDEX]; + if (indices.size()) { + int index_count = indices.size(); + const int *index_rptr = indices.ptr(); + Vector new_indices; + new_indices.resize(indices.size()); + int *index_wptr = new_indices.ptrw(); + + for (int j = 0; j < index_count; j++) { + int index = index_rptr[j]; + ERR_FAIL_INDEX(index, vertex_count); + index_wptr[j] = vertex_remap[index]; + } + + new_surface[RS::ARRAY_INDEX] = new_indices; + + // Make sure the same LODs as the full version are used. + // This makes it more coherent between rendered model and its shadows. + for (int j = 0; j < surfaces[i].lods.size(); j++) { + indices = surfaces[i].lods[j].indices; + + index_count = indices.size(); + index_rptr = indices.ptr(); + new_indices.resize(indices.size()); + index_wptr = new_indices.ptrw(); + + for (int k = 0; k < index_count; k++) { + int index = index_rptr[j]; + ERR_FAIL_INDEX(index, vertex_count); + index_wptr[j] = vertex_remap[index]; + } + + lods[surfaces[i].lods[j].distance] = new_indices; + } + } + + shadow_mesh->add_surface(surfaces[i].primitive, new_surface, Array(), lods, Ref(), surfaces[i].name); + } +} + +Ref EditorSceneImporterMesh::get_shadow_mesh() const { + return shadow_mesh; +} + void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) { clear(); if (p_data.has("blend_shape_names")) { diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h index 2adeb76b6c..42507cbe8c 100644 --- a/editor/import/scene_importer_mesh.h +++ b/editor/import/scene_importer_mesh.h @@ -61,6 +61,8 @@ class EditorSceneImporterMesh : public Resource { Ref mesh; + Ref shadow_mesh; + protected: void _set_data(const Dictionary &p_data); Dictionary _get_data() const; @@ -89,6 +91,9 @@ public: void generate_lods(); + void create_shadow_mesh(); + Ref get_shadow_mesh() const; + bool has_mesh() const; Ref get_mesh(); void clear(); -- cgit v1.2.3