1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """User interface for rendering parameters"""
7 from sys
import platform
# really import here, as in render.py?
9 # Or todo: handle this more crossplatform using QTpovray for Linux for instance
10 # from os.path import isfile
11 from bl_operators
.presets
import AddPresetBase
12 from bpy
.utils
import register_class
, unregister_class
13 from bpy
.types
import Operator
, Menu
, Panel
16 # Example of wrapping every class 'as is'
17 from bl_ui
import properties_output
19 for member
in dir(properties_output
):
20 subclass
= getattr(properties_output
, member
)
21 if hasattr(subclass
, "COMPAT_ENGINES"):
22 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
25 from bl_ui
import properties_freestyle
27 for member
in dir(properties_freestyle
):
28 subclass
= getattr(properties_freestyle
, member
)
29 if hasattr(subclass
, "COMPAT_ENGINES") and (
30 subclass
.bl_space_type
!= "PROPERTIES" or subclass
.bl_context
!= "render"
32 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
33 # subclass.bl_parent_id = "RENDER_PT_POV_filter"
34 del properties_freestyle
36 from bl_ui
import properties_view_layer
38 for member
in dir(properties_view_layer
):
39 subclass
= getattr(properties_view_layer
, member
)
40 if hasattr(subclass
, "COMPAT_ENGINES"):
41 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
42 del properties_view_layer
44 # Use some of the existing buttons.
45 # from bl_ui import properties_render
47 # DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
48 # DEPRECATED#properties_render.RENDER_PT_format.COMPAT_ENGINES.add('POVRAY_RENDER')
49 # properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
50 # TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
51 # DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
52 # del properties_render
55 def check_render_freestyle_svg():
56 """Test if Freestyle SVG Exporter addon is activated
58 This addon is currently used to generate the SVG lines file
59 when Freestyle is enabled alongside POV
61 return "render_freestyle_svg" in bpy
.context
.preferences
.addons
.keys()
64 class RenderButtonsPanel
:
65 """Use this class to define buttons from the render tab of
68 bl_space_type
= "PROPERTIES"
69 bl_region_type
= "WINDOW"
71 COMPAT_ENGINES
= {"POVRAY_RENDER"}
74 def poll(cls
, context
):
75 rd
= context
.scene
.render
76 return rd
.engine
in cls
.COMPAT_ENGINES
79 class RENDER_PT_POV_export_settings(RenderButtonsPanel
, Panel
):
80 """Use this class to define pov ini settings buttons."""
82 bl_options
= {"DEFAULT_CLOSED"}
83 bl_label
= "Auto Start"
84 COMPAT_ENGINES
= {"POVRAY_RENDER"}
86 def draw_header(self
, context
):
88 if scene
.pov
.tempfiles_enable
:
89 self
.layout
.prop(scene
.pov
, "tempfiles_enable", text
="", icon
="AUTO")
91 self
.layout
.prop(scene
.pov
, "tempfiles_enable", text
="", icon
="CONSOLE")
93 def draw(self
, context
):
99 layout
.active
= scene
.pov
.max_trace_level
!= 0
100 split
= layout
.split()
103 col
.label(text
="Command line options:")
104 col
.prop(scene
.pov
, "command_line_switches", text
="", icon
="RIGHTARROW")
105 split
= layout
.split()
107 # layout.active = not scene.pov.tempfiles_enable
108 if not scene
.pov
.tempfiles_enable
:
109 split
.prop(scene
.pov
, "deletefiles_enable", text
="Delete")
110 if not platform
.startswith("win"):
111 split
.prop(scene
.pov
, "sdl_window_enable", text
="Show")
112 split
.prop(scene
.pov
, "pov_editor", text
="Edit")
114 col
= layout
.column()
115 col
.prop(scene
.pov
, "scene_name", text
="Name")
116 col
.prop(scene
.pov
, "scene_path", text
="Path to files")
117 # col.prop(scene.pov, "scene_path", text="Path to POV-file")
118 # col.prop(scene.pov, "renderimage_path", text="Path to image")
120 split
= layout
.split()
121 split
.prop(scene
.pov
, "indentation_character", text
="Indent")
122 if scene
.pov
.indentation_character
== "SPACE":
123 split
.prop(scene
.pov
, "indentation_spaces", text
="Spaces")
126 row
.prop(scene
.pov
, "comments_enable", text
="Comments")
127 row
.prop(scene
.pov
, "list_lf_enable", text
="Line breaks in lists")
130 class RENDER_PT_POV_render_settings(RenderButtonsPanel
, Panel
):
131 """Use this class to host pov render settings buttons from other sub panels."""
133 bl_label
= "Global Settings"
135 bl_options
= {"DEFAULT_CLOSED"}
136 COMPAT_ENGINES
= {"POVRAY_RENDER"}
138 def draw_header(self
, context
):
139 scene
= context
.scene
140 if scene
.pov
.global_settings_advanced
:
141 self
.layout
.prop(scene
.pov
, "global_settings_advanced", text
="", icon
="PREFERENCES")
143 self
.layout
.prop(scene
.pov
, "global_settings_advanced", text
="", icon
="SETTINGS")
145 def draw(self
, context
):
148 scene
= context
.scene
150 layout
.active
= scene
.pov
.global_settings_advanced
153 class RENDER_PT_POV_light_paths(RenderButtonsPanel
, Panel
):
154 """Use this class to define pov's main light ray relative settings buttons."""
156 bl_label
= "Light Paths Tracing"
157 bl_parent_id
= "RENDER_PT_POV_render_settings"
158 bl_options
= {"DEFAULT_CLOSED"}
159 COMPAT_ENGINES
= {"POVRAY_RENDER"}
161 def draw(self
, context
):
164 scene
= context
.scene
165 # rd = context.scene.render
166 # layout.active = (scene.pov.max_trace_level != 0)
167 layout
.active
= scene
.pov
.global_settings_advanced
168 if scene
.pov
.use_shadows
:
169 layout
.prop(scene
.pov
, "use_shadows", icon
="COMMUNITY")
171 layout
.prop(scene
.pov
, "use_shadows", icon
="USER")
172 col
= layout
.column()
173 col
.prop(scene
.pov
, "max_trace_level", text
="Ray Depth")
174 row
= layout
.row(align
=True)
175 row
.prop(scene
.pov
, "adc_bailout")
178 class RENDER_PT_POV_film(RenderButtonsPanel
, Panel
):
179 """Use this class to define pov film settings buttons."""
182 bl_parent_id
= "RENDER_PT_POV_render_settings"
183 bl_options
= {"DEFAULT_CLOSED"}
184 COMPAT_ENGINES
= {"POVRAY_RENDER"}
186 def draw(self
, context
):
189 povprops
= context
.scene
.pov
190 agnosticprops
= context
.scene
.render
192 layout
.active
= povprops
.global_settings_advanced
193 col
= layout
.column()
194 col
.label(text
="Background")
195 row
= layout
.row(align
=True)
196 if agnosticprops
.film_transparent
:
200 text
="Blender alpha",
201 icon
="NODE_COMPOSITING",
202 invert_checkbox
=True,
210 invert_checkbox
=True,
212 row
.prop(povprops
, "alpha_mode", text
="")
213 if povprops
.alpha_mode
== "SKY":
214 row
.label(text
=" (color only)")
215 elif povprops
.alpha_mode
== "TRANSPARENT":
216 row
.prop(povprops
, "alpha_filter", text
="(premultiplied)", slider
=True)
218 # povprops.alpha_mode == 'STRAIGHT'
219 row
.label(text
=" (unassociated)")
222 class RENDER_PT_POV_hues(RenderButtonsPanel
, Panel
):
223 """Use this class to define pov RGB tweaking buttons."""
226 bl_parent_id
= "RENDER_PT_POV_render_settings"
227 bl_options
= {"DEFAULT_CLOSED"}
228 COMPAT_ENGINES
= {"POVRAY_RENDER"}
230 def draw(self
, context
):
233 scene
= context
.scene
235 layout
.active
= scene
.pov
.global_settings_advanced
237 row
= layout
.row(align
=True)
238 row
.prop(scene
.pov
, "ambient_light")
239 row
= layout
.row(align
=True)
240 row
.prop(scene
.pov
, "irid_wavelength")
241 row
= layout
.row(align
=True)
244 class RENDER_PT_POV_pattern_rules(RenderButtonsPanel
, Panel
):
245 """Use this class to change pov sets of texture generating algorithms."""
247 bl_label
= "Pattern Rules"
248 bl_parent_id
= "RENDER_PT_POV_render_settings"
249 bl_options
= {"DEFAULT_CLOSED"}
250 COMPAT_ENGINES
= {"POVRAY_RENDER"}
252 def draw(self
, context
):
255 scene
= context
.scene
257 layout
.active
= scene
.pov
.global_settings_advanced
259 row
= layout
.row(align
=True)
260 row
.prop(scene
.pov
, "number_of_waves")
261 row
= layout
.row(align
=True)
262 row
.prop(scene
.pov
, "noise_generator")
265 class RENDER_PT_POV_photons(RenderButtonsPanel
, Panel
):
266 """Use this class to define pov photons buttons."""
269 bl_options
= {"DEFAULT_CLOSED"}
270 COMPAT_ENGINES
= {"POVRAY_RENDER"}
272 # def draw_header(self, context):
273 # self.layout.label(icon='SETTINGS')
275 def draw_header(self
, context
):
276 scene
= context
.scene
277 if scene
.pov
.photon_enable
:
278 self
.layout
.prop(scene
.pov
, "photon_enable", text
="", icon
="PARTICLES")
280 self
.layout
.prop(scene
.pov
, "photon_enable", text
="", icon
="MOD_PARTICLES")
282 def draw(self
, context
):
283 scene
= context
.scene
285 layout
.active
= scene
.pov
.photon_enable
286 col
= layout
.column()
287 # col.label(text="Global Photons:")
288 col
.prop(scene
.pov
, "photon_max_trace_level", text
="Photon Depth")
290 split
= layout
.split()
293 col
.prop(scene
.pov
, "photon_spacing", text
="Spacing")
294 col
.prop(scene
.pov
, "photon_gather_min")
297 col
.prop(scene
.pov
, "photon_adc_bailout", text
="Photon ADC")
298 col
.prop(scene
.pov
, "photon_gather_max")
301 box
.label(text
="Photon Map File:")
303 row
.prop(scene
.pov
, "photon_map_file_save_load", expand
=True)
304 if scene
.pov
.photon_map_file_save_load
in {"save"}:
305 box
.prop(scene
.pov
, "photon_map_dir")
306 box
.prop(scene
.pov
, "photon_map_filename")
307 if scene
.pov
.photon_map_file_save_load
in {"load"}:
308 box
.prop(scene
.pov
, "photon_map_file")
312 def uberpov_only_qmc_til_pov38release(layout
):
313 col
= layout
.column()
314 col
.alignment
= "CENTER"
315 col
.label(text
="Stochastic Anti Aliasing is")
316 col
.label(text
="Only Available with UberPOV")
317 col
.label(text
="Feature Set in User Preferences.")
318 col
.label(text
="Using Type 2 (recursive) instead")
321 def no_qmc_fallbacks(row
, scene
, layout
):
322 row
.prop(scene
.pov
, "jitter_enable", text
="Jitter")
324 split
= layout
.split()
326 col
.prop(scene
.pov
, "antialias_depth", text
="AA Depth")
328 sub
.prop(scene
.pov
, "jitter_amount", text
="Jitter Amount")
329 sub
.enabled
= bool(scene
.pov
.jitter_enable
)
331 row
.prop(scene
.pov
, "antialias_threshold", text
="AA Threshold")
332 row
.prop(scene
.pov
, "antialias_gamma", text
="AA Gamma")
335 class RENDER_PT_POV_antialias(RenderButtonsPanel
, Panel
):
336 """Use this class to define pov antialiasing buttons."""
338 bl_label
= "Anti-Aliasing"
339 bl_options
= {"DEFAULT_CLOSED"}
340 COMPAT_ENGINES
= {"POVRAY_RENDER"}
342 def draw_header(self
, context
):
343 prefs
= bpy
.context
.preferences
.addons
[__package__
].preferences
344 scene
= context
.scene
345 if prefs
.branch_feature_set_povray
!= "uberpov" and scene
.pov
.antialias_method
== "2":
346 self
.layout
.prop(scene
.pov
, "antialias_enable", text
="", icon
="ERROR")
347 elif scene
.pov
.antialias_enable
:
348 self
.layout
.prop(scene
.pov
, "antialias_enable", text
="", icon
="ANTIALIASED")
350 self
.layout
.prop(scene
.pov
, "antialias_enable", text
="", icon
="ALIASED")
352 def draw(self
, context
):
353 prefs
= bpy
.context
.preferences
.addons
[__package__
].preferences
355 scene
= context
.scene
357 layout
.active
= scene
.pov
.antialias_enable
360 row
.prop(scene
.pov
, "antialias_method", text
="")
362 if prefs
.branch_feature_set_povray
!= "uberpov" and scene
.pov
.antialias_method
== "2":
363 uberpov_only_qmc_til_pov38release(layout
)
365 no_qmc_fallbacks(row
, scene
, layout
)
366 if prefs
.branch_feature_set_povray
== "uberpov":
368 row
.prop(scene
.pov
, "antialias_confidence", text
="AA Confidence")
369 row
.enabled
= scene
.pov
.antialias_method
== "2"
372 class RENDER_PT_POV_radiosity(RenderButtonsPanel
, Panel
):
373 """Use this class to define pov radiosity buttons."""
375 bl_label
= "Diffuse Radiosity"
376 bl_options
= {"DEFAULT_CLOSED"}
377 COMPAT_ENGINES
= {"POVRAY_RENDER"}
379 def draw_header(self
, context
):
380 scene
= context
.scene
381 if scene
.pov
.radio_enable
:
382 self
.layout
.prop(scene
.pov
, "radio_enable", text
="", icon
="OUTLINER_OB_LIGHTPROBE")
384 self
.layout
.prop(scene
.pov
, "radio_enable", text
="", icon
="LIGHTPROBE_CUBEMAP")
386 def draw(self
, context
):
389 scene
= context
.scene
391 layout
.active
= scene
.pov
.radio_enable
393 split
= layout
.split()
396 col
.prop(scene
.pov
, "radio_count", text
="Rays")
397 col
.prop(scene
.pov
, "radio_recursion_limit", text
="Recursions")
399 split
.prop(scene
.pov
, "radio_error_bound", text
="Error Bound")
401 layout
.prop(scene
.pov
, "radio_display_advanced")
403 if scene
.pov
.radio_display_advanced
:
404 split
= layout
.split()
407 col
.prop(scene
.pov
, "radio_adc_bailout", slider
=True)
408 col
.prop(scene
.pov
, "radio_minimum_reuse", text
="Min Reuse")
409 col
.prop(scene
.pov
, "radio_gray_threshold", slider
=True)
410 col
.prop(scene
.pov
, "radio_pretrace_start", slider
=True)
411 col
.prop(scene
.pov
, "radio_low_error_factor", slider
=True)
414 col
.prop(scene
.pov
, "radio_brightness")
415 col
.prop(scene
.pov
, "radio_maximum_reuse", text
="Max Reuse")
416 col
.prop(scene
.pov
, "radio_nearest_count")
417 col
.prop(scene
.pov
, "radio_pretrace_end", slider
=True)
419 col
= layout
.column()
420 col
.label(text
="Estimation Influence:")
421 col
.prop(scene
.pov
, "radio_always_sample")
422 col
.prop(scene
.pov
, "radio_normal")
423 col
.prop(scene
.pov
, "radio_media")
424 col
.prop(scene
.pov
, "radio_subsurface")
427 class RADIOSITY_MT_POV_presets(Menu
):
428 """Use this class to define pov radiosity presets menu."""
430 bl_label
= "Radiosity Presets"
431 preset_subdir
= "pov/radiosity"
432 preset_operator
= "script.execute_preset"
433 draw
= bpy
.types
.Menu
.draw_preset
436 class RENDER_OT_POV_radiosity_add_preset(AddPresetBase
, Operator
):
437 """Use this class to define pov radiosity add presets button"""
439 """Add a Radiosity Preset"""
440 bl_idname
= "scene.radiosity_preset_add"
441 bl_label
= "Add Radiosity Preset"
442 preset_menu
= "RADIOSITY_MT_POV_presets"
444 # variable used for all preset values
445 preset_defines
= ["scene = bpy.context.scene"]
447 # properties to store in the preset
449 "scene.pov.radio_display_advanced",
450 "scene.pov.radio_adc_bailout",
451 "scene.pov.radio_always_sample",
452 "scene.pov.radio_brightness",
453 "scene.pov.radio_count",
454 "scene.pov.radio_error_bound",
455 "scene.pov.radio_gray_threshold",
456 "scene.pov.radio_low_error_factor",
457 "scene.pov.radio_media",
458 "scene.pov.radio_subsurface",
459 "scene.pov.radio_minimum_reuse",
460 "scene.pov.radio_maximum_reuse",
461 "scene.pov.radio_nearest_count",
462 "scene.pov.radio_normal",
463 "scene.pov.radio_recursion_limit",
464 "scene.pov.radio_pretrace_start",
465 "scene.pov.radio_pretrace_end",
468 # where to store the preset
469 preset_subdir
= "pov/radiosity"
472 # Draw into an existing panel
473 def rad_panel_func(self
, context
):
474 """Display radiosity presets rolldown menu"""
477 row
= layout
.row(align
=True)
478 row
.menu(RADIOSITY_MT_POV_presets
.__name
__, text
=RADIOSITY_MT_POV_presets
.bl_label
)
479 row
.operator(RENDER_OT_POV_radiosity_add_preset
.bl_idname
, text
="", icon
="ADD")
481 RENDER_OT_POV_radiosity_add_preset
.bl_idname
, text
="", icon
="REMOVE"
482 ).remove_active
= True
485 # ---------------------------------------------------------------- #
487 # ---------------------------------------------------------------- #
489 # addon_utils.paths()[0]
490 # addon_utils.modules()
491 # mod.bl_info['name'] == 'Freestyle SVG Exporter':
492 bpy
.utils
.script_paths(subdir
="addons")
493 # render_freestyle_svg = os.path.join(bpy.utils.script_paths(subdir="addons"), "render_freestyle_svg.py")
495 render_freestyle_svg
= bpy
.context
.preferences
.addons
.get("render_freestyle_svg")
496 # mpath=addon_utils.paths()[0].render_freestyle_svg
498 # from mpath import render_freestyle_svg #= addon_utils.modules(module_cache=['Freestyle SVG Exporter'])
499 # from scripts\\addons import render_freestyle_svg
500 if check_render_freestyle_svg():
506 importlib.reload(myscript)
509 for member
in dir(render_freestyle_svg
):
510 subclass
= getattr(render_freestyle_svg
, member
)
511 if hasattr(subclass
, "COMPAT_ENGINES"):
512 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
513 if subclass
.bl_idname
== "RENDER_PT_SVGExporterPanel":
514 subclass
.bl_parent_id
= "RENDER_PT_POV_filter"
515 subclass
.bl_options
= {"HIDE_HEADER"}
516 # subclass.bl_order = 11
517 print(subclass
.bl_info
)
519 # del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
522 class RENDER_PT_POV_filter(RenderButtonsPanel
, Panel
):
523 """Use this class to invoke stuff like Freestyle UI."""
525 bl_label
= "Freestyle"
526 bl_options
= {"DEFAULT_CLOSED"}
527 COMPAT_ENGINES
= {"POVRAY_RENDER"}
530 def poll(cls
, context
):
531 with_freestyle
= bpy
.app
.build_options
.freestyle
532 engine
= context
.scene
.render
.engine
533 return with_freestyle
and engine
== "POVRAY_RENDER"
535 def draw_header(self
, context
):
537 # scene = context.scene
538 rd
= context
.scene
.render
542 layout
.prop(rd
, "use_freestyle", text
="", icon
="LINE_DATA")
545 layout
.prop(rd
, "use_freestyle", text
="", icon
="MOD_LINEART")
547 def draw(self
, context
):
548 rd
= context
.scene
.render
550 layout
.active
= rd
.use_freestyle
551 layout
.use_property_split
= True
552 layout
.use_property_decorate
= False # No animation.
553 flow
= layout
.grid_flow(
554 row_major
=True, columns
=0, even_columns
=True, even_rows
=False, align
=True
557 flow
.prop(rd
, "line_thickness_mode", expand
=True)
559 if rd
.line_thickness_mode
== "ABSOLUTE":
560 flow
.prop(rd
, "line_thickness")
562 # Warning if the Freestyle SVG Exporter addon is not enabled
563 if not check_render_freestyle_svg():
565 layout
.label(text
="Please enable Freestyle SVG Exporter addon", icon
="INFO")
568 "preferences.addon_show",
569 text
="Go to Render: Freestyle SVG Exporter addon",
571 ).module
= "render_freestyle_svg"
574 ##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
575 ## bl_label = "Baking"
576 ## COMPAT_ENGINES = {'POVRAY_RENDER'}
578 ## def draw_header(self, context):
579 ## scene = context.scene
581 ## self.layout.prop(scene.pov, "baking_enable", text="")
583 ## def draw(self, context):
584 ## layout = self.layout
586 ## scene = context.scene
589 ## layout.active = scene.pov.baking_enable
593 RENDER_PT_POV_export_settings
,
594 RENDER_PT_POV_render_settings
,
595 RENDER_PT_POV_light_paths
,
598 RENDER_PT_POV_pattern_rules
,
599 RENDER_PT_POV_photons
,
600 RENDER_PT_POV_antialias
,
601 RENDER_PT_POV_radiosity
,
602 RENDER_PT_POV_filter
,
603 # RENDER_PT_povray_baking,
604 RADIOSITY_MT_POV_presets
,
605 RENDER_OT_POV_radiosity_add_preset
,
612 RENDER_PT_POV_radiosity
.prepend(rad_panel_func
)
616 RENDER_PT_POV_radiosity
.remove(rad_panel_func
)
617 for cls
in reversed(classes
):
618 unregister_class(cls
)