summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/MultiplayerAPI.xml3
-rw-r--r--doc/classes/NetworkedMultiplayerPeer.xml3
-rw-r--r--editor/editor_settings.cpp4
-rw-r--r--editor/editor_themes.cpp19
-rw-r--r--editor/import/resource_importer_scene.cpp12
-rw-r--r--editor/import/resource_importer_scene.h2
-rw-r--r--editor/import/scene_importer_mesh.cpp102
-rw-r--r--editor/import/scene_importer_mesh.h5
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp5
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp5
-rw-r--r--modules/visual_script/visual_script_editor.cpp6
-rw-r--r--scene/gui/graph_edit.cpp6
-rw-r--r--scene/resources/default_theme/default_theme.cpp1
-rw-r--r--scene/resources/mesh.cpp17
-rw-r--r--scene/resources/mesh.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_forward.cpp14
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp40
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h11
-rw-r--r--servers/rendering/renderer_storage.h2
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h1
-rw-r--r--servers/rendering_server.h2
22 files changed, 252 insertions, 14 deletions
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index fcc259fb44..c168695d61 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -4,9 +4,10 @@
High-level multiplayer API.
</brief_description>
<description>
- This class implements most of the logic behind the high-level multiplayer API.
+ This class implements most of the logic behind the high-level multiplayer API. See also [NetworkedMultiplayerPeer].
By default, [SceneTree] has a reference to this class that is used to provide multiplayer capabilities (i.e. RPC/RSET) across the whole scene.
It is possible to override the MultiplayerAPI instance used by specific Nodes by setting the [member Node.custom_multiplayer] property, effectively allowing to run both client and server in the same scene.
+ [b]Note:[/b] The high-level multiplayer API protocol is an implementation detail and isn't meant to be used by non-Godot servers. It may change without notice.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NetworkedMultiplayerPeer.xml b/doc/classes/NetworkedMultiplayerPeer.xml
index 954d31794a..06ea46f023 100644
--- a/doc/classes/NetworkedMultiplayerPeer.xml
+++ b/doc/classes/NetworkedMultiplayerPeer.xml
@@ -4,7 +4,8 @@
A high-level network interface to simplify multiplayer interactions.
</brief_description>
<description>
- Manages the connection to network peers. Assigns unique IDs to each client connected to the server.
+ Manages the connection to network peers. Assigns unique IDs to each client connected to the server. See also [MultiplayerAPI].
+ [b]Note:[/b] The high-level multiplayer API protocol is an implementation detail and isn't meant to be used by non-Godot servers. It may change without notice.
</description>
<tutorials>
<link title="High-level multiplayer">https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 3eee7b2bfb..7a602912c9 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -659,6 +659,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0));
_initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0));
+ // Visual editors
+ _initial_set("editors/visual_editors/minimap_opacity", 0.85);
+ hints["editors/visual_editors/minimap_opacity"] = PropertyInfo(Variant::FLOAT, "editors/visual_editors/minimap_opacity", PROPERTY_HINT_RANGE, "0.0,1.0,0.01", PROPERTY_USAGE_DEFAULT);
+
/* Run */
// Window placement
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 054ada1e8d..37d32431cc 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -92,6 +92,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
Ref<ImageTexture> texture(memnew(ImageTexture));
Ref<Image> img = p_texture->get_data();
+ img = img->duplicate();
if (p_flip_y) {
img->flip_y();
@@ -1098,7 +1099,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("bezier_len_neg", "GraphEdit", 160 * EDSCALE);
// GraphEditMinimap
- theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(dark_color_1, 0, 0, 0, 0));
+ Ref<StyleBoxFlat> style_minimap_bg = make_flat_stylebox(dark_color_1, 0, 0, 0, 0);
+ style_minimap_bg->set_border_color(dark_color_3);
+ style_minimap_bg->set_border_width_all(1);
+ theme->set_stylebox("bg", "GraphEditMinimap", style_minimap_bg);
+
Ref<StyleBoxFlat> style_minimap_camera;
Ref<StyleBoxFlat> style_minimap_node;
if (dark_theme) {
@@ -1115,9 +1120,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera);
theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node);
- Ref<Texture2D> resizer_icon = theme->get_icon("GuiResizer", "EditorIcons");
- theme->set_icon("resizer", "GraphEditMinimap", flip_icon(resizer_icon, true, true));
- theme->set_color("resizer_color", "GraphEditMinimap", Color(1, 1, 1, 0.65));
+ Ref<Texture2D> minimap_resizer_icon = theme->get_icon("GuiResizer", "EditorIcons");
+ Color minimap_resizer_color;
+ if (dark_theme) {
+ minimap_resizer_color = Color(1, 1, 1, 0.65);
+ } else {
+ minimap_resizer_color = Color(0, 0, 0, 0.65);
+ }
+ theme->set_icon("resizer", "GraphEditMinimap", flip_icon(minimap_resizer_icon, true, true));
+ theme->set_color("resizer_color", "GraphEditMinimap", minimap_resizer_color);
// GraphNode
const float mv = dark_theme ? 0.0 : 1.0;
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<ImportOption> *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<Animation> 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<EditorSceneImporterMeshNode3D>(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<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 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<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
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;
@@ -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<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) {
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<ArrayMesh> mesh;
+ Ref<EditorSceneImporterMesh> 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<EditorSceneImporterMesh> get_shadow_mesh() const;
+
bool has_mesh() const;
Ref<ArrayMesh> get_mesh();
void clear();
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index fbfcac3d22..e7e069e8b6 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -255,6 +255,9 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
graph->connect_node(from, 0, to, to_idx);
}
+
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
}
void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) {
@@ -888,6 +891,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->connect("scroll_offset_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_scroll_changed));
graph->connect("delete_nodes_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_nodes_request));
graph->connect("popup_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_request));
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
VSeparator *vs = memnew(VSeparator);
graph->get_zoom_hbox()->add_child(vs);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 443e867a9f..4c3964289f 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1282,6 +1282,9 @@ void VisualShaderEditor::_update_graph() {
graph->connect_node(itos(from), from_idx, itos(to), to_idx);
}
+
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
}
VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
@@ -3161,6 +3164,8 @@ VisualShaderEditor::VisualShaderEditor() {
graph->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(graph);
graph->set_drag_forwarding(this);
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 1e82259e59..78e4a7f113 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -981,6 +981,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
}
_update_graph_connections();
+
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
+
// Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything.
graph->call_deferred("set_scroll_ofs", script->get_scroll() * EDSCALE);
updating_graph = false;
@@ -4326,6 +4330,8 @@ VisualScriptEditor::VisualScriptEditor() {
graph->connect("duplicate_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_duplicate));
graph->connect("gui_input", callable_mp(this, &VisualScriptEditor::_graph_gui_input));
graph->set_drag_forwarding(this);
+ float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ graph->set_minimap_opacity(graph_minimap_opacity);
graph->hide();
graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed));
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 6662992d46..bc87aabb2c 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -154,6 +154,10 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position)
}
void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
+ if (!ge->is_minimap_enabled()) {
+ return;
+ }
+
Ref<InputEventMouseButton> mb = p_ev;
Ref<InputEventMouseMotion> mm = p_ev;
@@ -1754,7 +1758,7 @@ GraphEdit::GraphEdit() {
top_layer->add_child(minimap);
minimap->set_name("_minimap");
minimap->set_modulate(Color(1, 1, 1, minimap_opacity));
- minimap->set_mouse_filter(MOUSE_FILTER_STOP);
+ minimap->set_mouse_filter(MOUSE_FILTER_PASS);
minimap->set_custom_minimum_size(Vector2(50, 50));
minimap->set_size(minimap_size);
minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 982239fe4e..5878467aaa 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -115,6 +115,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
Ref<ImageTexture> texture(memnew(ImageTexture));
Ref<Image> img = p_texture->get_data();
+ img = img->duplicate();
if (p_flip_y) {
img->flip_y();
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 32fede1e5f..e812ad3a01 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1565,6 +1565,19 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
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() {
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);
@@ -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("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("_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::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::OBJECT, "shadow_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh"), "set_shadow_mesh", "get_shadow_mesh");
}
void ArrayMesh::reload_from_file() {
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 2f25ecd60b..1fd45c880a 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -176,6 +176,7 @@ class ArrayMesh : public Mesh {
Array _get_surfaces() const;
void _set_surfaces(const Array &p_data);
+ Ref<ArrayMesh> shadow_mesh;
private:
struct Surface {
@@ -259,6 +260,9 @@ public:
virtual void reload_from_file() override;
+ void set_shadow_mesh(const Ref<ArrayMesh> &p_mesh);
+ Ref<ArrayMesh> get_shadow_mesh() const;
+
ArrayMesh();
~ArrayMesh();
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
index 0ae1e9c1a8..11ac95a0da 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
@@ -819,7 +819,7 @@ void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawList
ShaderData *shader;
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;
shader = surf->shader_shadow;
mesh_surface = surf->surface_shadow;
@@ -2645,10 +2645,17 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
}
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) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
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 {
material_shadow = p_material;
}
@@ -2670,7 +2677,8 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
//shadow
sdcache->shader_shadow = material_shadow->shader_data;
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;
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 6203f3ba64..96dd5a6669 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -2609,6 +2609,12 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
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();
}
@@ -2824,6 +2830,25 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
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) {
Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!mesh);
@@ -2871,6 +2896,12 @@ void RendererStorageRD::mesh_clear(RID p_mesh) {
}
mesh->has_bone_weights = false;
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) {
@@ -8161,17 +8192,26 @@ bool RendererStorageRD::free(RID p_rid) {
material_owner.free(p_rid);
} else if (mesh_owner.owns(p_rid)) {
mesh_clear(p_rid);
+ mesh_set_shadow_mesh(p_rid, RID());
Mesh *mesh = mesh_owner.getornull(p_rid);
mesh->dependency.deleted_notify(p_rid);
if (mesh->instances.size()) {
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);
} else if (mesh_instance_owner.owns(p_rid)) {
MeshInstance *mi = mesh_instance_owner.getornull(p_rid);
_mesh_instance_clear(mi);
mi->mesh->instances.erase(mi->I);
mi->I = nullptr;
+
mesh_instance_owner.free(p_rid);
memdelete(mi);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 2fb66ac573..aa7195232a 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -478,6 +478,9 @@ private:
List<MeshInstance *> instances;
+ RID shadow_mesh;
+ Set<Mesh *> shadow_owners;
+
Dependency dependency;
};
@@ -1423,6 +1426,7 @@ public:
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
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);
@@ -1461,6 +1465,13 @@ public:
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) {
Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
return surface->primitive;
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index 64c23c7803..7a80c2b0bf 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -234,6 +234,8 @@ public:
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 bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 6d600c61cc..83afd9096d 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -274,6 +274,8 @@ public:
BIND2(mesh_set_custom_aabb, RID, const AABB &)
BIND1RC(AABB, mesh_get_custom_aabb, RID)
+ BIND2(mesh_set_shadow_mesh, RID, RID)
+
BIND1(mesh_clear, RID)
/* MULTIMESH API */
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index 534159e095..2f76577474 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -172,6 +172,7 @@ public:
FUNC2(mesh_set_custom_aabb, RID, const AABB &)
FUNC1RC(AABB, mesh_get_custom_aabb, RID)
+ FUNC2(mesh_set_shadow_mesh, RID, RID)
FUNC1(mesh_clear, RID)
/* MULTIMESH API */
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index c4483133e4..fd8d8cd21d 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -354,6 +354,8 @@ public:
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 void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
+
virtual void mesh_clear(RID p_mesh) = 0;
/* MULTIMESH API */