1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """ Get POV-Ray specific objects In and Out of Blender """
4 from math
import pi
, cos
, sin
7 from bpy_extras
.object_utils
import object_data_add
8 from bpy_extras
.io_utils
import ImportHelper
9 from bpy
.utils
import register_class
, unregister_class
10 from bpy
.types
import Operator
12 from bpy
.props
import (
21 from mathutils
import Vector
, Matrix
27 def write_object_modifiers(ob
, File
):
28 """Translate some object level POV statements from Blender UI
29 to POV syntax and write to exported file"""
31 # Maybe return that string to be added instead of directly written.
34 # import .model_all.write_object_csg_inside_vector
35 write_object_csg_inside_vector(ob, file)
39 File
.write("\thollow\n")
40 if ob
.pov
.double_illuminate
:
41 File
.write("\tdouble_illuminate\n")
43 File
.write("\tsturm\n")
45 File
.write("\tno_shadow\n")
47 File
.write("\tno_image\n")
48 if ob
.pov
.no_reflection
:
49 File
.write("\tno_reflection\n")
50 if ob
.pov
.no_radiosity
:
51 File
.write("\tno_radiosity\n")
53 File
.write("\tinverse\n")
55 File
.write("\thierarchy\n")
57 # XXX, Commented definitions
59 if scene.pov.photon_enable:
60 File.write("photons {\n")
62 File.write("target %.4g\n"%ob.pov.target_value)
64 File.write("refraction on\n")
66 File.write("reflection on\n")
67 if ob.pov.pass_through:
68 File.write("pass_through\n")
70 if ob.pov.object_ior > 1:
71 File.write("interior {\n")
72 File.write("ior %.4g\n"%ob.pov.object_ior)
73 if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
74 File.write("ior %.4g\n"%ob.pov.dispersion_value)
75 File.write("ior %s\n"%ob.pov.dispersion_samples)
76 if scene.pov.photon_enable == False:
77 File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
81 def pov_define_mesh(mesh
, verts
, edges
, faces
, name
, hide_geometry
=True):
82 """Generate proxy mesh."""
84 mesh
= bpy
.data
.meshes
.new(name
)
85 mesh
.from_pydata(verts
, edges
, faces
)
86 # Function Arguments change : now bpy.types.Mesh.update (calc_edges, calc_edges_loose,
87 # calc_loop_triangles), was (calc_edges, calc_tessface)
93 ) # Set it to True to see debug messages (helps ensure you generate valid geometry).
95 mesh
.vertices
.foreach_set("hide", [True] * len(mesh
.vertices
))
96 mesh
.edges
.foreach_set("hide", [True] * len(mesh
.edges
))
97 mesh
.polygons
.foreach_set("hide", [True] * len(mesh
.polygons
))
101 class POV_OT_plane_add(Operator
):
102 """Add the representation of POV infinite plane using just a very big Blender Plane.
104 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
105 to keep proxy consistency by hiding edit geometry."""
107 bl_idname
= "pov.addplane"
109 bl_description
= "Add Plane"
110 bl_options
= {'REGISTER', 'UNDO'}
111 COMPAT_ENGINES
= {"POVRAY_RENDER"}
113 def execute(self
, context
):
114 # layers = 20*[False]
116 bpy
.ops
.mesh
.primitive_plane_add(size
=10000)
118 ob
.name
= ob
.data
.name
= "PovInfinitePlane"
119 bpy
.ops
.object.mode_set(mode
="EDIT")
121 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
123 bpy
.ops
.mesh
.hide(unselected
=False)
124 bpy
.ops
.object.mode_set(mode
="OBJECT")
125 bpy
.ops
.object.shade_smooth()
126 ob
.pov
.object_as
= "PLANE"
127 ob
.update_tag() # as prop set via python not updated in depsgraph
131 class POV_OT_box_add(Operator
):
132 """Add the representation of POV box using a simple Blender mesh cube.
134 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
135 to keep proxy consistency by hiding edit geometry."""
137 bl_idname
= "pov.addbox"
139 bl_description
= "Add Box"
140 bl_options
= {'REGISTER', 'UNDO'}
141 COMPAT_ENGINES
= {"POVRAY_RENDER"}
143 def execute(self
, context
):
144 # layers = 20*[False]
146 bpy
.ops
.mesh
.primitive_cube_add()
148 ob
.name
= ob
.data
.name
= "PovBox"
149 bpy
.ops
.object.mode_set(mode
="EDIT")
151 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
153 bpy
.ops
.mesh
.hide(unselected
=False)
154 bpy
.ops
.object.mode_set(mode
="OBJECT")
155 ob
.pov
.object_as
= "BOX"
156 ob
.update_tag() # as prop set via python not updated in depsgraph
160 def pov_cylinder_define(context
, op
, ob
, radius
, loc
, loc_cap
):
161 """Pick POV cylinder properties either from creation operator, import, or data update"""
164 loc
= bpy
.context
.scene
.cursor
.location
167 loc_cap
[2] = loc
[2] + 2
168 vec
= Vector(loc_cap
) - Vector(loc
)
170 rot
= Vector((0, 0, 1)).rotation_difference(vec
) # Rotation from Z axis.
171 trans
= rot
@ Vector(
173 ) # Such that origin is at center of the base of the cylinder.
174 roteuler
= rot
.to_euler()
176 bpy
.ops
.object.add(type="MESH", location
=loc
)
178 ob
.name
= ob
.data
.name
= "PovCylinder"
179 ob
.pov
.cylinder_radius
= radius
180 ob
.pov
.cylinder_location_cap
= vec
181 ob
.data
.use_auto_smooth
= True
182 ob
.pov
.object_as
= "CYLINDER"
183 ob
.update_tag() # as prop set via python not updated in depsgraph
188 bpy
.ops
.object.mode_set(mode
="EDIT")
189 bpy
.ops
.mesh
.reveal()
190 bpy
.ops
.mesh
.select_all(action
="SELECT")
191 bpy
.ops
.mesh
.delete(type="VERT")
192 bpy
.ops
.mesh
.primitive_cylinder_add(
193 radius
=radius
, depth
=depth
, location
=loc
, rotation
=roteuler
, end_fill_type
="NGON"
195 bpy
.ops
.transform
.translate(value
=trans
)
197 bpy
.ops
.mesh
.hide(unselected
=False)
198 bpy
.ops
.object.mode_set(mode
="OBJECT")
199 bpy
.ops
.object.shade_smooth()
202 class POV_OT_cylinder_add(Operator
):
203 """Add the representation of POV cylinder using pov_cylinder_define() function.
205 Use imported_cyl_loc when this operator is run by POV importer."""
206 bl_options
= {'REGISTER', 'UNDO'}
207 bl_idname
= "pov.addcylinder"
208 bl_label
= "Cylinder"
209 bl_description
= "Add Cylinder"
211 COMPAT_ENGINES
= {"POVRAY_RENDER"}
213 # Keep in sync within model_properties.py section Cylinder
214 # as this allows interactive update
215 cy_rad
: FloatProperty(name
="Cylinder radius", min=0.00, max=10.0, default
=1.0)
217 imported_cyl_loc
: FloatVectorProperty(
218 name
="Imported Pov base location", precision
=6, default
=(0.0, 0.0, 0.0)
221 imported_cyl_loc_cap
: FloatVectorProperty(
222 name
="Imported Pov cap location", precision
=6, default
=(0.0, 0.0, 2.0)
225 def execute(self
, context
):
226 props
= self
.properties
227 cy_rad
= props
.cy_rad
228 if ob
:= context
.object:
229 if ob
.pov
.imported_cyl_loc
:
230 LOC
= ob
.pov
.imported_cyl_loc
231 if ob
.pov
.imported_cyl_loc_cap
:
232 LOC_CAP
= ob
.pov
.imported_cyl_loc_cap
233 elif not props
.imported_cyl_loc
:
234 LOC_CAP
= LOC
= bpy
.context
.scene
.cursor
.location
237 LOC
= props
.imported_cyl_loc
238 LOC_CAP
= props
.imported_cyl_loc_cap
241 "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
244 pov_cylinder_define(context
, self
, None, self
.cy_rad
, LOC
, LOC_CAP
)
249 class POV_OT_cylinder_update(Operator
):
250 """Update the POV cylinder.
252 Delete its previous proxy geometry and rerun pov_cylinder_define() function
253 with the new parameters"""
255 bl_idname
= "pov.cylinder_update"
257 bl_description
= "Update Cylinder"
258 bl_options
= {'REGISTER', 'UNDO'}
259 COMPAT_ENGINES
= {"POVRAY_RENDER"}
262 def poll(cls
, context
):
263 engine
= context
.scene
.render
.engine
268 and ob
.type == "MESH"
269 and ob
.pov
.object_as
== "CYLINDER"
270 and engine
in cls
.COMPAT_ENGINES
273 def execute(self
, context
):
275 radius
= ob
.pov
.cylinder_radius
277 loc_cap
= loc
+ ob
.pov
.cylinder_location_cap
279 pov_cylinder_define(context
, None, ob
, radius
, loc
, loc_cap
)
284 # ----------------------------------- SPHERE---------------------------------- #
285 def pov_sphere_define(context
, op
, ob
, loc
):
286 """create the representation of POV sphere using a Blender icosphere.
288 Its nice platonic solid curvature better represents pov rendertime
289 tessellation than a UV sphere"""
292 sphe_rad
= op
.sphe_rad
293 loc
= bpy
.context
.scene
.cursor
.location
296 sphe_rad
= ob
.pov
.sphere_radius
298 # keep object rotation and location for the add object operator
299 obrot
= ob
.rotation_euler
300 # obloc = ob.location
303 bpy
.ops
.object.mode_set(mode
="EDIT")
304 bpy
.ops
.mesh
.reveal()
305 bpy
.ops
.mesh
.select_all(action
="SELECT")
306 bpy
.ops
.mesh
.delete(type="VERT")
307 bpy
.ops
.mesh
.primitive_ico_sphere_add(
308 subdivisions
=4, radius
=ob
.pov
.sphere_radius
, location
=loc
, rotation
=obrot
310 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
311 bpy
.ops
.transform
.resize(value
=obscale
)
312 # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
314 bpy
.ops
.mesh
.hide(unselected
=False)
315 bpy
.ops
.object.mode_set(mode
="OBJECT")
317 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
320 bpy
.ops
.mesh
.primitive_ico_sphere_add(subdivisions
=4, radius
=sphe_rad
, location
=loc
)
322 ob
.name
= ob
.data
.name
= "PovSphere"
323 ob
.pov
.sphere_radius
= sphe_rad
324 bpy
.ops
.object.mode_set(mode
="EDIT")
325 bpy
.ops
.mesh
.hide(unselected
=False)
326 bpy
.ops
.object.mode_set(mode
="OBJECT")
327 ob
.data
.use_auto_smooth
= True
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 ob
.data
.use_auto_smooth
= True
473 bpy
.ops
.object.shade_smooth()
474 ob
.pov
.object_as
= "CONE"
475 ob
.update_tag() # as prop set via python not updated in depsgraph
477 class POV_OT_cone_add(Operator
):
478 """Add the representation of POV cone using pov_cone_define() function."""
480 bl_idname
= "pov.addcone"
482 bl_description
= "Add Cone"
483 bl_options
= {'REGISTER', 'UNDO'}
484 COMPAT_ENGINES
= {"POVRAY_RENDER"}
486 # Keep in sync within model_properties.py section Cone
487 # If someone knows how to define operators' props from a func, I'd be delighted to learn it!
490 description
="The first radius of the cone",
497 description
="The second radius of the cone",
504 description
="Radial segmentation of the proxy mesh",
509 height
: FloatProperty(
510 name
="Height", description
="Height of the cone", default
=2.0, min=0.01, max=100.0
514 def poll(cls
, context
):
515 engine
= context
.scene
.render
.engine
516 return engine
in cls
.COMPAT_ENGINES
518 def execute(self
, context
):
519 pov_cone_define(context
, self
, None)
522 {"INFO"}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
527 class POV_OT_cone_update(Operator
):
528 """Update the POV cone.
530 Delete its previous proxy geometry and rerun pov_cone_define() function
531 with the new parameters"""
533 bl_idname
= "pov.cone_update"
535 bl_description
= "Update Cone"
536 bl_options
= {'REGISTER', 'UNDO'}
537 COMPAT_ENGINES
= {"POVRAY_RENDER"}
540 def poll(cls
, context
):
541 engine
= context
.scene
.render
.engine
547 and ob
.type == "MESH"
548 and ob
.pov
.object_as
== "CONE"
549 and engine
in cls
.COMPAT_ENGINES
551 def execute(self
, context
):
552 bpy
.ops
.object.mode_set(mode
="EDIT")
553 bpy
.ops
.mesh
.reveal()
554 bpy
.ops
.mesh
.select_all(action
="SELECT")
555 bpy
.ops
.mesh
.delete(type="VERT")
556 bpy
.ops
.object.mode_set(mode
="OBJECT")
558 pov_cone_define(context
, None, context
.object)
563 class POV_OT_rainbow_add(Operator
):
564 """Add the representation of POV rainbow using a Blender spot light.
566 Rainbows indeed propagate along a visibility cone.
567 Flag its primitive type with a specific ob.pov.object_as attribute
568 and leave access to edit mode to keep user editable handles.
569 Add a constraint to orient it towards camera because POV Rainbows
570 are view dependant and having it always initially visible is less
573 bl_idname
= "pov.addrainbow"
575 bl_description
= "Add Rainbow"
576 bl_options
= {'REGISTER', 'UNDO'}
577 COMPAT_ENGINES
= {"POVRAY_RENDER"}
579 def execute(self
, context
):
580 cam
= context
.scene
.camera
581 bpy
.ops
.object.light_add(type="SPOT", radius
=1)
583 ob
.data
.show_cone
= False
584 ob
.data
.spot_blend
= 0.5
585 # ob.data.shadow_buffer_clip_end = 0 # deprecated in 2.8
586 ob
.data
.shadow_buffer_clip_start
= 4 * cam
.location
.length
587 ob
.data
.distance
= cam
.location
.length
589 ob
.name
= ob
.data
.name
= "PovRainbow"
590 ob
.pov
.object_as
= "RAINBOW"
591 ob
.update_tag() # as prop set via python not updated in depsgraph
593 # obj = context.object
594 bpy
.ops
.object.constraint_add(type="DAMPED_TRACK")
596 ob
.constraints
["Damped Track"].target
= cam
597 ob
.constraints
["Damped Track"].track_axis
= "TRACK_NEGATIVE_Z"
598 ob
.location
= -cam
.location
600 # refocus on the actual rainbow
601 bpy
.context
.view_layer
.objects
.active
= ob
607 # ----------------------------------- TORUS ----------------------------------- #
608 def pov_torus_define(context
, op
, ob
):
609 """Add the representation of POV torus using just a Blender torus.
611 Picking properties either from creation operator, import, or data update.
612 But flag its primitive type with a specific pov.object_as attribute and lock edit mode
613 to keep proxy consistency by hiding edit geometry."""
622 mas
= ob
.pov
.torus_major_segments
623 mis
= ob
.pov
.torus_minor_segments
624 mar
= ob
.pov
.torus_major_radius
625 mir
= ob
.pov
.torus_minor_radius
627 # keep object rotation and location for the add object operator
628 obrot
= ob
.rotation_euler
631 bpy
.ops
.object.mode_set(mode
="EDIT")
632 bpy
.ops
.mesh
.reveal()
633 bpy
.ops
.mesh
.select_all(action
="SELECT")
634 bpy
.ops
.mesh
.delete(type="VERT")
635 bpy
.ops
.mesh
.primitive_torus_add(
644 bpy
.ops
.mesh
.hide(unselected
=False)
645 bpy
.ops
.object.mode_set(mode
="OBJECT")
648 bpy
.ops
.mesh
.primitive_torus_add(
649 major_segments
=mas
, minor_segments
=mis
, major_radius
=mar
, minor_radius
=mir
652 ob
.name
= ob
.data
.name
= "PovTorus"
653 ob
.pov
.torus_major_segments
= mas
654 ob
.pov
.torus_minor_segments
= mis
655 ob
.pov
.torus_major_radius
= mar
656 ob
.pov
.torus_minor_radius
= mir
657 bpy
.ops
.object.mode_set(mode
="EDIT")
658 bpy
.ops
.mesh
.hide(unselected
=False)
659 bpy
.ops
.object.mode_set(mode
="OBJECT")
660 ob
.data
.use_auto_smooth
= True
661 ob
.data
.auto_smooth_angle
= 0.6
662 bpy
.ops
.object.shade_smooth()
663 ob
.pov
.object_as
= "TORUS"
664 ob
.update_tag() # as prop set via python not updated in depsgraph
666 class POV_OT_torus_add(Operator
):
667 """Add the representation of POV torus using using pov_torus_define() function."""
669 bl_idname
= "pov.addtorus"
671 bl_description
= "Add Torus"
672 bl_options
= {'REGISTER', 'UNDO'}
673 COMPAT_ENGINES
= {"POVRAY_RENDER"}
675 # Keep in sync within model_properties.py section Torus
676 # as this allows interactive update
677 mas
: IntProperty(name
="Major Segments", description
="", default
=48, min=3, max=720)
678 mis
: IntProperty(name
="Minor Segments", description
="", default
=12, min=3, max=720)
679 mar
: FloatProperty(name
="Major Radius", description
="", default
=1.0)
680 mir
: FloatProperty(name
="Minor Radius", description
="", default
=0.25)
682 def execute(self
, context
):
683 props
= self
.properties
688 pov_torus_define(context
, self
, None)
690 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
695 class POV_OT_torus_update(Operator
):
696 """Update the POV torus.
698 Delete its previous proxy geometry and rerun pov_torus_define() function
699 with the new parameters"""
701 bl_idname
= "pov.torus_update"
703 bl_description
= "Update Torus"
704 bl_options
= {'REGISTER', 'UNDO'}
705 COMPAT_ENGINES
= {"POVRAY_RENDER"}
708 def poll(cls
, context
):
709 engine
= context
.scene
.render
.engine
714 and ob
.type == "MESH"
715 and ob
.pov
.object_as
== "TORUS"
716 and engine
in cls
.COMPAT_ENGINES
719 def execute(self
, context
):
721 pov_torus_define(context
, None, context
.object)
726 # -----------------------------------------------------------------------------
729 class POV_OT_prism_add(Operator
):
730 """Add the representation of POV prism using using an extruded curve."""
732 bl_idname
= "pov.addprism"
734 bl_description
= "Create Prism"
735 bl_options
= {'REGISTER', 'UNDO'}
736 COMPAT_ENGINES
= {"POVRAY_RENDER"}
738 prism_n
: IntProperty(name
="Sides", description
="Number of sides", default
=5, min=3, max=720)
739 prism_r
: FloatProperty(name
="Radius", description
="Radius", default
=1.0)
741 def execute(self
, context
):
743 props
= self
.properties
744 loft_data
= bpy
.data
.curves
.new("Prism", type="CURVE")
745 loft_data
.dimensions
= "2D"
746 loft_data
.resolution_u
= 2
747 # loft_data.show_normal_face = False
748 loft_data
.extrude
= 2
757 coords
.append((x
, y
, z
))
759 poly
= loft_data
.splines
.new("POLY")
760 poly
.points
.add(len(coords
) - 1)
761 for i
, coord
in enumerate(coords
):
763 poly
.points
[i
].co
= (x
, y
, z
, 1)
764 poly
.use_cyclic_u
= True
766 ob
= bpy
.data
.objects
.new("Prism_shape", loft_data
)
767 scn
= bpy
.context
.scene
768 scn
.collection
.objects
.link(ob
)
769 context
.view_layer
.objects
.active
= ob
771 bpy
.ops
.object.mode_set(mode
="OBJECT")
772 bpy
.ops
.object.shade_flat()
773 ob
.data
.fill_mode
= 'BOTH'
774 ob
.pov
.curveshape
= "prism"
775 ob
.name
= ob
.data
.name
= "Prism"
783 POV_OT_cylinder_update
,
785 POV_OT_sphere_update
,
801 for cls
in reversed(classes
):
802 unregister_class(cls
)