1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """User interface to camera frame, optics distortions, and environment
5 with world, sky, atmospheric effects such as rainbows or smoke """
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 from bl_ui
import properties_data_camera
14 for member
in dir(properties_data_camera
):
15 subclass
= getattr(properties_data_camera
, member
)
16 if hasattr(subclass
, "COMPAT_ENGINES"):
17 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
18 del properties_data_camera
20 # -------- Use only a subset of the world panels
21 # from bl_ui import properties_world
23 # # TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
24 # properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
25 # # TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
26 # del properties_world
29 # Physics Main wrapping every class 'as is'
30 from bl_ui
import properties_physics_common
32 for member
in dir(properties_physics_common
):
33 subclass
= getattr(properties_physics_common
, member
)
34 if hasattr(subclass
, "COMPAT_ENGINES"):
35 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
36 del properties_physics_common
38 # Physics Rigid Bodies wrapping every class 'as is'
39 from bl_ui
import properties_physics_rigidbody
41 for member
in dir(properties_physics_rigidbody
):
42 subclass
= getattr(properties_physics_rigidbody
, member
)
43 if hasattr(subclass
, "COMPAT_ENGINES"):
44 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
45 del properties_physics_rigidbody
47 # Physics Rigid Body Constraint wrapping every class 'as is'
48 from bl_ui
import properties_physics_rigidbody_constraint
50 for member
in dir(properties_physics_rigidbody_constraint
):
51 subclass
= getattr(properties_physics_rigidbody_constraint
, member
)
52 if hasattr(subclass
, "COMPAT_ENGINES"):
53 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
54 del properties_physics_rigidbody_constraint
56 # Physics Smoke and fluids wrapping every class 'as is'
57 from bl_ui
import properties_physics_fluid
59 for member
in dir(properties_physics_fluid
):
60 subclass
= getattr(properties_physics_fluid
, member
)
61 if hasattr(subclass
, "COMPAT_ENGINES"):
62 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
63 del properties_physics_fluid
65 # Physics softbody wrapping every class 'as is'
66 from bl_ui
import properties_physics_softbody
68 for member
in dir(properties_physics_softbody
):
69 subclass
= getattr(properties_physics_softbody
, member
)
70 if hasattr(subclass
, "COMPAT_ENGINES"):
71 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
72 del properties_physics_softbody
74 # Physics Field wrapping every class 'as is'
75 from bl_ui
import properties_physics_field
77 for member
in dir(properties_physics_field
):
78 subclass
= getattr(properties_physics_field
, member
)
79 if hasattr(subclass
, "COMPAT_ENGINES"):
80 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
81 del properties_physics_field
83 # Physics Cloth wrapping every class 'as is'
84 from bl_ui
import properties_physics_cloth
86 for member
in dir(properties_physics_cloth
):
87 subclass
= getattr(properties_physics_cloth
, member
)
88 if hasattr(subclass
, "COMPAT_ENGINES"):
89 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
90 del properties_physics_cloth
92 # Physics Dynamic Paint wrapping every class 'as is'
93 from bl_ui
import properties_physics_dynamicpaint
95 for member
in dir(properties_physics_dynamicpaint
):
96 subclass
= getattr(properties_physics_dynamicpaint
, member
)
97 if hasattr(subclass
, "COMPAT_ENGINES"):
98 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
99 del properties_physics_dynamicpaint
101 from bl_ui
import properties_particle
103 for member
in dir(properties_particle
): # add all "particle" panels from blender
104 subclass
= getattr(properties_particle
, member
)
105 if hasattr(subclass
, "COMPAT_ENGINES"):
106 subclass
.COMPAT_ENGINES
.add("POVRAY_RENDER")
107 del properties_particle
110 class CameraDataButtonsPanel
:
111 """Use this class to define buttons from the camera data tab of
112 properties window."""
114 bl_space_type
= "PROPERTIES"
115 bl_region_type
= "WINDOW"
117 COMPAT_ENGINES
= {"POVRAY_RENDER"}
120 def poll(cls
, context
):
122 rd
= context
.scene
.render
123 return cam
and (rd
.engine
in cls
.COMPAT_ENGINES
)
126 class WorldButtonsPanel
:
127 """Use this class to define buttons from the world tab of
128 properties window."""
130 bl_space_type
= "PROPERTIES"
131 bl_region_type
= "WINDOW"
133 COMPAT_ENGINES
= {"POVRAY_RENDER"}
136 def poll(cls
, context
):
138 rd
= context
.scene
.render
139 return wld
and (rd
.engine
in cls
.COMPAT_ENGINES
)
142 # ---------------------------------------------------------------- #
144 # ---------------------------------------------------------------- #
145 class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel
, Panel
):
146 """Use this class for camera depth of field focal blur buttons."""
148 bl_label
= "POV Aperture"
149 COMPAT_ENGINES
= {"POVRAY_RENDER"}
150 bl_parent_id
= "DATA_PT_camera_dof_aperture"
151 bl_options
= {"HIDE_HEADER"}
152 # def draw_header(self, context):
153 # cam = context.camera
155 # self.layout.prop(cam.pov, "dof_enable", text="")
157 def draw(self
, context
):
162 layout
.active
= cam
.dof
.use_dof
163 layout
.use_property_split
= True # Active single-column layout
165 flow
= layout
.grid_flow(
166 row_major
=True, columns
=0, even_columns
=True, even_rows
=False, align
=False
170 col
.label(text
="F-Stop value will export as")
171 col
.label(text
="POV aperture : " + "%.3f" % (1 / cam
.dof
.aperture_fstop
* 1000))
174 col
.prop(cam
.pov
, "dof_samples_min")
175 col
.prop(cam
.pov
, "dof_samples_max")
176 col
.prop(cam
.pov
, "dof_variance")
177 col
.prop(cam
.pov
, "dof_confidence")
180 class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel
, Panel
):
181 """Use this class for camera normal perturbation buttons."""
183 bl_label
= "POV Perturbation"
184 COMPAT_ENGINES
= {"POVRAY_RENDER"}
186 def draw_header(self
, context
):
189 self
.layout
.prop(cam
.pov
, "normal_enable", text
="")
191 def draw(self
, context
):
196 layout
.active
= cam
.pov
.normal_enable
198 layout
.prop(cam
.pov
, "normal_patterns")
199 layout
.prop(cam
.pov
, "cam_normal")
200 layout
.prop(cam
.pov
, "turbulence")
201 layout
.prop(cam
.pov
, "scale")
204 class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel
, Panel
):
205 """Use this class for camera text replacement field."""
207 bl_label
= "Custom POV Code"
208 COMPAT_ENGINES
= {"POVRAY_RENDER"}
210 def draw(self
, context
):
215 col
= layout
.column()
216 col
.label(text
="Replace properties with:")
217 col
.prop(cam
.pov
, "replacement_text", text
="")
220 # ---------------------------------------------------------------- #
221 # World background and sky sphere Settings
222 # ---------------------------------------------------------------- #
225 class WORLD_PT_POV_world(WorldButtonsPanel
, Panel
):
226 """Use this class to define pov world buttons"""
230 COMPAT_ENGINES
= {"POVRAY_RENDER"}
232 def draw(self
, context
):
235 world
= context
.world
.pov
237 row
= layout
.row(align
=True)
238 row
.menu(WORLD_MT_POV_presets
.__name
__, text
=WORLD_MT_POV_presets
.bl_label
)
239 row
.operator(WORLD_OT_POV_add_preset
.bl_idname
, text
="", icon
="ADD")
240 row
.operator(WORLD_OT_POV_add_preset
.bl_idname
, text
="", icon
="REMOVE").remove_active
= True
243 row
.prop(world
, "use_sky_paper")
244 row
.prop(world
, "use_sky_blend")
245 row
.prop(world
, "use_sky_real")
248 row
.column().prop(world
, "horizon_color")
250 col
.prop(world
, "zenith_color")
251 col
.active
= world
.use_sky_blend
252 row
.column().prop(world
, "ambient_color")
255 # row.prop(world, "exposure") #Re-implement later as a light multiplier
256 # row.prop(world, "color_range")
259 class WORLD_PT_POV_mist(WorldButtonsPanel
, Panel
):
260 """Use this class to define pov mist buttons."""
263 bl_options
= {"DEFAULT_CLOSED"}
264 COMPAT_ENGINES
= {"POVRAY_RENDER"}
266 def draw_header(self
, context
):
267 world
= context
.world
269 self
.layout
.prop(world
.mist_settings
, "use_mist", text
="")
271 def draw(self
, context
):
274 world
= context
.world
276 layout
.active
= world
.mist_settings
.use_mist
278 split
= layout
.split()
281 col
.prop(world
.mist_settings
, "intensity")
282 col
.prop(world
.mist_settings
, "start")
285 col
.prop(world
.mist_settings
, "depth")
286 col
.prop(world
.mist_settings
, "height")
288 layout
.prop(world
.mist_settings
, "falloff")
291 class WORLD_MT_POV_presets(Menu
):
292 """Apply world preset to all concerned properties"""
294 bl_label
= "World Presets"
295 preset_subdir
= "pov/world"
296 preset_operator
= "script.execute_preset"
297 draw
= bpy
.types
.Menu
.draw_preset
300 class WORLD_OT_POV_add_preset(AddPresetBase
, Operator
):
301 """Add a World Preset recording current values"""
303 bl_idname
= "object.world_preset_add"
304 bl_label
= "Add World Preset"
305 preset_menu
= "WORLD_MT_POV_presets"
307 # variable used for all preset values
308 preset_defines
= ["scene = bpy.context.scene"]
310 # properties to store in the preset
312 "scene.world.use_sky_blend",
313 "scene.world.horizon_color",
314 "scene.world.zenith_color",
315 "scene.world.ambient_color",
316 "scene.world.mist_settings.use_mist",
317 "scene.world.mist_settings.intensity",
318 "scene.world.mist_settings.depth",
319 "scene.world.mist_settings.start",
320 "scene.pov.media_enable",
321 "scene.pov.media_scattering_type",
322 "scene.pov.media_samples",
323 "scene.pov.media_diffusion_scale",
324 "scene.pov.media_diffusion_color",
325 "scene.pov.media_absorption_scale",
326 "scene.pov.media_absorption_color",
327 "scene.pov.media_eccentricity",
330 # where to store the preset
331 preset_subdir
= "pov/world"
334 class RENDER_PT_POV_media(WorldButtonsPanel
, Panel
):
335 """Use this class to define a pov global atmospheric media buttons."""
337 bl_label
= "Atmosphere Media"
338 COMPAT_ENGINES
= {"POVRAY_RENDER"}
340 def draw_header(self
, context
):
341 scene
= context
.scene
343 self
.layout
.prop(scene
.pov
, "media_enable", text
="")
345 def draw(self
, context
):
348 scene
= context
.scene
350 layout
.active
= scene
.pov
.media_enable
352 col
= layout
.column()
353 col
.prop(scene
.pov
, "media_scattering_type", text
="")
354 col
= layout
.column()
355 col
.prop(scene
.pov
, "media_samples", text
="Samples")
356 split
= layout
.split()
357 col
= split
.column(align
=True)
358 col
.label(text
="Scattering:")
359 col
.prop(scene
.pov
, "media_diffusion_scale")
360 col
.prop(scene
.pov
, "media_diffusion_color", text
="")
361 col
= split
.column(align
=True)
362 col
.label(text
="Absorption:")
363 col
.prop(scene
.pov
, "media_absorption_scale")
364 col
.prop(scene
.pov
, "media_absorption_color", text
="")
365 if scene
.pov
.media_scattering_type
== "5":
366 col
= layout
.column()
367 col
.prop(scene
.pov
, "media_eccentricity", text
="Eccentricity")
370 # ---------------------------------------------------------------- #
372 # ---------------------------------------------------------------- #
374 # ----------------------------------------------------------------
375 # from bl_ui import properties_data_light
376 # for member in dir(properties_data_light):
377 # subclass = getattr(properties_data_light, member)
379 # subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
380 # except BaseException as e:
382 # print('An exception occurred: {}'.format(e))
384 # del properties_data_light
385 # -------- LIGHTS -------- #
387 from bl_ui
import properties_data_light
389 # -------- These panels are kept
390 # properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
391 # properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
393 # make some native panels contextual to some object variable
394 # by recreating custom panels inheriting their properties
397 class PovLightButtonsPanel(properties_data_light
.DataButtonsPanel
):
398 """Use this class to define buttons from the light data tab of
399 properties window."""
401 COMPAT_ENGINES
= {"POVRAY_RENDER"}
402 POV_OBJECT_TYPES
= {"RAINBOW"}
405 def poll(cls
, context
):
407 # We use our parent class poll func too, avoids to re-define too much things...
409 super(PovLightButtonsPanel
, cls
).poll(context
)
411 and obj
.pov
.object_as
not in cls
.POV_OBJECT_TYPES
415 # We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
416 # Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
417 # So we simply have to explicitly copy here the interesting bits. ;)
418 from bl_ui
import properties_data_light
420 # for member in dir(properties_data_light):
421 # subclass = getattr(properties_data_light, member)
423 # subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
424 # except BaseException as e:
426 # print('An exception occurred: {}'.format(e))
429 # Now only These panels are kept
430 properties_data_light
.DATA_PT_custom_props_light
.COMPAT_ENGINES
.add("POVRAY_RENDER")
431 properties_data_light
.DATA_PT_context_light
.COMPAT_ENGINES
.add("POVRAY_RENDER")
434 class LIGHT_PT_POV_preview(PovLightButtonsPanel
, Panel
):
435 # XXX Needs update and docstring
436 bl_label
= properties_data_light
.DATA_PT_preview
.bl_label
438 draw
= properties_data_light
.DATA_PT_preview
.draw
441 class LIGHT_PT_POV_light(PovLightButtonsPanel
, Panel
):
442 """UI panel to main pov light parameters"""
444 # bl_label = properties_data_light.DATA_PT_light.bl_label
446 # draw = properties_data_light.DATA_PT_light.draw
447 # class DATA_PT_POV_light(DataButtonsPanel, Panel):
449 # COMPAT_ENGINES = {'POVRAY_RENDER'}
451 def draw(self
, context
):
454 light
= context
.light
456 layout
.row().prop(light
, "type", expand
=True)
458 split
= layout
.split()
462 sub
.prop(light
, "color", text
="")
463 sub
.prop(light
, "energy")
465 if light
.type in {"POINT", "SPOT"}:
466 sub
.label(text
="Falloff:")
467 sub
.prop(light
, "falloff_type", text
="")
468 sub
.prop(light
, "distance")
470 if light
.falloff_type
== "LINEAR_QUADRATIC_WEIGHTED":
471 col
.label(text
="Attenuation Factors:")
472 sub
= col
.column(align
=True)
473 sub
.prop(light
, "linear_attenuation", slider
=True, text
="Linear")
474 sub
.prop(light
, "quadratic_attenuation", slider
=True, text
="Quadratic")
476 elif light
.falloff_type
== "INVERSE_COEFFICIENTS":
477 col
.label(text
="Inverse Coefficients:")
478 sub
= col
.column(align
=True)
479 sub
.prop(light
, "constant_coefficient", text
="Constant")
480 sub
.prop(light
, "linear_coefficient", text
="Linear")
481 sub
.prop(light
, "quadratic_coefficient", text
="Quadratic")
483 if light
.type == "AREA":
484 col
.prop(light
, "distance")
488 col
.prop(light
, "shape")
490 sub
= col
.column(align
=True)
492 if light
.shape
in {'SQUARE', 'DISK'}:
493 sub
.prop(light
, "size")
494 elif light
.shape
in {'RECTANGLE', 'ELLIPSE'}:
495 sub
.prop(light
, "size", text
="Size X")
496 sub
.prop(light
, "size_y", text
="Y")
498 # restore later as interface to POV light groups ?
499 # col = split.column()
500 # col.prop(light, "use_own_layer", text="This Layer Only")
503 class LIGHT_MT_POV_presets(Menu
):
504 """Use this class to define preset menu for pov lights."""
506 bl_label
= "Lamp Presets"
507 preset_subdir
= "pov/light"
508 preset_operator
= "script.execute_preset"
509 draw
= bpy
.types
.Menu
.draw_preset
512 class LIGHT_OT_POV_add_preset(AddPresetBase
, Operator
):
513 """Operator to add a Light Preset"""
515 bl_idname
= "object.light_preset_add"
516 bl_label
= "Add Light Preset"
517 preset_menu
= "LIGHT_MT_POV_presets"
519 # variable used for all preset values
520 preset_defines
= ["lightdata = bpy.context.object.data"]
522 # properties to store in the preset
523 preset_values
= ["lightdata.type", "lightdata.color"]
525 # where to store the preset
526 preset_subdir
= "pov/light"
529 # Draw into the existing light panel
530 def light_panel_func(self
, context
):
531 """Menu to browse and add light preset"""
534 row
= layout
.row(align
=True)
535 row
.menu(LIGHT_MT_POV_presets
.__name
__, text
=LIGHT_MT_POV_presets
.bl_label
)
536 row
.operator(LIGHT_OT_POV_add_preset
.bl_idname
, text
="", icon
="ADD")
537 row
.operator(LIGHT_OT_POV_add_preset
.bl_idname
, text
="", icon
="REMOVE").remove_active
= True
540 """#TORECREATE##DEPRECATED#
541 class LIGHT_PT_POV_sunsky(PovLightButtonsPanel, Panel):
542 bl_label = properties_data_light.DATA_PT_sunsky.bl_label
545 def poll(cls, context):
547 engine = context.scene.render.engine
548 return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
550 draw = properties_data_light.DATA_PT_sunsky.draw
555 class LIGHT_PT_POV_shadow(PovLightButtonsPanel
, Panel
):
556 # Todo : update and docstring
560 def poll(cls
, context
):
561 light
= context
.light
562 engine
= context
.scene
.render
.engine
563 return light
and (engine
in cls
.COMPAT_ENGINES
)
565 def draw(self
, context
):
568 light
= context
.light
570 layout
.row().prop(light
.pov
, "shadow_method", expand
=True)
572 split
= layout
.split()
575 col
.prop(light
.pov
, "use_halo")
576 sub
= col
.column(align
=True)
577 sub
.active
= light
.pov
.use_halo
578 sub
.prop(light
.pov
, "halo_intensity", text
="Intensity")
580 if light
.pov
.shadow_method
== "NOSHADOW" and light
.type == "AREA":
581 split
= layout
.split()
584 col
.label(text
="Form factor sampling:")
586 sub
= col
.row(align
=True)
588 if light
.shape
== "SQUARE":
589 sub
.prop(light
, "shadow_ray_samples_x", text
="Samples")
590 elif light
.shape
== "RECTANGLE":
591 sub
.prop(light
.pov
, "shadow_ray_samples_x", text
="Samples X")
592 sub
.prop(light
.pov
, "shadow_ray_samples_y", text
="Samples Y")
594 if light
.pov
.shadow_method
!= "NOSHADOW":
595 split
= layout
.split()
598 col
.prop(light
, "shadow_color", text
="")
600 # col = split.column()
601 # col.prop(light.pov, "use_shadow_layer", text="This Layer Only")
602 # col.prop(light.pov, "use_only_shadow")
604 if light
.pov
.shadow_method
== "RAY_SHADOW":
605 split
= layout
.split()
608 col
.label(text
="Sampling:")
610 if light
.type in {"POINT", "SUN", "SPOT"}:
613 sub
.prop(light
.pov
, "shadow_ray_samples_x", text
="Samples")
614 # any equivalent in pov?
615 # sub.prop(light, "shadow_soft_size", text="Soft Size")
617 elif light
.type == "AREA":
618 sub
= col
.row(align
=True)
620 if light
.shape
== "SQUARE":
621 sub
.prop(light
.pov
, "shadow_ray_samples_x", text
="Samples")
622 elif light
.shape
== "RECTANGLE":
623 sub
.prop(light
.pov
, "shadow_ray_samples_x", text
="Samples X")
624 sub
.prop(light
.pov
, "shadow_ray_samples_y", text
="Samples Y")
627 class LIGHT_PT_POV_spot(PovLightButtonsPanel
, Panel
):
628 bl_label
= properties_data_light
.DATA_PT_spot
.bl_label
629 bl_parent_id
= "LIGHT_PT_POV_light"
633 def poll(cls
, context
):
635 engine
= context
.scene
.render
.engine
636 return (lamp
and lamp
.type == "SPOT") and (engine
in cls
.COMPAT_ENGINES
)
638 draw
= properties_data_light
.DATA_PT_spot
.draw
641 class LIGHT_PT_POV_falloff_curve(PovLightButtonsPanel
, Panel
):
642 bl_label
= properties_data_light
.DATA_PT_falloff_curve
.bl_label
643 bl_options
= properties_data_light
.DATA_PT_falloff_curve
.bl_options
646 def poll(cls
, context
):
648 engine
= context
.scene
.render
.engine
651 lamp
and lamp
.type in {"POINT", "SPOT"} and lamp
.falloff_type
== "CUSTOM_CURVE"
652 ) and (engine
in cls
.COMPAT_ENGINES
)
654 draw
= properties_data_light
.DATA_PT_falloff_curve
.draw
657 class OBJECT_PT_POV_rainbow(PovLightButtonsPanel
, Panel
):
658 """Use this class to define buttons from the rainbow panel of
659 properties window. inheriting lamp buttons panel class"""
661 bl_label
= "POV-Ray Rainbow"
662 COMPAT_ENGINES
= {"POVRAY_RENDER"}
663 # bl_options = {'HIDE_HEADER'}
666 def poll(cls
, context
):
667 engine
= context
.scene
.render
.engine
669 return obj
and obj
.pov
.object_as
== "RAINBOW" and (engine
in cls
.COMPAT_ENGINES
)
671 def draw(self
, context
):
676 col
= layout
.column()
678 if obj
.pov
.object_as
== "RAINBOW":
679 if not obj
.pov
.unlock_parameters
:
681 obj
.pov
, "unlock_parameters", text
="Exported parameters below", icon
="LOCKED"
683 col
.label(text
="Rainbow projection angle: " + str(obj
.data
.spot_size
))
684 col
.label(text
="Rainbow width: " + str(obj
.data
.spot_blend
))
685 col
.label(text
="Rainbow distance: " + str(obj
.data
.shadow_buffer_clip_start
))
686 col
.label(text
="Rainbow arc angle: " + str(obj
.pov
.arc_angle
))
687 col
.label(text
="Rainbow falloff angle: " + str(obj
.pov
.falloff_angle
))
691 obj
.pov
, "unlock_parameters", text
="Edit exported parameters", icon
="UNLOCKED"
693 col
.label(text
="3D view proxy may get out of synch")
694 col
.active
= obj
.pov
.unlock_parameters
696 layout
.operator("pov.cone_update", text
="Update", icon
="MESH_CONE")
698 # col.label(text="Parameters:")
699 col
.prop(obj
.data
, "spot_size", text
="Rainbow Projection Angle")
700 col
.prop(obj
.data
, "spot_blend", text
="Rainbow width")
701 col
.prop(obj
.data
, "shadow_buffer_clip_start", text
="Visibility distance")
702 col
.prop(obj
.pov
, "arc_angle")
703 col
.prop(obj
.pov
, "falloff_angle")
706 del properties_data_light
711 WORLD_MT_POV_presets
,
712 WORLD_OT_POV_add_preset
,
715 LIGHT_PT_POV_preview
,
719 LIGHT_MT_POV_presets
,
720 LIGHT_OT_POV_add_preset
,
721 OBJECT_PT_POV_rainbow
,
722 CAMERA_PT_POV_cam_dof
,
723 CAMERA_PT_POV_cam_nor
,
724 CAMERA_PT_POV_replacement_text
,
732 LIGHT_PT_POV_light
.prepend(light_panel_func
)
736 LIGHT_PT_POV_light
.remove(light_panel_func
)
737 for cls
in reversed(classes
):
738 unregister_class(cls
)