Skip to content

Commit 79b7adf

Browse files
committed
Add custom shader support to SpriteBase3D
1 parent 1753893 commit 79b7adf

File tree

5 files changed

+148
-40
lines changed

5 files changed

+148
-40
lines changed

editor/shader_create_dialog.cpp

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,13 @@ void ShaderCreateDialog::_path_hbox_sorted() {
120120
void ShaderCreateDialog::_mode_changed(int p_mode) {
121121
current_mode = p_mode;
122122
EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_mode", p_mode);
123+
124+
_update_templates();
123125
}
124126

125127
void ShaderCreateDialog::_template_changed(int p_template) {
126128
current_template = p_template;
127-
EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_template", p_template);
129+
EditorSettings::get_singleton()->set_project_metadata("shader_setup", vformat("last_selected_template_%d", current_mode), p_template);
128130
}
129131

130132
void ShaderCreateDialog::ok_pressed() {
@@ -213,6 +215,33 @@ void fog() {
213215
}
214216
)";
215217
}
218+
} else if (current_mode == Shader::MODE_SPATIAL && current_template == TEMPLATE_SPATIAL_SPRITE3D) {
219+
// Spatial: Sprite3D template.
220+
code += R"(render_mode unshaded;
221+
222+
uniform sampler2D texture_albedo;
223+
uniform ivec2 albedo_texture_size;
224+
225+
varying vec4 color;
226+
void vertex() {
227+
// Called for every vertex the material is visible on.
228+
// Sprite3D's "modulate" property changes the vertex color, so
229+
// assigning COLOR to a varying lets the material take advantage of modulate.
230+
color = COLOR;
231+
}
232+
233+
void fragment() {
234+
// Called for every pixel the material is visible on.
235+
vec4 col = color * texture(texture_albedo, UV);
236+
ALBEDO = col.rgb;
237+
ALPHA = col.a;
238+
}
239+
240+
//void light() {
241+
// // Called for every pixel for every light affecting the material.
242+
// // Uncomment to replace the default light processing function with this one.
243+
//}
244+
)";
216245
}
217246
text_shader->set_code(code.as_string());
218247
} break;
@@ -310,13 +339,10 @@ void ShaderCreateDialog::_type_changed(int p_language) {
310339
template_menu->clear();
311340

312341
if (shader_type_data.use_templates) {
313-
int last_template = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_template", 0);
314-
315342
template_menu->add_item(TTR("Default"));
316343
template_menu->add_item(TTR("Empty"));
317344

318-
template_menu->select(last_template);
319-
current_template = last_template;
345+
_update_templates();
320346
} else {
321347
template_menu->add_item(TTR("N/A"));
322348
}
@@ -409,17 +435,19 @@ void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabl
409435
built_in_enabled = p_built_in_enabled;
410436
load_enabled = p_load_enabled;
411437

412-
if (p_preferred_type > -1) {
413-
type_menu->select(p_preferred_type);
414-
_type_changed(p_preferred_type);
415-
}
416-
438+
// Mode change should happen before type change because the list of templates also depends on the shader mode.
417439
if (p_preferred_mode > -1) {
418440
mode_menu->select(p_preferred_mode);
419441
_mode_changed(p_preferred_mode);
420442
}
421443

422-
_type_changed(current_type);
444+
if (p_preferred_type > -1) {
445+
type_menu->select(p_preferred_type);
446+
_type_changed(p_preferred_type);
447+
} else {
448+
_type_changed(current_type);
449+
}
450+
423451
_path_changed(file_path->get_text());
424452
}
425453

@@ -534,6 +562,25 @@ void ShaderCreateDialog::_update_dialog() {
534562
}
535563
}
536564

565+
void ShaderCreateDialog::_update_templates() {
566+
int last_template = EditorSettings::get_singleton()->get_project_metadata("shader_setup", vformat("last_selected_template_%d", current_mode), 0);
567+
568+
// Remove previous mode-specific templates.
569+
for (int i = template_menu->get_item_count() - 1; i >= 2; i--) {
570+
template_menu->remove_item(i);
571+
}
572+
573+
// Add new mode-specific templates.
574+
switch (current_mode) {
575+
case Shader::MODE_SPATIAL: {
576+
template_menu->add_icon_item(get_editor_theme_icon(SNAME("Sprite3D")), TTR("Spatial: Sprite3D"));
577+
} break;
578+
}
579+
580+
template_menu->select(last_template);
581+
_template_changed(last_template);
582+
}
583+
537584
void ShaderCreateDialog::_bind_methods() {
538585
ClassDB::bind_method(D_METHOD("config", "path", "built_in_enabled", "load_enabled"), &ShaderCreateDialog::config, DEFVAL(true), DEFVAL(true));
539586

editor/shader_create_dialog.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ class ShaderCreateDialog : public ConfirmationDialog {
5151
MSG_ID_BUILT_IN,
5252
};
5353

54+
enum {
55+
TEMPLATE_SPATIAL_SPRITE3D = 2,
56+
};
57+
5458
struct ShaderTypeData {
5559
List<String> extensions;
5660
String default_extension;
@@ -99,6 +103,7 @@ class ShaderCreateDialog : public ConfirmationDialog {
99103
void _create_new();
100104
void _load_exist();
101105
void _update_dialog();
106+
void _update_templates();
102107

103108
protected:
104109
void _notification(int p_what);

scene/3d/sprite_3d.cpp

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ void SpriteBase3D::_notification(int p_what) {
8787
}
8888
}
8989

90+
void SpriteBase3D::_validate_property(PropertyInfo &p_property) const {
91+
if (get_material_override().is_valid()) {
92+
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") {
93+
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
94+
}
95+
}
96+
}
97+
9098
void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect) {
9199
ERR_FAIL_COND(p_texture.is_null());
92100

@@ -250,38 +258,46 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
250258
RS::get_singleton()->mesh_set_custom_aabb(mesh_new, aabb_new);
251259
set_aabb(aabb_new);
252260

253-
RS::get_singleton()->material_set_param(get_material(), "alpha_scissor_threshold", alpha_scissor_threshold);
254-
RS::get_singleton()->material_set_param(get_material(), "alpha_hash_scale", alpha_hash_scale);
255-
RS::get_singleton()->material_set_param(get_material(), "alpha_antialiasing_edge", alpha_antialiasing_edge);
256-
257-
BaseMaterial3D::Transparency mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_DISABLED;
258-
if (get_draw_flag(FLAG_TRANSPARENT)) {
259-
if (get_alpha_cut_mode() == ALPHA_CUT_DISCARD) {
260-
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_SCISSOR;
261-
} else if (get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS) {
262-
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS;
263-
} else if (get_alpha_cut_mode() == ALPHA_CUT_HASH) {
264-
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_HASH;
265-
} else {
266-
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA;
261+
if (get_material_override().is_null()) {
262+
RS::get_singleton()->material_set_param(get_material(), "alpha_scissor_threshold", alpha_scissor_threshold);
263+
RS::get_singleton()->material_set_param(get_material(), "alpha_hash_scale", alpha_hash_scale);
264+
RS::get_singleton()->material_set_param(get_material(), "alpha_antialiasing_edge", alpha_antialiasing_edge);
265+
266+
BaseMaterial3D::Transparency mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_DISABLED;
267+
if (get_draw_flag(FLAG_TRANSPARENT)) {
268+
if (get_alpha_cut_mode() == ALPHA_CUT_DISCARD) {
269+
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_SCISSOR;
270+
} else if (get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS) {
271+
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS;
272+
} else if (get_alpha_cut_mode() == ALPHA_CUT_HASH) {
273+
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_HASH;
274+
} else {
275+
mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA;
276+
}
267277
}
268-
}
269278

270-
RID shader_rid;
271-
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);
279+
RID shader_rid;
280+
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);
272281

273-
if (last_shader != shader_rid) {
274-
RS::get_singleton()->material_set_shader(get_material(), shader_rid);
275-
last_shader = shader_rid;
276-
}
277-
if (last_texture != p_texture->get_rid()) {
278-
RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid());
279-
RS::get_singleton()->material_set_param(get_material(), "albedo_texture_size", Vector2i(p_texture->get_width(), p_texture->get_height()));
280-
last_texture = p_texture->get_rid();
281-
}
282-
if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
283-
RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
284-
RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
282+
if (last_shader != shader_rid) {
283+
RS::get_singleton()->material_set_shader(get_material(), shader_rid);
284+
last_shader = shader_rid;
285+
}
286+
if (last_texture != p_texture->get_rid()) {
287+
RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid());
288+
RS::get_singleton()->material_set_param(get_material(), "albedo_texture_size", Vector2i(p_texture->get_width(), p_texture->get_height()));
289+
last_texture = p_texture->get_rid();
290+
}
291+
if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
292+
RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
293+
RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
294+
}
295+
} else {
296+
if (last_texture != p_texture->get_rid()) {
297+
RS::get_singleton()->material_set_param(get_material_override()->get_rid(), "texture_albedo", p_texture->get_rid());
298+
RS::get_singleton()->material_set_param(get_material_override()->get_rid(), "albedo_texture_size", Vector2i(p_texture->get_width(), p_texture->get_height()));
299+
last_texture = p_texture->get_rid();
300+
}
285301
}
286302
}
287303

@@ -477,6 +493,37 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
477493
return triangle_mesh;
478494
}
479495

496+
PackedStringArray SpriteBase3D::get_configuration_warnings() const {
497+
PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings();
498+
Ref<Material> mat_override = get_material_override();
499+
if (mat_override.is_valid()) {
500+
RID shader = mat_override->get_shader_rid();
501+
if (shader.is_null()) {
502+
warnings.push_back(RTR("Material Override must be assigned a shader in order to work correctly."));
503+
} else {
504+
List<PropertyInfo> parameters;
505+
RS::get_singleton()->get_shader_parameter_list(shader, &parameters);
506+
bool found_texture_albedo = false;
507+
bool found_albedo_texture_size = false;
508+
for (const PropertyInfo &parameter : parameters) {
509+
if (!found_texture_albedo && parameter.name == "texture_albedo" && parameter.type == Variant::OBJECT && parameter.hint_string == "Texture2D") {
510+
found_texture_albedo = true;
511+
} else if (!found_albedo_texture_size && parameter.name == "albedo_texture_size" && parameter.type == Variant::VECTOR2I) {
512+
found_albedo_texture_size = true;
513+
}
514+
}
515+
516+
if (!found_texture_albedo) {
517+
warnings.push_back(RTR("Sprite shaders must contain uniform \"texture_albedo\" of type: sampler2D."));
518+
}
519+
if (!found_albedo_texture_size) {
520+
warnings.push_back(RTR("Sprite shaders must contain uniform \"albedo_texture_size\" of type: ivec2."));
521+
}
522+
}
523+
}
524+
return warnings;
525+
}
526+
480527
void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
481528
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
482529

@@ -747,6 +794,8 @@ SpriteBase3D::SpriteBase3D() {
747794
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);
748795
RS::get_singleton()->mesh_add_surface(mesh, sd);
749796
set_base(mesh);
797+
798+
connect(CoreStringName(property_list_changed), callable_mp((Node *)this, &Node::update_configuration_warnings));
750799
}
751800

752801
SpriteBase3D::~SpriteBase3D() {

scene/3d/sprite_3d.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class SpriteBase3D : public GeometryInstance3D {
103103
void _notification(int p_what);
104104
static void _bind_methods();
105105
virtual void _draw() = 0;
106+
void _validate_property(PropertyInfo &p_property) const;
106107
void draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect);
107108
_FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; }
108109
_FORCE_INLINE_ RID &get_mesh() { return mesh; }
@@ -173,6 +174,7 @@ class SpriteBase3D : public GeometryInstance3D {
173174
virtual AABB get_aabb() const override;
174175

175176
virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
177+
virtual PackedStringArray get_configuration_warnings() const override;
176178

177179
SpriteBase3D();
178180
~SpriteBase3D();

scene/3d/visual_instance_3d.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ VisualInstance3D::~VisualInstance3D() {
224224
}
225225

226226
void GeometryInstance3D::set_material_override(const Ref<Material> &p_material) {
227+
bool changed = material_override != p_material;
227228
if (material_override.is_valid()) {
228229
material_override->disconnect(CoreStringName(property_list_changed), callable_mp((Object *)this, &Object::notify_property_list_changed));
229230
}
@@ -232,6 +233,10 @@ void GeometryInstance3D::set_material_override(const Ref<Material> &p_material)
232233
material_override->connect(CoreStringName(property_list_changed), callable_mp((Object *)this, &Object::notify_property_list_changed));
233234
}
234235
RS::get_singleton()->instance_geometry_set_material_override(get_instance(), p_material.is_valid() ? p_material->get_rid() : RID());
236+
if (changed) {
237+
notify_property_list_changed();
238+
update_configuration_warnings();
239+
}
235240
}
236241

237242
Ref<Material> GeometryInstance3D::get_material_override() const {

0 commit comments

Comments
 (0)