1 # SPDX-FileCopyrightText: 2021-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """User interface for rendering parameters"""
9 from sys
import platform
# really import here, as in render.py?
11 # Or todo: handle this more crossplatform using QTpovray for Linux for instance
12 # from os.path import isfile
13 from bl_operators
.presets
import AddPresetBase
14 from bpy
.utils
import register_class
, unregister_class
15 from bpy
.types
import Operator
, Menu
, Panel
18 # Example of wrapping every class 'as is'
19 from bl_ui
import properties_output
21 for member
in dir(properties_output
):
22 subclass
= getattr(properties_output
, member
)
23 if hasattr(subclass
, "COMPAT_ENGINES"):
24 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
27 from bl_ui
import properties_freestyle
29 for member
in dir(properties_freestyle
):
30 subclass
= getattr(properties_freestyle
, member
)
31 if hasattr(subclass
, "COMPAT_ENGINES") and (
32 subclass
.bl_space_type
!= "PROPERTIES" or subclass
.bl_context
!= "render"
34 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
35 # subclass.bl_parent_id = "RENDER_PT_POV_filter"
36 del properties_freestyle
38 from bl_ui
import properties_view_layer
40 for member
in dir(properties_view_layer
):
41 subclass
= getattr(properties_view_layer
, member
)
42 if hasattr(subclass
, "COMPAT_ENGINES"):
43 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
44 del properties_view_layer
46 # Use some of the existing buttons.
47 # from bl_ui import properties_render
49 # DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
50 # DEPRECATED#properties_render.RENDER_PT_format.COMPAT_ENGINES.add('POVRAY_RENDER')
51 # properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
52 # TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
53 # DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
54 # del properties_render
57 def check_render_freestyle_svg():
58 """Test if Freestyle SVG Exporter addon is activated
60 This addon is currently used to generate the SVG lines file
61 when Freestyle is enabled alongside POV
63 return "render_freestyle_svg" in bpy
.context
.preferences
.addons
.keys()
66 class RenderButtonsPanel
:
67 """Use this class to define buttons from the render tab of
70 bl_space_type
= "PROPERTIES"
71 bl_region_type
= "WINDOW"
73 COMPAT_ENGINES
= {"POVRAY_RENDER"}
76 def poll(cls
, context
):
77 rd
= context
.scene
.render
78 return rd
.engine
in cls
.COMPAT_ENGINES
81 class RENDER_PT_POV_export_settings(RenderButtonsPanel
, Panel
):
82 """Use this class to define pov ini settings buttons."""
84 bl_options
= {"DEFAULT_CLOSED"}
85 bl_label
= "Auto Start"
86 COMPAT_ENGINES
= {"POVRAY_RENDER"}
88 def draw_header(self
, context
):
90 if scene
.pov
.tempfiles_enable
:
91 self
.layout
.prop(scene
.pov
, "tempfiles_enable", text
="", icon
="AUTO")
93 self
.layout
.prop(scene
.pov
, "tempfiles_enable", text
="", icon
="CONSOLE")
95 def draw(self
, context
):
101 layout
.active
= scene
.pov
.max_trace_level
!= 0
102 split
= layout
.split()
105 col
.label(text
="Command line options:")
106 col
.prop(scene
.pov
, "command_line_switches", text
="", icon
="RIGHTARROW")
107 split
= layout
.split()
109 # layout.active = not scene.pov.tempfiles_enable
110 if not scene
.pov
.tempfiles_enable
:
111 split
.prop(scene
.pov
, "deletefiles_enable", text
="Delete")
112 if not platform
.startswith("win"):
113 split
.prop(scene
.pov
, "sdl_window_enable", text
="Show")
114 split
.prop(scene
.pov
, "pov_editor", text
="Edit")
116 col
= layout
.column()
117 col
.prop(scene
.pov
, "scene_name", text
="Name")
118 col
.prop(scene
.pov
, "scene_path", text
="Path to files")
119 # col.prop(scene.pov, "scene_path", text="Path to POV-file")
120 # col.prop(scene.pov, "renderimage_path", text="Path to image")
122 split
= layout
.split()
123 split
.prop(scene
.pov
, "indentation_character", text
="Indent")
124 if scene
.pov
.indentation_character
== "SPACE":
125 split
.prop(scene
.pov
, "indentation_spaces", text
="Spaces")
128 row
.prop(scene
.pov
, "comments_enable", text
="Comments")
129 row
.prop(scene
.pov
, "list_lf_enable", text
="Line breaks in lists")
132 class RENDER_PT_POV_render_settings(RenderButtonsPanel
, Panel
):
133 """Use this class to host pov render settings buttons from other sub panels."""
135 bl_label
= "Global Settings"
137 bl_options
= {"DEFAULT_CLOSED"}
138 COMPAT_ENGINES
= {"POVRAY_RENDER"}
140 def draw_header(self
, context
):
141 scene
= context
.scene
142 if scene
.pov
.global_settings_advanced
:
143 self
.layout
.prop(scene
.pov
, "global_settings_advanced", text
="", icon
="PREFERENCES")
145 self
.layout
.prop(scene
.pov
, "global_settings_advanced", text
="", icon
="SETTINGS")
147 def draw(self
, context
):
150 scene
= context
.scene
152 layout
.active
= scene
.pov
.global_settings_advanced
155 class RENDER_PT_POV_light_paths(RenderButtonsPanel
, Panel
):
156 """Use this class to define pov's main light ray relative settings buttons."""
158 bl_label
= "Light Paths Tracing"
159 bl_parent_id
= "RENDER_PT_POV_render_settings"
160 bl_options
= {"DEFAULT_CLOSED"}
161 COMPAT_ENGINES
= {"POVRAY_RENDER"}
163 def draw(self
, context
):
166 scene
= context
.scene
167 # rd = context.scene.render
168 # layout.active = (scene.pov.max_trace_level != 0)
169 layout
.active
= scene
.pov
.global_settings_advanced
170 if scene
.pov
.use_shadows
:
171 layout
.prop(scene
.pov
, "use_shadows", icon
="COMMUNITY")
173 layout
.prop(scene
.pov
, "use_shadows", icon
="USER")
174 col
= layout
.column()
175 col
.prop(scene
.pov
, "max_trace_level", text
="Ray Depth")
176 row
= layout
.row(align
=True)
177 row
.prop(scene
.pov
, "adc_bailout")
180 class RENDER_PT_POV_film(RenderButtonsPanel
, Panel
):
181 """Use this class to define pov film settings buttons."""
184 bl_parent_id
= "RENDER_PT_POV_render_settings"
185 bl_options
= {"DEFAULT_CLOSED"}
186 COMPAT_ENGINES
= {"POVRAY_RENDER"}
188 def draw(self
, context
):
191 povprops
= context
.scene
.pov
192 agnosticprops
= context
.scene
.render
194 layout
.active
= povprops
.global_settings_advanced
195 col
= layout
.column()
196 col
.label(text
="Background")
197 row
= layout
.row(align
=True)
198 if agnosticprops
.film_transparent
:
202 text
="Blender alpha",
203 icon
="NODE_COMPOSITING",
204 invert_checkbox
=True,
212 invert_checkbox
=True,
214 row
.prop(povprops
, "alpha_mode", text
="")
215 if povprops
.alpha_mode
== "SKY":
216 row
.label(text
=" (color only)")
217 elif povprops
.alpha_mode
== "TRANSPARENT":
218 row
.prop(povprops
, "alpha_filter", text
="(premultiplied)", slider
=True)
220 # povprops.alpha_mode == 'STRAIGHT'
221 row
.label(text
=" (unassociated)")
224 class RENDER_PT_POV_hues(RenderButtonsPanel
, Panel
):
225 """Use this class to define pov RGB tweaking buttons."""
228 bl_parent_id
= "RENDER_PT_POV_render_settings"
229 bl_options
= {"DEFAULT_CLOSED"}
230 COMPAT_ENGINES
= {"POVRAY_RENDER"}
232 def draw(self
, context
):
235 scene
= context
.scene
237 layout
.active
= scene
.pov
.global_settings_advanced
239 row
= layout
.row(align
=True)
240 row
.prop(scene
.pov
, "ambient_light")
241 row
= layout
.row(align
=True)
242 row
.prop(scene
.pov
, "irid_wavelength")
243 row
= layout
.row(align
=True)
246 class RENDER_PT_POV_pattern_rules(RenderButtonsPanel
, Panel
):
247 """Use this class to change pov sets of texture generating algorithms."""
249 bl_label
= "Pattern Rules"
250 bl_parent_id
= "RENDER_PT_POV_render_settings"
251 bl_options
= {"DEFAULT_CLOSED"}
252 COMPAT_ENGINES
= {"POVRAY_RENDER"}
254 def draw(self
, context
):
257 scene
= context
.scene
259 layout
.active
= scene
.pov
.global_settings_advanced
261 row
= layout
.row(align
=True)
262 row
.prop(scene
.pov
, "number_of_waves")
263 row
= layout
.row(align
=True)
264 row
.prop(scene
.pov
, "noise_generator")
267 class RENDER_PT_POV_photons(RenderButtonsPanel
, Panel
):
268 """Use this class to define pov photons buttons."""
271 bl_options
= {"DEFAULT_CLOSED"}
272 COMPAT_ENGINES
= {"POVRAY_RENDER"}
274 # def draw_header(self, context):
275 # self.layout.label(icon='SETTINGS')
277 def draw_header(self
, context
):
278 scene
= context
.scene
279 if scene
.pov
.photon_enable
:
280 self
.layout
.prop(scene
.pov
, "photon_enable", text
="", icon
="PARTICLES")
282 self
.layout
.prop(scene
.pov
, "photon_enable", text
="", icon
="MOD_PARTICLES")
284 def draw(self
, context
):
285 scene
= context
.scene
287 layout
.active
= scene
.pov
.photon_enable
288 col
= layout
.column()
289 # col.label(text="Global Photons:")
290 col
.prop(scene
.pov
, "photon_max_trace_level", text
="Photon Depth")
292 split
= layout
.split()
295 col
.prop(scene
.pov
, "photon_spacing", text
="Spacing")
296 col
.prop(scene
.pov
, "photon_gather_min")
299 col
.prop(scene
.pov
, "photon_adc_bailout", text
="Photon ADC")
300 col
.prop(scene
.pov
, "photon_gather_max")
303 box
.label(text
="Photon Map File:")
305 row
.prop(scene
.pov
, "photon_map_file_save_load", expand
=True)
306 if scene
.pov
.photon_map_file_save_load
in {"save"}:
307 box
.prop(scene
.pov
, "photon_map_dir")
308 box
.prop(scene
.pov
, "photon_map_filename")
309 if scene
.pov
.photon_map_file_save_load
in {"load"}:
310 box
.prop(scene
.pov
, "photon_map_file")
314 def uberpov_only_qmc_til_pov38release(layout
):
315 col
= layout
.column()
316 col
.alignment
= "CENTER"
317 col
.label(text
="Stochastic Anti Aliasing is")
318 col
.label(text
="Only Available with UberPOV")
319 col
.label(text
="Feature Set in User Preferences.")
320 col
.label(text
="Using Type 2 (recursive) instead")
323 def no_qmc_fallbacks(row
, scene
, layout
):
324 row
.prop(scene
.pov
, "jitter_enable", text
="Jitter")
326 split
= layout
.split()
328 col
.prop(scene
.pov
, "antialias_depth", text
="AA Depth")
330 sub
.prop(scene
.pov
, "jitter_amount", text
="Jitter Amount")
331 sub
.enabled
= bool(scene
.pov
.jitter_enable
)
333 row
.prop(scene
.pov
, "antialias_threshold", text
="AA Threshold")
334 row
.prop(scene
.pov
, "antialias_gamma", text
="AA Gamma")
337 class RENDER_PT_POV_antialias(RenderButtonsPanel
, Panel
):
338 """Use this class to define pov antialiasing buttons."""
340 bl_label
= "Anti-Aliasing"
341 bl_options
= {"DEFAULT_CLOSED"}
342 COMPAT_ENGINES
= {"POVRAY_RENDER"}
344 def draw_header(self
, context
):
345 prefs
= bpy
.context
.preferences
.addons
[__package__
].preferences
346 scene
= context
.scene
347 if prefs
.branch_feature_set_povray
!= "uberpov" and scene
.pov
.antialias_method
== "2":
348 self
.layout
.prop(scene
.pov
, "antialias_enable", text
="", icon
="ERROR")
349 elif scene
.pov
.antialias_enable
:
350 self
.layout
.prop(scene
.pov
, "antialias_enable", text
="", icon
="ANTIALIASED")
352 self
.layout
.prop(scene
.pov
, "antialias_enable", text
="", icon
="ALIASED")
354 def draw(self
, context
):
355 prefs
= bpy
.context
.preferences
.addons
[__package__
].preferences
357 scene
= context
.scene
359 layout
.active
= scene
.pov
.antialias_enable
362 row
.prop(scene
.pov
, "antialias_method", text
="")
364 if prefs
.branch_feature_set_povray
!= "uberpov" and scene
.pov
.antialias_method
== "2":
365 uberpov_only_qmc_til_pov38release(layout
)
367 no_qmc_fallbacks(row
, scene
, layout
)
368 if prefs
.branch_feature_set_povray
== "uberpov":
370 row
.prop(scene
.pov
, "antialias_confidence", text
="AA Confidence")
371 row
.enabled
= scene
.pov
.antialias_method
== "2"
374 class RENDER_PT_POV_radiosity(RenderButtonsPanel
, Panel
):
375 """Use this class to define pov radiosity buttons."""
377 bl_label
= "Diffuse Radiosity"
378 bl_options
= {"DEFAULT_CLOSED"}
379 COMPAT_ENGINES
= {"POVRAY_RENDER"}
381 def draw_header(self
, context
):
382 scene
= context
.scene
383 if scene
.pov
.radio_enable
:
384 self
.layout
.prop(scene
.pov
, "radio_enable", text
="", icon
="OUTLINER_OB_LIGHTPROBE")
386 self
.layout
.prop(scene
.pov
, "radio_enable", text
="", icon
="LIGHTPROBE_CUBEMAP")
388 def draw(self
, context
):
391 scene
= context
.scene
393 layout
.active
= scene
.pov
.radio_enable
395 split
= layout
.split()
398 col
.prop(scene
.pov
, "radio_count", text
="Rays")
399 col
.prop(scene
.pov
, "radio_recursion_limit", text
="Recursions")
401 split
.prop(scene
.pov
, "radio_error_bound", text
="Error Bound")
403 layout
.prop(scene
.pov
, "radio_display_advanced")
405 if scene
.pov
.radio_display_advanced
:
406 split
= layout
.split()
409 col
.prop(scene
.pov
, "radio_adc_bailout", slider
=True)
410 col
.prop(scene
.pov
, "radio_minimum_reuse", text
="Min Reuse")
411 col
.prop(scene
.pov
, "radio_gray_threshold", slider
=True)
412 col
.prop(scene
.pov
, "radio_pretrace_start", slider
=True)
413 col
.prop(scene
.pov
, "radio_low_error_factor", slider
=True)
416 col
.prop(scene
.pov
, "radio_brightness")
417 col
.prop(scene
.pov
, "radio_maximum_reuse", text
="Max Reuse")
418 col
.prop(scene
.pov
, "radio_nearest_count")
419 col
.prop(scene
.pov
, "radio_pretrace_end", slider
=True)
421 col
= layout
.column()
422 col
.label(text
="Estimation Influence:")
423 col
.prop(scene
.pov
, "radio_always_sample")
424 col
.prop(scene
.pov
, "radio_normal")
425 col
.prop(scene
.pov
, "radio_media")
426 col
.prop(scene
.pov
, "radio_subsurface")
429 class RADIOSITY_MT_POV_presets(Menu
):
430 """Use this class to define pov radiosity presets menu."""
432 bl_label
= "Radiosity Presets"
433 preset_subdir
= "pov/radiosity"
434 preset_operator
= "script.execute_preset"
435 draw
= bpy
.types
.Menu
.draw_preset
438 class RENDER_OT_POV_radiosity_add_preset(AddPresetBase
, Operator
):
439 """Use this class to define pov radiosity add presets button"""
441 """Add a Radiosity Preset"""
442 bl_idname
= "scene.radiosity_preset_add"
443 bl_label
= "Add Radiosity Preset"
444 preset_menu
= "RADIOSITY_MT_POV_presets"
446 # variable used for all preset values
447 preset_defines
= ["scene = bpy.context.scene"]
449 # properties to store in the preset
451 "scene.pov.radio_display_advanced",
452 "scene.pov.radio_adc_bailout",
453 "scene.pov.radio_always_sample",
454 "scene.pov.radio_brightness",
455 "scene.pov.radio_count",
456 "scene.pov.radio_error_bound",
457 "scene.pov.radio_gray_threshold",
458 "scene.pov.radio_low_error_factor",
459 "scene.pov.radio_media",
460 "scene.pov.radio_subsurface",
461 "scene.pov.radio_minimum_reuse",
462 "scene.pov.radio_maximum_reuse",
463 "scene.pov.radio_nearest_count",
464 "scene.pov.radio_normal",
465 "scene.pov.radio_recursion_limit",
466 "scene.pov.radio_pretrace_start",
467 "scene.pov.radio_pretrace_end",
470 # where to store the preset
471 preset_subdir
= "pov/radiosity"
474 # Draw into an existing panel
475 def rad_panel_func(self
, context
):
476 """Display radiosity presets rolldown menu"""
479 row
= layout
.row(align
=True)
480 row
.menu(RADIOSITY_MT_POV_presets
.__name
__, text
=RADIOSITY_MT_POV_presets
.bl_label
)
481 row
.operator(RENDER_OT_POV_radiosity_add_preset
.bl_idname
, text
="", icon
="ADD")
483 RENDER_OT_POV_radiosity_add_preset
.bl_idname
, text
="", icon
="REMOVE"
484 ).remove_active
= True
487 # ---------------------------------------------------------------- #
489 # ---------------------------------------------------------------- #
491 # addon_utils.paths()[0]
492 # addon_utils.modules()
493 # mod.bl_info['name'] == 'Freestyle SVG Exporter':
494 bpy
.utils
.script_paths(subdir
="addons")
495 # render_freestyle_svg = os.path.join(bpy.utils.script_paths(subdir="addons"), "render_freestyle_svg.py")
497 render_freestyle_svg
= bpy
.context
.preferences
.addons
.get("render_freestyle_svg")
498 # mpath=addon_utils.paths()[0].render_freestyle_svg
500 # from mpath import render_freestyle_svg #= addon_utils.modules(module_cache=['Freestyle SVG Exporter'])
501 # from scripts\\addons import render_freestyle_svg
502 if check_render_freestyle_svg():
508 importlib.reload(myscript)
511 for member
in dir(render_freestyle_svg
):
512 subclass
= getattr(render_freestyle_svg
, member
)
513 if hasattr(subclass
, "COMPAT_ENGINES"):
514 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
515 if subclass
.bl_idname
== "RENDER_PT_SVGExporterPanel":
516 subclass
.bl_parent_id
= "RENDER_PT_POV_filter"
517 subclass
.bl_options
= {"HIDE_HEADER"}
518 # subclass.bl_order = 11
519 print(subclass
.bl_info
)
521 # del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
524 class RENDER_PT_POV_filter(RenderButtonsPanel
, Panel
):
525 """Use this class to invoke stuff like Freestyle UI."""
527 bl_label
= "Freestyle"
528 bl_options
= {"DEFAULT_CLOSED"}
529 COMPAT_ENGINES
= {"POVRAY_RENDER"}
532 def poll(cls
, context
):
533 with_freestyle
= bpy
.app
.build_options
.freestyle
534 engine
= context
.scene
.render
.engine
535 return with_freestyle
and engine
== "POVRAY_RENDER"
537 def draw_header(self
, context
):
539 # scene = context.scene
540 rd
= context
.scene
.render
544 layout
.prop(rd
, "use_freestyle", text
="", icon
="LINE_DATA")
547 layout
.prop(rd
, "use_freestyle", text
="", icon
="MOD_LINEART")
549 def draw(self
, context
):
550 rd
= context
.scene
.render
552 layout
.active
= rd
.use_freestyle
553 layout
.use_property_split
= True
554 layout
.use_property_decorate
= False # No animation.
555 flow
= layout
.grid_flow(
556 row_major
=True, columns
=0, even_columns
=True, even_rows
=False, align
=True
559 flow
.prop(rd
, "line_thickness_mode", expand
=True)
561 if rd
.line_thickness_mode
== "ABSOLUTE":
562 flow
.prop(rd
, "line_thickness")
564 # Warning if the Freestyle SVG Exporter addon is not enabled
565 if not check_render_freestyle_svg():
567 layout
.label(text
="Please enable Freestyle SVG Exporter addon", icon
="INFO")
570 "preferences.addon_show",
571 text
="Go to Render: Freestyle SVG Exporter addon",
573 ).module
= "render_freestyle_svg"
576 ##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
577 ## bl_label = "Baking"
578 ## COMPAT_ENGINES = {'POVRAY_RENDER'}
580 ## def draw_header(self, context):
581 ## scene = context.scene
583 ## self.layout.prop(scene.pov, "baking_enable", text="")
585 ## def draw(self, context):
586 ## layout = self.layout
588 ## scene = context.scene
591 ## layout.active = scene.pov.baking_enable
595 RENDER_PT_POV_export_settings
,
596 RENDER_PT_POV_render_settings
,
597 RENDER_PT_POV_light_paths
,
600 RENDER_PT_POV_pattern_rules
,
601 RENDER_PT_POV_photons
,
602 RENDER_PT_POV_antialias
,
603 RENDER_PT_POV_radiosity
,
604 RENDER_PT_POV_filter
,
605 # RENDER_PT_povray_baking,
606 RADIOSITY_MT_POV_presets
,
607 RENDER_OT_POV_radiosity_add_preset
,
614 RENDER_PT_POV_radiosity
.prepend(rad_panel_func
)
618 RENDER_PT_POV_radiosity
.remove(rad_panel_func
)
619 for cls
in reversed(classes
):
620 unregister_class(cls
)