diff --git a/editor/icons/MaterialPreviewQuad.svg b/editor/icons/MaterialPreviewQuad.svg new file mode 100644 index 00000000000..9765a15df77 --- /dev/null +++ b/editor/icons/MaterialPreviewQuad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index be44d573765..8bdc763ebef 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -56,9 +56,15 @@ void MaterialEditor::gui_input(const Ref &p_event) { if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) { rot.x -= mm->get_relative().y * 0.01; rot.y -= mm->get_relative().x * 0.01; - - rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2); + if (quad_instance->is_visible()) { + // Clamp rotation so the quad is always visible. + const real_t limit = Math::deg_to_rad(80.0); + rot = rot.clampf(-limit, limit); + } else { + rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2); + } _update_rotation(); + _store_rotation_metadata(); } } @@ -70,6 +76,7 @@ void MaterialEditor::_update_theme_item_cache() { theme_cache.sphere_icon = get_editor_theme_icon(SNAME("MaterialPreviewSphere")); theme_cache.box_icon = get_editor_theme_icon(SNAME("MaterialPreviewCube")); + theme_cache.quad_icon = get_editor_theme_icon(SNAME("MaterialPreviewQuad")); theme_cache.checkerboard = get_editor_theme_icon(SNAME("Checkerboard")); } @@ -82,6 +89,7 @@ void MaterialEditor::_notification(int p_what) { sphere_switch->set_button_icon(theme_cache.sphere_icon); box_switch->set_button_icon(theme_cache.box_icon); + quad_switch->set_button_icon(theme_cache.quad_icon); error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor))); } break; @@ -95,6 +103,18 @@ void MaterialEditor::_notification(int p_what) { } } +void MaterialEditor::_set_rotation(real_t p_x_degrees, real_t p_y_degrees) { + rot.x = Math::deg_to_rad(p_x_degrees); + rot.y = Math::deg_to_rad(p_y_degrees); + _update_rotation(); +} + +// Store the rotation so it can persist when switching between materials. +void MaterialEditor::_store_rotation_metadata() { + Vector2 rotation_degrees = Vector2(Math::rad_to_deg(rot.x), Math::rad_to_deg(rot.y)); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_rotation", rotation_degrees); +} + void MaterialEditor::_update_rotation() { Transform3D t; t.basis.rotate(Vector3(0, 1, 0), -rot.y); @@ -124,6 +144,7 @@ void MaterialEditor::edit(Ref p_material, const Ref &p_en vc->show(); sphere_instance->set_material_override(material); box_instance->set_material_override(material); + quad_instance->set_material_override(material); break; default: layout_error->show(); @@ -136,10 +157,6 @@ void MaterialEditor::edit(Ref p_material, const Ref &p_en } else { hide(); } - - rot.x = Math::deg_to_rad(-15.0); - rot.y = Math::deg_to_rad(30.0); - _update_rotation(); } void MaterialEditor::_on_light_1_switch_pressed() { @@ -151,19 +168,36 @@ void MaterialEditor::_on_light_2_switch_pressed() { } void MaterialEditor::_on_sphere_switch_pressed() { - box_instance->hide(); sphere_instance->show(); + box_instance->hide(); + quad_instance->hide(); box_switch->set_pressed(false); - sphere_switch->set_pressed(true); - EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true); + quad_switch->set_pressed(false); + _set_rotation(-15.0, 30.0); + _store_rotation_metadata(); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_mesh", "sphere"); } void MaterialEditor::_on_box_switch_pressed() { - box_instance->show(); sphere_instance->hide(); - box_switch->set_pressed(true); + box_instance->show(); + quad_instance->hide(); sphere_switch->set_pressed(false); - EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false); + quad_switch->set_pressed(false); + _set_rotation(-15.0, 30.0); + _store_rotation_metadata(); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_mesh", "box"); +} + +void MaterialEditor::_on_quad_switch_pressed() { + sphere_instance->hide(); + box_instance->hide(); + quad_instance->show(); + sphere_switch->set_pressed(false); + box_switch->set_pressed(false); + _set_rotation(0.0, 0.0); + _store_rotation_metadata(); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_mesh", "quad"); } MaterialEditor::MaterialEditor() { @@ -213,7 +247,7 @@ MaterialEditor::MaterialEditor() { viewport = memnew(SubViewport); Ref world_3d; world_3d.instantiate(); - viewport->set_world_3d(world_3d); //use own world + viewport->set_world_3d(world_3d); // Use own world. vc->add_child(viewport); viewport->set_disable_input(true); viewport->set_transparent_background(true); @@ -221,7 +255,7 @@ MaterialEditor::MaterialEditor() { camera = memnew(Camera3D); camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1))); - // Use low field of view so the sphere/box is fully encompassed within the preview, + // Use low field of view so the sphere/box/quad is fully encompassed within the preview, // without much distortion. camera->set_perspective(20, 0.1, 10); camera->make_current(); @@ -249,13 +283,19 @@ MaterialEditor::MaterialEditor() { box_instance = memnew(MeshInstance3D); rotation->add_child(box_instance); - box_instance->set_transform(Transform3D() * 0.25); + quad_instance = memnew(MeshInstance3D); + rotation->add_child(quad_instance); + sphere_instance->set_transform(Transform3D() * 0.375); + box_instance->set_transform(Transform3D() * 0.25); + quad_instance->set_transform(Transform3D() * 0.375); sphere_mesh.instantiate(); sphere_instance->set_mesh(sphere_mesh); box_mesh.instantiate(); box_instance->set_mesh(box_mesh); + quad_mesh.instantiate(); + quad_instance->set_mesh(quad_mesh); set_custom_minimum_size(Size2(1, 150) * EDSCALE); @@ -269,17 +309,21 @@ MaterialEditor::MaterialEditor() { sphere_switch = memnew(Button); sphere_switch->set_theme_type_variation("PreviewLightButton"); sphere_switch->set_toggle_mode(true); - sphere_switch->set_pressed(true); vb_shape->add_child(sphere_switch); sphere_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_sphere_switch_pressed)); box_switch = memnew(Button); box_switch->set_theme_type_variation("PreviewLightButton"); box_switch->set_toggle_mode(true); - box_switch->set_pressed(false); vb_shape->add_child(box_switch); box_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_box_switch_pressed)); + quad_switch = memnew(Button); + quad_switch->set_theme_type_variation("PreviewLightButton"); + quad_switch->set_toggle_mode(true); + vb_shape->add_child(quad_switch); + quad_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_quad_switch_pressed)); + layout_3d->add_spacer(); VBoxContainer *vb_light = memnew(VBoxContainer); @@ -299,14 +343,23 @@ MaterialEditor::MaterialEditor() { vb_light->add_child(light_2_switch); light_2_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_light_2_switch_pressed)); - if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) { + String shape = EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_mesh", "sphere"); + if (shape == "sphere") { box_instance->hide(); - } else { - box_instance->show(); + quad_instance->hide(); + sphere_switch->set_pressed_no_signal(true); + } else if (shape == "box") { sphere_instance->hide(); - box_switch->set_pressed(true); - sphere_switch->set_pressed(false); + quad_instance->hide(); + box_switch->set_pressed_no_signal(true); + } else { + sphere_instance->hide(); + box_instance->hide(); + quad_switch->set_pressed_no_signal(true); } + + Vector2 stored_rot = EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_rotation", Vector2()); + _set_rotation(stored_rot.x, stored_rot.y); } /////////////////////// diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 28c59d27dba..c1b37a5831b 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -62,6 +62,7 @@ class MaterialEditor : public Control { Node3D *rotation = nullptr; MeshInstance3D *sphere_instance = nullptr; MeshInstance3D *box_instance = nullptr; + MeshInstance3D *quad_instance = nullptr; DirectionalLight3D *light1 = nullptr; DirectionalLight3D *light2 = nullptr; Camera3D *camera = nullptr; @@ -69,6 +70,7 @@ class MaterialEditor : public Control { Ref sphere_mesh; Ref box_mesh; + Ref quad_mesh; VBoxContainer *layout_error = nullptr; Label *error_label = nullptr; @@ -80,6 +82,7 @@ class MaterialEditor : public Control { Button *sphere_switch = nullptr; Button *box_switch = nullptr; + Button *quad_switch = nullptr; Button *light_1_switch = nullptr; Button *light_2_switch = nullptr; @@ -88,6 +91,7 @@ class MaterialEditor : public Control { Ref light_2_icon; Ref sphere_icon; Ref box_icon; + Ref quad_icon; Ref checkerboard; } theme_cache; @@ -95,11 +99,14 @@ class MaterialEditor : public Control { void _on_light_2_switch_pressed(); void _on_sphere_switch_pressed(); void _on_box_switch_pressed(); + void _on_quad_switch_pressed(); protected: virtual void _update_theme_item_cache() override; void _notification(int p_what); void gui_input(const Ref &p_event) override; + void _set_rotation(real_t p_x_degrees, real_t p_y_degrees); + void _store_rotation_metadata(); void _update_rotation(); public: diff --git a/editor/themes/editor_color_map.cpp b/editor/themes/editor_color_map.cpp index 9046a8b688f..3c3d755586d 100644 --- a/editor/themes/editor_color_map.cpp +++ b/editor/themes/editor_color_map.cpp @@ -173,6 +173,8 @@ void EditorColorMap::create() { add_conversion_exception("OverbrightIndicator"); add_conversion_exception("MaterialPreviewCube"); add_conversion_exception("MaterialPreviewSphere"); + add_conversion_exception("MaterialPreviewQuad"); + add_conversion_exception("MaterialPreviewLight1"); add_conversion_exception("MaterialPreviewLight2");