1/**************************************************************************/
2/* material_editor_plugin.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "material_editor_plugin.h"
32
33#include "core/config/project_settings.h"
34#include "editor/editor_node.h"
35#include "editor/editor_scale.h"
36#include "editor/editor_settings.h"
37#include "editor/editor_undo_redo_manager.h"
38#include "scene/3d/camera_3d.h"
39#include "scene/3d/light_3d.h"
40#include "scene/3d/mesh_instance_3d.h"
41#include "scene/gui/box_container.h"
42#include "scene/gui/button.h"
43#include "scene/gui/color_rect.h"
44#include "scene/gui/subviewport_container.h"
45#include "scene/main/viewport.h"
46#include "scene/resources/fog_material.h"
47#include "scene/resources/particle_process_material.h"
48#include "scene/resources/sky_material.h"
49
50void MaterialEditor::gui_input(const Ref<InputEvent> &p_event) {
51 ERR_FAIL_COND(p_event.is_null());
52
53 Ref<InputEventMouseMotion> mm = p_event;
54 if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
55 rot.x -= mm->get_relative().y * 0.01;
56 rot.y -= mm->get_relative().x * 0.01;
57
58 rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2);
59 _update_rotation();
60 }
61}
62
63void MaterialEditor::_update_theme_item_cache() {
64 Control::_update_theme_item_cache();
65
66 theme_cache.light_1_icon = get_editor_theme_icon(SNAME("MaterialPreviewLight1"));
67 theme_cache.light_2_icon = get_editor_theme_icon(SNAME("MaterialPreviewLight2"));
68
69 theme_cache.sphere_icon = get_editor_theme_icon(SNAME("MaterialPreviewSphere"));
70 theme_cache.box_icon = get_editor_theme_icon(SNAME("MaterialPreviewCube"));
71
72 theme_cache.checkerboard = get_editor_theme_icon(SNAME("Checkerboard"));
73}
74
75void MaterialEditor::_notification(int p_what) {
76 switch (p_what) {
77 case NOTIFICATION_THEME_CHANGED: {
78 light_1_switch->set_icon(theme_cache.light_1_icon);
79 light_2_switch->set_icon(theme_cache.light_2_icon);
80
81 sphere_switch->set_icon(theme_cache.sphere_icon);
82 box_switch->set_icon(theme_cache.box_icon);
83 } break;
84
85 case NOTIFICATION_DRAW: {
86 Size2 size = get_size();
87 draw_texture_rect(theme_cache.checkerboard, Rect2(Point2(), size), true);
88 } break;
89 }
90}
91
92void MaterialEditor::_update_rotation() {
93 Transform3D t;
94 t.basis.rotate(Vector3(0, 1, 0), -rot.y);
95 t.basis.rotate(Vector3(1, 0, 0), -rot.x);
96 rotation->set_transform(t);
97}
98
99void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
100 material = p_material;
101 camera->set_environment(p_env);
102 if (!material.is_null()) {
103 Shader::Mode mode = p_material->get_shader_mode();
104 switch (mode) {
105 case Shader::MODE_CANVAS_ITEM:
106 layout_3d->hide();
107 layout_2d->show();
108 vc->hide();
109 rect_instance->set_material(material);
110 break;
111 case Shader::MODE_SPATIAL:
112 layout_2d->hide();
113 layout_3d->show();
114 vc->show();
115 sphere_instance->set_material_override(material);
116 box_instance->set_material_override(material);
117 break;
118 default:
119 break;
120 }
121 } else {
122 hide();
123 }
124
125 rot.x = Math::deg_to_rad(-15.0);
126 rot.y = Math::deg_to_rad(30.0);
127 _update_rotation();
128}
129
130void MaterialEditor::_on_light_1_switch_pressed() {
131 light1->set_visible(light_1_switch->is_pressed());
132}
133
134void MaterialEditor::_on_light_2_switch_pressed() {
135 light2->set_visible(light_2_switch->is_pressed());
136}
137
138void MaterialEditor::_on_sphere_switch_pressed() {
139 box_instance->hide();
140 sphere_instance->show();
141 box_switch->set_pressed(false);
142 sphere_switch->set_pressed(true);
143 EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true);
144}
145
146void MaterialEditor::_on_box_switch_pressed() {
147 box_instance->show();
148 sphere_instance->hide();
149 box_switch->set_pressed(true);
150 sphere_switch->set_pressed(false);
151 EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false);
152}
153
154MaterialEditor::MaterialEditor() {
155 // Canvas item
156
157 vc_2d = memnew(SubViewportContainer);
158 vc_2d->set_stretch(true);
159 add_child(vc_2d);
160 vc_2d->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
161
162 viewport_2d = memnew(SubViewport);
163 vc_2d->add_child(viewport_2d);
164 viewport_2d->set_disable_input(true);
165 viewport_2d->set_transparent_background(true);
166
167 layout_2d = memnew(HBoxContainer);
168 layout_2d->set_alignment(BoxContainer::ALIGNMENT_CENTER);
169 viewport_2d->add_child(layout_2d);
170 layout_2d->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
171
172 rect_instance = memnew(ColorRect);
173 layout_2d->add_child(rect_instance);
174 rect_instance->set_custom_minimum_size(Size2(150, 150) * EDSCALE);
175
176 layout_2d->set_visible(false);
177
178 // Spatial
179
180 vc = memnew(SubViewportContainer);
181 vc->set_stretch(true);
182 add_child(vc);
183 vc->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
184 viewport = memnew(SubViewport);
185 Ref<World3D> world_3d;
186 world_3d.instantiate();
187 viewport->set_world_3d(world_3d); //use own world
188 vc->add_child(viewport);
189 viewport->set_disable_input(true);
190 viewport->set_transparent_background(true);
191 viewport->set_msaa_3d(Viewport::MSAA_4X);
192
193 camera = memnew(Camera3D);
194 camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
195 // Use low field of view so the sphere/box is fully encompassed within the preview,
196 // without much distortion.
197 camera->set_perspective(20, 0.1, 10);
198 camera->make_current();
199 if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
200 camera_attributes.instantiate();
201 camera->set_attributes(camera_attributes);
202 }
203 viewport->add_child(camera);
204
205 light1 = memnew(DirectionalLight3D);
206 light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
207 viewport->add_child(light1);
208
209 light2 = memnew(DirectionalLight3D);
210 light2->set_transform(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
211 light2->set_color(Color(0.7, 0.7, 0.7));
212 viewport->add_child(light2);
213
214 rotation = memnew(Node3D);
215 viewport->add_child(rotation);
216
217 sphere_instance = memnew(MeshInstance3D);
218 rotation->add_child(sphere_instance);
219
220 box_instance = memnew(MeshInstance3D);
221 rotation->add_child(box_instance);
222
223 box_instance->set_transform(Transform3D() * 0.25);
224 sphere_instance->set_transform(Transform3D() * 0.375);
225
226 sphere_mesh.instantiate();
227 sphere_instance->set_mesh(sphere_mesh);
228 box_mesh.instantiate();
229 box_instance->set_mesh(box_mesh);
230
231 set_custom_minimum_size(Size2(1, 150) * EDSCALE);
232
233 layout_3d = memnew(HBoxContainer);
234 add_child(layout_3d);
235 layout_3d->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 2);
236
237 VBoxContainer *vb_shape = memnew(VBoxContainer);
238 layout_3d->add_child(vb_shape);
239
240 sphere_switch = memnew(Button);
241 sphere_switch->set_theme_type_variation("PreviewLightButton");
242 sphere_switch->set_toggle_mode(true);
243 sphere_switch->set_pressed(true);
244 vb_shape->add_child(sphere_switch);
245 sphere_switch->connect("pressed", callable_mp(this, &MaterialEditor::_on_sphere_switch_pressed));
246
247 box_switch = memnew(Button);
248 box_switch->set_theme_type_variation("PreviewLightButton");
249 box_switch->set_toggle_mode(true);
250 box_switch->set_pressed(false);
251 vb_shape->add_child(box_switch);
252 box_switch->connect("pressed", callable_mp(this, &MaterialEditor::_on_box_switch_pressed));
253
254 layout_3d->add_spacer();
255
256 VBoxContainer *vb_light = memnew(VBoxContainer);
257 layout_3d->add_child(vb_light);
258
259 light_1_switch = memnew(Button);
260 light_1_switch->set_theme_type_variation("PreviewLightButton");
261 light_1_switch->set_toggle_mode(true);
262 light_1_switch->set_pressed(true);
263 vb_light->add_child(light_1_switch);
264 light_1_switch->connect("pressed", callable_mp(this, &MaterialEditor::_on_light_1_switch_pressed));
265
266 light_2_switch = memnew(Button);
267 light_2_switch->set_theme_type_variation("PreviewLightButton");
268 light_2_switch->set_toggle_mode(true);
269 light_2_switch->set_pressed(true);
270 vb_light->add_child(light_2_switch);
271 light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_on_light_2_switch_pressed));
272
273 if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
274 box_instance->hide();
275 } else {
276 box_instance->show();
277 sphere_instance->hide();
278 box_switch->set_pressed(true);
279 sphere_switch->set_pressed(false);
280 }
281}
282
283///////////////////////
284
285bool EditorInspectorPluginMaterial::can_handle(Object *p_object) {
286 Material *material = Object::cast_to<Material>(p_object);
287 if (!material) {
288 return false;
289 }
290 Shader::Mode mode = material->get_shader_mode();
291 return mode == Shader::MODE_SPATIAL || mode == Shader::MODE_CANVAS_ITEM;
292}
293
294void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
295 Material *material = Object::cast_to<Material>(p_object);
296 if (!material) {
297 return;
298 }
299 Ref<Material> m(material);
300
301 MaterialEditor *editor = memnew(MaterialEditor);
302 editor->edit(m, env);
303 add_custom_control(editor);
304}
305
306void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
307 EditorUndoRedoManager *undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
308 ERR_FAIL_NULL(undo_redo);
309
310 // For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot,
311 // set the respective metallic or roughness factor to 1.0 as a convenience feature
312 BaseMaterial3D *base_material = Object::cast_to<StandardMaterial3D>(p_edited);
313 if (base_material) {
314 Texture2D *texture = Object::cast_to<Texture2D>(p_new_value);
315 if (texture) {
316 if (p_property == "roughness_texture") {
317 if (base_material->get_texture(StandardMaterial3D::TEXTURE_ROUGHNESS).is_null()) {
318 undo_redo->add_do_property(p_edited, "roughness", 1.0);
319
320 bool valid = false;
321 Variant value = p_edited->get("roughness", &valid);
322 if (valid) {
323 undo_redo->add_undo_property(p_edited, "roughness", value);
324 }
325 }
326 } else if (p_property == "metallic_texture") {
327 if (base_material->get_texture(StandardMaterial3D::TEXTURE_METALLIC).is_null()) {
328 undo_redo->add_do_property(p_edited, "metallic", 1.0);
329
330 bool valid = false;
331 Variant value = p_edited->get("metallic", &valid);
332 if (valid) {
333 undo_redo->add_undo_property(p_edited, "metallic", value);
334 }
335 }
336 }
337 }
338 }
339}
340
341EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
342 env.instantiate();
343 Ref<Sky> sky = memnew(Sky());
344 env->set_sky(sky);
345 env->set_background(Environment::BG_COLOR);
346 env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY);
347 env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY);
348
349 EditorNode::get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &EditorInspectorPluginMaterial::_undo_redo_inspector_callback));
350}
351
352MaterialEditorPlugin::MaterialEditorPlugin() {
353 Ref<EditorInspectorPluginMaterial> plugin;
354 plugin.instantiate();
355 add_inspector_plugin(plugin);
356}
357
358String StandardMaterial3DConversionPlugin::converts_to() const {
359 return "ShaderMaterial";
360}
361
362bool StandardMaterial3DConversionPlugin::handles(const Ref<Resource> &p_resource) const {
363 Ref<StandardMaterial3D> mat = p_resource;
364 return mat.is_valid();
365}
366
367Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p_resource) const {
368 Ref<StandardMaterial3D> mat = p_resource;
369 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
370
371 Ref<ShaderMaterial> smat;
372 smat.instantiate();
373
374 Ref<Shader> shader;
375 shader.instantiate();
376
377 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
378
379 shader->set_code(code);
380
381 smat->set_shader(shader);
382
383 List<PropertyInfo> params;
384 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
385
386 for (const PropertyInfo &E : params) {
387 // Texture parameter has to be treated specially since StandardMaterial3D saved it
388 // as RID but ShaderMaterial needs Texture itself
389 Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
390 if (texture.is_valid()) {
391 smat->set_shader_parameter(E.name, texture);
392 } else {
393 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
394 smat->set_shader_parameter(E.name, value);
395 }
396 }
397
398 smat->set_render_priority(mat->get_render_priority());
399 smat->set_local_to_scene(mat->is_local_to_scene());
400 smat->set_name(mat->get_name());
401 return smat;
402}
403
404String ORMMaterial3DConversionPlugin::converts_to() const {
405 return "ShaderMaterial";
406}
407
408bool ORMMaterial3DConversionPlugin::handles(const Ref<Resource> &p_resource) const {
409 Ref<ORMMaterial3D> mat = p_resource;
410 return mat.is_valid();
411}
412
413Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_resource) const {
414 Ref<ORMMaterial3D> mat = p_resource;
415 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
416
417 Ref<ShaderMaterial> smat;
418 smat.instantiate();
419
420 Ref<Shader> shader;
421 shader.instantiate();
422
423 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
424
425 shader->set_code(code);
426
427 smat->set_shader(shader);
428
429 List<PropertyInfo> params;
430 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
431
432 for (const PropertyInfo &E : params) {
433 // Texture parameter has to be treated specially since ORMMaterial3D saved it
434 // as RID but ShaderMaterial needs Texture itself
435 Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
436 if (texture.is_valid()) {
437 smat->set_shader_parameter(E.name, texture);
438 } else {
439 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
440 smat->set_shader_parameter(E.name, value);
441 }
442 }
443
444 smat->set_render_priority(mat->get_render_priority());
445 smat->set_local_to_scene(mat->is_local_to_scene());
446 smat->set_name(mat->get_name());
447 return smat;
448}
449
450String ParticleProcessMaterialConversionPlugin::converts_to() const {
451 return "ShaderMaterial";
452}
453
454bool ParticleProcessMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
455 Ref<ParticleProcessMaterial> mat = p_resource;
456 return mat.is_valid();
457}
458
459Ref<Resource> ParticleProcessMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
460 Ref<ParticleProcessMaterial> mat = p_resource;
461 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
462
463 Ref<ShaderMaterial> smat;
464 smat.instantiate();
465
466 Ref<Shader> shader;
467 shader.instantiate();
468
469 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
470
471 shader->set_code(code);
472
473 smat->set_shader(shader);
474
475 List<PropertyInfo> params;
476 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
477
478 for (const PropertyInfo &E : params) {
479 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
480 smat->set_shader_parameter(E.name, value);
481 }
482
483 smat->set_render_priority(mat->get_render_priority());
484 smat->set_local_to_scene(mat->is_local_to_scene());
485 smat->set_name(mat->get_name());
486 return smat;
487}
488
489String CanvasItemMaterialConversionPlugin::converts_to() const {
490 return "ShaderMaterial";
491}
492
493bool CanvasItemMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
494 Ref<CanvasItemMaterial> mat = p_resource;
495 return mat.is_valid();
496}
497
498Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
499 Ref<CanvasItemMaterial> mat = p_resource;
500 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
501
502 Ref<ShaderMaterial> smat;
503 smat.instantiate();
504
505 Ref<Shader> shader;
506 shader.instantiate();
507
508 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
509
510 shader->set_code(code);
511
512 smat->set_shader(shader);
513
514 List<PropertyInfo> params;
515 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
516
517 for (const PropertyInfo &E : params) {
518 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
519 smat->set_shader_parameter(E.name, value);
520 }
521
522 smat->set_render_priority(mat->get_render_priority());
523 smat->set_local_to_scene(mat->is_local_to_scene());
524 smat->set_name(mat->get_name());
525 return smat;
526}
527
528String ProceduralSkyMaterialConversionPlugin::converts_to() const {
529 return "ShaderMaterial";
530}
531
532bool ProceduralSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
533 Ref<ProceduralSkyMaterial> mat = p_resource;
534 return mat.is_valid();
535}
536
537Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
538 Ref<ProceduralSkyMaterial> mat = p_resource;
539 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
540
541 Ref<ShaderMaterial> smat;
542 smat.instantiate();
543
544 Ref<Shader> shader;
545 shader.instantiate();
546
547 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
548
549 shader->set_code(code);
550
551 smat->set_shader(shader);
552
553 List<PropertyInfo> params;
554 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
555
556 for (const PropertyInfo &E : params) {
557 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
558 smat->set_shader_parameter(E.name, value);
559 }
560
561 smat->set_render_priority(mat->get_render_priority());
562 smat->set_local_to_scene(mat->is_local_to_scene());
563 smat->set_name(mat->get_name());
564 return smat;
565}
566
567String PanoramaSkyMaterialConversionPlugin::converts_to() const {
568 return "ShaderMaterial";
569}
570
571bool PanoramaSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
572 Ref<PanoramaSkyMaterial> mat = p_resource;
573 return mat.is_valid();
574}
575
576Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
577 Ref<PanoramaSkyMaterial> mat = p_resource;
578 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
579
580 Ref<ShaderMaterial> smat;
581 smat.instantiate();
582
583 Ref<Shader> shader;
584 shader.instantiate();
585
586 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
587
588 shader->set_code(code);
589
590 smat->set_shader(shader);
591
592 List<PropertyInfo> params;
593 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
594
595 for (const PropertyInfo &E : params) {
596 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
597 smat->set_shader_parameter(E.name, value);
598 }
599
600 smat->set_render_priority(mat->get_render_priority());
601 smat->set_local_to_scene(mat->is_local_to_scene());
602 smat->set_name(mat->get_name());
603 return smat;
604}
605
606String PhysicalSkyMaterialConversionPlugin::converts_to() const {
607 return "ShaderMaterial";
608}
609
610bool PhysicalSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
611 Ref<PhysicalSkyMaterial> mat = p_resource;
612 return mat.is_valid();
613}
614
615Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
616 Ref<PhysicalSkyMaterial> mat = p_resource;
617 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
618
619 Ref<ShaderMaterial> smat;
620 smat.instantiate();
621
622 Ref<Shader> shader;
623 shader.instantiate();
624
625 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
626
627 shader->set_code(code);
628
629 smat->set_shader(shader);
630
631 List<PropertyInfo> params;
632 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
633
634 for (const PropertyInfo &E : params) {
635 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
636 smat->set_shader_parameter(E.name, value);
637 }
638
639 smat->set_render_priority(mat->get_render_priority());
640 smat->set_local_to_scene(mat->is_local_to_scene());
641 smat->set_name(mat->get_name());
642 return smat;
643}
644
645String FogMaterialConversionPlugin::converts_to() const {
646 return "ShaderMaterial";
647}
648
649bool FogMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
650 Ref<FogMaterial> mat = p_resource;
651 return mat.is_valid();
652}
653
654Ref<Resource> FogMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
655 Ref<FogMaterial> mat = p_resource;
656 ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
657
658 Ref<ShaderMaterial> smat;
659 smat.instantiate();
660
661 Ref<Shader> shader;
662 shader.instantiate();
663
664 String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
665
666 shader->set_code(code);
667
668 smat->set_shader(shader);
669
670 List<PropertyInfo> params;
671 RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
672
673 for (const PropertyInfo &E : params) {
674 Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
675 smat->set_shader_parameter(E.name, value);
676 }
677
678 smat->set_render_priority(mat->get_render_priority());
679 return smat;
680}
681