From 8330368564b4beb52c1539b88f98cad0dca5be86 Mon Sep 17 00:00:00 2001 From: chocola-mint <56677134+chocola-mint@users.noreply.github.com> Date: Tue, 25 Feb 2025 19:05:55 +0900 Subject: [PATCH] Add custom shader support to SpriteBase3D --- scene/3d/sprite_3d.cpp | 105 +++++++++++++++++++++++--------- scene/3d/sprite_3d.h | 2 + scene/3d/visual_instance_3d.cpp | 5 ++ 3 files changed, 84 insertions(+), 28 deletions(-) diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index fb62b46e863..5b2a3fad543 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -87,6 +87,14 @@ void SpriteBase3D::_notification(int p_what) { } } +void SpriteBase3D::_validate_property(PropertyInfo &p_property) const { + if (get_material_override().is_valid()) { + if (p_property.name == "billboard" || p_property.name == "transparent" || p_property.name == "shaded" || p_property.name == "double_sided" || p_property.name == "no_depth_test" || p_property.name == "fixed_size" || p_property.name == "alpha_cut" || p_property.name == "alpha_scissor_threshold" || p_property.name == "alpha_hash_scale" || p_property.name == "alpha_antialiasing_mode" || p_property.name == "alpha_antialiasing_edge" || p_property.name == "texture_filter" || p_property.name == "render_priority") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } +} + void SpriteBase3D::draw_texture_rect(Ref p_texture, Rect2 p_dst_rect, Rect2 p_src_rect) { ERR_FAIL_COND(p_texture.is_null()); @@ -250,38 +258,46 @@ void SpriteBase3D::draw_texture_rect(Ref p_texture, Rect2 p_dst_rect, RS::get_singleton()->mesh_set_custom_aabb(mesh_new, aabb_new); set_aabb(aabb_new); - RS::get_singleton()->material_set_param(get_material(), "alpha_scissor_threshold", alpha_scissor_threshold); - RS::get_singleton()->material_set_param(get_material(), "alpha_hash_scale", alpha_hash_scale); - RS::get_singleton()->material_set_param(get_material(), "alpha_antialiasing_edge", alpha_antialiasing_edge); + if (get_material_override().is_null()) { + RS::get_singleton()->material_set_param(get_material(), "alpha_scissor_threshold", alpha_scissor_threshold); + RS::get_singleton()->material_set_param(get_material(), "alpha_hash_scale", alpha_hash_scale); + RS::get_singleton()->material_set_param(get_material(), "alpha_antialiasing_edge", alpha_antialiasing_edge); - BaseMaterial3D::Transparency mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_DISABLED; - if (get_draw_flag(FLAG_TRANSPARENT)) { - if (get_alpha_cut_mode() == ALPHA_CUT_DISCARD) { - mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_SCISSOR; - } else if (get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS) { - mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS; - } else if (get_alpha_cut_mode() == ALPHA_CUT_HASH) { - mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_HASH; - } else { - mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA; + BaseMaterial3D::Transparency mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_DISABLED; + if (get_draw_flag(FLAG_TRANSPARENT)) { + if (get_alpha_cut_mode() == ALPHA_CUT_DISCARD) { + mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_SCISSOR; + } else if (get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS) { + mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS; + } else if (get_alpha_cut_mode() == ALPHA_CUT_HASH) { + mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_HASH; + } else { + mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA; + } } - } - RID shader_rid; - StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), mat_transparency, get_draw_flag(FLAG_DOUBLE_SIDED), get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), alpha_antialiasing_mode, &shader_rid); + RID shader_rid; + StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), mat_transparency, get_draw_flag(FLAG_DOUBLE_SIDED), get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), alpha_antialiasing_mode, &shader_rid); - if (last_shader != shader_rid) { - RS::get_singleton()->material_set_shader(get_material(), shader_rid); - last_shader = shader_rid; - } - if (last_texture != p_texture->get_rid()) { - RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid()); - RS::get_singleton()->material_set_param(get_material(), "albedo_texture_size", Vector2i(p_texture->get_width(), p_texture->get_height())); - last_texture = p_texture->get_rid(); - } - if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) { - RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority()); - RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material()); + if (last_shader != shader_rid) { + RS::get_singleton()->material_set_shader(get_material(), shader_rid); + last_shader = shader_rid; + } + if (last_texture != p_texture->get_rid()) { + RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid()); + RS::get_singleton()->material_set_param(get_material(), "albedo_texture_size", Vector2i(p_texture->get_width(), p_texture->get_height())); + last_texture = p_texture->get_rid(); + } + if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) { + RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority()); + RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material()); + } + } else { + if (last_texture != p_texture->get_rid()) { + RS::get_singleton()->material_set_param(get_material_override()->get_rid(), "texture_albedo", p_texture->get_rid()); + RS::get_singleton()->material_set_param(get_material_override()->get_rid(), "albedo_texture_size", Vector2i(p_texture->get_width(), p_texture->get_height())); + last_texture = p_texture->get_rid(); + } } } @@ -477,6 +493,37 @@ Ref SpriteBase3D::generate_triangle_mesh() const { return triangle_mesh; } +PackedStringArray SpriteBase3D::get_configuration_warnings() const { + PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings(); + Ref mat_override = get_material_override(); + if (mat_override.is_valid()) { + RID shader = mat_override->get_shader_rid(); + if (shader.is_null()) { + warnings.push_back(RTR("Material Override must be assigned a shader in order to work correctly.")); + } else { + List parameters; + RS::get_singleton()->get_shader_parameter_list(shader, ¶meters); + bool found_texture_albedo = false; + bool found_albedo_texture_size = false; + for (const PropertyInfo ¶meter : parameters) { + if (!found_texture_albedo && parameter.name == "texture_albedo" && parameter.type == Variant::OBJECT && parameter.hint_string == "Texture2D") { + found_texture_albedo = true; + } else if (!found_albedo_texture_size && parameter.name == "albedo_texture_size" && parameter.type == Variant::VECTOR2I) { + found_albedo_texture_size = true; + } + } + + if (!found_texture_albedo) { + warnings.push_back(RTR("Sprite shaders must contain uniform \"texture_albedo\" of type: sampler2D.")); + } + if (!found_albedo_texture_size) { + warnings.push_back(RTR("Sprite shaders must contain uniform \"albedo_texture_size\" of type: ivec2.")); + } + } + } + return warnings; +} + void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); @@ -747,6 +794,8 @@ SpriteBase3D::SpriteBase3D() { RS::get_singleton()->mesh_surface_make_offsets_from_format(sd.format, sd.vertex_count, sd.index_count, mesh_surface_offsets, vertex_stride, normal_tangent_stride, attrib_stride, skin_stride); RS::get_singleton()->mesh_add_surface(mesh, sd); set_base(mesh); + + connect(CoreStringName(property_list_changed), callable_mp((Node *)this, &Node::update_configuration_warnings)); } SpriteBase3D::~SpriteBase3D() { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 87327caca27..2852edde89a 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -103,6 +103,7 @@ protected: void _notification(int p_what); static void _bind_methods(); virtual void _draw() = 0; + void _validate_property(PropertyInfo &p_property) const; void draw_texture_rect(Ref p_texture, Rect2 p_dst_rect, Rect2 p_src_rect); _FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; } _FORCE_INLINE_ RID &get_mesh() { return mesh; } @@ -173,6 +174,7 @@ public: virtual AABB get_aabb() const override; virtual Ref generate_triangle_mesh() const override; + virtual PackedStringArray get_configuration_warnings() const override; SpriteBase3D(); ~SpriteBase3D(); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 9617e0b9127..226e489ce14 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -224,6 +224,7 @@ VisualInstance3D::~VisualInstance3D() { } void GeometryInstance3D::set_material_override(const Ref &p_material) { + bool changed = material_override != p_material; if (material_override.is_valid()) { material_override->disconnect(CoreStringName(property_list_changed), callable_mp((Object *)this, &Object::notify_property_list_changed)); } @@ -232,6 +233,10 @@ void GeometryInstance3D::set_material_override(const Ref &p_material) material_override->connect(CoreStringName(property_list_changed), callable_mp((Object *)this, &Object::notify_property_list_changed)); } RS::get_singleton()->instance_geometry_set_material_override(get_instance(), p_material.is_valid() ? p_material->get_rid() : RID()); + if (changed) { + notify_property_list_changed(); + update_configuration_warnings(); + } } Ref GeometryInstance3D::get_material_override() const {