procfunc 0.30.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. procfunc/__init__.py +87 -0
  2. procfunc/color.py +57 -0
  3. procfunc/compute_graph/__init__.py +28 -0
  4. procfunc/compute_graph/compute_graph.py +115 -0
  5. procfunc/compute_graph/node.py +200 -0
  6. procfunc/compute_graph/operators_info.py +92 -0
  7. procfunc/compute_graph/proxy.py +173 -0
  8. procfunc/compute_graph/util.py +282 -0
  9. procfunc/context.py +115 -0
  10. procfunc/control.py +174 -0
  11. procfunc/nodes/__init__.py +66 -0
  12. procfunc/nodes/bindings_util.py +196 -0
  13. procfunc/nodes/bpy_node_info.py +280 -0
  14. procfunc/nodes/compositor.py +2242 -0
  15. procfunc/nodes/execute/construct_nodes.py +571 -0
  16. procfunc/nodes/execute/construct_special_cases.py +246 -0
  17. procfunc/nodes/execute/execute.py +548 -0
  18. procfunc/nodes/execute/infer_runtime_data_type.py +195 -0
  19. procfunc/nodes/execute/util.py +247 -0
  20. procfunc/nodes/func.py +1417 -0
  21. procfunc/nodes/geo.py +4240 -0
  22. procfunc/nodes/manifest.json +8769 -0
  23. procfunc/nodes/math.py +644 -0
  24. procfunc/nodes/node_function.py +160 -0
  25. procfunc/nodes/shader.py +2359 -0
  26. procfunc/nodes/types.py +347 -0
  27. procfunc/ops/__init__.py +35 -0
  28. procfunc/ops/_util.py +275 -0
  29. procfunc/ops/addons.py +59 -0
  30. procfunc/ops/attr.py +426 -0
  31. procfunc/ops/collection.py +90 -0
  32. procfunc/ops/curve.py +18 -0
  33. procfunc/ops/file.py +126 -0
  34. procfunc/ops/manifest.json +39149 -0
  35. procfunc/ops/mesh.py +1510 -0
  36. procfunc/ops/modifier.py +603 -0
  37. procfunc/ops/object.py +258 -0
  38. procfunc/ops/primitives/__init__.py +31 -0
  39. procfunc/ops/primitives/camera.py +45 -0
  40. procfunc/ops/primitives/curve.py +71 -0
  41. procfunc/ops/primitives/light.py +114 -0
  42. procfunc/ops/primitives/mesh.py +358 -0
  43. procfunc/ops/uv.py +271 -0
  44. procfunc/random.py +247 -0
  45. procfunc/tracer/__init__.py +43 -0
  46. procfunc/tracer/decorator.py +121 -0
  47. procfunc/tracer/patch.py +494 -0
  48. procfunc/tracer/proxy.py +127 -0
  49. procfunc/tracer/trace.py +222 -0
  50. procfunc/transforms/__init__.py +49 -0
  51. procfunc/transforms/cleanup.py +214 -0
  52. procfunc/transforms/convert.py +20 -0
  53. procfunc/transforms/distribution.py +191 -0
  54. procfunc/transforms/extract_materials.py +116 -0
  55. procfunc/transforms/infer_distribution.py +326 -0
  56. procfunc/transforms/parameters.py +15 -0
  57. procfunc/transforms/util.py +35 -0
  58. procfunc/transpiler/__init__.py +24 -0
  59. procfunc/transpiler/bpy_to_computegraph.py +1348 -0
  60. procfunc/transpiler/codegen.py +919 -0
  61. procfunc/transpiler/identifiers.py +595 -0
  62. procfunc/transpiler/main.py +299 -0
  63. procfunc/types.py +380 -0
  64. procfunc/util/__init__.py +0 -0
  65. procfunc/util/bpy_info.py +145 -0
  66. procfunc/util/camera.py +0 -0
  67. procfunc/util/keyframe.py +70 -0
  68. procfunc/util/log.py +96 -0
  69. procfunc/util/manifest.py +121 -0
  70. procfunc/util/pytree.py +343 -0
  71. procfunc/util/teardown.py +37 -0
  72. procfunc-0.30.0.dist-info/METADATA +120 -0
  73. procfunc-0.30.0.dist-info/RECORD +76 -0
  74. procfunc-0.30.0.dist-info/WHEEL +5 -0
  75. procfunc-0.30.0.dist-info/licenses/LICENSE.md +11 -0
  76. procfunc-0.30.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,358 @@
1
+ from typing import Any
2
+
3
+ import bpy
4
+ import numpy as np
5
+ from mathutils import Euler, Vector
6
+
7
+ from procfunc import types as t
8
+
9
+
10
+ def mesh_single_vertex() -> t.MeshObject:
11
+ mesh = bpy.data.meshes.new(mesh_single_vertex.__name__)
12
+ mesh.vertices.add(1)
13
+ mesh.vertices[0].co = (0, 0, 0)
14
+ obj = bpy.data.objects.new(mesh_single_vertex.__name__, mesh)
15
+ bpy.context.scene.collection.objects.link(obj)
16
+ return t.MeshObject(obj)
17
+
18
+
19
+ """
20
+ def point_cloud(
21
+ points: list[Vector],
22
+ edges: list[tuple[int, int]] | None = None,
23
+ ) -> t.MeshObject:
24
+ mesh = bpy.data.meshes.new(point_cloud.__name__)
25
+ mesh.from_pydata(points, edges, [])
26
+ obj = bpy.data.objects.new(point_cloud.__name__, mesh)
27
+ bpy.context.scene.collection.objects.link(obj)
28
+ return t.MeshObject(obj)
29
+ """
30
+
31
+
32
+ def mesh_from_numpy(
33
+ vertices: np.ndarray | None = None,
34
+ edges: np.ndarray | None = None,
35
+ faces: np.ndarray | None = None,
36
+ ) -> t.MeshObject:
37
+ if vertices is None:
38
+ vertices = np.array([])
39
+ if edges is None:
40
+ edges = np.array([])
41
+ if faces is None:
42
+ faces = np.array([])
43
+
44
+ mesh = bpy.data.meshes.new(mesh_from_numpy.__name__)
45
+ mesh.from_pydata(vertices, edges, faces)
46
+ obj = bpy.data.objects.new(mesh_from_numpy.__name__, mesh)
47
+ bpy.context.scene.collection.objects.link(obj)
48
+ return t.MeshObject(obj)
49
+
50
+
51
+ def mesh_line(
52
+ points: list[Vector] | np.ndarray,
53
+ ) -> t.MeshObject:
54
+ idxs = np.arange(len(points))
55
+ edges = np.stack([idxs[:-1], idxs[1:]], axis=-1)
56
+
57
+ mesh = bpy.data.meshes.new(mesh_line.__name__)
58
+ mesh.from_pydata(points, edges, [])
59
+ obj = bpy.data.objects.new(mesh_line.__name__, mesh)
60
+ bpy.context.scene.collection.objects.link(obj)
61
+ return t.MeshObject(obj)
62
+
63
+
64
+ def empty(
65
+ disp_type: str = "PLAIN_AXES",
66
+ display_size: float = 0.1,
67
+ ) -> t.MeshObject:
68
+ obj = bpy.data.objects.new(empty.__name__, None)
69
+ bpy.context.scene.collection.objects.link(obj)
70
+ obj.empty_display_size = display_size
71
+ obj.empty_display_type = disp_type
72
+ return t.MeshObject(obj)
73
+
74
+
75
+ def mesh_uv_sphere(
76
+ segments: int = 32,
77
+ ring_count: int = 16,
78
+ radius: float = 1.0,
79
+ calc_uvs: bool = True,
80
+ enter_editmode: bool = False,
81
+ align: str = "WORLD",
82
+ location: Vector = Vector((0.0, 0.0, 0.0)),
83
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
84
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
85
+ **kwargs: Any,
86
+ ) -> t.MeshObject:
87
+ """Generate a UV sphere primitive with specified parameters."""
88
+ bpy.ops.mesh.primitive_uv_sphere_add(
89
+ segments=segments,
90
+ ring_count=ring_count,
91
+ radius=radius,
92
+ calc_uvs=calc_uvs,
93
+ enter_editmode=enter_editmode,
94
+ align=align,
95
+ location=location,
96
+ rotation=rotation,
97
+ scale=scale,
98
+ **kwargs,
99
+ )
100
+ obj = bpy.context.active_object
101
+ return t.MeshObject(obj)
102
+
103
+
104
+ def mesh_plane(
105
+ size: float = 2.0,
106
+ calc_uvs: bool = True,
107
+ enter_editmode: bool = False,
108
+ align: str = "WORLD",
109
+ location: Vector = Vector((0.0, 0.0, 0.0)),
110
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
111
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
112
+ **kwargs: Any,
113
+ ) -> t.MeshObject:
114
+ """Generate a plane primitive with specified parameters."""
115
+ bpy.ops.mesh.primitive_plane_add(
116
+ size=size,
117
+ calc_uvs=calc_uvs,
118
+ enter_editmode=enter_editmode,
119
+ align=align,
120
+ location=location,
121
+ rotation=rotation,
122
+ scale=scale,
123
+ **kwargs,
124
+ )
125
+ obj = bpy.context.active_object
126
+ return t.MeshObject(obj)
127
+
128
+
129
+ def mesh_cube(
130
+ size: float = 2.0,
131
+ calc_uvs: bool = True,
132
+ enter_editmode: bool = False,
133
+ align: str = "WORLD",
134
+ location: Vector = Vector((0.0, 0.0, 0.0)),
135
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
136
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
137
+ **kwargs: Any,
138
+ ) -> t.MeshObject:
139
+ """Generate a cube primitive with specified parameters."""
140
+ bpy.ops.mesh.primitive_cube_add(
141
+ size=size,
142
+ calc_uvs=calc_uvs,
143
+ enter_editmode=enter_editmode,
144
+ align=align,
145
+ location=Vector(location),
146
+ rotation=Euler(rotation),
147
+ scale=Vector(scale),
148
+ **kwargs,
149
+ )
150
+ obj = bpy.context.active_object
151
+ return t.MeshObject(obj)
152
+
153
+
154
+ def mesh_icosphere(
155
+ subdivisions: int = 2,
156
+ radius: float = 1.0,
157
+ calc_uvs: bool = True,
158
+ enter_editmode: bool = False,
159
+ align: str = "WORLD",
160
+ location: Vector = Vector((0.0, 0.0, 0.0)),
161
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
162
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
163
+ **kwargs: Any,
164
+ ) -> t.MeshObject:
165
+ """Generate an icosphere primitive with specified parameters."""
166
+ bpy.ops.mesh.primitive_ico_sphere_add(
167
+ subdivisions=subdivisions,
168
+ radius=radius,
169
+ calc_uvs=calc_uvs,
170
+ enter_editmode=enter_editmode,
171
+ align=align,
172
+ location=location,
173
+ rotation=rotation,
174
+ scale=scale,
175
+ **kwargs,
176
+ )
177
+ obj = bpy.context.active_object
178
+ return t.MeshObject(obj)
179
+
180
+
181
+ def mesh_cylinder(
182
+ vertices: int = 32,
183
+ radius: float = 1.0,
184
+ depth: float = 2.0,
185
+ end_fill_type: str = "NGON",
186
+ calc_uvs: bool = True,
187
+ enter_editmode: bool = False,
188
+ align: str = "WORLD",
189
+ location: Vector = Vector((0.0, 0.0, 0.0)),
190
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
191
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
192
+ **kwargs: Any,
193
+ ) -> t.MeshObject:
194
+ """Generate a cylinder primitive with specified parameters."""
195
+ bpy.ops.mesh.primitive_cylinder_add(
196
+ vertices=vertices,
197
+ radius=radius,
198
+ depth=depth,
199
+ end_fill_type=end_fill_type,
200
+ calc_uvs=calc_uvs,
201
+ enter_editmode=enter_editmode,
202
+ align=align,
203
+ location=location,
204
+ rotation=rotation,
205
+ scale=scale,
206
+ **kwargs,
207
+ )
208
+ obj = bpy.context.active_object
209
+ return t.MeshObject(obj)
210
+
211
+
212
+ def mesh_cone(
213
+ vertices: int = 32,
214
+ radius1: float = 1.0,
215
+ radius2: float = 0.0,
216
+ depth: float = 2.0,
217
+ end_fill_type: str = "NGON",
218
+ calc_uvs: bool = True,
219
+ enter_editmode: bool = False,
220
+ align: str = "WORLD",
221
+ location: Vector = Vector((0.0, 0.0, 0.0)),
222
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
223
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
224
+ **kwargs: Any,
225
+ ) -> t.MeshObject:
226
+ """Generate a cone primitive with specified parameters."""
227
+ bpy.ops.mesh.primitive_cone_add(
228
+ vertices=vertices,
229
+ radius1=radius1,
230
+ radius2=radius2,
231
+ depth=depth,
232
+ end_fill_type=end_fill_type,
233
+ calc_uvs=calc_uvs,
234
+ enter_editmode=enter_editmode,
235
+ align=align,
236
+ location=location,
237
+ rotation=rotation,
238
+ scale=scale,
239
+ **kwargs,
240
+ )
241
+ obj = bpy.context.active_object
242
+ return t.MeshObject(obj)
243
+
244
+
245
+ def mesh_torus(
246
+ align: str = "WORLD",
247
+ location: Vector = Vector((0.0, 0.0, 0.0)),
248
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
249
+ major_segments: int = 48,
250
+ minor_segments: int = 12,
251
+ mode: str = "MAJOR_MINOR",
252
+ major_radius: float = 1.0,
253
+ minor_radius: float = 0.25,
254
+ abso_major_rad: float = 1.25,
255
+ abso_minor_rad: float = 0.75,
256
+ generate_uvs: bool = True,
257
+ **kwargs: Any,
258
+ ) -> t.MeshObject:
259
+ """Generate a torus primitive with specified parameters."""
260
+ bpy.ops.mesh.primitive_torus_add(
261
+ align=align,
262
+ location=location,
263
+ rotation=rotation,
264
+ major_segments=major_segments,
265
+ minor_segments=minor_segments,
266
+ mode=mode,
267
+ major_radius=major_radius,
268
+ minor_radius=minor_radius,
269
+ abso_major_rad=abso_major_rad,
270
+ abso_minor_rad=abso_minor_rad,
271
+ generate_uvs=generate_uvs,
272
+ **kwargs,
273
+ )
274
+ obj = bpy.context.active_object
275
+ return t.MeshObject(obj)
276
+
277
+
278
+ def mesh_circle(
279
+ vertices: int = 32,
280
+ radius: float = 1.0,
281
+ fill_type: str = "NOTHING",
282
+ calc_uvs: bool = True,
283
+ enter_editmode: bool = False,
284
+ align: str = "WORLD",
285
+ location: Vector = Vector((0.0, 0.0, 0.0)),
286
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
287
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
288
+ **kwargs: Any,
289
+ ) -> t.MeshObject:
290
+ """Generate a circle primitive with specified parameters."""
291
+ bpy.ops.mesh.primitive_circle_add(
292
+ vertices=vertices,
293
+ radius=radius,
294
+ fill_type=fill_type,
295
+ calc_uvs=calc_uvs,
296
+ enter_editmode=enter_editmode,
297
+ align=align,
298
+ location=location,
299
+ rotation=rotation,
300
+ scale=scale,
301
+ **kwargs,
302
+ )
303
+ obj = bpy.context.active_object
304
+ return t.MeshObject(obj)
305
+
306
+
307
+ def mesh_grid(
308
+ x_subdivisions: int = 10,
309
+ y_subdivisions: int = 10,
310
+ size: float = 2.0,
311
+ calc_uvs: bool = True,
312
+ enter_editmode: bool = False,
313
+ align: str = "WORLD",
314
+ location: Vector = Vector((0.0, 0.0, 0.0)),
315
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
316
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
317
+ **kwargs: Any,
318
+ ) -> t.MeshObject:
319
+ """Generate a grid primitive with specified parameters."""
320
+ bpy.ops.mesh.primitive_grid_add(
321
+ x_subdivisions=x_subdivisions,
322
+ y_subdivisions=y_subdivisions,
323
+ size=size,
324
+ calc_uvs=calc_uvs,
325
+ enter_editmode=enter_editmode,
326
+ align=align,
327
+ location=location,
328
+ rotation=rotation,
329
+ scale=scale,
330
+ **kwargs,
331
+ )
332
+ obj = bpy.context.active_object
333
+ return t.MeshObject(obj)
334
+
335
+
336
+ def mesh_monkey(
337
+ size: float = 2.0,
338
+ calc_uvs: bool = True,
339
+ enter_editmode: bool = False,
340
+ align: str = "WORLD",
341
+ location: Vector = Vector((0.0, 0.0, 0.0)),
342
+ rotation: Euler = Euler((0.0, 0.0, 0.0)),
343
+ scale: Vector = Vector((1.0, 1.0, 1.0)),
344
+ **kwargs: Any,
345
+ ) -> t.MeshObject:
346
+ """Generate a monkey (Suzanne) primitive with specified parameters."""
347
+ bpy.ops.mesh.primitive_monkey_add(
348
+ size=size,
349
+ calc_uvs=calc_uvs,
350
+ enter_editmode=enter_editmode,
351
+ align=align,
352
+ location=location,
353
+ rotation=rotation,
354
+ scale=scale,
355
+ **kwargs,
356
+ )
357
+ obj = bpy.context.active_object
358
+ return t.MeshObject(obj)
procfunc/ops/uv.py ADDED
@@ -0,0 +1,271 @@
1
+ from typing import Literal
2
+
3
+ import bpy
4
+ import numpy as np
5
+
6
+ import procfunc as pf
7
+ from procfunc import types as t
8
+ from procfunc.ops._util import execute_mesh_op
9
+
10
+
11
+ def _ensure_uv_layer(obj: bpy.types.Object, uv_name: str) -> None:
12
+ """Ensure a UV layer exists with the given name, removing any existing one first."""
13
+ mesh = obj.data
14
+ if uv_name in mesh.uv_layers:
15
+ mesh.uv_layers.remove(mesh.uv_layers[uv_name])
16
+ new_layer = mesh.uv_layers.new(name=uv_name)
17
+ mesh.uv_layers.active = new_layer
18
+
19
+
20
+ @pf.tracer.primitive(mutates=["mutates_obj"])
21
+ def cube_project(
22
+ mutates_obj: t.MeshObject,
23
+ vertex_mask: np.ndarray | None = None,
24
+ edge_mask: np.ndarray | None = None,
25
+ face_mask: np.ndarray | None = None,
26
+ uv_name: str = "UVMap",
27
+ cube_size: float = 1.0,
28
+ correct_aspect: bool = True,
29
+ clip_to_bounds: bool = False,
30
+ scale_to_bounds: bool = False,
31
+ ) -> None:
32
+ """
33
+ Project the UV vertices of the mesh over the six faces of a cube
34
+
35
+ Based on bpy.ops.uv.cube_project
36
+
37
+ Args:
38
+ vertex_mask: Boolean array selecting vertices to project.
39
+ edge_mask: Boolean array selecting edges to project.
40
+ face_mask: Boolean array selecting faces to project.
41
+ uv_name: Name of the UV layer to create/replace.
42
+ """
43
+ _ensure_uv_layer(mutates_obj.item(), uv_name)
44
+ execute_mesh_op(
45
+ bpy.ops.uv.cube_project,
46
+ mutates_obj,
47
+ vertex_mask=vertex_mask,
48
+ edge_mask=edge_mask,
49
+ face_mask=face_mask,
50
+ cube_size=cube_size,
51
+ correct_aspect=correct_aspect,
52
+ clip_to_bounds=clip_to_bounds,
53
+ scale_to_bounds=scale_to_bounds,
54
+ )
55
+
56
+
57
+ @pf.tracer.primitive(mutates=["mutates_obj"])
58
+ def cylinder_project(
59
+ mutates_obj: t.MeshObject,
60
+ vertex_mask: np.ndarray | None = None,
61
+ edge_mask: np.ndarray | None = None,
62
+ face_mask: np.ndarray | None = None,
63
+ uv_name: str = "UVMap",
64
+ direction: Literal[
65
+ "VIEW_ON_EQUATOR", "VIEW_ON_POLES", "ALIGN_TO_OBJECT"
66
+ ] = "VIEW_ON_EQUATOR",
67
+ align: Literal["POLAR_ZX", "POLAR_ZY"] = "POLAR_ZX",
68
+ pole: Literal["PINCH", "FAN"] = "PINCH",
69
+ seam: bool = False,
70
+ radius: float = 1.0,
71
+ correct_aspect: bool = True,
72
+ clip_to_bounds: bool = False,
73
+ scale_to_bounds: bool = False,
74
+ ) -> None:
75
+ """
76
+ Project the UV vertices of the mesh over the curved wall of a cylinder
77
+
78
+ Based on bpy.ops.uv.cylinder_project
79
+
80
+ Args:
81
+ vertex_mask: Boolean array selecting vertices to project.
82
+ edge_mask: Boolean array selecting edges to project.
83
+ face_mask: Boolean array selecting faces to project.
84
+ uv_name: Name of the UV layer to create/replace.
85
+ """
86
+ _ensure_uv_layer(mutates_obj.item(), uv_name)
87
+ execute_mesh_op(
88
+ bpy.ops.uv.cylinder_project,
89
+ mutates_obj,
90
+ vertex_mask=vertex_mask,
91
+ edge_mask=edge_mask,
92
+ face_mask=face_mask,
93
+ direction=direction,
94
+ align=align,
95
+ pole=pole,
96
+ seam=seam,
97
+ radius=radius,
98
+ correct_aspect=correct_aspect,
99
+ clip_to_bounds=clip_to_bounds,
100
+ scale_to_bounds=scale_to_bounds,
101
+ )
102
+
103
+
104
+ @pf.tracer.primitive(mutates=["mutates_obj"])
105
+ def project_from_view(
106
+ mutates_obj: t.MeshObject,
107
+ vertex_mask: np.ndarray | None = None,
108
+ edge_mask: np.ndarray | None = None,
109
+ face_mask: np.ndarray | None = None,
110
+ uv_name: str = "UVMap",
111
+ orthographic: bool = False,
112
+ camera_bounds: bool = True,
113
+ correct_aspect: bool = True,
114
+ clip_to_bounds: bool = False,
115
+ scale_to_bounds: bool = False,
116
+ ) -> None:
117
+ """
118
+ Project the UV vertices of the mesh as seen in current 3D view
119
+
120
+ Based on bpy.ops.uv.project_from_view
121
+
122
+ Args:
123
+ vertex_mask: Boolean array selecting vertices to project.
124
+ edge_mask: Boolean array selecting edges to project.
125
+ face_mask: Boolean array selecting faces to project.
126
+ uv_name: Name of the UV layer to create/replace.
127
+ """
128
+ _ensure_uv_layer(mutates_obj.item(), uv_name)
129
+ execute_mesh_op(
130
+ bpy.ops.uv.project_from_view,
131
+ mutates_obj,
132
+ vertex_mask=vertex_mask,
133
+ edge_mask=edge_mask,
134
+ face_mask=face_mask,
135
+ orthographic=orthographic,
136
+ camera_bounds=camera_bounds,
137
+ correct_aspect=correct_aspect,
138
+ clip_to_bounds=clip_to_bounds,
139
+ scale_to_bounds=scale_to_bounds,
140
+ )
141
+
142
+
143
+ @pf.tracer.primitive(mutates=["mutates_obj"])
144
+ def smart_project(
145
+ mutates_obj: t.MeshObject,
146
+ vertex_mask: np.ndarray | None = None,
147
+ edge_mask: np.ndarray | None = None,
148
+ face_mask: np.ndarray | None = None,
149
+ uv_name: str = "UVMap",
150
+ angle_limit: float = 1.15192,
151
+ margin_method: Literal["SCALED", "ADD", "FRACTION"] = "SCALED",
152
+ rotate_method: Literal[
153
+ "AXIS_ALIGNED", "AXIS_ALIGNED_X", "AXIS_ALIGNED_Y"
154
+ ] = "AXIS_ALIGNED_Y",
155
+ island_margin: float = 0.0,
156
+ area_weight: float = 0.0,
157
+ correct_aspect: bool = True,
158
+ scale_to_bounds: bool = False,
159
+ ) -> None:
160
+ """
161
+ Projection unwraps the selected faces of mesh objects
162
+
163
+ Based on bpy.ops.uv.smart_project
164
+
165
+ Args:
166
+ vertex_mask: Boolean array selecting vertices to project.
167
+ edge_mask: Boolean array selecting edges to project.
168
+ face_mask: Boolean array selecting faces to project.
169
+ uv_name: Name of the UV layer to create/replace.
170
+ """
171
+ _ensure_uv_layer(mutates_obj.item(), uv_name)
172
+ execute_mesh_op(
173
+ bpy.ops.uv.smart_project,
174
+ mutates_obj,
175
+ vertex_mask=vertex_mask,
176
+ edge_mask=edge_mask,
177
+ face_mask=face_mask,
178
+ angle_limit=angle_limit,
179
+ margin_method=margin_method,
180
+ rotate_method=rotate_method,
181
+ island_margin=island_margin,
182
+ area_weight=area_weight,
183
+ correct_aspect=correct_aspect,
184
+ scale_to_bounds=scale_to_bounds,
185
+ )
186
+
187
+
188
+ @pf.tracer.primitive(mutates=["mutates_obj"])
189
+ def sphere_project(
190
+ mutates_obj: t.MeshObject,
191
+ vertex_mask: np.ndarray | None = None,
192
+ edge_mask: np.ndarray | None = None,
193
+ face_mask: np.ndarray | None = None,
194
+ uv_name: str = "UVMap",
195
+ direction: Literal[
196
+ "VIEW_ON_EQUATOR", "VIEW_ON_POLES", "ALIGN_TO_OBJECT"
197
+ ] = "VIEW_ON_EQUATOR",
198
+ align: Literal["POLAR_ZX", "POLAR_ZY"] = "POLAR_ZX",
199
+ pole: Literal["PINCH", "FAN"] = "PINCH",
200
+ seam: bool = False,
201
+ correct_aspect: bool = True,
202
+ clip_to_bounds: bool = False,
203
+ scale_to_bounds: bool = False,
204
+ ) -> None:
205
+ """
206
+ Project the UV vertices of the mesh over the curved surface of a sphere
207
+
208
+ Based on bpy.ops.uv.sphere_project
209
+
210
+ Args:
211
+ vertex_mask: Boolean array selecting vertices to project.
212
+ edge_mask: Boolean array selecting edges to project.
213
+ face_mask: Boolean array selecting faces to project.
214
+ uv_name: Name of the UV layer to create/replace.
215
+ """
216
+ _ensure_uv_layer(mutates_obj.item(), uv_name)
217
+ execute_mesh_op(
218
+ bpy.ops.uv.sphere_project,
219
+ mutates_obj,
220
+ vertex_mask=vertex_mask,
221
+ edge_mask=edge_mask,
222
+ face_mask=face_mask,
223
+ direction=direction,
224
+ align=align,
225
+ pole=pole,
226
+ seam=seam,
227
+ correct_aspect=correct_aspect,
228
+ clip_to_bounds=clip_to_bounds,
229
+ scale_to_bounds=scale_to_bounds,
230
+ )
231
+
232
+
233
+ @pf.tracer.primitive(mutates=["mutates_obj"])
234
+ def unwrap(
235
+ mutates_obj: t.MeshObject,
236
+ vertex_mask: np.ndarray | None = None,
237
+ edge_mask: np.ndarray | None = None,
238
+ face_mask: np.ndarray | None = None,
239
+ uv_name: str = "UVMap",
240
+ method: Literal["ANGLE_BASED", "CONFORMAL"] = "ANGLE_BASED",
241
+ fill_holes: bool = True,
242
+ correct_aspect: bool = True,
243
+ use_subsurf_data: bool = False,
244
+ margin_method: Literal["SCALED", "ADD", "FRACTION"] = "SCALED",
245
+ margin: float = 0.001,
246
+ ) -> None:
247
+ """
248
+ Unwrap the mesh of the object being edited
249
+
250
+ Based on bpy.ops.uv.unwrap
251
+
252
+ Args:
253
+ vertex_mask: Boolean array selecting vertices to unwrap.
254
+ edge_mask: Boolean array selecting edges to unwrap.
255
+ face_mask: Boolean array selecting faces to unwrap.
256
+ uv_name: Name of the UV layer to create/replace.
257
+ """
258
+ _ensure_uv_layer(mutates_obj.item(), uv_name)
259
+ execute_mesh_op(
260
+ bpy.ops.uv.unwrap,
261
+ mutates_obj,
262
+ vertex_mask=vertex_mask,
263
+ edge_mask=edge_mask,
264
+ face_mask=face_mask,
265
+ method=method,
266
+ fill_holes=fill_holes,
267
+ correct_aspect=correct_aspect,
268
+ use_subsurf_data=use_subsurf_data,
269
+ margin_method=margin_method,
270
+ margin=margin,
271
+ )