1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """ Get POV-Ray specific objects In and Out of Blender """
5 from math
import pi
, cos
, sin
8 from bpy_extras
.object_utils
import object_data_add
9 from bpy_extras
.io_utils
import ImportHelper
10 from bpy
.utils
import register_class
, unregister_class
11 from bpy
.types
import Operator
13 from bpy
.props
import (
22 from mathutils
import Vector
, Matrix
24 from . import model_primitives
26 class POV_OT_lathe_add(Operator
):
27 """Add the representation of POV lathe using a screw modifier."""
29 bl_idname
= "pov.addlathe"
31 bl_description
= "adds lathe"
32 bl_options
= {'REGISTER', 'UNDO'}
33 COMPAT_ENGINES
= {"POVRAY_RENDER"}
35 def execute(self
, context
):
38 bpy
.ops
.curve
.primitive_bezier_curve_add(
39 location
=context
.scene
.cursor
.location
,
43 ob
= context
.view_layer
.objects
.active
45 ob
.name
= ob_data
.name
= "PovLathe"
46 ob_data
.dimensions
= "2D"
47 ob_data
.transform(Matrix
.Rotation(-pi
/ 2.0, 4, "Z"))
48 ob
.pov
.object_as
= "LATHE"
50 {"INFO"}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
52 ob
.pov
.curveshape
= "lathe"
53 bpy
.ops
.object.modifier_add(type="SCREW")
54 mod
= ob
.modifiers
[-1]
56 mod
.show_render
= False
57 ob
.update_tag() # as prop set via python not updated in depsgraph
61 def pov_superellipsoid_define(context
, op
, ob
):
62 """Create the proxy mesh of a POV superellipsoid using pov_superellipsoid_define()."""
72 se_param1
= n2
# op.se_param1
73 se_param2
= n1
# op.se_param2
84 se_param1
= ob
.pov
.se_param1
85 se_param2
= ob
.pov
.se_param2
90 stepSegment
= 360 / v
* pi
/ 180
96 for ring
in range(0, u
- 1):
98 for segment
in range(0, v
):
100 angSegment
+= stepSegment
101 x
= r
* (abs(cos(angRing
)) ** n1
) * (abs(cos(angSegment
)) ** n2
)
102 if (cos(angRing
) < 0 < cos(angSegment
)) or (cos(angRing
) > 0 > cos(angSegment
)):
104 y
= r
* (abs(cos(angRing
)) ** n1
) * (abs(sin(angSegment
)) ** n2
)
105 if (cos(angRing
) < 0 < sin(angSegment
)) or (cos(angRing
) > 0 > sin(angSegment
)):
107 z
= r
* (abs(sin(angRing
)) ** n1
)
113 verts
.append((x
, y
, z
))
114 if edit
== "TRIANGLES":
115 verts
.extend([(0, 0, 1),(0, 0, -1)])
119 for i
in range(0, u
- 2):
121 for p
in range(0, v
):
123 face
= (m
+ p
, 1 + m
+ p
, v
+ 1 + m
+ p
, v
+ m
+ p
)
125 face
= (m
+ p
, m
, v
+ m
, v
+ m
+ p
)
127 if edit
== "TRIANGLES":
128 indexUp
= len(verts
) - 2
129 indexDown
= len(verts
) - 1
130 indexStartDown
= len(verts
) - 2 - v
131 for i
in range(0, v
):
133 face
= (indexDown
, i
, i
+ 1)
136 face
= (indexDown
, i
, 0)
138 for i
in range(0, v
):
140 face
= (indexUp
, i
+ indexStartDown
, i
+ indexStartDown
+ 1)
143 face
= (indexUp
, i
+ indexStartDown
, indexStartDown
)
146 face
= list(range(v
))
149 indexUp
= len(verts
) - 1
150 for i
in range(0, v
):
151 face
.append(indexUp
- i
)
153 mesh
= model_primitives
.pov_define_mesh(mesh
, verts
, [], faces
, "SuperEllipsoid")
156 ob
= object_data_add(context
, mesh
, operator
=None)
157 # engine = context.scene.render.engine what for?
159 ob
.name
= ob
.data
.name
= "PovSuperellipsoid"
160 ob
.pov
.se_param1
= n2
161 ob
.pov
.se_param2
= n1
167 ob
.pov
.se_edit
= edit
169 bpy
.ops
.object.mode_set(mode
="EDIT")
170 bpy
.ops
.mesh
.hide(unselected
=False)
171 bpy
.ops
.object.mode_set(mode
="OBJECT")
172 ob
.data
.auto_smooth_angle
= 1.3
173 bpy
.ops
.object.shade_smooth()
174 ob
.pov
.object_as
= "SUPERELLIPSOID"
175 ob
.update_tag() # as prop set via python not updated in depsgraph
177 class POV_OT_superellipsoid_add(Operator
):
178 """Add the representation of POV superellipsoid using the pov_superellipsoid_define()."""
180 bl_idname
= "pov.addsuperellipsoid"
181 bl_label
= "Add SuperEllipsoid"
182 bl_description
= "Create a SuperEllipsoid"
183 bl_options
= {'REGISTER', 'UNDO'}
184 COMPAT_ENGINES
= {"POVRAY_RENDER"}
186 # Keep in sync within model_properties.py section Superellipsoid
187 # as this allows interactive update
188 # If someone knows how to define operators' props from a func, I'd be delighted to learn it!
189 # XXX ARE the first two used for import ? could we hide or suppress them otherwise?
190 se_param1
: FloatProperty(name
="Parameter 1", description
="", min=0.00, max=10.0, default
=0.04)
192 se_param2
: FloatProperty(name
="Parameter 2", description
="", min=0.00, max=10.0, default
=0.04)
195 name
="U-segments", description
="radial segmentation", default
=20, min=4, max=265
198 name
="V-segments", description
="lateral segmentation", default
=20, min=4, max=265
200 se_n1
: FloatProperty(
201 name
="Ring manipulator",
202 description
="Manipulates the shape of the Ring",
207 se_n2
: FloatProperty(
208 name
="Cross manipulator",
209 description
="Manipulates the shape of the cross-section",
214 se_edit
: EnumProperty(
215 items
=[("NOTHING", "Nothing", ""), ("NGONS", "N-Gons", ""), ("TRIANGLES", "Triangles", "")],
216 name
="Fill up and down",
222 def poll(cls
, context
):
223 engine
= context
.scene
.render
.engine
224 return engine
in cls
.COMPAT_ENGINES
226 def execute(self
, context
):
227 pov_superellipsoid_define(context
, self
, None)
230 {"INFO"}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
236 class POV_OT_superellipsoid_update(Operator
):
237 """Update the superellipsoid.
239 Delete its previous proxy geometry and rerun pov_superellipsoid_define() function
240 with the new parameters"""
242 bl_idname
= "pov.superellipsoid_update"
244 bl_description
= "Update Superellipsoid"
245 bl_options
= {'REGISTER', 'UNDO'}
246 COMPAT_ENGINES
= {"POVRAY_RENDER"}
249 def poll(cls
, context
):
250 engine
= context
.scene
.render
.engine
252 return ob
and ob
.data
and ob
.type == "MESH" and engine
in cls
.COMPAT_ENGINES
254 def execute(self
, context
):
255 bpy
.ops
.object.mode_set(mode
="EDIT")
256 bpy
.ops
.mesh
.reveal()
257 bpy
.ops
.mesh
.select_all(action
="SELECT")
258 bpy
.ops
.mesh
.delete(type="VERT")
259 bpy
.ops
.object.mode_set(mode
="OBJECT")
261 pov_superellipsoid_define(context
, None, context
.object)
266 def create_faces(vert_idx_1
, vert_idx_2
, closed
=False, flipped
=False):
267 """Generate viewport proxy mesh data for some pov primitives"""
269 if not vert_idx_1
or not vert_idx_2
:
271 if len(vert_idx_1
) < 2 and len(vert_idx_2
) < 2:
274 if len(vert_idx_1
) != len(vert_idx_2
):
275 if len(vert_idx_1
) == 1 and len(vert_idx_2
) > 1:
279 total
= len(vert_idx_2
)
282 face
= [vert_idx_1
[0], vert_idx_2
[0], vert_idx_2
[total
- 1]]
284 face
.append(vert_idx_1
[total
- 1])
286 face
= [vert_idx_2
[0], vert_idx_1
[0]]
288 face
.append(vert_idx_1
[total
- 1])
289 face
.append(vert_idx_2
[total
- 1])
292 for num
in range(total
- 1):
295 face
= [vert_idx_2
[num
], vert_idx_1
[0], vert_idx_2
[num
+ 1]]
297 face
= [vert_idx_2
[num
], vert_idx_1
[num
], vert_idx_1
[num
+ 1], vert_idx_2
[num
+ 1]]
299 face
= [vert_idx_1
[0], vert_idx_2
[num
], vert_idx_2
[num
+ 1]]
301 face
= [vert_idx_1
[num
], vert_idx_2
[num
], vert_idx_2
[num
+ 1], vert_idx_1
[num
+ 1]]
307 """Workaround to negative a, where the math.pow() method would return a ValueError."""
308 return -((-a
) ** b
) if a
< 0 else a
**b
311 def supertoroid(R
, r
, u
, v
, n1
, n2
):
317 s
= power(sin(i
* a
), n1
)
318 c
= power(cos(i
* a
), n1
)
320 c2
= R
+ r
* power(cos(j
* b
), n2
)
321 s2
= r
* power(sin(j
* b
), n2
)
322 verts
.append((c
* c2
, s
* c2
, s2
)) # type as a (mathutils.Vector(c*c2,s*c2,s2))?
324 f
= create_faces(range((i
- 1) * v
, i
* v
), range(i
* v
, (i
+ 1) * v
), closed
=True)
326 f
= create_faces(range((u
- 1) * v
, u
* v
), range(v
), closed
=True)
331 def pov_supertorus_define(context
, op
, ob
):
332 """Get POV supertorus properties from operator (object creation/import) or data update."""
347 st_R
= ob
.pov
.st_major_radius
348 st_r
= ob
.pov
.st_minor_radius
351 st_n1
= ob
.pov
.st_ring
352 st_n2
= ob
.pov
.st_cross
354 st_edit
= ob
.pov
.st_edit
357 rad1
= (st_R
+ st_r
) / 2
358 rad2
= (st_R
- st_r
) / 2
360 [rad1
, rad2
] = [rad2
, rad1
]
366 verts
, faces
= supertoroid(rad1
, rad2
, st_u
, st_v
, st_n1
, st_n2
)
367 mesh
= model_primitives
.pov_define_mesh(mesh
, verts
, [], faces
, "PovSuperTorus", True)
369 ob
= object_data_add(context
, mesh
, operator
=None)
370 ob
.pov
.object_as
= "SUPERTORUS"
371 ob
.pov
.st_major_radius
= st_R
372 ob
.pov
.st_minor_radius
= st_r
375 ob
.pov
.st_ring
= st_n1
376 ob
.pov
.st_cross
= st_n2
378 ob
.pov
.st_edit
= st_edit
379 ob
.update_tag() # as prop set via python not updated in depsgraph
382 class POV_OT_supertorus_add(Operator
):
383 """Add the representation of POV supertorus using the pov_supertorus_define() function."""
385 bl_idname
= "pov.addsupertorus"
386 bl_label
= "Add Supertorus"
387 bl_description
= "Create a SuperTorus"
388 bl_options
= {'REGISTER', 'UNDO'}
389 COMPAT_ENGINES
= {"POVRAY_RENDER"}
393 description
="The radius inside the tube",
399 name
="small radius", description
="The radius of the tube", default
=0.3, min=0.01, max=100.0
402 name
="U-segments", description
="radial segmentation", default
=16, min=3, max=265
405 name
="V-segments", description
="lateral segmentation", default
=8, min=3, max=265
407 st_n1
: FloatProperty(
408 name
="Ring manipulator",
409 description
="Manipulates the shape of the Ring",
414 st_n2
: FloatProperty(
415 name
="Cross manipulator",
416 description
="Manipulates the shape of the cross-section",
422 name
="Use Int.+Ext. radii", description
="Use internal and external radii", default
=False
424 st_edit
: BoolProperty(name
="", description
="", default
=False, options
={"HIDDEN"})
427 def poll(cls
, context
):
428 engine
= context
.scene
.render
.engine
429 return engine
in cls
.COMPAT_ENGINES
431 def execute(self
, context
):
432 pov_supertorus_define(context
, self
, None)
435 {"INFO"}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
440 class POV_OT_supertorus_update(Operator
):
441 """Update the supertorus.
443 Delete its previous proxy geometry and rerun pov_supetorus_define() function
444 with the new parameters"""
446 bl_idname
= "pov.supertorus_update"
448 bl_description
= "Update SuperTorus"
449 bl_options
= {'REGISTER', 'UNDO'}
450 COMPAT_ENGINES
= {"POVRAY_RENDER"}
453 def poll(cls
, context
):
454 engine
= context
.scene
.render
.engine
456 return ob
and ob
.data
and ob
.type == "MESH" and engine
in cls
.COMPAT_ENGINES
458 def execute(self
, context
):
459 bpy
.ops
.object.mode_set(mode
="EDIT")
460 bpy
.ops
.mesh
.reveal()
461 bpy
.ops
.mesh
.select_all(action
="SELECT")
462 bpy
.ops
.mesh
.delete(type="VERT")
463 bpy
.ops
.object.mode_set(mode
="OBJECT")
465 pov_supertorus_define(context
, None, context
.object)
470 # -----------------------------------------------------------------------------
471 class POV_OT_loft_add(Operator
):
472 """Create the representation of POV loft using Blender curves."""
474 bl_idname
= "pov.addloft"
475 bl_label
= "Add Loft Data"
476 bl_description
= "Create a Curve data for Meshmaker"
477 bl_options
= {'REGISTER', 'UNDO'}
478 COMPAT_ENGINES
= {"POVRAY_RENDER"}
481 name
="Segments", description
="Vertical segments", default
=16, min=3, max=720
483 loft_rings_bottom
: IntProperty(
484 name
="Bottom", description
="Bottom rings", default
=5, min=2, max=100
486 loft_rings_side
: IntProperty(name
="Side", description
="Side rings", default
=10, min=2, max=100)
487 loft_thick
: FloatProperty(
489 description
="Manipulates the shape of the Ring",
494 loft_r
: FloatProperty(name
="Radius", description
="Radius", default
=1, min=0.01, max=10)
495 loft_height
: FloatProperty(
497 description
="Manipulates the shape of the Ring",
503 def execute(self
, context
):
505 props
= self
.properties
506 loft_data
= bpy
.data
.curves
.new("Loft", type="CURVE")
507 loft_data
.dimensions
= "3D"
508 loft_data
.resolution_u
= 2
509 # loft_data.show_normal_face = False # deprecated in 2.8
511 thick
= props
.loft_thick
512 side
= props
.loft_rings_side
513 bottom
= props
.loft_rings_bottom
514 h
= props
.loft_height
520 for i
in range(bottom
+ 1):
526 coords
.append((x
, y
, z
))
529 nurbs
= loft_data
.splines
.new("NURBS")
530 nurbs
.points
.add(len(coords
) - 1)
531 for c
, coord
in enumerate(coords
):
533 nurbs
.points
[c
].co
= (x
, y
, z
, 1)
534 nurbs
.use_cyclic_u
= True
535 for i
in range(side
):
542 coords
.append((x
, y
, z
))
544 nurbs
= loft_data
.splines
.new("NURBS")
545 nurbs
.points
.add(len(coords
) - 1)
546 for c
, coord
in enumerate(coords
):
548 nurbs
.points
[c
].co
= (x
, y
, z
, 1)
549 nurbs
.use_cyclic_u
= True
551 for i
in range(side
):
557 coords
.append((x
, y
, z
))
559 nurbs
= loft_data
.splines
.new("NURBS")
560 nurbs
.points
.add(len(coords
) - 1)
561 for c
, coord
in enumerate(coords
):
563 nurbs
.points
[c
].co
= (x
, y
, z
, 1)
564 nurbs
.use_cyclic_u
= True
567 distB
= (r
- 0.00001) / bottom
568 for i
in range(bottom
+ 1):
574 coords
.append((x
, y
, z
))
577 nurbs
= loft_data
.splines
.new("NURBS")
578 nurbs
.points
.add(len(coords
) - 1)
579 for c
, coord
in enumerate(coords
):
581 nurbs
.points
[c
].co
= (x
, y
, z
, 1)
582 nurbs
.use_cyclic_u
= True
583 ob
= bpy
.data
.objects
.new("Loft_shape", loft_data
)
584 scn
= bpy
.context
.scene
585 scn
.collection
.objects
.link(ob
)
586 context
.view_layer
.objects
.active
= ob
588 ob
.pov
.curveshape
= "loft"
592 # ----------------------------------- ISOSURFACES ----------------------------------- #
595 def pov_isosurface_view_define(context
, op
, ob
, loc
):
596 """create the representation of POV isosurface using a Blender empty."""
599 eq
= op
.isosurface_eq
601 loc
= bpy
.context
.scene
.cursor
.location
605 eq
= ob
.pov
.isosurface_eq
607 # keep object rotation and location for the add object operator
608 obrot
= ob
.rotation_euler
609 # obloc = ob.location
612 # bpy.ops.object.empty_add(type='CUBE', location=loc, rotation=obrot)
613 bpy
.ops
.mesh
.primitive_emptyvert_add()
615 # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
616 bpy
.ops
.transform
.resize(value
=obscale
)
617 # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
618 bpy
.ops
.object.mode_set(mode
="OBJECT")
620 # bpy.ops.object.empty_add(type='CUBE', location=loc)
621 bpy
.ops
.mesh
.primitive_emptyvert_add()
623 ob
.name
= ob
.data
.name
= "PovIsosurface"
624 ob
.pov
.object_as
= "ISOSURFACE_VIEW"
625 ob
.pov
.isosurface_eq
= eq
626 ob
.pov
.contained_by
= "box"
627 bpy
.ops
.object.mode_set(mode
="OBJECT")
628 ob
.update_tag() # as prop set via python not updated in depsgraph
631 class POV_OT_isosurface_add(Operator
):
632 """Add the representation of POV isosurface sphere by a Blender mesh icosphere.
634 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
635 to keep proxy consistency by hiding edit geometry."""
637 bl_idname
= "pov.addisosurface"
638 bl_label
= "Generic Isosurface"
639 bl_description
= "Add Isosurface"
640 bl_options
= {'REGISTER', 'UNDO'}
641 COMPAT_ENGINES
= {"POVRAY_RENDER"}
643 # Keep in sync within model_properties.py section Sphere
644 # as this allows interactive update
645 isosurface_eq
: StringProperty(
647 description
="Type the POV Isosurface function syntax for equation, "
648 "pattern,etc. ruling an implicit surface to be rendered",
649 default
="sqrt(pow(x,2) + pow(y,2) + pow(z,2)) - 1.5",
651 imported_loc
: FloatVectorProperty(
652 name
="Imported Pov location", precision
=6, default
=(0.0, 0.0, 0.0)
655 def execute(self
, context
):
656 # layers = 20*[False]
658 props
= self
.properties
659 if ob
:= context
.object:
660 if ob
.pov
.imported_loc
:
661 LOC
= ob
.pov
.imported_loc
662 elif not props
.imported_loc
:
663 LOC
= bpy
.context
.scene
.cursor
.location
665 LOC
= props
.imported_loc
667 pov_isosurface_view_define(context
, self
, None, LOC
)
669 {"INFO"}, "This native POV-Ray primitive " "is only an abstract proxy in Blender"
671 except AttributeError:
672 self
.report({"INFO"}, "Please enable Add Mesh: Extra Objects addon")
676 class POV_OT_isosurface_update(Operator
):
677 """Update the POV isosurface.
679 Rerun pov_isosurface_view_define() function
680 with the new parameters"""
682 bl_idname
= "pov.isosurface_update"
684 bl_description
= "Update Isosurface"
685 bl_options
= {'REGISTER', 'UNDO'}
686 COMPAT_ENGINES
= {"POVRAY_RENDER"}
689 def poll(cls
, context
):
690 engine
= context
.scene
.render
.engine
692 return ob
and ob
.data
and ob
.type == "ISOSURFACE_VIEW" and engine
in cls
.COMPAT_ENGINES
694 def execute(self
, context
):
696 pov_isosurface_view_define(context
, None, context
.object, context
.object.location
)
701 class POV_OT_isosurface_box_add(Operator
):
702 """Add the representation of POV isosurface box using also just a Blender mesh cube.
704 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
705 to keep proxy consistency by hiding edit geometry."""
707 bl_idname
= "pov.addisosurfacebox"
708 bl_label
= "Isosurface Box"
709 bl_description
= "Add Isosurface contained by Box"
710 bl_options
= {'REGISTER', 'UNDO'}
711 COMPAT_ENGINES
= {"POVRAY_RENDER"}
713 def execute(self
, context
):
714 # layers = 20*[False]
716 bpy
.ops
.mesh
.primitive_cube_add()
718 bpy
.ops
.object.mode_set(mode
="EDIT")
720 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
722 bpy
.ops
.mesh
.hide(unselected
=False)
723 bpy
.ops
.object.mode_set(mode
="OBJECT")
724 ob
.pov
.object_as
= "ISOSURFACE_NODE"
725 ob
.pov
.contained_by
= "box"
726 ob
.name
= "PovIsosurfaceBox"
727 ob
.update_tag() # as prop set via python not updated in depsgraph
731 class POV_OT_isosurface_sphere_add(Operator
):
732 """Add the representation of POV isosurface sphere by a Blender mesh icosphere.
734 Flag its primitive type with a specific pov.object_as attribute and lock edit mode
735 to keep proxy consistency by hiding edit geometry."""
737 bl_idname
= "pov.addisosurfacesphere"
738 bl_label
= "Isosurface Sphere"
739 bl_description
= "Add Isosurface contained by Sphere"
740 bl_options
= {'REGISTER', 'UNDO'}
741 COMPAT_ENGINES
= {"POVRAY_RENDER"}
743 def execute(self
, context
):
744 # layers = 20*[False]
746 bpy
.ops
.mesh
.primitive_ico_sphere_add(subdivisions
=4)
748 bpy
.ops
.object.mode_set(mode
="EDIT")
750 {"INFO"}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
752 bpy
.ops
.mesh
.hide(unselected
=False)
753 bpy
.ops
.object.mode_set(mode
="OBJECT")
754 bpy
.ops
.object.shade_smooth()
755 ob
.pov
.object_as
= "ISOSURFACE_NODE"
756 ob
.pov
.contained_by
= "sphere"
757 ob
.name
= "PovIsosurfaceSphere"
758 ob
.update_tag() # as prop set via python not updated in depsgraph
762 class POV_OT_sphere_sweep_add(Operator
):
763 """Add the representation of POV sphere_sweep using a Blender NURBS curve.
765 Flag its primitive type with a specific ob.pov.curveshape attribute and
766 leave access to edit mode to keep user editable handles."""
768 bl_idname
= "pov.addspheresweep"
769 bl_label
= "Sphere Sweep"
770 bl_description
= "Create Sphere Sweep along curve"
771 bl_options
= {'REGISTER', 'UNDO'}
772 COMPAT_ENGINES
= {"POVRAY_RENDER"}
774 def execute(self
, context
):
775 # layers = 20*[False]
777 bpy
.ops
.curve
.primitive_nurbs_curve_add()
779 ob
.name
= ob
.data
.name
= "PovSphereSweep"
780 ob
.pov
.curveshape
= "sphere_sweep"
781 ob
.data
.bevel_depth
= 0.02
782 ob
.data
.bevel_resolution
= 4
783 ob
.data
.fill_mode
= "FULL"
784 # ob.data.splines[0].order_u = 4
789 class POV_OT_blobsphere_add(Operator
):
790 """Add the representation of POV blob using a Blender meta ball.
792 No need to flag its primitive type as meta are exported to blobs
793 and leave access to edit mode to keep user editable thresholds."""
795 bl_idname
= "pov.addblobsphere"
796 bl_label
= "Blob Sphere"
797 bl_description
= "Add Blob Sphere"
798 bl_options
= {'REGISTER', 'UNDO'}
799 COMPAT_ENGINES
= {"POVRAY_RENDER"}
801 def execute(self
, context
):
802 # layers = 20*[False]
804 bpy
.ops
.object.metaball_add(type="BALL")
810 class POV_OT_blobcapsule_add(Operator
):
811 """Add the representation of POV blob using a Blender meta ball.
813 No need to flag its primitive type as meta are exported to blobs
814 and leave access to edit mode to keep user editable thresholds."""
816 bl_idname
= "pov.addblobcapsule"
817 bl_label
= "Blob Capsule"
818 bl_description
= "Add Blob Capsule"
819 bl_options
= {'REGISTER', 'UNDO'}
820 COMPAT_ENGINES
= {"POVRAY_RENDER"}
822 def execute(self
, context
):
823 # layers = 20*[False]
825 bpy
.ops
.object.metaball_add(type="CAPSULE")
831 class POV_OT_blobplane_add(Operator
):
832 """Add the representation of POV blob using a Blender meta ball.
834 No need to flag its primitive type as meta are exported to blobs
835 and leave access to edit mode to keep user editable thresholds."""
837 bl_idname
= "pov.addblobplane"
838 bl_label
= "Blob Plane"
839 bl_description
= "Add Blob Plane"
840 bl_options
= {'REGISTER', 'UNDO'}
841 COMPAT_ENGINES
= {"POVRAY_RENDER"}
843 def execute(self
, context
):
844 # layers = 20*[False]
846 bpy
.ops
.object.metaball_add(type="PLANE")
852 class POV_OT_blobellipsoid_add(Operator
):
853 """Add the representation of POV blob using a Blender meta ball.
855 No need to flag its primitive type as meta are exported to blobs
856 and leave access to edit mode to keep user editable thresholds."""
858 bl_idname
= "pov.addblobellipsoid"
859 bl_label
= "Blob Ellipsoid"
860 bl_description
= "Add Blob Ellipsoid"
863 def execute(self
, context
):
864 # layers = 20*[False]
866 bpy
.ops
.object.metaball_add(type="ELLIPSOID")
872 class POV_OT_blobcube_add(Operator
):
873 """Add the representation of POV blob using a Blender meta ball.
875 No need to flag its primitive type as meta are exported to blobs
876 and leave access to edit mode to keep user editable thresholds."""
878 bl_idname
= "pov.addblobcube"
879 bl_label
= "Blob Cube"
880 bl_description
= "Add Blob Cube"
881 bl_options
= {'REGISTER', 'UNDO'}
882 COMPAT_ENGINES
= {"POVRAY_RENDER"}
884 def execute(self
, context
):
885 # layers = 20*[False]
887 bpy
.ops
.object.metaball_add(type="CUBE")
893 class POV_OT_height_field_add(bpy
.types
.Operator
, ImportHelper
):
894 """Add the representation of POV height_field using a displaced grid.
896 texture slot fix and displace modifier will be needed because noise
897 displace operator was deprecated in 2.8"""
899 bl_idname
= "pov.addheightfield"
900 bl_label
= "Height Field"
901 bl_description
= "Add Height Field"
902 bl_options
= {'REGISTER', 'UNDO'}
903 COMPAT_ENGINES
= {"POVRAY_RENDER"}
905 # Keep in sync within model_properties.py section HeightFields
906 # as this allows interactive update
908 # filename_ext = ".png"
910 # filter_glob = StringProperty(
911 # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
912 # options={'HIDDEN'},
914 quality
: IntProperty(name
="Quality", description
="", default
=100, min=1, max=100)
915 hf_filename
: StringProperty(maxlen
=1024)
917 hf_gamma
: FloatProperty(name
="Gamma", description
="Gamma", min=0.0001, max=20.0, default
=1.0)
919 hf_premultiplied
: BoolProperty(name
="Premultiplied", description
="Premultiplied", default
=True)
921 hf_smooth
: BoolProperty(name
="Smooth", description
="Smooth", default
=False)
923 hf_water
: FloatProperty(
924 name
="Water Level", description
="Wather Level", min=0.00, max=1.00, default
=0.0
927 hf_hierarchy
: BoolProperty(name
="Hierarchy", description
="Height field hierarchy", default
=True)
929 def execute(self
, context
):
930 props
= self
.properties
931 impath
= bpy
.path
.abspath(self
.filepath
)
932 img
= bpy
.data
.images
.load(impath
)
934 im_name
, file_extension
= os
.path
.splitext(im_name
)
935 hf_tex
= bpy
.data
.textures
.new("%s_hf_image" % im_name
, type="IMAGE")
937 mat
= bpy
.data
.materials
.new("Tex_%s_hf" % im_name
)
938 hf_slot
= mat
.pov_texture_slots
.add()
939 hf_slot
.texture
= hf_tex
.name
940 # layers = 20*[False]
942 quality
= props
.quality
944 w
, h
= hf_tex
.image
.size
[:]
947 bpy
.ops
.mesh
.primitive_grid_add(x_subdivisions
=w
, y_subdivisions
=h
, size
=0.5)
949 ob
.name
= ob
.data
.name
= "%s" % im_name
950 ob
.data
.materials
.append(mat
)
951 bpy
.ops
.object.mode_set(mode
="EDIT")
952 # bpy.ops.mesh.noise(factor=1) # TODO replace by displace modifier, noise deprecated in 2.8
953 bpy
.ops
.object.mode_set(mode
="OBJECT")
955 # needs a loop to select by index?
956 # bpy.ops.object.material_slot_remove()
957 # material just left there for now
959 mat
.pov_texture_slots
.clear()
960 bpy
.ops
.object.mode_set(mode
="EDIT")
961 bpy
.ops
.mesh
.hide(unselected
=False)
962 bpy
.ops
.object.mode_set(mode
="OBJECT")
963 ob
.pov
.object_as
= "HEIGHT_FIELD"
964 # POV-Ray will soon use only forwards slashes on every OS and already can
965 forward_impath
= impath
.replace(os
.sep
, "/")
966 ob
.pov
.hf_filename
= forward_impath
967 ob
.update_tag() # as prop set via python not updated in depsgraph
971 # ----------------------------------- PARAMETRIC ----------------------------------- #
972 def pov_parametric_define(context
, op
, ob
):
973 """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon.
975 Picking properties either from creation operator, import, or data update.
976 But flag its primitive type with a specific pov.object_as attribute and lock edit mode
977 to keep proxy consistency by hiding edit geometry."""
997 # keep object rotation and location for the updated object
999 obrot
= ob
.rotation_euler
# In radians
1000 # Parametric addon has no loc rot, some extra work is needed
1001 # in case cursor has moved
1002 curloc
= bpy
.context
.scene
.cursor
.location
1004 bpy
.ops
.object.mode_set(mode
="EDIT")
1005 bpy
.ops
.mesh
.reveal()
1006 bpy
.ops
.mesh
.select_all(action
="SELECT")
1007 bpy
.ops
.mesh
.delete(type="VERT")
1008 bpy
.ops
.mesh
.primitive_xyz_function_surface(
1017 bpy
.ops
.mesh
.select_all(action
="SELECT")
1019 bpy
.ops
.transform
.translate(value
=(obloc
- curloc
), proportional_size
=1)
1020 # XXX TODO : https://devtalk.blender.org/t/bpy-ops-transform-rotate-option-axis/6235/7
1021 # to complete necessary extra work rotation, after updating from blender version > 2.92
1022 # update and uncomment below, but simple axis deprecated since 2.8
1023 # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
1025 bpy
.ops
.mesh
.hide(unselected
=False)
1026 bpy
.ops
.object.mode_set(mode
="OBJECT")
1029 bpy
.ops
.mesh
.primitive_xyz_function_surface(
1039 ob
.name
= ob
.data
.name
= "PovParametric"
1041 ob
.pov
.u_min
= u_min
1042 ob
.pov
.u_max
= u_max
1043 ob
.pov
.v_min
= v_min
1044 ob
.pov
.v_max
= v_max
1049 bpy
.ops
.object.mode_set(mode
="EDIT")
1050 bpy
.ops
.mesh
.hide(unselected
=False)
1051 bpy
.ops
.object.mode_set(mode
="OBJECT")
1052 ob
.data
.auto_smooth_angle
= 0.6
1053 bpy
.ops
.object.shade_smooth()
1054 ob
.pov
.object_as
= "PARAMETRIC"
1055 ob
.update_tag() # as prop set via python not updated in depsgraph
1058 class POV_OT_parametric_add(Operator
):
1059 """Add the representation of POV parametric surfaces using pov_parametric_define() function."""
1061 bl_idname
= "pov.addparametric"
1062 bl_label
= "Parametric"
1063 bl_description
= "Add Paramertic"
1064 bl_options
= {'REGISTER', 'UNDO'}
1065 COMPAT_ENGINES
= {"POVRAY_RENDER"}
1067 # Keep in sync within model_properties.py section Parametric primitive
1068 # as this allows interactive update
1069 u_min
: FloatProperty(name
="U Min", description
="", default
=0.0)
1070 v_min
: FloatProperty(name
="V Min", description
="", default
=0.0)
1071 u_max
: FloatProperty(name
="U Max", description
="", default
=6.28)
1072 v_max
: FloatProperty(name
="V Max", description
="", default
=12.57)
1073 x_eq
: StringProperty(maxlen
=1024, default
="cos(v)*(1+cos(u))*sin(v/8)")
1074 y_eq
: StringProperty(maxlen
=1024, default
="sin(u)*sin(v/8)+cos(v/8)*1.5")
1075 z_eq
: StringProperty(maxlen
=1024, default
="sin(v)*(1+cos(u))*sin(v/8)")
1077 def execute(self
, context
):
1078 props
= self
.properties
1087 pov_parametric_define(context
, self
, None)
1090 "This native POV-Ray primitive " "won't have any vertex to show in edit mode",
1092 except AttributeError:
1093 self
.report({"INFO"}, "Please enable Add Mesh: Extra Objects addon")
1097 class POV_OT_parametric_update(Operator
):
1098 """Update the representation of POV parametric surfaces.
1100 Delete its previous proxy geometry and rerun pov_parametric_define() function
1101 with the new parameters"""
1103 bl_idname
= "pov.parametric_update"
1105 bl_description
= "Update parametric object"
1106 bl_options
= {'REGISTER', 'UNDO'}
1107 COMPAT_ENGINES
= {"POVRAY_RENDER"}
1110 def poll(cls
, context
):
1111 engine
= context
.scene
.render
.engine
1113 return ob
and ob
.data
and ob
.type == "MESH" and engine
in cls
.COMPAT_ENGINES
1115 def execute(self
, context
):
1117 pov_parametric_define(context
, None, context
.object)
1122 # -----------------------------------------------------------------------------
1125 class POV_OT_polygon_to_circle_add(Operator
):
1126 """Add the proxy mesh for POV Polygon to circle lofting macro"""
1128 bl_idname
= "pov.addpolygontocircle"
1129 bl_label
= "Polygon To Circle Blending"
1130 bl_description
= "Add Polygon To Circle Blending Surface"
1131 bl_options
= {'REGISTER', 'UNDO'}
1132 COMPAT_ENGINES
= {"POVRAY_RENDER"}
1134 # Keep in sync within model_properties.py section PolygonToCircle properties
1135 # as this allows interactive update
1136 polytocircle_resolution
: IntProperty(
1137 name
="Resolution", description
="", default
=3, min=0, max=256
1139 polytocircle_ngon
: IntProperty(name
="NGon", description
="", min=3, max=64, default
=5)
1140 polytocircle_ngonR
: FloatProperty(name
="NGon Radius", description
="", default
=0.3)
1141 polytocircle_circleR
: FloatProperty(name
="Circle Radius", description
="", default
=1.0)
1143 def execute(self
, context
):
1144 props
= self
.properties
1145 ngon
= props
.polytocircle_ngon
1146 ngonR
= props
.polytocircle_ngonR
1147 circleR
= props
.polytocircle_circleR
1148 resolution
= props
.polytocircle_resolution
1149 # layers = 20*[False]
1151 bpy
.ops
.mesh
.primitive_circle_add(
1152 vertices
=ngon
, radius
=ngonR
, fill_type
="NGON", enter_editmode
=True
1154 bpy
.ops
.transform
.translate(value
=(0, 0, 1))
1155 bpy
.ops
.mesh
.subdivide(number_cuts
=resolution
)
1156 numCircleVerts
= ngon
+ (ngon
* resolution
)
1157 bpy
.ops
.mesh
.select_all(action
="DESELECT")
1158 bpy
.ops
.mesh
.primitive_circle_add(
1159 vertices
=numCircleVerts
, radius
=circleR
, fill_type
="NGON", enter_editmode
=True
1161 bpy
.ops
.transform
.translate(value
=(0, 0, -1))
1162 bpy
.ops
.mesh
.select_all(action
="SELECT")
1163 bpy
.ops
.mesh
.bridge_edge_loops()
1165 bpy
.ops
.mesh
.select_all(action
="DESELECT")
1166 bpy
.ops
.mesh
.primitive_circle_add(
1167 vertices
=ngon
, radius
=ngonR
, fill_type
="TRIFAN", enter_editmode
=True
1169 bpy
.ops
.transform
.translate(value
=(0, 0, 1))
1170 bpy
.ops
.mesh
.select_all(action
="SELECT")
1171 bpy
.ops
.mesh
.remove_doubles()
1172 bpy
.ops
.object.mode_set(mode
="OBJECT")
1174 ob
.name
= "Polygon_To_Circle"
1176 ob
.pov
.ngonR
= ngonR
1177 ob
.pov
.circleR
= circleR
1178 bpy
.ops
.object.mode_set(mode
="EDIT")
1179 bpy
.ops
.mesh
.hide(unselected
=False)
1180 bpy
.ops
.object.mode_set(mode
="OBJECT")
1181 #ob.data.auto_smooth_angle = 0.1
1182 #bpy.ops.object.shade_smooth()
1183 ob
.pov
.object_as
= "POLYCIRCLE"
1184 ob
.update_tag() # as prop set via python not updated in depsgraph
1190 POV_OT_superellipsoid_add
,
1191 POV_OT_superellipsoid_update
,
1192 POV_OT_supertorus_add
,
1193 POV_OT_supertorus_update
,
1195 POV_OT_isosurface_add
,
1196 POV_OT_isosurface_update
,
1197 POV_OT_isosurface_box_add
,
1198 POV_OT_isosurface_sphere_add
,
1199 POV_OT_sphere_sweep_add
,
1200 POV_OT_blobsphere_add
,
1201 POV_OT_blobcapsule_add
,
1202 POV_OT_blobplane_add
,
1203 POV_OT_blobellipsoid_add
,
1204 POV_OT_blobcube_add
,
1205 POV_OT_height_field_add
,
1206 POV_OT_parametric_add
,
1207 POV_OT_parametric_update
,
1208 POV_OT_polygon_to_circle_add
,
1218 for cls
in reversed(classes
):
1219 unregister_class(cls
)