1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """"User interface for shaders exported to POV textures."""
6 from bpy
.utils
import register_class
, unregister_class
7 from bpy
.types
import Operator
, Menu
, Panel
8 from bl_operators
.presets
import AddPresetBase
10 # Example of wrapping every class 'as is' except some
11 from bl_ui
import properties_material
13 for member
in dir(properties_material
):
14 subclass
= getattr(properties_material
, member
)
15 if hasattr(subclass
, "COMPAT_ENGINES"):
16 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
17 del properties_material
19 from .shading_properties
import check_material
22 def simple_material(mat
):
23 """Test if a material uses nodes"""
24 return (mat
is not None) and (not mat
.use_nodes
)
27 class MaterialButtonsPanel
:
28 """Use this class to define buttons from the material tab of properties window."""
30 bl_space_type
= "PROPERTIES"
31 bl_region_type
= "WINDOW"
32 bl_context
= "material"
33 COMPAT_ENGINES
= {"POVRAY_RENDER"}
36 def poll(cls
, context
):
37 mat
= context
.material
38 rd
= context
.scene
.render
39 return mat
and (rd
.engine
in cls
.COMPAT_ENGINES
)
42 class MATERIAL_PT_POV_shading(MaterialButtonsPanel
, Panel
):
44 COMPAT_ENGINES
= {"POVRAY_RENDER"}
47 def poll(cls
, context
):
48 mat
= context
.material
49 engine
= context
.scene
.render
.engine
52 and (mat
.pov
.type in {"SURFACE", "WIRE"})
53 and (engine
in cls
.COMPAT_ENGINES
)
56 def draw(self
, context
):
59 mat
= context
.material
# FORMERLY : #active_node_mat(context.material)
61 if mat
.pov
.type in {"SURFACE", "WIRE"}:
62 split
= layout
.split()
66 sub
.active
= not mat
.pov
.use_shadeless
67 sub
.prop(mat
.pov
, "emit")
68 sub
.prop(mat
.pov
, "ambient")
70 sub
.prop(mat
.pov
, "translucency")
73 col
.prop(mat
.pov
, "use_shadeless")
75 sub
.active
= not mat
.pov
.use_shadeless
76 sub
.prop(mat
.pov
, "use_tangent_shading")
77 sub
.prop(mat
.pov
, "use_cubic")
80 class MATERIAL_MT_POV_sss_presets(Menu
):
81 """Use this class to define pov sss preset menu."""
83 bl_label
= "SSS Presets"
84 preset_subdir
= "pov/material/sss"
85 preset_operator
= "script.execute_preset"
86 draw
= bpy
.types
.Menu
.draw_preset
89 class MATERIAL_OT_POV_sss_add_preset(AddPresetBase
, Operator
):
90 """Add an SSS Preset"""
92 bl_idname
= "material.sss_preset_add"
93 bl_label
= "Add SSS Preset"
94 preset_menu
= "MATERIAL_MT_POV_sss_presets"
96 # variable used for all preset values
97 preset_defines
= ["material = bpy.context.material"]
99 # properties to store in the preset
101 "material.pov_subsurface_scattering.radius",
102 "material.pov_subsurface_scattering.color",
105 # where to store the preset
106 preset_subdir
= "pov/material/sss"
109 class MATERIAL_PT_POV_sss(MaterialButtonsPanel
, Panel
):
110 """Use this class to define pov sss buttons panel."""
112 bl_label
= "Subsurface Scattering"
113 bl_options
= {"DEFAULT_CLOSED"}
114 COMPAT_ENGINES
= {"POVRAY_RENDER"}
117 def poll(cls
, context
):
118 mat
= context
.material
119 engine
= context
.scene
.render
.engine
122 and (mat
.pov
.type in {"SURFACE", "WIRE"})
123 and (engine
in cls
.COMPAT_ENGINES
)
126 def draw_header(self
, context
):
127 mat
= context
.material
# FORMERLY : #active_node_mat(context.material)
128 sss
= mat
.pov_subsurface_scattering
130 self
.layout
.active
= not mat
.pov
.use_shadeless
131 self
.layout
.prop(sss
, "use", text
="")
133 def draw(self
, context
):
136 mat
= context
.material
# FORMERLY : #active_node_mat(context.material)
137 sss
= mat
.pov_subsurface_scattering
139 layout
.active
= sss
.use
and (not mat
.pov
.use_shadeless
)
141 row
= layout
.row().split()
142 sub
= row
.row(align
=True).split(align
=True, factor
=0.75)
143 sub
.menu(MATERIAL_MT_POV_sss_presets
.__name
__, text
=MATERIAL_MT_POV_sss_presets
.bl_label
)
144 sub
.operator(MATERIAL_OT_POV_sss_add_preset
.bl_idname
, text
="", icon
="ADD")
146 MATERIAL_OT_POV_sss_add_preset
.bl_idname
, text
="", icon
="REMOVE"
147 ).remove_active
= True
149 split
= layout
.split()
153 col
.prop(sss
, "scale")
154 col
.prop(sss
, "color", text
="")
155 col
.prop(sss
, "radius", text
="RGB Radius", expand
=True)
158 sub
= col
.column(align
=True)
159 sub
.label(text
="Blend:")
160 sub
.prop(sss
, "color_factor", text
="Color")
161 sub
.prop(sss
, "texture_factor", text
="Texture")
162 sub
.label(text
="Scattering Weight:")
163 sub
.prop(sss
, "front")
164 sub
.prop(sss
, "back")
166 col
.prop(sss
, "error_threshold", text
="Error")
169 class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel
, Panel
):
170 """Use this class to define an activate pov nodes button."""
172 bl_label
= "Activate Node Settings"
173 bl_context
= "material"
174 bl_options
= {"HIDE_HEADER"}
175 COMPAT_ENGINES
= {"POVRAY_RENDER"}
178 def poll(cls
, context
):
179 engine
= context
.scene
.render
.engine
180 mat
= context
.material
183 and mat
.pov
.type == "SURFACE"
184 and engine
in cls
.COMPAT_ENGINES
185 and not mat
.pov
.material_use_nodes
186 and not mat
.use_nodes
189 def draw(self
, context
):
191 # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
192 # the above replaced with a context hook below:
194 "WM_OT_context_toggle", text
="Use POV-Ray Nodes", icon
="NODETREE"
195 ).data_path
= "material.pov.material_use_nodes"
198 class MATERIAL_PT_POV_active_node(MaterialButtonsPanel
, Panel
):
199 """Use this class to show pov active node properties buttons."""
201 bl_label
= "Active Node Settings"
202 bl_context
= "material"
203 bl_options
= {"HIDE_HEADER"}
204 COMPAT_ENGINES
= {"POVRAY_RENDER"}
207 def poll(cls
, context
):
208 engine
= context
.scene
.render
.engine
209 mat
= context
.material
212 and mat
.pov
.type == "SURFACE"
213 and (engine
in cls
.COMPAT_ENGINES
)
214 and mat
.pov
.material_use_nodes
217 def draw(self
, context
):
218 mat
= context
.material
219 node_tree
= mat
.node_tree
220 if node_tree
and mat
.use_nodes
:
222 if node
:= node_tree
.nodes
.active
:
223 layout
.prop(mat
.pov
, "material_active_node")
224 layout
.context_pointer_set("node", node
)
225 if hasattr(node
, "draw_buttons_ext"):
226 node
.draw_buttons_ext(context
, layout
)
227 elif hasattr(node
, "draw_buttons"):
228 node
.draw_buttons(context
, layout
)
230 socket
for socket
in node
.inputs
if socket
.enabled
and not socket
.is_linked
233 layout
.label(text
="Inputs:")
234 for socket
in value_inputs
:
236 socket
.draw(context
, row
, node
, socket
.name
)
238 layout
.label(text
="No active nodes!")
241 class MATERIAL_PT_POV_specular(MaterialButtonsPanel
, Panel
):
242 """Use this class to define standard material specularity (highlights) buttons."""
244 bl_label
= "Specular"
245 COMPAT_ENGINES
= {"POVRAY_RENDER"}
248 def poll(cls
, context
):
249 mat
= context
.material
250 engine
= context
.scene
.render
.engine
253 and (mat
.pov
.type in {"SURFACE", "WIRE"})
254 and (engine
in cls
.COMPAT_ENGINES
)
257 def draw(self
, context
):
260 mat
= context
.material
262 layout
.active
= not mat
.pov
.use_shadeless
264 split
= layout
.split()
267 col
.prop(mat
, "specular_color", text
="")
268 col
.prop(mat
, "specular_intensity", text
="Intensity")
271 col
.prop(mat
.pov
, "specular_shader", text
="")
272 col
.prop(mat
.pov
, "use_specular_ramp", text
="Ramp")
274 col
= layout
.column()
275 if mat
.pov
.specular_shader
in {"COOKTORR", "PHONG"}:
276 col
.prop(mat
.pov
, "specular_hardness", text
="Hardness")
277 elif mat
.pov
.specular_shader
== "BLINN":
279 row
.prop(mat
.pov
, "specular_hardness", text
="Hardness")
280 row
.prop(mat
.pov
, "specular_ior", text
="IOR")
281 elif mat
.pov
.specular_shader
== "WARDISO":
282 col
.prop(mat
.pov
, "specular_slope", text
="Slope")
283 elif mat
.pov
.specular_shader
== "TOON":
285 row
.prop(mat
.pov
, "specular_toon_size", text
="Size")
286 row
.prop(mat
.pov
, "specular_toon_smooth", text
="Smooth")
288 if mat
.pov
.use_specular_ramp
:
290 layout
.template_color_ramp(mat
.pov
, "specular_ramp", expand
=True)
294 row
.prop(mat
, "specular_ramp_input", text
="Input")
295 row
.prop(mat
, "specular_ramp_blend", text
="Blend")
297 layout
.prop(mat
, "specular_ramp_factor", text
="Factor")
300 class MATERIAL_PT_POV_mirror(MaterialButtonsPanel
, Panel
):
301 """Use this class to define standard material reflectivity (mirror) buttons."""
304 bl_options
= {"DEFAULT_CLOSED"}
305 bl_idname
= "MATERIAL_PT_POV_raytrace_mirror"
306 COMPAT_ENGINES
= {"POVRAY_RENDER"}
309 def poll(cls
, context
):
310 mat
= context
.material
311 engine
= context
.scene
.render
.engine
314 and (mat
.pov
.type in {"SURFACE", "WIRE"})
315 and (engine
in cls
.COMPAT_ENGINES
)
318 def draw_header(self
, context
):
319 mat
= context
.material
320 raym
= mat
.pov_raytrace_mirror
322 self
.layout
.prop(raym
, "use", text
="")
324 def draw(self
, context
):
327 mat
= context
.material
# Formerly : #mat = active_node_mat(context.material)
328 raym
= mat
.pov_raytrace_mirror
330 layout
.active
= raym
.use
332 split
= layout
.split()
335 col
.prop(raym
, "reflect_factor")
336 col
.prop(raym
, "mirror_color", text
="")
339 col
.prop(raym
, "fresnel")
341 sub
.active
= raym
.fresnel
> 0.0
342 sub
.prop(raym
, "fresnel_factor", text
="Blend")
344 split
= layout
.split()
348 col
.prop(raym
, "depth")
349 col
.prop(raym
, "distance", text
="Max Dist")
351 sub
= col
.split(factor
=0.4)
352 sub
.active
= raym
.distance
> 0.0
353 sub
.label(text
="Fade To:")
354 sub
.prop(raym
, "fade_to", text
="")
357 col
.label(text
="Gloss:")
358 col
.prop(raym
, "gloss_factor", text
="Amount")
360 sub
.active
= raym
.gloss_factor
< 1.0
361 sub
.prop(raym
, "gloss_threshold", text
="Threshold")
362 sub
.prop(raym
, "gloss_samples", text
="Noise")
363 sub
.prop(raym
, "gloss_anisotropic", text
="Anisotropic")
366 class MATERIAL_PT_POV_transp(MaterialButtonsPanel
, Panel
):
367 """Use this class to define pov material transparency (alpha) buttons."""
369 bl_label
= "Transparency"
370 COMPAT_ENGINES
= {"POVRAY_RENDER"}
373 def poll(cls
, context
):
374 mat
= context
.material
375 engine
= context
.scene
.render
.engine
378 and (mat
.pov
.type in {"SURFACE", "WIRE"})
379 and (engine
in cls
.COMPAT_ENGINES
)
382 def draw_header(self
, context
):
383 mat
= context
.material
385 if simple_material(mat
):
386 self
.layout
.prop(mat
.pov
, "use_transparency", text
="")
388 def draw(self
, context
):
391 base_mat
= context
.material
392 mat
= context
.material
# FORMERLY active_node_mat(context.material)
393 rayt
= mat
.pov_raytrace_transparency
395 if simple_material(base_mat
):
397 row
.active
= mat
.pov
.use_transparency
398 row
.prop(mat
.pov
, "transparency_method", expand
=True)
400 split
= layout
.split()
401 split
.active
= base_mat
.pov
.use_transparency
404 col
.prop(mat
.pov
, "alpha")
406 row
.active
= (base_mat
.pov
.transparency_method
!= "MASK") and (not mat
.pov
.use_shadeless
)
407 row
.prop(mat
.pov
, "specular_alpha", text
="Specular")
410 col
.active
= not mat
.pov
.use_shadeless
411 col
.prop(rayt
, "fresnel")
413 sub
.active
= rayt
.fresnel
> 0.0
414 sub
.prop(rayt
, "fresnel_factor", text
="Blend")
416 if base_mat
.pov
.transparency_method
== "RAYTRACE":
418 split
= layout
.split()
419 split
.active
= base_mat
.pov
.use_transparency
422 col
.prop(rayt
, "ior")
423 col
.prop(rayt
, "filter")
424 col
.prop(rayt
, "falloff")
425 col
.prop(rayt
, "depth_max")
426 col
.prop(rayt
, "depth")
429 col
.label(text
="Gloss:")
430 col
.prop(rayt
, "gloss_factor", text
="Amount")
432 sub
.active
= rayt
.gloss_factor
< 1.0
433 sub
.prop(rayt
, "gloss_threshold", text
="Threshold")
434 sub
.prop(rayt
, "gloss_samples", text
="Samples")
437 class MATERIAL_PT_POV_reflection(MaterialButtonsPanel
, Panel
):
438 """Use this class to define more pov specific reflectivity buttons."""
440 bl_label
= "POV-Ray Reflection"
441 bl_parent_id
= "MATERIAL_PT_POV_raytrace_mirror"
442 COMPAT_ENGINES
= {"POVRAY_RENDER"}
445 def poll(cls
, context
):
446 engine
= context
.scene
.render
.engine
447 mat
= context
.material
450 and mat
.pov
.type == "SURFACE"
451 and engine
in cls
.COMPAT_ENGINES
452 and not mat
.pov
.material_use_nodes
453 and not mat
.use_nodes
456 def draw(self
, context
):
458 mat
= context
.material
459 col
= layout
.column()
460 col
.prop(mat
.pov
, "irid_enable")
461 if mat
.pov
.irid_enable
:
462 col
= layout
.column()
463 col
.prop(mat
.pov
, "irid_amount", slider
=True)
464 col
.prop(mat
.pov
, "irid_thickness", slider
=True)
465 col
.prop(mat
.pov
, "irid_turbulence", slider
=True)
466 col
.prop(mat
.pov
, "conserve_energy")
467 col2
= col
.split().column()
469 if not mat
.pov_raytrace_mirror
.use
:
470 col2
.label(text
="Please Check Mirror settings :")
471 col2
.active
= mat
.pov_raytrace_mirror
.use
472 col2
.prop(mat
.pov
, "mirror_use_IOR")
473 if mat
.pov
.mirror_use_IOR
:
474 col2
.alignment
= "CENTER"
475 col2
.label(text
="The current Raytrace ")
476 col2
.label(text
="Transparency IOR is: " + str(mat
.pov_raytrace_transparency
.ior
))
481 #group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
482 class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
483 bl_label = "POV-Ray Interior"
484 bl_idname = "material.pov_interior"
485 #bl_parent_id = "material.absorption"
486 COMPAT_ENGINES = {'POVRAY_RENDER'}
488 def poll(cls, context):
489 engine = context.scene.render.engine
491 return mat and mat.pov.type == "SURFACE"
492 and (engine in cls.COMPAT_ENGINES)
493 and not (mat.pov.material_use_nodes or mat.use_nodes)
496 def draw_header(self, context):
497 mat = context.material
501 class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel
, Panel
):
502 """Use this class to define pov fading (absorption) color buttons."""
504 bl_label
= "POV-Ray Absorption"
505 COMPAT_ENGINES
= {"POVRAY_RENDER"}
506 # bl_parent_id = "material.pov_interior"
509 def poll(cls
, context
):
510 engine
= context
.scene
.render
.engine
511 mat
= context
.material
514 and mat
.pov
.type == "SURFACE"
515 and engine
in cls
.COMPAT_ENGINES
516 and not mat
.pov
.material_use_nodes
517 and not mat
.use_nodes
520 def draw_header(self
, context
):
521 mat
= context
.material
523 self
.layout
.prop(mat
.pov
, "interior_fade_color", text
="")
525 def draw(self
, context
):
526 mat
= context
.material
527 if mat
.pov
.interior_fade_color
!= (0.0, 0.0, 0.0):
529 # layout.active = mat.pov.interior_fade_color
530 layout
.label(text
="Raytrace transparency")
531 layout
.label(text
="depth max Limit needs")
532 layout
.label(text
="to be non zero to fade")
535 class MATERIAL_PT_POV_caustics(MaterialButtonsPanel
, Panel
):
536 """Use this class to define pov caustics buttons."""
538 bl_label
= "Caustics"
539 COMPAT_ENGINES
= {"POVRAY_RENDER"}
542 def poll(cls
, context
):
543 engine
= context
.scene
.render
.engine
544 mat
= context
.material
547 and mat
.pov
.type == "SURFACE"
548 and engine
in cls
.COMPAT_ENGINES
549 and not mat
.pov
.material_use_nodes
550 and not mat
.use_nodes
553 def draw_header(self
, context
):
554 mat
= context
.material
555 if mat
.pov
.caustics_enable
:
556 self
.layout
.prop(mat
.pov
, "caustics_enable", text
="", icon
="PMARKER_SEL")
558 self
.layout
.prop(mat
.pov
, "caustics_enable", text
="", icon
="PMARKER")
560 def draw(self
, context
):
564 mat
= context
.material
565 layout
.active
= mat
.pov
.caustics_enable
566 col
= layout
.column()
567 if mat
.pov
.caustics_enable
:
568 col
.prop(mat
.pov
, "refraction_caustics")
569 if mat
.pov
.refraction_caustics
:
571 col
.prop(mat
.pov
, "refraction_type", text
="")
573 if mat
.pov
.refraction_type
== "1":
574 col
.prop(mat
.pov
, "fake_caustics_power", slider
=True)
575 elif mat
.pov
.refraction_type
== "2":
576 col
.prop(mat
.pov
, "photons_dispersion", slider
=True)
577 col
.prop(mat
.pov
, "photons_dispersion_samples", slider
=True)
578 col
.prop(mat
.pov
, "photons_reflection")
580 if not mat
.pov
.refraction_caustics
and not mat
.pov
.photons_reflection
:
581 col
= layout
.column()
582 col
.alignment
= "CENTER"
583 col
.label(text
="Caustics override is on, ")
584 col
.label(text
="but you didn't chose any !")
587 class MATERIAL_PT_strand(MaterialButtonsPanel
, Panel
):
588 """Use this class to define Blender strand antialiasing buttons."""
591 bl_options
= {"DEFAULT_CLOSED"}
592 COMPAT_ENGINES
= {"POVRAY_RENDER"}
595 def poll(cls
, context
):
596 mat
= context
.material
597 engine
= context
.scene
.render
.engine
599 mat
and (mat
.pov
.type in {"SURFACE", "WIRE", "HALO"}) and (engine
in cls
.COMPAT_ENGINES
)
602 def draw(self
, context
):
605 mat
= context
.material
# don't use node material
608 split
= layout
.split()
611 sub
= col
.column(align
=True)
612 sub
.label(text
="Size:")
613 sub
.prop(tan
, "root_size", text
="Root")
614 sub
.prop(tan
, "tip_size", text
="Tip")
615 sub
.prop(tan
, "size_min", text
="Minimum")
616 sub
.prop(tan
, "use_blender_units")
618 sub
.active
= not mat
.pov
.use_shadeless
619 sub
.prop(tan
, "use_tangent_shading")
620 col
.prop(tan
, "shape")
623 col
.label(text
="Shading:")
624 col
.prop(tan
, "width_fade")
626 if ob
and ob
.type == "MESH":
627 col
.prop_search(tan
, "uv_layer", ob
.data
, "uv_layers", text
="")
629 col
.prop(tan
, "uv_layer", text
="")
632 sub
.active
= not mat
.pov
.use_shadeless
633 sub
.label(text
="Surface diffuse:")
635 sub
.prop(tan
, "blend_distance", text
="Distance")
638 class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel
, Panel
):
639 """Use this class to define pov custom code declared name field."""
641 bl_label
= "Custom POV Code"
642 COMPAT_ENGINES
= {"POVRAY_RENDER"}
644 def draw(self
, context
):
646 mat
= context
.material
647 col
= layout
.column()
648 col
.alignment
= "RIGHT"
649 col
.label(text
="Override properties with this")
650 col
.label(text
="text editor {pov code} block")
651 layout
.prop(mat
.pov
, "replacement_text", text
="#declare name", icon
="SYNTAX_ON")
655 MATERIAL_PT_POV_shading
,
657 MATERIAL_MT_POV_sss_presets
,
658 MATERIAL_OT_POV_sss_add_preset
,
660 MATERIAL_PT_POV_activate_node
,
661 MATERIAL_PT_POV_active_node
,
662 MATERIAL_PT_POV_specular
,
663 MATERIAL_PT_POV_mirror
,
664 MATERIAL_PT_POV_transp
,
665 MATERIAL_PT_POV_reflection
,
666 # MATERIAL_PT_POV_interior,
667 MATERIAL_PT_POV_fade_color
,
668 MATERIAL_PT_POV_caustics
,
669 MATERIAL_PT_POV_replacement_text
,
679 for cls
in reversed(classes
):
680 unregister_class(cls
)