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.
This commit is contained in:
parent
c5c9517e1e
commit
51d8e32c93
|
@ -1129,6 +1129,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
|
||||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
|
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::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/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::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::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));
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
|
||||||
|
@ -1221,7 +1222,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
|
||||||
return importer->import_animation(p_path, p_flags, p_bake_fps);
|
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<EditorSceneImporterMeshNode3D>(p_node);
|
EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
|
||||||
if (src_mesh_node) {
|
if (src_mesh_node) {
|
||||||
//is mesh
|
//is mesh
|
||||||
|
@ -1237,8 +1238,12 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods)
|
||||||
if (p_generate_lods) {
|
if (p_generate_lods) {
|
||||||
src_mesh_node->get_mesh()->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();
|
mesh = src_mesh_node->get_mesh()->get_mesh();
|
||||||
|
|
||||||
if (mesh.is_valid()) {
|
if (mesh.is_valid()) {
|
||||||
mesh_node->set_mesh(mesh);
|
mesh_node->set_mesh(mesh);
|
||||||
for (int i = 0; i < mesh->get_surface_count(); i++) {
|
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++) {
|
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<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *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 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;
|
err = OK;
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ class ResourceImporterScene : public ResourceImporter {
|
||||||
};
|
};
|
||||||
|
|
||||||
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
|
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:
|
public:
|
||||||
static ResourceImporterScene *get_singleton() { return singleton; }
|
static ResourceImporterScene *get_singleton() { return singleton; }
|
||||||
|
|
|
@ -250,6 +250,11 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
|
||||||
mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name);
|
mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shadow_mesh.is_valid()) {
|
||||||
|
Ref<ArrayMesh> shadow = shadow_mesh->get_mesh();
|
||||||
|
mesh->set_shadow_mesh(shadow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
|
@ -261,6 +266,103 @@ void EditorSceneImporterMesh::clear() {
|
||||||
mesh.unref();
|
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<int> vertex_remap;
|
||||||
|
Vector<Vector3> new_vertices;
|
||||||
|
Vector<Vector3> vertices = surfaces[i].arrays[RS::ARRAY_VERTEX];
|
||||||
|
int vertex_count = vertices.size();
|
||||||
|
{
|
||||||
|
Map<Vector3, int> unique_vertices;
|
||||||
|
const Vector3 *vptr = vertices.ptr();
|
||||||
|
for (int j = 0; j < vertex_count; j++) {
|
||||||
|
Vector3 v = vptr[j];
|
||||||
|
|
||||||
|
Map<Vector3, int>::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<int> indices = surfaces[i].arrays[RS::ARRAY_INDEX];
|
||||||
|
if (indices.size()) {
|
||||||
|
int index_count = indices.size();
|
||||||
|
const int *index_rptr = indices.ptr();
|
||||||
|
Vector<int> 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<Material>(), surfaces[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<EditorSceneImporterMesh> EditorSceneImporterMesh::get_shadow_mesh() const {
|
||||||
|
return shadow_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
|
void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
|
||||||
clear();
|
clear();
|
||||||
if (p_data.has("blend_shape_names")) {
|
if (p_data.has("blend_shape_names")) {
|
||||||
|
|
|
@ -61,6 +61,8 @@ class EditorSceneImporterMesh : public Resource {
|
||||||
|
|
||||||
Ref<ArrayMesh> mesh;
|
Ref<ArrayMesh> mesh;
|
||||||
|
|
||||||
|
Ref<EditorSceneImporterMesh> shadow_mesh;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _set_data(const Dictionary &p_data);
|
void _set_data(const Dictionary &p_data);
|
||||||
Dictionary _get_data() const;
|
Dictionary _get_data() const;
|
||||||
|
@ -89,6 +91,9 @@ public:
|
||||||
|
|
||||||
void generate_lods();
|
void generate_lods();
|
||||||
|
|
||||||
|
void create_shadow_mesh();
|
||||||
|
Ref<EditorSceneImporterMesh> get_shadow_mesh() const;
|
||||||
|
|
||||||
bool has_mesh() const;
|
bool has_mesh() const;
|
||||||
Ref<ArrayMesh> get_mesh();
|
Ref<ArrayMesh> get_mesh();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -1565,6 +1565,19 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArrayMesh::set_shadow_mesh(const Ref<ArrayMesh> &p_mesh) {
|
||||||
|
shadow_mesh = p_mesh;
|
||||||
|
if (shadow_mesh.is_valid()) {
|
||||||
|
RS::get_singleton()->mesh_set_shadow_mesh(mesh, shadow_mesh->get_rid());
|
||||||
|
} else {
|
||||||
|
RS::get_singleton()->mesh_set_shadow_mesh(mesh, RID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<ArrayMesh> ArrayMesh::get_shadow_mesh() const {
|
||||||
|
return shadow_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
void ArrayMesh::_bind_methods() {
|
void ArrayMesh::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape);
|
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape);
|
||||||
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ArrayMesh::get_blend_shape_count);
|
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ArrayMesh::get_blend_shape_count);
|
||||||
|
@ -1596,6 +1609,9 @@ void ArrayMesh::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb);
|
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb);
|
||||||
ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb);
|
ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_shadow_mesh", "mesh"), &ArrayMesh::set_shadow_mesh);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_shadow_mesh"), &ArrayMesh::get_shadow_mesh);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("_set_blend_shape_names", "blend_shape_names"), &ArrayMesh::_set_blend_shape_names);
|
ClassDB::bind_method(D_METHOD("_set_blend_shape_names", "blend_shape_names"), &ArrayMesh::_set_blend_shape_names);
|
||||||
ClassDB::bind_method(D_METHOD("_get_blend_shape_names"), &ArrayMesh::_get_blend_shape_names);
|
ClassDB::bind_method(D_METHOD("_get_blend_shape_names"), &ArrayMesh::_get_blend_shape_names);
|
||||||
|
|
||||||
|
@ -1606,6 +1622,7 @@ void ArrayMesh::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
|
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shadow_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh"), "set_shadow_mesh", "get_shadow_mesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArrayMesh::reload_from_file() {
|
void ArrayMesh::reload_from_file() {
|
||||||
|
|
|
@ -176,6 +176,7 @@ class ArrayMesh : public Mesh {
|
||||||
|
|
||||||
Array _get_surfaces() const;
|
Array _get_surfaces() const;
|
||||||
void _set_surfaces(const Array &p_data);
|
void _set_surfaces(const Array &p_data);
|
||||||
|
Ref<ArrayMesh> shadow_mesh;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Surface {
|
struct Surface {
|
||||||
|
@ -259,6 +260,9 @@ public:
|
||||||
|
|
||||||
virtual void reload_from_file() override;
|
virtual void reload_from_file() override;
|
||||||
|
|
||||||
|
void set_shadow_mesh(const Ref<ArrayMesh> &p_mesh);
|
||||||
|
Ref<ArrayMesh> get_shadow_mesh() const;
|
||||||
|
|
||||||
ArrayMesh();
|
ArrayMesh();
|
||||||
|
|
||||||
~ArrayMesh();
|
~ArrayMesh();
|
||||||
|
|
|
@ -819,7 +819,7 @@ void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawList
|
||||||
ShaderData *shader;
|
ShaderData *shader;
|
||||||
void *mesh_surface;
|
void *mesh_surface;
|
||||||
|
|
||||||
if (shadow_pass) {
|
if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
|
||||||
material_uniform_set = surf->material_uniform_set_shadow;
|
material_uniform_set = surf->material_uniform_set_shadow;
|
||||||
shader = surf->shader_shadow;
|
shader = surf->shader_shadow;
|
||||||
mesh_surface = surf->surface_shadow;
|
mesh_surface = surf->surface_shadow;
|
||||||
|
@ -2645,10 +2645,17 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialData *material_shadow = nullptr;
|
MaterialData *material_shadow = nullptr;
|
||||||
//void *surface_shadow = nullptr;
|
void *surface_shadow = nullptr;
|
||||||
if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
|
if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
|
||||||
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
|
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
|
||||||
material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
|
material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
|
||||||
|
|
||||||
|
RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
|
||||||
|
|
||||||
|
if (shadow_mesh.is_valid()) {
|
||||||
|
surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
material_shadow = p_material;
|
material_shadow = p_material;
|
||||||
}
|
}
|
||||||
|
@ -2670,7 +2677,8 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
|
||||||
//shadow
|
//shadow
|
||||||
sdcache->shader_shadow = material_shadow->shader_data;
|
sdcache->shader_shadow = material_shadow->shader_data;
|
||||||
sdcache->material_uniform_set_shadow = material_shadow->uniform_set;
|
sdcache->material_uniform_set_shadow = material_shadow->uniform_set;
|
||||||
sdcache->surface_shadow = sdcache->surface; //when adding special shadow meshes, will use this
|
|
||||||
|
sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface;
|
||||||
|
|
||||||
sdcache->owner = ginstance;
|
sdcache->owner = ginstance;
|
||||||
|
|
||||||
|
|
|
@ -2609,6 +2609,12 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
|
||||||
|
|
||||||
mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
||||||
|
|
||||||
|
for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) {
|
||||||
|
Mesh *shadow_owner = E->get();
|
||||||
|
shadow_owner->shadow_mesh = RID();
|
||||||
|
shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
||||||
|
}
|
||||||
|
|
||||||
mesh->material_cache.clear();
|
mesh->material_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2824,6 +2830,25 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
|
||||||
return aabb;
|
return aabb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
|
||||||
|
Mesh *mesh = mesh_owner.getornull(p_mesh);
|
||||||
|
ERR_FAIL_COND(!mesh);
|
||||||
|
|
||||||
|
Mesh *shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh);
|
||||||
|
if (shadow_mesh) {
|
||||||
|
shadow_mesh->shadow_owners.erase(mesh);
|
||||||
|
}
|
||||||
|
mesh->shadow_mesh = p_shadow_mesh;
|
||||||
|
|
||||||
|
shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh);
|
||||||
|
|
||||||
|
if (shadow_mesh) {
|
||||||
|
shadow_mesh->shadow_owners.insert(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
||||||
|
}
|
||||||
|
|
||||||
void RendererStorageRD::mesh_clear(RID p_mesh) {
|
void RendererStorageRD::mesh_clear(RID p_mesh) {
|
||||||
Mesh *mesh = mesh_owner.getornull(p_mesh);
|
Mesh *mesh = mesh_owner.getornull(p_mesh);
|
||||||
ERR_FAIL_COND(!mesh);
|
ERR_FAIL_COND(!mesh);
|
||||||
|
@ -2871,6 +2896,12 @@ void RendererStorageRD::mesh_clear(RID p_mesh) {
|
||||||
}
|
}
|
||||||
mesh->has_bone_weights = false;
|
mesh->has_bone_weights = false;
|
||||||
mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
||||||
|
|
||||||
|
for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) {
|
||||||
|
Mesh *shadow_owner = E->get();
|
||||||
|
shadow_owner->shadow_mesh = RID();
|
||||||
|
shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
|
bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
|
||||||
|
@ -8161,17 +8192,26 @@ bool RendererStorageRD::free(RID p_rid) {
|
||||||
material_owner.free(p_rid);
|
material_owner.free(p_rid);
|
||||||
} else if (mesh_owner.owns(p_rid)) {
|
} else if (mesh_owner.owns(p_rid)) {
|
||||||
mesh_clear(p_rid);
|
mesh_clear(p_rid);
|
||||||
|
mesh_set_shadow_mesh(p_rid, RID());
|
||||||
Mesh *mesh = mesh_owner.getornull(p_rid);
|
Mesh *mesh = mesh_owner.getornull(p_rid);
|
||||||
mesh->dependency.deleted_notify(p_rid);
|
mesh->dependency.deleted_notify(p_rid);
|
||||||
if (mesh->instances.size()) {
|
if (mesh->instances.size()) {
|
||||||
ERR_PRINT("deleting mesh with active instances");
|
ERR_PRINT("deleting mesh with active instances");
|
||||||
}
|
}
|
||||||
|
if (mesh->shadow_owners.size()) {
|
||||||
|
for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) {
|
||||||
|
Mesh *shadow_owner = E->get();
|
||||||
|
shadow_owner->shadow_mesh = RID();
|
||||||
|
shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH);
|
||||||
|
}
|
||||||
|
}
|
||||||
mesh_owner.free(p_rid);
|
mesh_owner.free(p_rid);
|
||||||
} else if (mesh_instance_owner.owns(p_rid)) {
|
} else if (mesh_instance_owner.owns(p_rid)) {
|
||||||
MeshInstance *mi = mesh_instance_owner.getornull(p_rid);
|
MeshInstance *mi = mesh_instance_owner.getornull(p_rid);
|
||||||
_mesh_instance_clear(mi);
|
_mesh_instance_clear(mi);
|
||||||
mi->mesh->instances.erase(mi->I);
|
mi->mesh->instances.erase(mi->I);
|
||||||
mi->I = nullptr;
|
mi->I = nullptr;
|
||||||
|
|
||||||
mesh_instance_owner.free(p_rid);
|
mesh_instance_owner.free(p_rid);
|
||||||
memdelete(mi);
|
memdelete(mi);
|
||||||
|
|
||||||
|
|
|
@ -478,6 +478,9 @@ private:
|
||||||
|
|
||||||
List<MeshInstance *> instances;
|
List<MeshInstance *> instances;
|
||||||
|
|
||||||
|
RID shadow_mesh;
|
||||||
|
Set<Mesh *> shadow_owners;
|
||||||
|
|
||||||
Dependency dependency;
|
Dependency dependency;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1423,6 +1426,7 @@ public:
|
||||||
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
|
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
|
||||||
|
|
||||||
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID());
|
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID());
|
||||||
|
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh);
|
||||||
|
|
||||||
virtual void mesh_clear(RID p_mesh);
|
virtual void mesh_clear(RID p_mesh);
|
||||||
|
|
||||||
|
@ -1461,6 +1465,13 @@ public:
|
||||||
return mesh->surfaces[p_surface_index];
|
return mesh->surfaces[p_surface_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
|
||||||
|
Mesh *mesh = mesh_owner.getornull(p_mesh);
|
||||||
|
ERR_FAIL_COND_V(!mesh, RID());
|
||||||
|
|
||||||
|
return mesh->shadow_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
|
_FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
|
||||||
Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
|
Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||||
return surface->primitive;
|
return surface->primitive;
|
||||||
|
|
|
@ -234,6 +234,8 @@ public:
|
||||||
|
|
||||||
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
|
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
|
||||||
|
|
||||||
|
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
|
||||||
|
|
||||||
virtual void mesh_clear(RID p_mesh) = 0;
|
virtual void mesh_clear(RID p_mesh) = 0;
|
||||||
|
|
||||||
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
|
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
|
||||||
|
|
|
@ -274,6 +274,8 @@ public:
|
||||||
BIND2(mesh_set_custom_aabb, RID, const AABB &)
|
BIND2(mesh_set_custom_aabb, RID, const AABB &)
|
||||||
BIND1RC(AABB, mesh_get_custom_aabb, RID)
|
BIND1RC(AABB, mesh_get_custom_aabb, RID)
|
||||||
|
|
||||||
|
BIND2(mesh_set_shadow_mesh, RID, RID)
|
||||||
|
|
||||||
BIND1(mesh_clear, RID)
|
BIND1(mesh_clear, RID)
|
||||||
|
|
||||||
/* MULTIMESH API */
|
/* MULTIMESH API */
|
||||||
|
|
|
@ -172,6 +172,7 @@ public:
|
||||||
FUNC2(mesh_set_custom_aabb, RID, const AABB &)
|
FUNC2(mesh_set_custom_aabb, RID, const AABB &)
|
||||||
FUNC1RC(AABB, mesh_get_custom_aabb, RID)
|
FUNC1RC(AABB, mesh_get_custom_aabb, RID)
|
||||||
|
|
||||||
|
FUNC2(mesh_set_shadow_mesh, RID, RID)
|
||||||
FUNC1(mesh_clear, RID)
|
FUNC1(mesh_clear, RID)
|
||||||
|
|
||||||
/* MULTIMESH API */
|
/* MULTIMESH API */
|
||||||
|
|
|
@ -354,6 +354,8 @@ public:
|
||||||
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
|
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
|
||||||
virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
|
virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
|
||||||
|
|
||||||
|
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
|
||||||
|
|
||||||
virtual void mesh_clear(RID p_mesh) = 0;
|
virtual void mesh_clear(RID p_mesh) = 0;
|
||||||
|
|
||||||
/* MULTIMESH API */
|
/* MULTIMESH API */
|
||||||
|
|
Loading…
Reference in New Issue