1 # SPDX-FileCopyrightText: 2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """ Get POV-Ray specific objects In and Out of Blender """
6 from math
import pi
, cos
, sin
9 from bpy_extras
.object_utils
import object_data_add
10 from bpy_extras
.io_utils
import ImportHelper
11 from bpy
.utils
import register_class
, unregister_class
12 from bpy
.types
import Operator
14 from bpy
.props
import (
23 from mathutils
import Vector
, Matrix
29 def write_object_modifiers(ob
, File
):
30 """Translate some object level POV statements from Blender UI
31 to POV syntax and write to exported file"""
33 # Maybe return that string to be added instead of directly written.
36 # import .model_all.write_object_csg_inside_vector
37 write_object_csg_inside_vector(ob, file)
41 File
.write("\thollow\n")
42 if ob
.pov
.double_illuminate
:
43 File
.write("\tdouble_illuminate\n")
45 File
.write("\tsturm\n")
47 File
.write("\tno_shadow\n")
49 File
.write("\tno_image\n")
50 if ob
.pov
.no_reflection
:
51 File
.write("\tno_reflection\n")
52 if ob
.pov
.no_radiosity
:
53 File
.write("\tno_radiosity\n")
55 File
.write("\tinverse\n")
57 File
.write("\thierarchy\n")
59 # XXX, Commented definitions
61 if scene.pov.photon_enable:
62 File.write("photons {\n")
64 File.write("target %.4g\n"%ob.pov.target_value)
66 File.write("refraction on\n")
68 File.write("reflection on\n")
69 if ob.pov.pass_through:
70 File.write("pass_through\n")
72 if ob.pov.object_ior > 1:
73 File.write("interior {\n")
74 File.write("ior %.4g\n"%ob.pov.object_ior)
75 if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
76 File.write("ior %.4g\n"%ob.pov.dispersion_value)
77 File.write("ior %s\n"%ob.pov.dispersion_samples)
78 if scene.pov.photon_enable == False:
79 File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
83 def pov_define_mesh(mesh
, verts
, edges
, faces
, name
, hide_geometry
=True):
84 """Generate proxy mesh."""
86 mesh
= bpy
.data
.meshes
.new(name
)
87 mesh
.from_pydata(verts
, edges
, faces
)
88 # Function Arguments change : now bpy.types.Mesh.update (calc_edges, calc_edges_loose,
89 # calc_loop_triangles), was (calc_edges, calc_tessface)
95 ) # Set it to True to see debug messages (helps ensure you generate valid geometry).
97 mesh
.vertices
.foreach_set("hide", [True] * len(mesh
.vertices
))
98 mesh
.edges
.foreach_set("hide", [True] * len(mesh
.edges
))
99 mesh
.polygons
.foreach_set("hide", [True] * len(mesh
.polygons
))
103 class POV_OT_plane_add(Operator
):
104 """Add the representation of POV infinite plane using just a very big Blender Plane.
106 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
107 to keep proxy consistency by hiding edit geometry."""
109 bl_idname
= "pov.addplane"
111 bl_description
= "Add Plane"
112 bl_options
= {'REGISTER', 'UNDO'}
113 COMPAT_ENGINES
= {"POVRAY_RENDER"}
115 def execute(self
, context
):
116 # layers = 20*[False]
118 bpy
.ops
.mesh
.primitive_plane_add(size
=10000)
120 ob
.name
= ob
.data
.name
= "PovInfinitePlane"
121 bpy
.ops
.object.mode_set(mode
="EDIT")
123 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
125 bpy
.ops
.mesh
.hide(unselected
=False)
126 bpy
.ops
.object.mode_set(mode
="OBJECT")
127 bpy
.ops
.object.shade_smooth()
128 ob
.pov
.object_as
= "PLANE"
129 ob
.update_tag() # as prop set via python not updated in depsgraph
133 class POV_OT_box_add(Operator
):
134 """Add the representation of POV box using a simple Blender mesh cube.
136 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
137 to keep proxy consistency by hiding edit geometry."""
139 bl_idname
= "pov.addbox"
141 bl_description
= "Add Box"
142 bl_options
= {'REGISTER', 'UNDO'}
143 COMPAT_ENGINES
= {"POVRAY_RENDER"}
145 def execute(self
, context
):
146 # layers = 20*[False]
148 bpy
.ops
.mesh
.primitive_cube_add()
150 ob
.name
= ob
.data
.name
= "PovBox"
151 bpy
.ops
.object.mode_set(mode
="EDIT")
153 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
155 bpy
.ops
.mesh
.hide(unselected
=False)
156 bpy
.ops
.object.mode_set(mode
="OBJECT")
157 ob
.pov
.object_as
= "BOX"
158 ob
.update_tag() # as prop set via python not updated in depsgraph
162 def pov_cylinder_define(context
, op
, ob
, radius
, loc
, loc_cap
):
163 """Pick POV cylinder properties either from creation operator, import, or data update"""
166 loc
= bpy
.context
.scene
.cursor
.location
169 loc_cap
[2] = loc
[2] + 2
170 vec
= Vector(loc_cap
) - Vector(loc
)
172 rot
= Vector((0, 0, 1)).rotation_difference(vec
) # Rotation from Z axis.
173 trans
= rot
@ Vector(
175 ) # Such that origin is at center of the base of the cylinder.
176 roteuler
= rot
.to_euler()
178 bpy
.ops
.object.add(type="MESH", location
=loc
)
180 ob
.name
= ob
.data
.name
= "PovCylinder"
181 ob
.pov
.cylinder_radius
= radius
182 ob
.pov
.cylinder_location_cap
= vec
183 ob
.pov
.object_as
= "CYLINDER"
184 ob
.update_tag() # as prop set via python not updated in depsgraph
189 bpy
.ops
.object.mode_set(mode
="EDIT")
190 bpy
.ops
.mesh
.reveal()
191 bpy
.ops
.mesh
.select_all(action
="SELECT")
192 bpy
.ops
.mesh
.delete(type="VERT")
193 bpy
.ops
.mesh
.primitive_cylinder_add(
194 radius
=radius
, depth
=depth
, location
=loc
, rotation
=roteuler
, end_fill_type
="NGON"
196 bpy
.ops
.transform
.translate(value
=trans
)
198 bpy
.ops
.mesh
.hide(unselected
=False)
199 bpy
.ops
.object.mode_set(mode
="OBJECT")
200 bpy
.ops
.object.shade_smooth()
203 class POV_OT_cylinder_add(Operator
):
204 """Add the representation of POV cylinder using pov_cylinder_define() function.
206 Use imported_cyl_loc when this operator is run by POV importer."""
207 bl_options
= {'REGISTER', 'UNDO'}
208 bl_idname
= "pov.addcylinder"
209 bl_label
= "Cylinder"
210 bl_description
= "Add Cylinder"
212 COMPAT_ENGINES
= {"POVRAY_RENDER"}
214 # Keep in sync within model_properties.py section Cylinder
215 # as this allows interactive update
216 cy_rad
: FloatProperty(name
="Cylinder radius", min=0.00, max=10.0, default
=1.0)
218 imported_cyl_loc
: FloatVectorProperty(
219 name
="Imported Pov base location", precision
=6, default
=(0.0, 0.0, 0.0)
222 imported_cyl_loc_cap
: FloatVectorProperty(
223 name
="Imported Pov cap location", precision
=6, default
=(0.0, 0.0, 2.0)
226 def execute(self
, context
):
227 props
= self
.properties
228 cy_rad
= props
.cy_rad
229 if ob
:= context
.object:
230 if ob
.pov
.imported_cyl_loc
:
231 LOC
= ob
.pov
.imported_cyl_loc
232 if ob
.pov
.imported_cyl_loc_cap
:
233 LOC_CAP
= ob
.pov
.imported_cyl_loc_cap
234 elif not props
.imported_cyl_loc
:
235 LOC_CAP
= LOC
= bpy
.context
.scene
.cursor
.location
238 LOC
= props
.imported_cyl_loc
239 LOC_CAP
= props
.imported_cyl_loc_cap
242 "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
245 pov_cylinder_define(context
, self
, None, self
.cy_rad
, LOC
, LOC_CAP
)
250 class POV_OT_cylinder_update(Operator
):
251 """Update the POV cylinder.
253 Delete its previous proxy geometry and rerun pov_cylinder_define() function
254 with the new parameters"""
256 bl_idname
= "pov.cylinder_update"
258 bl_description
= "Update Cylinder"
259 bl_options
= {'REGISTER', 'UNDO'}
260 COMPAT_ENGINES
= {"POVRAY_RENDER"}
263 def poll(cls
, context
):
264 engine
= context
.scene
.render
.engine
269 and ob
.type == "MESH"
270 and ob
.pov
.object_as
== "CYLINDER"
271 and engine
in cls
.COMPAT_ENGINES
274 def execute(self
, context
):
276 radius
= ob
.pov
.cylinder_radius
278 loc_cap
= loc
+ ob
.pov
.cylinder_location_cap
280 pov_cylinder_define(context
, None, ob
, radius
, loc
, loc_cap
)
285 # ----------------------------------- SPHERE---------------------------------- #
286 def pov_sphere_define(context
, op
, ob
, loc
):
287 """create the representation of POV sphere using a Blender icosphere.
289 Its nice platonic solid curvature better represents pov rendertime
290 tessellation than a UV sphere"""
293 sphe_rad
= op
.sphe_rad
294 loc
= bpy
.context
.scene
.cursor
.location
297 sphe_rad
= ob
.pov
.sphere_radius
299 # keep object rotation and location for the add object operator
300 obrot
= ob
.rotation_euler
301 # obloc = ob.location
304 bpy
.ops
.object.mode_set(mode
="EDIT")
305 bpy
.ops
.mesh
.reveal()
306 bpy
.ops
.mesh
.select_all(action
="SELECT")
307 bpy
.ops
.mesh
.delete(type="VERT")
308 bpy
.ops
.mesh
.primitive_ico_sphere_add(
309 subdivisions
=4, radius
=ob
.pov
.sphere_radius
, location
=loc
, rotation
=obrot
311 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
312 bpy
.ops
.transform
.resize(value
=obscale
)
313 # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
315 bpy
.ops
.mesh
.hide(unselected
=False)
316 bpy
.ops
.object.mode_set(mode
="OBJECT")
318 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
321 bpy
.ops
.mesh
.primitive_ico_sphere_add(subdivisions
=4, radius
=sphe_rad
, location
=loc
)
323 ob
.name
= ob
.data
.name
= "PovSphere"
324 ob
.pov
.sphere_radius
= sphe_rad
325 bpy
.ops
.object.mode_set(mode
="EDIT")
326 bpy
.ops
.mesh
.hide(unselected
=False)
327 bpy
.ops
.object.mode_set(mode
="OBJECT")
328 bpy
.ops
.object.shade_smooth()
329 ob
.pov
.object_as
= "SPHERE"
330 ob
.update_tag() # as prop set via python not updated in depsgraph
333 class POV_OT_sphere_add(Operator
):
334 """Add the representation of POV sphere using pov_sphere_define() function.
336 Use imported_loc when this operator is run by POV importer."""
338 bl_idname
= "pov.addsphere"
340 bl_description
= "Add Sphere Shape"
341 bl_options
= {'REGISTER', 'UNDO'}
342 COMPAT_ENGINES
= {"POVRAY_RENDER"}
344 # Keep in sync within model_properties.py section Sphere
345 # as this allows interactive update
346 sphe_rad
: FloatProperty(name
="Sphere radius", min=0.00, max=10.0, default
=0.5)
348 imported_loc
: FloatVectorProperty(
349 name
="Imported Pov location", precision
=6, default
=(0.0, 0.0, 0.0)
352 def execute(self
, context
):
353 props
= self
.properties
354 sphe_rad
= props
.sphe_rad
355 if ob
:= context
.object:
356 if ob
.pov
.imported_loc
:
357 LOC
= ob
.pov
.imported_loc
358 elif not props
.imported_loc
:
359 LOC
= bpy
.context
.scene
.cursor
.location
362 LOC
= props
.imported_loc
365 "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
367 pov_sphere_define(context
, self
, None, LOC
)
371 # def execute(self,context):
372 # layers = 20*[False]
375 # bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=ob.pov.sphere_radius)
376 # ob = context.object
377 # bpy.ops.object.mode_set(mode="EDIT")
378 # self.report({'INFO'}, "This native POV-Ray primitive "
379 # "won't have any vertex to show in edit mode")
380 # bpy.ops.mesh.hide(unselected=False)
381 # bpy.ops.object.mode_set(mode="OBJECT")
382 # bpy.ops.object.shade_smooth()
383 # ob.pov.object_as = "SPHERE"
384 # ob.update_tag() # as prop set via python not updated in depsgraph
385 # ob.name = ob.data.name = 'PovSphere'
386 # return {'FINISHED'}
389 class POV_OT_sphere_update(Operator
):
390 """Update the POV sphere.
392 Delete its previous proxy geometry and rerun pov_sphere_define() function
393 with the new parameters"""
395 bl_idname
= "pov.sphere_update"
397 bl_description
= "Update Sphere"
398 bl_options
= {'REGISTER', 'UNDO'}
399 COMPAT_ENGINES
= {"POVRAY_RENDER"}
402 def poll(cls
, context
):
403 engine
= context
.scene
.render
.engine
408 and ob
.type == "MESH"
409 and ob
.pov
.object_as
== "SPHERE"
410 and engine
in cls
.COMPAT_ENGINES
412 def execute(self
, context
):
414 pov_sphere_define(context
, None, context
.object, context
.object.location
)
419 # ----------------------------------- CONE ---------------------------------- #
420 def pov_cone_define(context
, op
, ob
):
421 """Add the representation of POV cone using pov_define_mesh() function.
423 Blender cone does not offer the same features such as a second radius."""
435 base
= ob
.pov
.cone_base_radius
436 cap
= ob
.pov
.cone_cap_radius
437 seg
= ob
.pov
.cone_segments
438 height
= ob
.pov
.cone_height
449 verts
.extend([(xb
, yb
, zb
), (xc
, yc
, zc
)])
454 faces
.append([0, 1, f
+ 1, f
])
456 faces
.append([f
+ 2, f
+ 3, f
+ 1, f
])
458 base_face
= [i
* 2 for i
in range(seg
- 1, -1, -1)]
459 faces
.append(base_face
)
461 cap_face
= [i
* 2 + 1 for i
in range(seg
)]
462 faces
.append(cap_face
)
464 mesh
= pov_define_mesh(mesh
, verts
, [], faces
, "PovCone", True)
466 ob
= object_data_add(context
, mesh
, operator
=None)
467 ob
.pov
.cone_base_radius
= base
468 ob
.pov
.cone_cap_radius
= cap
469 ob
.pov
.cone_height
= height
470 ob
.pov
.cone_base_z
= zb
471 ob
.pov
.cone_cap_z
= zc
472 bpy
.ops
.object.shade_smooth()
473 ob
.pov
.object_as
= "CONE"
474 ob
.update_tag() # as prop set via python not updated in depsgraph
476 class POV_OT_cone_add(Operator
):
477 """Add the representation of POV cone using pov_cone_define() function."""
479 bl_idname
= "pov.addcone"
481 bl_description
= "Add Cone"
482 bl_options
= {'REGISTER', 'UNDO'}
483 COMPAT_ENGINES
= {"POVRAY_RENDER"}
485 # Keep in sync within model_properties.py section Cone
486 # If someone knows how to define operators' props from a func, I'd be delighted to learn it!
489 description
="The first radius of the cone",
496 description
="The second radius of the cone",
503 description
="Radial segmentation of the proxy mesh",
508 height
: FloatProperty(
509 name
="Height", description
="Height of the cone", default
=2.0, min=0.01, max=100.0
513 def poll(cls
, context
):
514 engine
= context
.scene
.render
.engine
515 return engine
in cls
.COMPAT_ENGINES
517 def execute(self
, context
):
518 pov_cone_define(context
, self
, None)
521 {"INFO"}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
526 class POV_OT_cone_update(Operator
):
527 """Update the POV cone.
529 Delete its previous proxy geometry and rerun pov_cone_define() function
530 with the new parameters"""
532 bl_idname
= "pov.cone_update"
534 bl_description
= "Update Cone"
535 bl_options
= {'REGISTER', 'UNDO'}
536 COMPAT_ENGINES
= {"POVRAY_RENDER"}
539 def poll(cls
, context
):
540 engine
= context
.scene
.render
.engine
546 and ob
.type == "MESH"
547 and ob
.pov
.object_as
== "CONE"
548 and engine
in cls
.COMPAT_ENGINES
550 def execute(self
, context
):
551 bpy
.ops
.object.mode_set(mode
="EDIT")
552 bpy
.ops
.mesh
.reveal()
553 bpy
.ops
.mesh
.select_all(action
="SELECT")
554 bpy
.ops
.mesh
.delete(type="VERT")
555 bpy
.ops
.object.mode_set(mode
="OBJECT")
557 pov_cone_define(context
, None, context
.object)
562 class POV_OT_rainbow_add(Operator
):
563 """Add the representation of POV rainbow using a Blender spot light.
565 Rainbows indeed propagate along a visibility cone.
566 Flag its primitive type with a specific ob.pov.object_as attribute
567 and leave access to edit mode to keep user editable handles.
568 Add a constraint to orient it towards camera because POV Rainbows
569 are view dependant and having it always initially visible is less
572 bl_idname
= "pov.addrainbow"
574 bl_description
= "Add Rainbow"
575 bl_options
= {'REGISTER', 'UNDO'}
576 COMPAT_ENGINES
= {"POVRAY_RENDER"}
578 def execute(self
, context
):
579 cam
= context
.scene
.camera
580 bpy
.ops
.object.light_add(type="SPOT", radius
=1)
582 ob
.data
.show_cone
= False
583 ob
.data
.spot_blend
= 0.5
584 # ob.data.shadow_buffer_clip_end = 0 # deprecated in 2.8
585 ob
.data
.shadow_buffer_clip_start
= 4 * cam
.location
.length
586 ob
.data
.distance
= cam
.location
.length
588 ob
.name
= ob
.data
.name
= "PovRainbow"
589 ob
.pov
.object_as
= "RAINBOW"
590 ob
.update_tag() # as prop set via python not updated in depsgraph
592 # obj = context.object
593 bpy
.ops
.object.constraint_add(type="DAMPED_TRACK")
595 ob
.constraints
["Damped Track"].target
= cam
596 ob
.constraints
["Damped Track"].track_axis
= "TRACK_NEGATIVE_Z"
597 ob
.location
= -cam
.location
599 # refocus on the actual rainbow
600 bpy
.context
.view_layer
.objects
.active
= ob
606 # ----------------------------------- TORUS ----------------------------------- #
607 def pov_torus_define(context
, op
, ob
):
608 """Add the representation of POV torus using just a Blender torus.
610 Picking properties either from creation operator, import, or data update.
611 But flag its primitive type with a specific pov.object_as attribute and lock edit mode
612 to keep proxy consistency by hiding edit geometry."""
621 mas
= ob
.pov
.torus_major_segments
622 mis
= ob
.pov
.torus_minor_segments
623 mar
= ob
.pov
.torus_major_radius
624 mir
= ob
.pov
.torus_minor_radius
626 # keep object rotation and location for the add object operator
627 obrot
= ob
.rotation_euler
630 bpy
.ops
.object.mode_set(mode
="EDIT")
631 bpy
.ops
.mesh
.reveal()
632 bpy
.ops
.mesh
.select_all(action
="SELECT")
633 bpy
.ops
.mesh
.delete(type="VERT")
634 bpy
.ops
.mesh
.primitive_torus_add(
643 bpy
.ops
.mesh
.hide(unselected
=False)
644 bpy
.ops
.object.mode_set(mode
="OBJECT")
647 bpy
.ops
.mesh
.primitive_torus_add(
648 major_segments
=mas
, minor_segments
=mis
, major_radius
=mar
, minor_radius
=mir
651 ob
.name
= ob
.data
.name
= "PovTorus"
652 ob
.pov
.torus_major_segments
= mas
653 ob
.pov
.torus_minor_segments
= mis
654 ob
.pov
.torus_major_radius
= mar
655 ob
.pov
.torus_minor_radius
= mir
656 bpy
.ops
.object.mode_set(mode
="EDIT")
657 bpy
.ops
.mesh
.hide(unselected
=False)
658 bpy
.ops
.object.mode_set(mode
="OBJECT")
659 ob
.data
.set_sharp_from_angle(angle
=0.6)
660 ob
.pov
.object_as
= "TORUS"
661 ob
.update_tag() # as prop set via python not updated in depsgraph
663 class POV_OT_torus_add(Operator
):
664 """Add the representation of POV torus using using pov_torus_define() function."""
666 bl_idname
= "pov.addtorus"
668 bl_description
= "Add Torus"
669 bl_options
= {'REGISTER', 'UNDO'}
670 COMPAT_ENGINES
= {"POVRAY_RENDER"}
672 # Keep in sync within model_properties.py section Torus
673 # as this allows interactive update
674 mas
: IntProperty(name
="Major Segments", description
="", default
=48, min=3, max=720)
675 mis
: IntProperty(name
="Minor Segments", description
="", default
=12, min=3, max=720)
676 mar
: FloatProperty(name
="Major Radius", description
="", default
=1.0)
677 mir
: FloatProperty(name
="Minor Radius", description
="", default
=0.25)
679 def execute(self
, context
):
680 props
= self
.properties
685 pov_torus_define(context
, self
, None)
687 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
692 class POV_OT_torus_update(Operator
):
693 """Update the POV torus.
695 Delete its previous proxy geometry and rerun pov_torus_define() function
696 with the new parameters"""
698 bl_idname
= "pov.torus_update"
700 bl_description
= "Update Torus"
701 bl_options
= {'REGISTER', 'UNDO'}
702 COMPAT_ENGINES
= {"POVRAY_RENDER"}
705 def poll(cls
, context
):
706 engine
= context
.scene
.render
.engine
711 and ob
.type == "MESH"
712 and ob
.pov
.object_as
== "TORUS"
713 and engine
in cls
.COMPAT_ENGINES
716 def execute(self
, context
):
718 pov_torus_define(context
, None, context
.object)
723 # -----------------------------------------------------------------------------
726 class POV_OT_prism_add(Operator
):
727 """Add the representation of POV prism using using an extruded curve."""
729 bl_idname
= "pov.addprism"
731 bl_description
= "Create Prism"
732 bl_options
= {'REGISTER', 'UNDO'}
733 COMPAT_ENGINES
= {"POVRAY_RENDER"}
735 prism_n
: IntProperty(name
="Sides", description
="Number of sides", default
=5, min=3, max=720)
736 prism_r
: FloatProperty(name
="Radius", description
="Radius", default
=1.0)
738 def execute(self
, context
):
740 props
= self
.properties
741 loft_data
= bpy
.data
.curves
.new("Prism", type="CURVE")
742 loft_data
.dimensions
= "2D"
743 loft_data
.resolution_u
= 2
744 # loft_data.show_normal_face = False
745 loft_data
.extrude
= 2
754 coords
.append((x
, y
, z
))
756 poly
= loft_data
.splines
.new("POLY")
757 poly
.points
.add(len(coords
) - 1)
758 for i
, coord
in enumerate(coords
):
760 poly
.points
[i
].co
= (x
, y
, z
, 1)
761 poly
.use_cyclic_u
= True
763 ob
= bpy
.data
.objects
.new("Prism_shape", loft_data
)
764 scn
= bpy
.context
.scene
765 scn
.collection
.objects
.link(ob
)
766 context
.view_layer
.objects
.active
= ob
768 bpy
.ops
.object.mode_set(mode
="OBJECT")
769 bpy
.ops
.object.shade_flat()
770 ob
.data
.fill_mode
= 'BOTH'
771 ob
.pov
.curveshape
= "prism"
772 ob
.name
= ob
.data
.name
= "Prism"
780 POV_OT_cylinder_update
,
782 POV_OT_sphere_update
,
798 for cls
in reversed(classes
):
799 unregister_class(cls
)