Export_3ds: Improved distance cue node search
[blender-addons.git] / render_povray / shading_gui.py
blob559823cc70630d8c7d84e7cbadd7bca7a5e3daeb
1 # SPDX-FileCopyrightText: 2021-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """"User interface for shaders exported to POV textures."""
7 import bpy
8 from bpy.utils import register_class, unregister_class
9 from bpy.types import Operator, Menu, Panel
10 from bl_operators.presets import AddPresetBase
12 # Example of wrapping every class 'as is' except some
13 from bl_ui import properties_material
15 for member in dir(properties_material):
16 subclass = getattr(properties_material, member)
17 if hasattr(subclass, "COMPAT_ENGINES"):
18 subclass.COMPAT_ENGINES.add("POVRAY_RENDER")
19 del properties_material
21 from .shading_properties import check_material
24 def simple_material(mat):
25 """Test if a material uses nodes"""
26 return (mat is not None) and (not mat.use_nodes)
29 class MaterialButtonsPanel:
30 """Use this class to define buttons from the material tab of properties window."""
32 bl_space_type = "PROPERTIES"
33 bl_region_type = "WINDOW"
34 bl_context = "material"
35 COMPAT_ENGINES = {"POVRAY_RENDER"}
37 @classmethod
38 def poll(cls, context):
39 mat = context.material
40 rd = context.scene.render
41 return mat and (rd.engine in cls.COMPAT_ENGINES)
44 class MATERIAL_PT_POV_shading(MaterialButtonsPanel, Panel):
45 bl_label = "Shading"
46 COMPAT_ENGINES = {"POVRAY_RENDER"}
48 @classmethod
49 def poll(cls, context):
50 mat = context.material
51 engine = context.scene.render.engine
52 return (
53 check_material(mat)
54 and (mat.pov.type in {"SURFACE", "WIRE"})
55 and (engine in cls.COMPAT_ENGINES)
58 def draw(self, context):
59 layout = self.layout
61 mat = context.material # FORMERLY : #active_node_mat(context.material)
63 if mat.pov.type in {"SURFACE", "WIRE"}:
64 split = layout.split()
66 col = split.column()
67 sub = col.column()
68 sub.active = not mat.pov.use_shadeless
69 sub.prop(mat.pov, "emit")
70 sub.prop(mat.pov, "ambient")
71 sub = col.column()
72 sub.prop(mat.pov, "translucency")
74 col = split.column()
75 col.prop(mat.pov, "use_shadeless")
76 sub = col.column()
77 sub.active = not mat.pov.use_shadeless
78 sub.prop(mat.pov, "use_tangent_shading")
79 sub.prop(mat.pov, "use_cubic")
82 class MATERIAL_MT_POV_sss_presets(Menu):
83 """Use this class to define pov sss preset menu."""
85 bl_label = "SSS Presets"
86 preset_subdir = "pov/material/sss"
87 preset_operator = "script.execute_preset"
88 draw = bpy.types.Menu.draw_preset
91 class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
92 """Add an SSS Preset"""
94 bl_idname = "material.sss_preset_add"
95 bl_label = "Add SSS Preset"
96 preset_menu = "MATERIAL_MT_POV_sss_presets"
98 # variable used for all preset values
99 preset_defines = ["material = bpy.context.material"]
101 # properties to store in the preset
102 preset_values = [
103 "material.pov_subsurface_scattering.radius",
104 "material.pov_subsurface_scattering.color",
107 # where to store the preset
108 preset_subdir = "pov/material/sss"
111 class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
112 """Use this class to define pov sss buttons panel."""
114 bl_label = "Subsurface Scattering"
115 bl_options = {"DEFAULT_CLOSED"}
116 COMPAT_ENGINES = {"POVRAY_RENDER"}
118 @classmethod
119 def poll(cls, context):
120 mat = context.material
121 engine = context.scene.render.engine
122 return (
123 check_material(mat)
124 and (mat.pov.type in {"SURFACE", "WIRE"})
125 and (engine in cls.COMPAT_ENGINES)
128 def draw_header(self, context):
129 mat = context.material # FORMERLY : #active_node_mat(context.material)
130 sss = mat.pov_subsurface_scattering
132 self.layout.active = not mat.pov.use_shadeless
133 self.layout.prop(sss, "use", text="")
135 def draw(self, context):
136 layout = self.layout
138 mat = context.material # FORMERLY : #active_node_mat(context.material)
139 sss = mat.pov_subsurface_scattering
141 layout.active = sss.use and (not mat.pov.use_shadeless)
143 row = layout.row().split()
144 sub = row.row(align=True).split(align=True, factor=0.75)
145 sub.menu(MATERIAL_MT_POV_sss_presets.__name__, text=MATERIAL_MT_POV_sss_presets.bl_label)
146 sub.operator(MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon="ADD")
147 sub.operator(
148 MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon="REMOVE"
149 ).remove_active = True
151 split = layout.split()
153 col = split.column()
154 col.prop(sss, "ior")
155 col.prop(sss, "scale")
156 col.prop(sss, "color", text="")
157 col.prop(sss, "radius", text="RGB Radius", expand=True)
159 col = split.column()
160 sub = col.column(align=True)
161 sub.label(text="Blend:")
162 sub.prop(sss, "color_factor", text="Color")
163 sub.prop(sss, "texture_factor", text="Texture")
164 sub.label(text="Scattering Weight:")
165 sub.prop(sss, "front")
166 sub.prop(sss, "back")
167 col.separator()
168 col.prop(sss, "error_threshold", text="Error")
171 class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
172 """Use this class to define an activate pov nodes button."""
174 bl_label = "Activate Node Settings"
175 bl_context = "material"
176 bl_options = {"HIDE_HEADER"}
177 COMPAT_ENGINES = {"POVRAY_RENDER"}
179 @classmethod
180 def poll(cls, context):
181 engine = context.scene.render.engine
182 mat = context.material
183 return (
185 and mat.pov.type == "SURFACE"
186 and engine in cls.COMPAT_ENGINES
187 and not mat.pov.material_use_nodes
188 and not mat.use_nodes
191 def draw(self, context):
192 layout = self.layout
193 # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
194 # the above replaced with a context hook below:
195 layout.operator(
196 "WM_OT_context_toggle", text="Use POV-Ray Nodes", icon="NODETREE"
197 ).data_path = "material.pov.material_use_nodes"
200 class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
201 """Use this class to show pov active node properties buttons."""
203 bl_label = "Active Node Settings"
204 bl_context = "material"
205 bl_options = {"HIDE_HEADER"}
206 COMPAT_ENGINES = {"POVRAY_RENDER"}
208 @classmethod
209 def poll(cls, context):
210 engine = context.scene.render.engine
211 mat = context.material
212 return (
214 and mat.pov.type == "SURFACE"
215 and (engine in cls.COMPAT_ENGINES)
216 and mat.pov.material_use_nodes
219 def draw(self, context):
220 mat = context.material
221 node_tree = mat.node_tree
222 if node_tree and mat.use_nodes:
223 layout = self.layout
224 if node := node_tree.nodes.active:
225 layout.prop(mat.pov, "material_active_node")
226 layout.context_pointer_set("node", node)
227 if hasattr(node, "draw_buttons_ext"):
228 node.draw_buttons_ext(context, layout)
229 elif hasattr(node, "draw_buttons"):
230 node.draw_buttons(context, layout)
231 if value_inputs := [
232 socket for socket in node.inputs if socket.enabled and not socket.is_linked
234 layout.separator()
235 layout.label(text="Inputs:")
236 for socket in value_inputs:
237 row = layout.row()
238 socket.draw(context, row, node, socket.name)
239 else:
240 layout.label(text="No active nodes!")
243 class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
244 """Use this class to define standard material specularity (highlights) buttons."""
246 bl_label = "Specular"
247 COMPAT_ENGINES = {"POVRAY_RENDER"}
249 @classmethod
250 def poll(cls, context):
251 mat = context.material
252 engine = context.scene.render.engine
253 return (
254 check_material(mat)
255 and (mat.pov.type in {"SURFACE", "WIRE"})
256 and (engine in cls.COMPAT_ENGINES)
259 def draw(self, context):
260 layout = self.layout
262 mat = context.material
264 layout.active = not mat.pov.use_shadeless
266 split = layout.split()
268 col = split.column()
269 col.prop(mat, "specular_color", text="")
270 col.prop(mat, "specular_intensity", text="Intensity")
272 col = split.column()
273 col.prop(mat.pov, "specular_shader", text="")
274 col.prop(mat.pov, "use_specular_ramp", text="Ramp")
276 col = layout.column()
277 if mat.pov.specular_shader in {"COOKTORR", "PHONG"}:
278 col.prop(mat.pov, "specular_hardness", text="Hardness")
279 elif mat.pov.specular_shader == "BLINN":
280 row = col.row()
281 row.prop(mat.pov, "specular_hardness", text="Hardness")
282 row.prop(mat.pov, "specular_ior", text="IOR")
283 elif mat.pov.specular_shader == "WARDISO":
284 col.prop(mat.pov, "specular_slope", text="Slope")
285 elif mat.pov.specular_shader == "TOON":
286 row = col.row()
287 row.prop(mat.pov, "specular_toon_size", text="Size")
288 row.prop(mat.pov, "specular_toon_smooth", text="Smooth")
290 if mat.pov.use_specular_ramp:
291 layout.separator()
292 layout.template_color_ramp(mat.pov, "specular_ramp", expand=True)
293 layout.separator()
295 row = layout.row()
296 row.prop(mat, "specular_ramp_input", text="Input")
297 row.prop(mat, "specular_ramp_blend", text="Blend")
299 layout.prop(mat, "specular_ramp_factor", text="Factor")
302 class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
303 """Use this class to define standard material reflectivity (mirror) buttons."""
305 bl_label = "Mirror"
306 bl_options = {"DEFAULT_CLOSED"}
307 bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
308 COMPAT_ENGINES = {"POVRAY_RENDER"}
310 @classmethod
311 def poll(cls, context):
312 mat = context.material
313 engine = context.scene.render.engine
314 return (
315 check_material(mat)
316 and (mat.pov.type in {"SURFACE", "WIRE"})
317 and (engine in cls.COMPAT_ENGINES)
320 def draw_header(self, context):
321 mat = context.material
322 raym = mat.pov_raytrace_mirror
324 self.layout.prop(raym, "use", text="")
326 def draw(self, context):
327 layout = self.layout
329 mat = context.material # Formerly : #mat = active_node_mat(context.material)
330 raym = mat.pov_raytrace_mirror
332 layout.active = raym.use
334 split = layout.split()
336 col = split.column()
337 col.prop(raym, "reflect_factor")
338 col.prop(raym, "mirror_color", text="")
340 col = split.column()
341 col.prop(raym, "fresnel")
342 sub = col.column()
343 sub.active = raym.fresnel > 0.0
344 sub.prop(raym, "fresnel_factor", text="Blend")
346 split = layout.split()
348 col = split.column()
349 col.separator()
350 col.prop(raym, "depth")
351 col.prop(raym, "distance", text="Max Dist")
352 col.separator()
353 sub = col.split(factor=0.4)
354 sub.active = raym.distance > 0.0
355 sub.label(text="Fade To:")
356 sub.prop(raym, "fade_to", text="")
358 col = split.column()
359 col.label(text="Gloss:")
360 col.prop(raym, "gloss_factor", text="Amount")
361 sub = col.column()
362 sub.active = raym.gloss_factor < 1.0
363 sub.prop(raym, "gloss_threshold", text="Threshold")
364 sub.prop(raym, "gloss_samples", text="Noise")
365 sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
368 class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
369 """Use this class to define pov material transparency (alpha) buttons."""
371 bl_label = "Transparency"
372 COMPAT_ENGINES = {"POVRAY_RENDER"}
374 @classmethod
375 def poll(cls, context):
376 mat = context.material
377 engine = context.scene.render.engine
378 return (
379 check_material(mat)
380 and (mat.pov.type in {"SURFACE", "WIRE"})
381 and (engine in cls.COMPAT_ENGINES)
384 def draw_header(self, context):
385 mat = context.material
387 if simple_material(mat):
388 self.layout.prop(mat.pov, "use_transparency", text="")
390 def draw(self, context):
391 layout = self.layout
393 base_mat = context.material
394 mat = context.material # FORMERLY active_node_mat(context.material)
395 rayt = mat.pov_raytrace_transparency
397 if simple_material(base_mat):
398 row = layout.row()
399 row.active = mat.pov.use_transparency
400 row.prop(mat.pov, "transparency_method", expand=True)
402 split = layout.split()
403 split.active = base_mat.pov.use_transparency
405 col = split.column()
406 col.prop(mat.pov, "alpha")
407 row = col.row()
408 row.active = (base_mat.pov.transparency_method != "MASK") and (not mat.pov.use_shadeless)
409 row.prop(mat.pov, "specular_alpha", text="Specular")
411 col = split.column()
412 col.active = not mat.pov.use_shadeless
413 col.prop(rayt, "fresnel")
414 sub = col.column()
415 sub.active = rayt.fresnel > 0.0
416 sub.prop(rayt, "fresnel_factor", text="Blend")
418 if base_mat.pov.transparency_method == "RAYTRACE":
419 layout.separator()
420 split = layout.split()
421 split.active = base_mat.pov.use_transparency
423 col = split.column()
424 col.prop(rayt, "ior")
425 col.prop(rayt, "filter")
426 col.prop(rayt, "falloff")
427 col.prop(rayt, "depth_max")
428 col.prop(rayt, "depth")
430 col = split.column()
431 col.label(text="Gloss:")
432 col.prop(rayt, "gloss_factor", text="Amount")
433 sub = col.column()
434 sub.active = rayt.gloss_factor < 1.0
435 sub.prop(rayt, "gloss_threshold", text="Threshold")
436 sub.prop(rayt, "gloss_samples", text="Samples")
439 class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
440 """Use this class to define more pov specific reflectivity buttons."""
442 bl_label = "POV-Ray Reflection"
443 bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
444 COMPAT_ENGINES = {"POVRAY_RENDER"}
446 @classmethod
447 def poll(cls, context):
448 engine = context.scene.render.engine
449 mat = context.material
450 return (
452 and mat.pov.type == "SURFACE"
453 and engine in cls.COMPAT_ENGINES
454 and not mat.pov.material_use_nodes
455 and not mat.use_nodes
458 def draw(self, context):
459 layout = self.layout
460 mat = context.material
461 col = layout.column()
462 col.prop(mat.pov, "irid_enable")
463 if mat.pov.irid_enable:
464 col = layout.column()
465 col.prop(mat.pov, "irid_amount", slider=True)
466 col.prop(mat.pov, "irid_thickness", slider=True)
467 col.prop(mat.pov, "irid_turbulence", slider=True)
468 col.prop(mat.pov, "conserve_energy")
469 col2 = col.split().column()
471 if not mat.pov_raytrace_mirror.use:
472 col2.label(text="Please Check Mirror settings :")
473 col2.active = mat.pov_raytrace_mirror.use
474 col2.prop(mat.pov, "mirror_use_IOR")
475 if mat.pov.mirror_use_IOR:
476 col2.alignment = "CENTER"
477 col2.label(text="The current Raytrace ")
478 col2.label(text="Transparency IOR is: " + str(mat.pov_raytrace_transparency.ior))
483 #group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
484 class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
485 bl_label = "POV-Ray Interior"
486 bl_idname = "material.pov_interior"
487 #bl_parent_id = "material.absorption"
488 COMPAT_ENGINES = {'POVRAY_RENDER'}
489 @classmethod
490 def poll(cls, context):
491 engine = context.scene.render.engine
492 mat=context.material
493 return mat and mat.pov.type == "SURFACE"
494 and (engine in cls.COMPAT_ENGINES)
495 and not (mat.pov.material_use_nodes or mat.use_nodes)
498 def draw_header(self, context):
499 mat = context.material
503 class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
504 """Use this class to define pov fading (absorption) color buttons."""
506 bl_label = "POV-Ray Absorption"
507 COMPAT_ENGINES = {"POVRAY_RENDER"}
508 # bl_parent_id = "material.pov_interior"
510 @classmethod
511 def poll(cls, context):
512 engine = context.scene.render.engine
513 mat = context.material
514 return (
516 and mat.pov.type == "SURFACE"
517 and engine in cls.COMPAT_ENGINES
518 and not mat.pov.material_use_nodes
519 and not mat.use_nodes
522 def draw_header(self, context):
523 mat = context.material
525 self.layout.prop(mat.pov, "interior_fade_color", text="")
527 def draw(self, context):
528 mat = context.material
529 if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
530 layout = self.layout
531 # layout.active = mat.pov.interior_fade_color
532 layout.label(text="Raytrace transparency")
533 layout.label(text="depth max Limit needs")
534 layout.label(text="to be non zero to fade")
537 class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
538 """Use this class to define pov caustics buttons."""
540 bl_label = "Caustics"
541 COMPAT_ENGINES = {"POVRAY_RENDER"}
543 @classmethod
544 def poll(cls, context):
545 engine = context.scene.render.engine
546 mat = context.material
547 return (
549 and mat.pov.type == "SURFACE"
550 and engine in cls.COMPAT_ENGINES
551 and not mat.pov.material_use_nodes
552 and not mat.use_nodes
555 def draw_header(self, context):
556 mat = context.material
557 if mat.pov.caustics_enable:
558 self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER_SEL")
559 else:
560 self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER")
562 def draw(self, context):
564 layout = self.layout
566 mat = context.material
567 layout.active = mat.pov.caustics_enable
568 col = layout.column()
569 if mat.pov.caustics_enable:
570 col.prop(mat.pov, "refraction_caustics")
571 if mat.pov.refraction_caustics:
573 col.prop(mat.pov, "refraction_type", text="")
575 if mat.pov.refraction_type == "1":
576 col.prop(mat.pov, "fake_caustics_power", slider=True)
577 elif mat.pov.refraction_type == "2":
578 col.prop(mat.pov, "photons_dispersion", slider=True)
579 col.prop(mat.pov, "photons_dispersion_samples", slider=True)
580 col.prop(mat.pov, "photons_reflection")
582 if not mat.pov.refraction_caustics and not mat.pov.photons_reflection:
583 col = layout.column()
584 col.alignment = "CENTER"
585 col.label(text="Caustics override is on, ")
586 col.label(text="but you didn't chose any !")
589 class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
590 """Use this class to define Blender strand antialiasing buttons."""
592 bl_label = "Strand"
593 bl_options = {"DEFAULT_CLOSED"}
594 COMPAT_ENGINES = {"POVRAY_RENDER"}
596 @classmethod
597 def poll(cls, context):
598 mat = context.material
599 engine = context.scene.render.engine
600 return (
601 mat and (mat.pov.type in {"SURFACE", "WIRE", "HALO"}) and (engine in cls.COMPAT_ENGINES)
604 def draw(self, context):
605 layout = self.layout
607 mat = context.material # don't use node material
608 tan = mat.strand
610 split = layout.split()
612 col = split.column()
613 sub = col.column(align=True)
614 sub.label(text="Size:")
615 sub.prop(tan, "root_size", text="Root")
616 sub.prop(tan, "tip_size", text="Tip")
617 sub.prop(tan, "size_min", text="Minimum")
618 sub.prop(tan, "use_blender_units")
619 sub = col.column()
620 sub.active = not mat.pov.use_shadeless
621 sub.prop(tan, "use_tangent_shading")
622 col.prop(tan, "shape")
624 col = split.column()
625 col.label(text="Shading:")
626 col.prop(tan, "width_fade")
627 ob = context.object
628 if ob and ob.type == "MESH":
629 col.prop_search(tan, "uv_layer", ob.data, "uv_layers", text="")
630 else:
631 col.prop(tan, "uv_layer", text="")
632 col.separator()
633 sub = col.column()
634 sub.active = not mat.pov.use_shadeless
635 sub.label(text="Surface diffuse:")
636 sub = col.column()
637 sub.prop(tan, "blend_distance", text="Distance")
640 class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
641 """Use this class to define pov custom code declared name field."""
643 bl_label = "Custom POV Code"
644 COMPAT_ENGINES = {"POVRAY_RENDER"}
646 def draw(self, context):
647 layout = self.layout
648 mat = context.material
649 col = layout.column()
650 col.alignment = "RIGHT"
651 col.label(text="Override properties with this")
652 col.label(text="text editor {pov code} block")
653 layout.prop(mat.pov, "replacement_text", text="#declare name", icon="SYNTAX_ON")
656 classes = (
657 MATERIAL_PT_POV_shading,
658 MATERIAL_PT_POV_sss,
659 MATERIAL_MT_POV_sss_presets,
660 MATERIAL_OT_POV_sss_add_preset,
661 MATERIAL_PT_strand,
662 MATERIAL_PT_POV_activate_node,
663 MATERIAL_PT_POV_active_node,
664 MATERIAL_PT_POV_specular,
665 MATERIAL_PT_POV_mirror,
666 MATERIAL_PT_POV_transp,
667 MATERIAL_PT_POV_reflection,
668 # MATERIAL_PT_POV_interior,
669 MATERIAL_PT_POV_fade_color,
670 MATERIAL_PT_POV_caustics,
671 MATERIAL_PT_POV_replacement_text,
675 def register():
676 for cls in classes:
677 register_class(cls)
680 def unregister():
681 for cls in reversed(classes):
682 unregister_class(cls)