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
procfunc/nodes/geo.py ADDED
@@ -0,0 +1,4240 @@
1
+ """
2
+ Auto-generated Geometry Node bindings for Blender
3
+
4
+ WARNING: These type annotations are not guaranteed to be exhaustive or precise.
5
+
6
+ places of particular concern:
7
+ - What attribute nodes allow int/float/bool or also Color/Vector
8
+ - What geometry operations should we allow to apply on mismatching inputs? e.g. realize instances on a Mesh with no instances
9
+ """
10
+
11
+ import logging
12
+ from dataclasses import dataclass
13
+ from typing import Any, Generic, Literal, NamedTuple, TypeVar
14
+
15
+ from procfunc import types as pt
16
+ from procfunc.nodes import types as nt
17
+ from procfunc.nodes.bindings_util import RuntimeResolveDataType, raise_io_error
18
+ from procfunc.nodes.bpy_node_info import NodeDataType
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ TDomain = Literal["POINT", "EDGE", "FACE", "CORNER", "CURVE", "INSTANCE", "LAYER"]
23
+
24
+ TAttribute = TypeVar("TAttribute", int, float, bool)
25
+
26
+ TMeshOrCurve = TypeVar(
27
+ "TMeshOrCurve",
28
+ pt.MeshObject,
29
+ pt.CurveObject,
30
+ )
31
+ TAnyGeometry = TypeVar(
32
+ "TAnyGeometry",
33
+ pt.MeshObject,
34
+ pt.CurveObject,
35
+ pt.VolumeObject,
36
+ nt.Instances,
37
+ )
38
+
39
+
40
+ class AccumulateFieldResult(NamedTuple, Generic[TAttribute]):
41
+ leading: nt.ProcNode[TAttribute]
42
+ total: nt.ProcNode[TAttribute]
43
+ trailing: nt.ProcNode[TAttribute]
44
+
45
+
46
+ def accumulate_field(
47
+ value: nt.ProcNode[TAttribute] | None = None,
48
+ group_id: nt.SocketOrVal[int] = 0,
49
+ domain: TDomain = "POINT",
50
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
51
+ ) -> AccumulateFieldResult[TAttribute]:
52
+ """
53
+ Uses a AccumulateField Geometry Node.
54
+
55
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/field/accumulate_field.html
56
+ """
57
+ if data_type is None:
58
+ data_type = RuntimeResolveDataType(
59
+ [NodeDataType.INT, NodeDataType.FLOAT],
60
+ ["Value"],
61
+ )
62
+ res = nt.ProcNode.from_nodetype(
63
+ node_type="GeometryNodeAccumulateField",
64
+ inputs={"Group ID": group_id, "Value": value},
65
+ attrs={
66
+ "domain": domain,
67
+ "data_type": data_type,
68
+ },
69
+ )
70
+ return AccumulateFieldResult(
71
+ leading=res._output_socket("leading"),
72
+ total=res._output_socket("total"),
73
+ trailing=res._output_socket("trailing"),
74
+ )
75
+
76
+
77
+ class AttributeDomainSizeResult(NamedTuple):
78
+ point_count: nt.ProcNode[int]
79
+ edge_count: nt.ProcNode[int]
80
+ face_count: nt.ProcNode[int]
81
+ face_corner_count: nt.ProcNode[int]
82
+ spline_count: nt.ProcNode[int]
83
+ instance_count: nt.ProcNode[int]
84
+
85
+
86
+ def attribute_domain_size(
87
+ geometry: nt.ProcNode[nt.Geometry],
88
+ component: Literal["MESH", "POINTCLOUD", "CURVE", "INSTANCES"] = "MESH",
89
+ ) -> AttributeDomainSizeResult:
90
+ """
91
+ Uses a AttributeDomainSize Geometry Node.
92
+
93
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/attribute/domain_size.html
94
+ """
95
+ res = nt.ProcNode.from_nodetype(
96
+ node_type="GeometryNodeAttributeDomainSize",
97
+ inputs={"Geometry": geometry},
98
+ attrs={"component": component},
99
+ )
100
+ return AttributeDomainSizeResult(
101
+ point_count=res._output_socket("point_count"),
102
+ edge_count=res._output_socket("edge_count"),
103
+ face_count=res._output_socket("face_count"),
104
+ face_corner_count=res._output_socket("face_corner_count"),
105
+ spline_count=res._output_socket("spline_count"),
106
+ instance_count=res._output_socket("instance_count"),
107
+ )
108
+
109
+
110
+ class AttributeStatisticResult(NamedTuple, Generic[TAttribute]):
111
+ max: nt.ProcNode[TAttribute]
112
+ mean: nt.ProcNode[TAttribute]
113
+ median: nt.ProcNode[TAttribute]
114
+ min: nt.ProcNode[TAttribute]
115
+ range: nt.ProcNode[TAttribute]
116
+ standard_deviation: nt.ProcNode[TAttribute]
117
+ sum: nt.ProcNode[TAttribute]
118
+ variance: nt.ProcNode[TAttribute]
119
+
120
+
121
+ def attribute_statistic(
122
+ geometry: nt.ProcNode[nt.Geometry],
123
+ attribute: nt.ProcNode[TAttribute] | None = None,
124
+ selection: nt.SocketOrVal[bool] = True,
125
+ domain: TDomain = "POINT",
126
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
127
+ ) -> AttributeStatisticResult[TAttribute]:
128
+ """
129
+ Uses a AttributeStatistic Geometry Node.
130
+
131
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/attribute/attribute_statistic.html
132
+ """
133
+
134
+ if data_type is None:
135
+ data_type = RuntimeResolveDataType(
136
+ [
137
+ NodeDataType.INT,
138
+ NodeDataType.FLOAT,
139
+ NodeDataType.FLOAT_VECTOR,
140
+ NodeDataType.RGBA,
141
+ ],
142
+ ["Attribute"],
143
+ )
144
+
145
+ res = nt.ProcNode.from_nodetype(
146
+ node_type="GeometryNodeAttributeStatistic",
147
+ inputs={"Attribute": attribute, "Geometry": geometry, "Selection": selection},
148
+ attrs={"domain": domain, "data_type": data_type},
149
+ )
150
+ return AttributeStatisticResult(
151
+ max=res._output_socket("max"),
152
+ mean=res._output_socket("mean"),
153
+ median=res._output_socket("median"),
154
+ min=res._output_socket("min"),
155
+ range=res._output_socket("range"),
156
+ standard_deviation=res._output_socket("standard_deviation"),
157
+ sum=res._output_socket("sum"),
158
+ variance=res._output_socket("variance"),
159
+ )
160
+
161
+
162
+ def blur_attribute(
163
+ value: nt.ProcNode[TAttribute] | None = None,
164
+ iterations: nt.SocketOrVal[int] = 1,
165
+ weight: nt.SocketOrVal[float] = 1.0,
166
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
167
+ ) -> nt.ProcNode[TAttribute]:
168
+ """
169
+ Uses a BlurAttribute Geometry Node.
170
+
171
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/attribute/blur_attribute.html
172
+ """
173
+ if data_type is None:
174
+ data_type = RuntimeResolveDataType(
175
+ [NodeDataType.INT, NodeDataType.FLOAT],
176
+ ["Value"],
177
+ )
178
+ return nt.ProcNode.from_nodetype(
179
+ node_type="GeometryNodeBlurAttribute",
180
+ inputs={"Iterations": iterations, "Value": value, "Weight": weight},
181
+ attrs={
182
+ "data_type": data_type,
183
+ },
184
+ )
185
+
186
+
187
+ class BoundBoxResult(NamedTuple):
188
+ bounding_box: nt.ProcNode[pt.MeshObject]
189
+ min: nt.ProcNode[pt.Vector]
190
+ max: nt.ProcNode[pt.Vector]
191
+
192
+
193
+ def bound_box(geometry: nt.ProcNode[nt.Geometry]) -> BoundBoxResult:
194
+ """
195
+ Uses a BoundBox Geometry Node.
196
+
197
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/bounding_box.html
198
+ """
199
+ node = nt.ProcNode.from_nodetype(
200
+ node_type="GeometryNodeBoundBox",
201
+ inputs={"Geometry": geometry},
202
+ attrs={},
203
+ )
204
+ return BoundBoxResult(
205
+ node._output_socket("bounding_box"),
206
+ node._output_socket("min"),
207
+ node._output_socket("max"),
208
+ )
209
+
210
+
211
+ @dataclass
212
+ class CaptureAttributeResult(Generic[TAnyGeometry]):
213
+ geometry: nt.ProcNode[TAnyGeometry]
214
+ attributes: dict[str, nt.ProcNode]
215
+
216
+ def __getattr__(self, name: str) -> nt.ProcNode:
217
+ if name in self.attributes:
218
+ return self.attributes[name]
219
+ else:
220
+ return object.__getattribute__(self, name)
221
+
222
+
223
+ def capture_attribute(
224
+ geometry: nt.ProcNode[TAnyGeometry],
225
+ # active_index: int = 0, # TODO unsure how active_* function
226
+ # active_item: Any = None,
227
+ domain: TDomain = "POINT",
228
+ **attributes: nt.SocketOrVal[TAttribute],
229
+ ) -> CaptureAttributeResult[TAnyGeometry]:
230
+ """
231
+ Uses a CaptureAttribute Geometry Node.
232
+
233
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/attribute/capture_attribute.html
234
+ """
235
+ res = nt.ProcNode.from_nodetype(
236
+ node_type="GeometryNodeCaptureAttribute",
237
+ inputs={"Geometry": geometry, **attributes},
238
+ attrs={
239
+ "domain": domain,
240
+ },
241
+ )
242
+ return CaptureAttributeResult(
243
+ geometry=res._output_socket("geometry"),
244
+ attributes={k: res._output_socket(k) for k in attributes.keys()},
245
+ )
246
+
247
+
248
+ def collection_info(
249
+ collection: nt.SocketOrVal[pt.Collection],
250
+ separate_children: nt.SocketOrVal[bool] = False,
251
+ reset_children: nt.SocketOrVal[bool] = False,
252
+ transform_space: Literal["ORIGINAL", "RELATIVE"] = "ORIGINAL",
253
+ ) -> nt.ProcNode[nt.Instances]:
254
+ """
255
+ Uses a CollectionInfo Geometry Node.
256
+
257
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/collection_info.html
258
+ """
259
+ return nt.ProcNode.from_nodetype(
260
+ node_type="GeometryNodeCollectionInfo",
261
+ inputs={
262
+ "Collection": collection,
263
+ "Separate Children": separate_children,
264
+ "Reset Children": reset_children,
265
+ },
266
+ attrs={"transform_space": transform_space},
267
+ )
268
+
269
+
270
+ def convex_hull(geometry: nt.ProcNode[nt.Geometry]) -> nt.ProcNode[pt.MeshObject]:
271
+ """
272
+ Uses a ConvexHull Geometry Node.
273
+
274
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/convex_hull.html
275
+ """
276
+ return nt.ProcNode.from_nodetype(
277
+ node_type="GeometryNodeConvexHull",
278
+ inputs={"Geometry": geometry},
279
+ attrs={},
280
+ )
281
+
282
+
283
+ class CornerResult(NamedTuple):
284
+ corner_index: nt.ProcNode[int]
285
+ total: nt.ProcNode[int]
286
+
287
+
288
+ def corners_of_edge(
289
+ edge_index: nt.SocketOrVal[int] = 0,
290
+ weights: nt.SocketOrVal[float] = 0.0,
291
+ sort_index: nt.SocketOrVal[int] = 0,
292
+ ) -> CornerResult:
293
+ """
294
+ Uses a CornersOfEdge Geometry Node.
295
+
296
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/corners_of_edge.html
297
+ """
298
+ res = nt.ProcNode.from_nodetype(
299
+ node_type="GeometryNodeCornersOfEdge",
300
+ inputs={"Edge Index": edge_index, "Weights": weights, "Sort Index": sort_index},
301
+ attrs={},
302
+ )
303
+ return CornerResult(
304
+ corner_index=res._output_socket("corner_index"),
305
+ total=res._output_socket("total"),
306
+ )
307
+
308
+
309
+ def corners_of_face(
310
+ face_index: nt.SocketOrVal[int] = 0,
311
+ weights: nt.SocketOrVal[float] = 0.0,
312
+ sort_index: nt.SocketOrVal[int] = 0,
313
+ ) -> CornerResult:
314
+ """
315
+ Uses a CornersOfFace Geometry Node.
316
+
317
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/corners_of_face.html
318
+ """
319
+ res = nt.ProcNode.from_nodetype(
320
+ node_type="GeometryNodeCornersOfFace",
321
+ inputs={"Face Index": face_index, "Weights": weights, "Sort Index": sort_index},
322
+ attrs={},
323
+ )
324
+ return CornerResult(
325
+ corner_index=res._output_socket("corner_index"),
326
+ total=res._output_socket("total"),
327
+ )
328
+
329
+
330
+ def corners_of_vertex(
331
+ vertex_index: nt.SocketOrVal[int] = 0,
332
+ weights: nt.SocketOrVal[float] = 0.0,
333
+ sort_index: nt.SocketOrVal[int] = 0,
334
+ ) -> CornerResult:
335
+ """
336
+ Uses a CornersOfVertex Geometry Node.
337
+
338
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/corners_of_vertex.html
339
+ """
340
+ res = nt.ProcNode.from_nodetype(
341
+ node_type="GeometryNodeCornersOfVertex",
342
+ inputs={
343
+ "Vertex Index": vertex_index,
344
+ "Weights": weights,
345
+ "Sort Index": sort_index,
346
+ },
347
+ attrs={},
348
+ )
349
+ return CornerResult(
350
+ corner_index=res._output_socket("corner_index"),
351
+ total=res._output_socket("total"),
352
+ )
353
+
354
+
355
+ def curve_arc(
356
+ resolution: nt.SocketOrVal[int] = 16,
357
+ radius: nt.SocketOrVal[float] = 1.0,
358
+ start_angle: nt.SocketOrVal[float] = 0.0,
359
+ sweep_angle: nt.SocketOrVal[float] = 5.497787,
360
+ connect_center: nt.SocketOrVal[bool] = False,
361
+ invert_arc: nt.SocketOrVal[bool] = False,
362
+ mode: Literal["POINTS", "RADIUS"] = "RADIUS",
363
+ ) -> nt.ProcNode[pt.CurveObject]:
364
+ """
365
+ Uses a CurveArc Geometry Node.
366
+
367
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/arc.html
368
+ """
369
+ return nt.ProcNode.from_nodetype(
370
+ node_type="GeometryNodeCurveArc",
371
+ inputs={
372
+ "Resolution": resolution,
373
+ "Radius": radius,
374
+ "Start Angle": start_angle,
375
+ "Sweep Angle": sweep_angle,
376
+ "Connect Center": connect_center,
377
+ "Invert Arc": invert_arc,
378
+ },
379
+ attrs={"mode": mode},
380
+ )
381
+
382
+
383
+ def curve_endpoint_selection(
384
+ start_size: nt.SocketOrVal[int] = 1, end_size: nt.SocketOrVal[int] = 1
385
+ ) -> nt.ProcNode[bool]:
386
+ """
387
+ Uses a CurveEndpointSelection Geometry Node.
388
+
389
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/endpoint_selection.html
390
+ """
391
+ return nt.ProcNode.from_nodetype(
392
+ node_type="GeometryNodeCurveEndpointSelection",
393
+ inputs={"Start Size": start_size, "End Size": end_size},
394
+ attrs={},
395
+ )
396
+
397
+
398
+ # def curve_handle_type_selection(
399
+ # handle_type: Literal["FREE", "AUTO", "VECTOR", "ALIGN"] = "AUTO",
400
+ # mode: Literal["LEFT", "RIGHT"] = "RIGHT",
401
+ # ) -> t.ProcNode:
402
+ # """
403
+ # Uses a CurveHandleTypeSelection Geometry Node.
404
+ #
405
+ # See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/handle_type_selection.html
406
+ # """
407
+ # return t.ProcNode.from_nodetype(
408
+ # node_type="GeometryNodeCurveHandleTypeSelection",
409
+ # inputs={},
410
+ # attrs={"handle_type": handle_type, "mode": mode},
411
+ # )
412
+
413
+
414
+ def curve_length(curve: nt.ProcNode[pt.CurveObject]) -> nt.ProcNode[float]:
415
+ """
416
+ Uses a CurveLength Geometry Node.
417
+
418
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/curve_length.html
419
+ """
420
+ return nt.ProcNode.from_nodetype(
421
+ node_type="GeometryNodeCurveLength",
422
+ inputs={"Curve": curve},
423
+ attrs={},
424
+ )
425
+
426
+
427
+ class CurveOfPointResult(NamedTuple):
428
+ curve_index: nt.ProcNode[int]
429
+ index_in_curve: nt.ProcNode[int]
430
+
431
+
432
+ def curve_of_point(point_index: nt.SocketOrVal[int] = 0) -> CurveOfPointResult:
433
+ """
434
+ Uses a CurveOfPoint Geometry Node.
435
+
436
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/topology/curve_of_point.html
437
+ """
438
+ node = nt.ProcNode.from_nodetype(
439
+ node_type="GeometryNodeCurveOfPoint",
440
+ inputs={"Point Index": point_index},
441
+ attrs={},
442
+ )
443
+ return CurveOfPointResult(
444
+ node._output_socket("curve_index"), node._output_socket("index_in_curve")
445
+ )
446
+
447
+
448
+ def curve_bezier_segment(
449
+ resolution: nt.SocketOrVal[int] = 16,
450
+ start: nt.SocketOrVal[nt.pt.Vector] = (-1, 0, 0),
451
+ start_handle: nt.SocketOrVal[nt.pt.Vector] = (-0.5, 0.5, 0),
452
+ end_handle: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
453
+ end: nt.SocketOrVal[nt.pt.Vector] = (1, 0, 0),
454
+ mode: Literal["POSITION", "OFFSET"] = "POSITION",
455
+ ) -> nt.ProcNode[pt.CurveObject]:
456
+ """
457
+ Uses a CurvePrimitiveBezierSegment Geometry Node.
458
+
459
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/bezier_segment.html
460
+ """
461
+ return nt.ProcNode.from_nodetype(
462
+ node_type="GeometryNodeCurvePrimitiveBezierSegment",
463
+ inputs={
464
+ "Resolution": resolution,
465
+ "Start": start,
466
+ "Start Handle": start_handle,
467
+ "End Handle": end_handle,
468
+ "End": end,
469
+ },
470
+ attrs={"mode": mode},
471
+ )
472
+
473
+
474
+ def curve_circle(
475
+ resolution: nt.SocketOrVal[int] = 32,
476
+ radius: nt.SocketOrVal[float] = 1.0,
477
+ mode: Literal["POINTS", "RADIUS"] = "RADIUS",
478
+ ) -> nt.ProcNode[pt.CurveObject]:
479
+ """
480
+ Uses a CurvePrimitiveCircle Geometry Node.
481
+
482
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/curve_circle.html
483
+ """
484
+ return nt.ProcNode.from_nodetype(
485
+ node_type="GeometryNodeCurvePrimitiveCircle",
486
+ inputs={"Resolution": resolution, "Radius": radius},
487
+ attrs={"mode": mode},
488
+ )
489
+
490
+
491
+ def curve_line(
492
+ start: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
493
+ end: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 1),
494
+ ) -> nt.ProcNode[pt.CurveObject]:
495
+ """
496
+ Uses a CurvePrimitiveLine Geometry Node.
497
+
498
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/curve_line.html
499
+ """
500
+ return nt.ProcNode.from_nodetype(
501
+ node_type="GeometryNodeCurvePrimitiveLine",
502
+ inputs={"Start": start, "End": end},
503
+ attrs={"mode": "POINTS"},
504
+ )
505
+
506
+
507
+ def curve_line_from_direction(
508
+ start: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
509
+ direction: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 1),
510
+ length: nt.SocketOrVal[float] = 1.0,
511
+ ) -> nt.ProcNode[pt.CurveObject]:
512
+ """
513
+ Uses a CurveLineFromDirection Geometry Node.
514
+
515
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/curve_line.html
516
+ """
517
+ return nt.ProcNode.from_nodetype(
518
+ node_type="GeometryNodeCurveLineFromDirection",
519
+ inputs={"Start": start, "Direction": direction, "Length": length},
520
+ attrs={"mode": "DIRECTION"},
521
+ )
522
+
523
+
524
+ def curve_quadrilateral(
525
+ width: nt.SocketOrVal[float] = 2.0,
526
+ height: nt.SocketOrVal[float] = 2.0,
527
+ mode: Literal[
528
+ "RECTANGLE", "PARALLELOGRAM", "TRAPEZOID", "KITE", "POINTS"
529
+ ] = "RECTANGLE",
530
+ ) -> nt.ProcNode[pt.CurveObject]:
531
+ """
532
+ Uses a CurvePrimitiveQuadrilateral Geometry Node.
533
+
534
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/quadrilateral.html
535
+ """
536
+ return nt.ProcNode.from_nodetype(
537
+ node_type="GeometryNodeCurvePrimitiveQuadrilateral",
538
+ inputs={"Width": width, "Height": height},
539
+ attrs={"mode": mode},
540
+ )
541
+
542
+
543
+ def curve_bezier(
544
+ resolution: nt.SocketOrVal[int] = 16,
545
+ start: nt.SocketOrVal[nt.pt.Vector] = (-1, 0, 0),
546
+ middle: nt.SocketOrVal[nt.pt.Vector] = (0, 2, 0),
547
+ end: nt.SocketOrVal[nt.pt.Vector] = (1, 0, 0),
548
+ ) -> nt.ProcNode[pt.CurveObject]:
549
+ """
550
+ Uses a CurveQuadraticBezier Geometry Node.
551
+
552
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/quadratic_bezier.html
553
+ """
554
+ return nt.ProcNode.from_nodetype(
555
+ node_type="GeometryNodeCurveQuadraticBezier",
556
+ inputs={"Resolution": resolution, "Start": start, "Middle": middle, "End": end},
557
+ attrs={},
558
+ )
559
+
560
+
561
+ def curve_set_handles(
562
+ curve: nt.ProcNode[pt.CurveObject],
563
+ selection: nt.SocketOrVal[bool] = True,
564
+ handle_type: Literal["FREE", "AUTO", "VECTOR", "ALIGN"] = "AUTO",
565
+ mode: Literal["LEFT", "RIGHT"] = "RIGHT",
566
+ ) -> nt.ProcNode[pt.CurveObject]:
567
+ """
568
+ Uses a CurveSetHandles Geometry Node.
569
+
570
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_handle_type.html
571
+ """
572
+ return nt.ProcNode.from_nodetype(
573
+ node_type="GeometryNodeCurveSetHandles",
574
+ inputs={"Curve": curve, "Selection": selection},
575
+ attrs={"handle_type": handle_type, "mode": mode},
576
+ )
577
+
578
+
579
+ def curve_spiral(
580
+ resolution: nt.SocketOrVal[int] = 32,
581
+ rotations: nt.SocketOrVal[float] = 2.0,
582
+ start_radius: nt.SocketOrVal[float] = 1.0,
583
+ end_radius: nt.SocketOrVal[float] = 2.0,
584
+ height: nt.SocketOrVal[float] = 2.0,
585
+ reverse: nt.SocketOrVal[bool] = False,
586
+ ) -> nt.ProcNode[pt.CurveObject]:
587
+ """
588
+ Uses a CurveSpiral Geometry Node.
589
+
590
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/curve_spiral.html
591
+ """
592
+ return nt.ProcNode.from_nodetype(
593
+ node_type="GeometryNodeCurveSpiral",
594
+ inputs={
595
+ "Resolution": resolution,
596
+ "Rotations": rotations,
597
+ "Start Radius": start_radius,
598
+ "End Radius": end_radius,
599
+ "Height": height,
600
+ "Reverse": reverse,
601
+ },
602
+ attrs={},
603
+ )
604
+
605
+
606
+ def curve_spline_type(
607
+ curve: nt.ProcNode[pt.CurveObject],
608
+ selection: nt.SocketOrVal[bool] = True,
609
+ spline_type: Literal["CATMULL_ROM", "POLY", "BEZIER", "NURBS"] = "POLY",
610
+ ) -> nt.ProcNode[pt.CurveObject]:
611
+ """
612
+ Uses a CurveSplineType Geometry Node.
613
+
614
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_spline_type.html
615
+ """
616
+ return nt.ProcNode.from_nodetype(
617
+ node_type="GeometryNodeCurveSplineType",
618
+ inputs={"Curve": curve, "Selection": selection},
619
+ attrs={"spline_type": spline_type},
620
+ )
621
+
622
+
623
+ class CurveStarResult(NamedTuple):
624
+ curve: nt.ProcNode[pt.CurveObject]
625
+ outer_points: nt.ProcNode[bool]
626
+
627
+
628
+ def curve_star(
629
+ points: nt.SocketOrVal[int] = 8,
630
+ inner_radius: nt.SocketOrVal[float] = 1.0,
631
+ outer_radius: nt.SocketOrVal[float] = 2.0,
632
+ twist: nt.SocketOrVal[float] = 0.0,
633
+ ) -> CurveStarResult:
634
+ """
635
+ Uses a CurveStar Geometry Node.
636
+
637
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/star.html
638
+ """
639
+ res = nt.ProcNode.from_nodetype(
640
+ node_type="GeometryNodeCurveStar",
641
+ inputs={
642
+ "Points": points,
643
+ "Inner Radius": inner_radius,
644
+ "Outer Radius": outer_radius,
645
+ "Twist": twist,
646
+ },
647
+ attrs={},
648
+ )
649
+ return CurveStarResult(
650
+ curve=res._output_socket("curve"),
651
+ outer_points=res._output_socket("outer_points"),
652
+ )
653
+
654
+
655
+ def curve_to_mesh(
656
+ curve: nt.ProcNode[pt.CurveObject],
657
+ profile_curve: nt.ProcNode[pt.CurveObject] | None = None,
658
+ fill_caps: nt.SocketOrVal[bool] = False,
659
+ ) -> nt.ProcNode[pt.MeshObject]:
660
+ """
661
+ Uses a CurveToMesh Geometry Node.
662
+
663
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/curve_to_mesh.html
664
+ """
665
+ return nt.ProcNode.from_nodetype(
666
+ node_type="GeometryNodeCurveToMesh",
667
+ inputs={"Curve": curve, "Profile Curve": profile_curve, "Fill Caps": fill_caps},
668
+ attrs={},
669
+ )
670
+
671
+
672
+ class CurveToPointsResult(NamedTuple):
673
+ points: nt.ProcNode[pt.MeshObject]
674
+ tangent: nt.ProcNode[pt.Vector]
675
+ normal: nt.ProcNode[pt.Vector]
676
+ rotation: nt.ProcNode[pt.Vector]
677
+
678
+
679
+ def curve_to_points(
680
+ curve: nt.ProcNode[pt.CurveObject],
681
+ count: nt.SocketOrVal[int] = 10,
682
+ length: nt.SocketOrVal[float] = 1.0,
683
+ mode: Literal["EVALUATED", "COUNT", "LENGTH"] = "COUNT",
684
+ ) -> CurveToPointsResult:
685
+ """
686
+ Uses a CurveToPoints Geometry Node.
687
+
688
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/curve_to_points.html
689
+ """
690
+ inputs = {"Curve": curve}
691
+ if mode == "COUNT":
692
+ inputs["Count"] = count
693
+ elif mode == "LENGTH":
694
+ inputs["Length"] = length
695
+ res = nt.ProcNode.from_nodetype(
696
+ node_type="GeometryNodeCurveToPoints",
697
+ inputs=inputs,
698
+ attrs={"mode": mode},
699
+ )
700
+ return CurveToPointsResult(
701
+ points=res._output_socket("points"),
702
+ tangent=res._output_socket("tangent"),
703
+ normal=res._output_socket("normal"),
704
+ rotation=res._output_socket("rotation"),
705
+ )
706
+
707
+
708
+ def curve_to_points_evaluated(
709
+ curve: nt.ProcNode[pt.CurveObject],
710
+ ) -> CurveToPointsResult:
711
+ """
712
+ Uses a CurveToPoints Geometry Node with mode="EVALUATED".
713
+
714
+ From Blender docs: Creates points based on how the curve is evaluated.
715
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/curve_to_points.html
716
+ """
717
+ res = nt.ProcNode.from_nodetype(
718
+ node_type="GeometryNodeCurveToPoints",
719
+ inputs={"Curve": curve},
720
+ attrs={"mode": "EVALUATED"},
721
+ )
722
+ return CurveToPointsResult(
723
+ points=res._output_socket("points"),
724
+ tangent=res._output_socket("tangent"),
725
+ normal=res._output_socket("normal"),
726
+ rotation=res._output_socket("rotation"),
727
+ )
728
+
729
+
730
+ def curve_to_points_count(
731
+ curve: nt.ProcNode[pt.CurveObject],
732
+ count: nt.SocketOrVal[int] = 10,
733
+ ) -> CurveToPointsResult:
734
+ """
735
+ Uses a CurveToPoints Geometry Node with mode="COUNT".
736
+
737
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/curve_to_points.html
738
+ """
739
+ res = nt.ProcNode.from_nodetype(
740
+ node_type="GeometryNodeCurveToPoints",
741
+ inputs={"Curve": curve, "Count": count},
742
+ attrs={"mode": "COUNT"},
743
+ )
744
+ return CurveToPointsResult(
745
+ points=res._output_socket("points"),
746
+ tangent=res._output_socket("tangent"),
747
+ normal=res._output_socket("normal"),
748
+ rotation=res._output_socket("rotation"),
749
+ )
750
+
751
+
752
+ def curve_to_points_length(
753
+ curve: nt.ProcNode[pt.CurveObject],
754
+ length: nt.SocketOrVal[float] = 0.1,
755
+ ) -> CurveToPointsResult:
756
+ """
757
+ Uses a CurveToPoints Geometry Node with mode="LENGTH".
758
+
759
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/curve_to_points.html
760
+ """
761
+ res = nt.ProcNode.from_nodetype(
762
+ node_type="GeometryNodeCurveToPoints",
763
+ inputs={"Curve": curve, "Length": length},
764
+ attrs={"mode": "LENGTH"},
765
+ )
766
+ return CurveToPointsResult(
767
+ points=res._output_socket("points"),
768
+ tangent=res._output_socket("tangent"),
769
+ normal=res._output_socket("normal"),
770
+ rotation=res._output_socket("rotation"),
771
+ )
772
+
773
+
774
+ def deform_curves_on_surface(
775
+ curves: nt.ProcNode[pt.HairObject],
776
+ ) -> nt.ProcNode[pt.HairObject]:
777
+ """
778
+ Uses a DeformCurvesOnSurface Geometry Node.
779
+
780
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/deform_curves_on_surface.html
781
+ """
782
+ return nt.ProcNode.from_nodetype(
783
+ node_type="GeometryNodeDeformCurvesOnSurface",
784
+ inputs={"Curves": curves},
785
+ attrs={},
786
+ )
787
+
788
+
789
+ TDeleteGeometry = TypeVar(
790
+ "TDeleteGeometry",
791
+ nt.ProcNode[pt.MeshObject],
792
+ nt.ProcNode[pt.CurveObject],
793
+ )
794
+
795
+
796
+ def delete_geometry(
797
+ geometry: nt.ProcNode[TDeleteGeometry],
798
+ selection: nt.SocketOrVal[bool] = True,
799
+ domain: Literal["POINT", "EDGE", "FACE", "CURVE", "INSTANCE", "LAYER"] = "POINT",
800
+ mode: Literal["ALL", "EDGE_FACE", "ONLY_FACE"] = "ALL",
801
+ ) -> nt.ProcNode[TDeleteGeometry]:
802
+ """
803
+ Uses a DeleteGeometry Geometry Node.
804
+
805
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/delete_geometry.html
806
+ """
807
+ return nt.ProcNode.from_nodetype(
808
+ node_type="GeometryNodeDeleteGeometry",
809
+ inputs={"Geometry": geometry, "Selection": selection},
810
+ attrs={"domain": domain, "mode": mode},
811
+ )
812
+
813
+
814
+ def distribute_points_in_grid(
815
+ grid: nt.SocketOrVal[float] = 0.0,
816
+ density: nt.SocketOrVal[float] = 1.0,
817
+ seed: nt.SocketOrVal[int] = 0,
818
+ mode: Literal["DENSITY_RANDOM", "DENSITY_GRID"] = "DENSITY_RANDOM",
819
+ ) -> nt.ProcNode[pt.MeshObject]:
820
+ """
821
+ Uses a DistributePointsInGrid Geometry Node.
822
+
823
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/distribute_points_in_volume.html
824
+ """
825
+ return nt.ProcNode.from_nodetype(
826
+ node_type="GeometryNodeDistributePointsInGrid",
827
+ inputs={"Grid": grid, "Density": density, "Seed": seed},
828
+ attrs={"mode": mode},
829
+ )
830
+
831
+
832
+ def distribute_points_in_volume(
833
+ volume: nt.ProcNode[pt.VolumeObject],
834
+ density: nt.SocketOrVal[float] = 1.0,
835
+ seed: nt.SocketOrVal[int] = 0,
836
+ mode: Literal["DENSITY_RANDOM", "DENSITY_GRID"] = "DENSITY_RANDOM",
837
+ ) -> nt.ProcNode[pt.VolumeObject]:
838
+ """
839
+ Uses a DistributePointsInVolume Geometry Node.
840
+
841
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/distribute_points_in_volume.html
842
+ """
843
+ return nt.ProcNode.from_nodetype(
844
+ node_type="GeometryNodeDistributePointsInVolume",
845
+ inputs={"Volume": volume, "Density": density, "Seed": seed},
846
+ attrs={"mode": mode},
847
+ )
848
+
849
+
850
+ class DistributePointsOnFacesResult(NamedTuple):
851
+ points: nt.ProcNode[pt.MeshObject]
852
+ normal: nt.ProcNode[pt.Vector]
853
+ rotation: nt.ProcNode[pt.Vector]
854
+
855
+
856
+ def distribute_points_on_faces(
857
+ mesh: nt.ProcNode[pt.MeshObject],
858
+ selection: nt.SocketOrVal[bool] = True,
859
+ density: nt.SocketOrVal[float] | None = None,
860
+ seed: nt.SocketOrVal[int] = 0,
861
+ use_legacy_normal: bool = False,
862
+ ) -> DistributePointsOnFacesResult:
863
+ """
864
+ Uses a DistributePointsOnFaces Geometry Node with RANDOM distribution.
865
+
866
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/distribute_points_on_faces.html
867
+ """
868
+ inputs: dict = {
869
+ "Mesh": mesh,
870
+ "Selection": selection,
871
+ "Seed": seed,
872
+ }
873
+ if density is not None:
874
+ inputs["Density"] = density
875
+
876
+ res = nt.ProcNode.from_nodetype(
877
+ node_type="GeometryNodeDistributePointsOnFaces",
878
+ inputs=inputs,
879
+ attrs={
880
+ "distribute_method": "RANDOM",
881
+ "use_legacy_normal": use_legacy_normal,
882
+ },
883
+ )
884
+ return DistributePointsOnFacesResult(
885
+ points=res._output_socket("points"),
886
+ normal=res._output_socket("normal"),
887
+ rotation=res._output_socket("rotation"),
888
+ )
889
+
890
+
891
+ def distribute_points_on_faces_poisson(
892
+ mesh: nt.ProcNode[pt.MeshObject],
893
+ selection: nt.SocketOrVal[bool] = True,
894
+ distance_min: nt.SocketOrVal[float] = 0.0,
895
+ density_max: nt.SocketOrVal[float] = 10.0,
896
+ density_factor: nt.SocketOrVal[float] = 1.0,
897
+ seed: nt.SocketOrVal[int] = 0,
898
+ use_legacy_normal: bool = False,
899
+ ) -> DistributePointsOnFacesResult:
900
+ """
901
+ Uses a DistributePointsOnFaces Geometry Node with POISSON distribution.
902
+
903
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/distribute_points_on_faces.html
904
+ """
905
+ res = nt.ProcNode.from_nodetype(
906
+ node_type="GeometryNodeDistributePointsOnFaces",
907
+ inputs={
908
+ "Mesh": mesh,
909
+ "Selection": selection,
910
+ "Distance Min": distance_min,
911
+ "Density Max": density_max,
912
+ "Density Factor": density_factor,
913
+ "Seed": seed,
914
+ },
915
+ attrs={
916
+ "distribute_method": "POISSON",
917
+ "use_legacy_normal": use_legacy_normal,
918
+ },
919
+ )
920
+ return DistributePointsOnFacesResult(
921
+ points=res._output_socket("points"),
922
+ normal=res._output_socket("normal"),
923
+ rotation=res._output_socket("rotation"),
924
+ )
925
+
926
+
927
+ def dual_mesh(
928
+ mesh: nt.ProcNode[pt.MeshObject], keep_boundaries: nt.SocketOrVal[bool] = False
929
+ ) -> nt.ProcNode[pt.MeshObject]:
930
+ """
931
+ Uses a DualMesh Geometry Node.
932
+
933
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/dual_mesh.html
934
+ """
935
+ return nt.ProcNode.from_nodetype(
936
+ node_type="GeometryNodeDualMesh",
937
+ inputs={"Mesh": mesh, "Keep Boundaries": keep_boundaries},
938
+ attrs={},
939
+ )
940
+
941
+
942
+ class DuplicateElementsResult(NamedTuple, Generic[TAnyGeometry]):
943
+ geometry: nt.ProcNode[TAnyGeometry]
944
+ duplicate_index: nt.ProcNode[int]
945
+
946
+
947
+ def duplicate_elements(
948
+ geometry: nt.ProcNode[TAnyGeometry],
949
+ selection: nt.SocketOrVal[bool] = True,
950
+ amount: nt.SocketOrVal[int] = 1,
951
+ domain: Literal["POINT", "EDGE", "FACE", "SPLINE", "INSTANCE"] = "POINT",
952
+ ) -> DuplicateElementsResult[TAnyGeometry]:
953
+ """
954
+ Uses a DuplicateElements Geometry Node.
955
+
956
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/duplicate_elements.html
957
+ """
958
+ res = nt.ProcNode.from_nodetype(
959
+ node_type="GeometryNodeDuplicateElements",
960
+ inputs={"Geometry": geometry, "Selection": selection, "Amount": amount},
961
+ attrs={"domain": domain},
962
+ )
963
+ return DuplicateElementsResult(
964
+ geometry=res._output_socket("Geometry"),
965
+ duplicate_index=res._output_socket("Duplicate Index"),
966
+ )
967
+
968
+
969
+ def edge_paths_to_curves(
970
+ mesh: nt.ProcNode[pt.MeshObject],
971
+ start_vertices: nt.SocketOrVal[bool] = True,
972
+ next_vertex_index: nt.SocketOrVal[int] = -1,
973
+ ) -> nt.ProcNode[pt.CurveObject]:
974
+ """
975
+ Uses a EdgePathsToCurves Geometry Node.
976
+
977
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/edge_paths_to_curves.html
978
+ """
979
+ return nt.ProcNode.from_nodetype(
980
+ node_type="GeometryNodeEdgePathsToCurves",
981
+ inputs={
982
+ "Mesh": mesh,
983
+ "Start Vertices": start_vertices,
984
+ "Next Vertex Index": next_vertex_index,
985
+ },
986
+ attrs={},
987
+ )
988
+
989
+
990
+ def edge_paths_to_selection(
991
+ start_vertices: nt.SocketOrVal[bool] = True,
992
+ next_vertex_index: nt.SocketOrVal[int] = -1,
993
+ ) -> nt.ProcNode[bool]:
994
+ """
995
+ Uses a EdgePathsToSelection Geometry Node.
996
+
997
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/edge_paths_to_selection.html
998
+ """
999
+ return nt.ProcNode.from_nodetype(
1000
+ node_type="GeometryNodeEdgePathsToSelection",
1001
+ inputs={
1002
+ "Start Vertices": start_vertices,
1003
+ "Next Vertex Index": next_vertex_index,
1004
+ },
1005
+ attrs={},
1006
+ )
1007
+
1008
+
1009
+ class EdgesOfCornerResult(NamedTuple):
1010
+ next_edge_index: nt.ProcNode[int]
1011
+ previous_edge_index: nt.ProcNode[int]
1012
+
1013
+
1014
+ def edges_of_corner(corner_index: nt.SocketOrVal[int] = 0) -> EdgesOfCornerResult:
1015
+ """
1016
+ Uses a EdgesOfCorner Geometry Node.
1017
+
1018
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/edges_of_corner.html
1019
+ """
1020
+ res = nt.ProcNode.from_nodetype(
1021
+ node_type="GeometryNodeEdgesOfCorner",
1022
+ inputs={"Corner Index": corner_index},
1023
+ attrs={},
1024
+ )
1025
+ return EdgesOfCornerResult(
1026
+ next_edge_index=res._output_socket("next_edge_index"),
1027
+ previous_edge_index=res._output_socket("previous_edge_index"),
1028
+ )
1029
+
1030
+
1031
+ class EdgesOfVertexResult(NamedTuple):
1032
+ edge_index: nt.ProcNode[int]
1033
+ total: nt.ProcNode[int]
1034
+
1035
+
1036
+ def edges_of_vertex(
1037
+ vertex_index: nt.SocketOrVal[int] = 0,
1038
+ weights: nt.SocketOrVal[float] = 0.0,
1039
+ sort_index: nt.SocketOrVal[int] = 0,
1040
+ ) -> EdgesOfVertexResult:
1041
+ """
1042
+ Uses a EdgesOfVertex Geometry Node.
1043
+
1044
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/edges_of_vertex.html
1045
+ """
1046
+ res = nt.ProcNode.from_nodetype(
1047
+ node_type="GeometryNodeEdgesOfVertex",
1048
+ inputs={
1049
+ "Vertex Index": vertex_index,
1050
+ "Weights": weights,
1051
+ "Sort Index": sort_index,
1052
+ },
1053
+ attrs={},
1054
+ )
1055
+ return EdgesOfVertexResult(
1056
+ edge_index=res._output_socket("edge_index"),
1057
+ total=res._output_socket("total"),
1058
+ )
1059
+
1060
+
1061
+ def edges_to_face_groups(
1062
+ boundary_edges: nt.SocketOrVal[bool] = True,
1063
+ ) -> nt.ProcNode[int]:
1064
+ """
1065
+ Uses a EdgesToFaceGroups Geometry Node.
1066
+
1067
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/edges_to_face_groups.html
1068
+ """
1069
+ return nt.ProcNode.from_nodetype(
1070
+ node_type="GeometryNodeEdgesToFaceGroups",
1071
+ inputs={"Boundary Edges": boundary_edges},
1072
+ attrs={},
1073
+ )
1074
+
1075
+
1076
+ class ExtrudeMeshResult(NamedTuple):
1077
+ mesh: nt.ProcNode[pt.MeshObject]
1078
+ top: nt.ProcNode[bool]
1079
+ side: nt.ProcNode[bool]
1080
+
1081
+
1082
+ def extrude_mesh(
1083
+ mesh: nt.ProcNode[pt.MeshObject],
1084
+ selection: nt.SocketOrVal[bool] = True,
1085
+ offset: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1086
+ offset_scale: nt.SocketOrVal[float] = 1.0,
1087
+ individual: nt.SocketOrVal[bool] = True,
1088
+ mode: Literal["VERTICES", "EDGES", "FACES"] = "FACES",
1089
+ ) -> ExtrudeMeshResult:
1090
+ node = nt.ProcNode.from_nodetype(
1091
+ node_type="GeometryNodeExtrudeMesh",
1092
+ inputs={
1093
+ "Mesh": mesh,
1094
+ "Selection": selection,
1095
+ "Offset": offset,
1096
+ "Offset Scale": offset_scale,
1097
+ "Individual": individual,
1098
+ },
1099
+ attrs={"mode": mode},
1100
+ )
1101
+ return ExtrudeMeshResult(
1102
+ node._output_socket("mesh"),
1103
+ node._output_socket("top"),
1104
+ node._output_socket("side"),
1105
+ )
1106
+
1107
+
1108
+ class FaceOfCornerResult(NamedTuple):
1109
+ face_index: nt.ProcNode[int]
1110
+ index_in_face: nt.ProcNode[int]
1111
+
1112
+
1113
+ def face_of_corner(corner_index: nt.SocketOrVal[int] = 0) -> FaceOfCornerResult:
1114
+ """
1115
+ Uses a FaceOfCorner Geometry Node.
1116
+
1117
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/face_of_corner.html
1118
+ """
1119
+ node = nt.ProcNode.from_nodetype(
1120
+ node_type="GeometryNodeFaceOfCorner",
1121
+ inputs={"Corner Index": corner_index},
1122
+ attrs={},
1123
+ )
1124
+ return FaceOfCornerResult(
1125
+ node._output_socket("face_index"), node._output_socket("index_in_face")
1126
+ )
1127
+
1128
+
1129
+ def field_at_index(
1130
+ value: TAttribute | None = None,
1131
+ index: nt.SocketOrVal[int] = 0,
1132
+ domain: TDomain = "POINT",
1133
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
1134
+ ) -> nt.ProcNode[TAttribute]:
1135
+ """
1136
+ Uses a FieldAtIndex Geometry Node.
1137
+
1138
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/field/evaluate_at_index.html
1139
+ """
1140
+ if data_type is None:
1141
+ data_type = RuntimeResolveDataType(
1142
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
1143
+ ["Value"],
1144
+ )
1145
+ return nt.ProcNode.from_nodetype(
1146
+ node_type="GeometryNodeFieldAtIndex",
1147
+ inputs={"Index": index, "Value": value},
1148
+ attrs={
1149
+ "domain": domain,
1150
+ "data_type": data_type,
1151
+ },
1152
+ )
1153
+
1154
+
1155
+ TFieldOnDomain = TypeVar(
1156
+ "TFieldOnDomain", nt.SocketOrVal[bool], nt.SocketOrVal[int], nt.SocketOrVal[float]
1157
+ )
1158
+
1159
+
1160
+ def field_on_domain(
1161
+ value: TFieldOnDomain = 0,
1162
+ domain: TDomain = "POINT",
1163
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
1164
+ ) -> nt.ProcNode[TFieldOnDomain]:
1165
+ """
1166
+ Uses a FieldOnDomain Geometry Node.
1167
+
1168
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/field/evaluate_on_domain.html
1169
+ """
1170
+ if data_type is None:
1171
+ data_type = RuntimeResolveDataType(
1172
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
1173
+ ["Value"],
1174
+ )
1175
+ return nt.ProcNode.from_nodetype(
1176
+ node_type="GeometryNodeFieldOnDomain",
1177
+ inputs={"Value": value},
1178
+ attrs={
1179
+ "domain": domain,
1180
+ "data_type": data_type,
1181
+ },
1182
+ )
1183
+
1184
+
1185
+ def fill_curve(
1186
+ curve: nt.ProcNode[pt.CurveObject],
1187
+ group_id: nt.SocketOrVal[int] = 0,
1188
+ mode: Literal["TRIANGLES", "NGONS"] = "TRIANGLES",
1189
+ ) -> nt.ProcNode[pt.MeshObject]:
1190
+ """
1191
+ Uses a FillCurve Geometry Node.
1192
+
1193
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/fill_curve.html
1194
+ """
1195
+ return nt.ProcNode.from_nodetype(
1196
+ node_type="GeometryNodeFillCurve",
1197
+ inputs={"Curve": curve, "Group ID": group_id},
1198
+ attrs={"mode": mode},
1199
+ )
1200
+
1201
+
1202
+ def fillet_curve(
1203
+ curve: nt.ProcNode[pt.CurveObject],
1204
+ radius: nt.SocketOrVal[float] = 0.25,
1205
+ limit_radius: nt.SocketOrVal[bool] = False,
1206
+ count: nt.SocketOrVal[int] = 1,
1207
+ mode: Literal["BEZIER", "POLY"] = "BEZIER",
1208
+ ) -> nt.ProcNode[pt.CurveObject]:
1209
+ """
1210
+ Uses a FilletCurve Geometry Node.
1211
+
1212
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/fillet_curve.html
1213
+ """
1214
+ return nt.ProcNode.from_nodetype(
1215
+ node_type="GeometryNodeFilletCurve",
1216
+ inputs={
1217
+ "Curve": curve,
1218
+ "Radius": radius,
1219
+ "Limit Radius": limit_radius,
1220
+ "Count": count,
1221
+ },
1222
+ attrs={"mode": mode},
1223
+ )
1224
+
1225
+
1226
+ def flip_faces(
1227
+ mesh: nt.ProcNode[pt.MeshObject], selection: nt.SocketOrVal[bool] = True
1228
+ ) -> nt.ProcNode[pt.MeshObject]:
1229
+ """
1230
+ Uses a FlipFaces Geometry Node.
1231
+
1232
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/flip_faces.html
1233
+ """
1234
+ return nt.ProcNode.from_nodetype(
1235
+ node_type="GeometryNodeFlipFaces",
1236
+ inputs={"Mesh": mesh, "Selection": selection},
1237
+ attrs={},
1238
+ )
1239
+
1240
+
1241
+ def geometry_to_instance(
1242
+ geometry: nt.ProcNode[TAnyGeometry],
1243
+ ) -> nt.ProcNode[nt.Instances]:
1244
+ """
1245
+ Uses a GeometryToInstance Geometry Node.
1246
+
1247
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/geometry_to_instance.html
1248
+ """
1249
+ return nt.ProcNode.from_nodetype(
1250
+ node_type="GeometryNodeGeometryToInstance",
1251
+ inputs={"Geometry": geometry},
1252
+ attrs={},
1253
+ )
1254
+
1255
+
1256
+ def get_named_grid(
1257
+ volume: nt.ProcNode[nt.Geometry],
1258
+ name: nt.SocketOrVal[str] = "",
1259
+ remove: nt.SocketOrVal[bool] = True,
1260
+ ) -> nt.ProcNode:
1261
+ """
1262
+ Uses a GetNamedGrid Geometry Node.
1263
+
1264
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/index.html
1265
+ """
1266
+ return nt.ProcNode.from_nodetype(
1267
+ node_type="GeometryNodeGetNamedGrid",
1268
+ inputs={"Name": name, "Remove": remove, "Volume": volume},
1269
+ attrs={},
1270
+ )
1271
+
1272
+
1273
+ def grid_to_mesh(
1274
+ grid: nt.SocketOrVal[float] = 0.0,
1275
+ threshold: nt.SocketOrVal[float] = 0.1,
1276
+ adaptivity: nt.SocketOrVal[float] = 0.0,
1277
+ ) -> nt.ProcNode[pt.MeshObject]:
1278
+ """
1279
+ Uses a GridToMesh Geometry Node.
1280
+
1281
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/operations/volume_to_mesh.html
1282
+ """
1283
+ return nt.ProcNode.from_nodetype(
1284
+ node_type="GeometryNodeGridToMesh",
1285
+ inputs={"Grid": grid, "Threshold": threshold, "Adaptivity": adaptivity},
1286
+ attrs={},
1287
+ )
1288
+
1289
+
1290
+ '''
1291
+ def group(node_tree: Any = None) -> t.ProcNode:
1292
+ """
1293
+ Uses a Group Geometry Node.
1294
+
1295
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/group.html
1296
+ """
1297
+ return t.ProcNode.from_nodetype(
1298
+ node_type="GeometryNodeGroup",
1299
+ inputs={},
1300
+ attrs={"node_tree": node_tree},
1301
+ )
1302
+ '''
1303
+
1304
+
1305
+ class ImageInfoResult(NamedTuple):
1306
+ width: nt.ProcNode[int]
1307
+ height: nt.ProcNode[int]
1308
+ has_alpha: nt.ProcNode[bool]
1309
+ frame_count: nt.ProcNode[int]
1310
+ fps: nt.ProcNode[float]
1311
+
1312
+
1313
+ def image_info(
1314
+ image: nt.SocketOrVal[pt.Image], frame: nt.SocketOrVal[int] = 0
1315
+ ) -> ImageInfoResult:
1316
+ """
1317
+ Uses a ImageInfo Geometry Node.
1318
+
1319
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/image_info.html
1320
+ """
1321
+ node = nt.ProcNode.from_nodetype(
1322
+ node_type="GeometryNodeImageInfo",
1323
+ inputs={"Image": image, "Frame": frame},
1324
+ attrs={},
1325
+ )
1326
+ return ImageInfoResult(
1327
+ node._output_socket("width"),
1328
+ node._output_socket("height"),
1329
+ node._output_socket("has_alpha"),
1330
+ node._output_socket("frame_count"),
1331
+ node._output_socket("fps"),
1332
+ )
1333
+
1334
+
1335
+ def image_texture(
1336
+ image: nt.SocketOrVal[pt.Image],
1337
+ vector: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1338
+ frame: nt.SocketOrVal[int] = 0,
1339
+ extension: Literal["REPEAT", "EXTEND", "CLIP", "MIRROR"] = "REPEAT",
1340
+ interpolation: Literal["Linear", "Closest", "Cubic"] = "Linear",
1341
+ ) -> nt.ProcNode:
1342
+ """
1343
+ Uses a ImageTexture Geometry Node.
1344
+
1345
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/image_info.html
1346
+ """
1347
+ return nt.ProcNode.from_nodetype(
1348
+ node_type="GeometryNodeImageTexture",
1349
+ inputs={"Image": image, "pt.Vector": vector, "Frame": frame},
1350
+ attrs={"extension": extension, "interpolation": interpolation},
1351
+ )
1352
+
1353
+
1354
+ def index_of_nearest(
1355
+ position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1356
+ group_id: nt.SocketOrVal[int] = 0,
1357
+ ) -> nt.ProcNode[int]:
1358
+ """
1359
+ Uses a IndexOfNearest Geometry Node.
1360
+
1361
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/sample/index_of_nearest.html
1362
+ """
1363
+ return nt.ProcNode.from_nodetype(
1364
+ node_type="GeometryNodeIndexOfNearest",
1365
+ inputs={"Position": position, "Group ID": group_id},
1366
+ attrs={},
1367
+ )
1368
+
1369
+
1370
+ def input_active_camera() -> nt.ProcNode[pt.Object]:
1371
+ """
1372
+ Uses a InputActiveCamera Geometry Node.
1373
+
1374
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/active_camera.html
1375
+ """
1376
+ raise_io_error("input_active_camera", logger=logger)
1377
+
1378
+ return nt.ProcNode.from_nodetype(
1379
+ node_type="GeometryNodeInputActiveCamera",
1380
+ inputs={},
1381
+ attrs={},
1382
+ )
1383
+
1384
+
1385
+ class InputCurveHandlePositionsResult(NamedTuple):
1386
+ left: nt.ProcNode[pt.Vector]
1387
+ right: nt.ProcNode[pt.Vector]
1388
+
1389
+
1390
+ def input_curve_handle_positions(
1391
+ relative: nt.SocketOrVal[bool] = False,
1392
+ ) -> InputCurveHandlePositionsResult:
1393
+ """
1394
+ Uses a InputCurveHandlePositions Geometry Node.
1395
+
1396
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/curve_handle_position.html
1397
+ """
1398
+ node = nt.ProcNode.from_nodetype(
1399
+ node_type="GeometryNodeInputCurveHandlePositions",
1400
+ inputs={"Relative": relative},
1401
+ attrs={},
1402
+ )
1403
+ return InputCurveHandlePositionsResult(
1404
+ node._output_socket("left"), node._output_socket("right")
1405
+ )
1406
+
1407
+
1408
+ def input_curve_tilt() -> nt.ProcNode[float]:
1409
+ """
1410
+ Uses a InputCurveTilt Geometry Node.
1411
+
1412
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/curve_tilt.html
1413
+ """
1414
+ return nt.ProcNode.from_nodetype(
1415
+ node_type="GeometryNodeInputCurveTilt",
1416
+ inputs={},
1417
+ attrs={},
1418
+ )
1419
+
1420
+
1421
+ def input_edge_smooth() -> nt.ProcNode[bool]:
1422
+ """
1423
+ Uses a InputEdgeSmooth Geometry Node.
1424
+
1425
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/is_edge_smooth.html
1426
+ """
1427
+ return nt.ProcNode.from_nodetype(
1428
+ node_type="GeometryNodeInputEdgeSmooth",
1429
+ inputs={},
1430
+ attrs={},
1431
+ )
1432
+
1433
+
1434
+ def input_id() -> nt.ProcNode[int]:
1435
+ """
1436
+ Uses a InputID Geometry Node.
1437
+
1438
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/id.html
1439
+ """
1440
+ return nt.ProcNode.from_nodetype(
1441
+ node_type="GeometryNodeInputID", inputs={}, attrs={}
1442
+ )
1443
+
1444
+
1445
+ def input_image(image: Any = None) -> nt.ProcNode[pt.Image]:
1446
+ """
1447
+ Uses a InputImage Geometry Node.
1448
+
1449
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/image.html
1450
+ """
1451
+
1452
+ raise_io_error("input_image", logger=logger)
1453
+ return nt.ProcNode.from_nodetype(
1454
+ node_type="GeometryNodeInputImage",
1455
+ inputs={},
1456
+ attrs={"image": image},
1457
+ )
1458
+
1459
+
1460
+ def input_index() -> nt.ProcNode[int]:
1461
+ """
1462
+ Uses a InputIndex Geometry Node.
1463
+
1464
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/input_index.html
1465
+ """
1466
+ return nt.ProcNode.from_nodetype(
1467
+ node_type="GeometryNodeInputIndex",
1468
+ inputs={},
1469
+ attrs={},
1470
+ )
1471
+
1472
+
1473
+ def input_instance_rotation() -> nt.ProcNode[pt.Vector]:
1474
+ """
1475
+ Uses a InputInstanceRotation Geometry Node.
1476
+
1477
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/rotation.html
1478
+ """
1479
+ return nt.ProcNode.from_nodetype(
1480
+ node_type="GeometryNodeInputInstanceRotation",
1481
+ inputs={},
1482
+ attrs={},
1483
+ )
1484
+
1485
+
1486
+ def input_instance_scale() -> nt.ProcNode[pt.Vector]:
1487
+ """
1488
+ Uses a InputInstanceScale Geometry Node.
1489
+
1490
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/instance_scale.html
1491
+ """
1492
+ return nt.ProcNode.from_nodetype(
1493
+ node_type="GeometryNodeInputInstanceScale",
1494
+ inputs={},
1495
+ attrs={},
1496
+ )
1497
+
1498
+
1499
+ def input_material(material: Any = None) -> nt.ProcNode[pt.Material]:
1500
+ """
1501
+ Uses a InputMaterial Geometry Node.
1502
+
1503
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/material.html
1504
+ """
1505
+ raise_io_error("input_material", logger=logger)
1506
+
1507
+ return nt.ProcNode.from_nodetype(
1508
+ node_type="GeometryNodeInputMaterial",
1509
+ inputs={},
1510
+ attrs={"material": material},
1511
+ )
1512
+
1513
+
1514
+ def input_material_index() -> nt.ProcNode[int]:
1515
+ """
1516
+ Uses a InputMaterialIndex Geometry Node.
1517
+
1518
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/material/material_index.html
1519
+ """
1520
+ return nt.ProcNode.from_nodetype(
1521
+ node_type="GeometryNodeInputMaterialIndex",
1522
+ inputs={},
1523
+ attrs={},
1524
+ )
1525
+
1526
+
1527
+ class InputMeshEdgeAngleResult(NamedTuple):
1528
+ unsigned_angle: nt.ProcNode[float]
1529
+ signed_angle: nt.ProcNode[float]
1530
+
1531
+
1532
+ def input_mesh_edge_angle() -> InputMeshEdgeAngleResult:
1533
+ """
1534
+ Uses a InputMeshEdgeAngle Geometry Node.
1535
+
1536
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/edge_angle.html
1537
+ """
1538
+ node = nt.ProcNode.from_nodetype(
1539
+ node_type="GeometryNodeInputMeshEdgeAngle",
1540
+ inputs={},
1541
+ attrs={},
1542
+ )
1543
+ return InputMeshEdgeAngleResult(
1544
+ node._output_socket("unsigned_angle"), node._output_socket("signed_angle")
1545
+ )
1546
+
1547
+
1548
+ def input_mesh_edge_neighbors() -> nt.ProcNode[int]:
1549
+ """
1550
+ Uses a InputMeshEdgeNeighbors Geometry Node.
1551
+
1552
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/edge_neighbors.html
1553
+ """
1554
+ return nt.ProcNode.from_nodetype(
1555
+ node_type="GeometryNodeInputMeshEdgeNeighbors",
1556
+ inputs={},
1557
+ attrs={},
1558
+ )
1559
+
1560
+
1561
+ class InputMeshEdgeVerticesResult(NamedTuple):
1562
+ vertex_index_1: nt.ProcNode[int]
1563
+ vertex_index_2: nt.ProcNode[int]
1564
+ position_1: nt.ProcNode[pt.Vector]
1565
+ position_2: nt.ProcNode[pt.Vector]
1566
+
1567
+
1568
+ def input_mesh_edge_vertices() -> InputMeshEdgeVerticesResult:
1569
+ """
1570
+ Uses a InputMeshEdgeVertices Geometry Node.
1571
+
1572
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/edge_vertices.html
1573
+ """
1574
+ node = nt.ProcNode.from_nodetype(
1575
+ node_type="GeometryNodeInputMeshEdgeVertices",
1576
+ inputs={},
1577
+ attrs={},
1578
+ )
1579
+ return InputMeshEdgeVerticesResult(
1580
+ node._output_socket("vertex_index_1"),
1581
+ node._output_socket("vertex_index_2"),
1582
+ node._output_socket("position_1"),
1583
+ node._output_socket("position_2"),
1584
+ )
1585
+
1586
+
1587
+ def input_mesh_face_area() -> nt.ProcNode[float]:
1588
+ """
1589
+ Uses a InputMeshFaceArea Geometry Node.
1590
+
1591
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/face_area.html
1592
+ """
1593
+ return nt.ProcNode.from_nodetype(
1594
+ node_type="GeometryNodeInputMeshFaceArea",
1595
+ inputs={},
1596
+ attrs={},
1597
+ )
1598
+
1599
+
1600
+ def input_mesh_face_is_planar(
1601
+ threshold: nt.SocketOrVal[float] = 0.01,
1602
+ ) -> nt.ProcNode[bool]:
1603
+ """
1604
+ Uses a InputMeshFaceIsPlanar Geometry Node.
1605
+
1606
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/face_is_planar.html
1607
+ """
1608
+ return nt.ProcNode.from_nodetype(
1609
+ node_type="GeometryNodeInputMeshFaceIsPlanar",
1610
+ inputs={"Threshold": threshold},
1611
+ attrs={},
1612
+ )
1613
+
1614
+
1615
+ class InputMeshFaceNeighborsResult(NamedTuple):
1616
+ vertex_count: nt.ProcNode[int]
1617
+ face_count: nt.ProcNode[int]
1618
+
1619
+
1620
+ def input_mesh_face_neighbors() -> InputMeshFaceNeighborsResult:
1621
+ """
1622
+ Uses a InputMeshFaceNeighbors Geometry Node.
1623
+
1624
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/face_neighbors.html
1625
+ """
1626
+ res = nt.ProcNode.from_nodetype(
1627
+ node_type="GeometryNodeInputMeshFaceNeighbors",
1628
+ inputs={},
1629
+ attrs={},
1630
+ )
1631
+
1632
+ return InputMeshFaceNeighborsResult(
1633
+ vertex_count=res._output_socket("vertex_count"),
1634
+ face_count=res._output_socket("face_count"),
1635
+ )
1636
+
1637
+
1638
+ class InputMeshIslandResult(NamedTuple):
1639
+ island_index: nt.ProcNode[int]
1640
+ island_count: nt.ProcNode[int]
1641
+
1642
+
1643
+ def input_mesh_island() -> InputMeshIslandResult:
1644
+ """
1645
+ Uses a InputMeshIsland Geometry Node.
1646
+
1647
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/mesh_island.html
1648
+ """
1649
+ node = nt.ProcNode.from_nodetype(
1650
+ node_type="GeometryNodeInputMeshIsland",
1651
+ inputs={},
1652
+ attrs={},
1653
+ )
1654
+ return InputMeshIslandResult(
1655
+ node._output_socket("island_index"), node._output_socket("island_count")
1656
+ )
1657
+
1658
+
1659
+ class InputMeshVertexNeighborsResult(NamedTuple):
1660
+ vertex_count: nt.ProcNode[int]
1661
+ face_count: nt.ProcNode[int]
1662
+
1663
+
1664
+ def input_mesh_vertex_neighbors() -> InputMeshVertexNeighborsResult:
1665
+ """
1666
+ Uses a InputMeshVertexNeighbors Geometry Node.
1667
+
1668
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/vertex_neighbors.html
1669
+ """
1670
+ node = nt.ProcNode.from_nodetype(
1671
+ node_type="GeometryNodeInputMeshVertexNeighbors",
1672
+ inputs={},
1673
+ attrs={},
1674
+ )
1675
+ return InputMeshVertexNeighborsResult(
1676
+ node._output_socket("vertex_count"), node._output_socket("face_count")
1677
+ )
1678
+
1679
+
1680
+ class InputNamedAttributeResult(NamedTuple):
1681
+ attribute: nt.ProcNode
1682
+ exists: nt.ProcNode[bool]
1683
+
1684
+
1685
+ def input_named_attribute(
1686
+ name: nt.SocketOrVal[str] = "",
1687
+ data_type: NodeDataType | None = None,
1688
+ ) -> InputNamedAttributeResult:
1689
+ """
1690
+ Uses a InputNamedAttribute Geometry Node.
1691
+
1692
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/named_attribute.html
1693
+ """
1694
+ assert data_type is not NodeDataType.FLOAT_VECTOR_2D, (
1695
+ "GeometryNodeInputNamedAttribute does not support FLOAT_VECTOR_2D; use FLOAT_VECTOR instead"
1696
+ )
1697
+ node = nt.ProcNode.from_nodetype(
1698
+ node_type="GeometryNodeInputNamedAttribute",
1699
+ inputs={"Name": name},
1700
+ attrs={"data_type": data_type},
1701
+ )
1702
+ return InputNamedAttributeResult(
1703
+ node._output_socket("attribute"), node._output_socket("exists")
1704
+ )
1705
+
1706
+
1707
+ def input_named_layer_selection(name: nt.SocketOrVal[str] = "") -> nt.ProcNode[bool]:
1708
+ """
1709
+ Uses a InputNamedLayerSelection Geometry Node.
1710
+
1711
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/selection.html
1712
+ """
1713
+ return nt.ProcNode.from_nodetype(
1714
+ node_type="GeometryNodeInputNamedLayerSelection",
1715
+ inputs={"Name": name},
1716
+ attrs={},
1717
+ )
1718
+
1719
+
1720
+ def input_normal() -> nt.ProcNode[pt.Vector]:
1721
+ """
1722
+ Uses a InputNormal Geometry Node.
1723
+
1724
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/normal.html
1725
+ """
1726
+ return nt.ProcNode.from_nodetype(
1727
+ node_type="GeometryNodeInputNormal",
1728
+ inputs={},
1729
+ attrs={},
1730
+ )
1731
+
1732
+
1733
+ def input_position() -> nt.ProcNode[pt.Vector]:
1734
+ """
1735
+ Uses a InputPosition Geometry Node.
1736
+
1737
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/position.html
1738
+ """
1739
+ return nt.ProcNode.from_nodetype(
1740
+ node_type="GeometryNodeInputPosition",
1741
+ inputs={},
1742
+ attrs={},
1743
+ )
1744
+
1745
+
1746
+ def input_radius() -> nt.ProcNode[float]:
1747
+ """
1748
+ Uses a InputRadius Geometry Node.
1749
+
1750
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/radius.html
1751
+ """
1752
+ return nt.ProcNode.from_nodetype(
1753
+ node_type="GeometryNodeInputRadius",
1754
+ inputs={},
1755
+ attrs={},
1756
+ )
1757
+
1758
+
1759
+ class InputSceneTimeResult(NamedTuple):
1760
+ seconds: nt.ProcNode[float]
1761
+ frame: nt.ProcNode[int]
1762
+
1763
+
1764
+ def input_scene_time() -> InputSceneTimeResult:
1765
+ """
1766
+ Uses a InputSceneTime Geometry Node.
1767
+
1768
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/scene_time.html
1769
+ """
1770
+ node = nt.ProcNode.from_nodetype(
1771
+ node_type="GeometryNodeInputSceneTime",
1772
+ inputs={},
1773
+ attrs={},
1774
+ )
1775
+ return InputSceneTimeResult(
1776
+ seconds=node._output_socket("seconds"),
1777
+ frame=node._output_socket("frame"),
1778
+ )
1779
+
1780
+
1781
+ def input_shade_smooth() -> nt.ProcNode[bool]:
1782
+ """
1783
+ Uses a InputShadeSmooth Geometry Node.
1784
+
1785
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/write/set_shade_smooth.html
1786
+ """
1787
+ return nt.ProcNode.from_nodetype(
1788
+ node_type="GeometryNodeInputShadeSmooth",
1789
+ inputs={},
1790
+ attrs={},
1791
+ )
1792
+
1793
+
1794
+ class InputShortestEdgePathsResult(NamedTuple):
1795
+ next_vertex_index: nt.ProcNode[int]
1796
+ total_cost: nt.ProcNode[float]
1797
+
1798
+
1799
+ def input_shortest_edge_paths(
1800
+ end_vertex: nt.SocketOrVal[bool] = False, edge_cost: nt.SocketOrVal[float] = 1.0
1801
+ ) -> InputShortestEdgePathsResult:
1802
+ """
1803
+ Uses a InputShortestEdgePaths Geometry Node.
1804
+
1805
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/shortest_edge_paths.html
1806
+ """
1807
+ res = nt.ProcNode.from_nodetype(
1808
+ node_type="GeometryNodeInputShortestEdgePaths",
1809
+ inputs={"End Vertex": end_vertex, "Edge Cost": edge_cost},
1810
+ attrs={},
1811
+ )
1812
+ return InputShortestEdgePathsResult(
1813
+ next_vertex_index=res._output_socket("next_vertex_index"),
1814
+ total_cost=res._output_socket("total_cost"),
1815
+ )
1816
+
1817
+
1818
+ def input_spline_cyclic() -> nt.ProcNode[bool]:
1819
+ """
1820
+ Uses a InputSplineCyclic Geometry Node.
1821
+
1822
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/is_spline_cyclic.html
1823
+ """
1824
+ return nt.ProcNode.from_nodetype(
1825
+ node_type="GeometryNodeInputSplineCyclic",
1826
+ inputs={},
1827
+ attrs={},
1828
+ )
1829
+
1830
+
1831
+ def input_spline_resolution() -> nt.ProcNode[int]:
1832
+ """
1833
+ Uses a InputSplineResolution Geometry Node.
1834
+
1835
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/spline_resolution.html
1836
+ """
1837
+ return nt.ProcNode.from_nodetype(
1838
+ node_type="GeometryNodeInputSplineResolution",
1839
+ inputs={},
1840
+ attrs={},
1841
+ )
1842
+
1843
+
1844
+ def input_tangent() -> nt.ProcNode[pt.Vector]:
1845
+ """
1846
+ Uses a InputTangent Geometry Node.
1847
+
1848
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/curve_tangent.html
1849
+ """
1850
+ return nt.ProcNode.from_nodetype(
1851
+ node_type="GeometryNodeInputTangent",
1852
+ inputs={},
1853
+ attrs={},
1854
+ )
1855
+
1856
+
1857
+ def instance_on_points(
1858
+ points: nt.ProcNode[nt.Geometry] | None = None,
1859
+ instance: nt.ProcNode[nt.Geometry] | None = None,
1860
+ selection: nt.SocketOrVal[bool] = True,
1861
+ pick_instance: nt.SocketOrVal[bool] = False,
1862
+ instance_index: nt.SocketOrVal[int] = 0,
1863
+ rotation: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1864
+ scale: nt.SocketOrVal[nt.pt.Vector] = (1, 1, 1),
1865
+ ) -> nt.ProcNode[nt.Instances]:
1866
+ """
1867
+ Uses a InstanceOnPoints Geometry Node.
1868
+
1869
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/instance_on_points.html
1870
+ """
1871
+ return nt.ProcNode.from_nodetype(
1872
+ node_type="GeometryNodeInstanceOnPoints",
1873
+ inputs={
1874
+ "Points": points,
1875
+ "Selection": selection,
1876
+ "Instance": instance,
1877
+ "Pick Instance": pick_instance,
1878
+ "Instance Index": instance_index,
1879
+ "Rotation": rotation,
1880
+ "Scale": scale,
1881
+ },
1882
+ attrs={},
1883
+ )
1884
+
1885
+
1886
+ def instance_transform() -> nt.ProcNode:
1887
+ """
1888
+ Uses a InstanceTransform Geometry Node.
1889
+
1890
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/instance_transform.html
1891
+ """
1892
+ return nt.ProcNode.from_nodetype(
1893
+ node_type="GeometryNodeInstanceTransform",
1894
+ inputs={},
1895
+ attrs={},
1896
+ )
1897
+
1898
+
1899
+ def instances_to_points(
1900
+ instances: nt.ProcNode[nt.Instances] | None = None,
1901
+ selection: nt.SocketOrVal[bool] = True,
1902
+ position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1903
+ radius: nt.SocketOrVal[float] = 0.05,
1904
+ ) -> nt.ProcNode[nt.Points]:
1905
+ """
1906
+ Uses a InstancesToPoints Geometry Node.
1907
+
1908
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/instances_to_points.html
1909
+ """
1910
+ return nt.ProcNode.from_nodetype(
1911
+ node_type="GeometryNodeInstancesToPoints",
1912
+ inputs={
1913
+ "Instances": instances,
1914
+ "Selection": selection,
1915
+ "Position": position,
1916
+ "Radius": radius,
1917
+ },
1918
+ attrs={},
1919
+ )
1920
+
1921
+
1922
+ class InterpolateCurvesResult(NamedTuple):
1923
+ curves: nt.ProcNode[pt.HairObject]
1924
+ closest_index: nt.ProcNode[int]
1925
+ closest_weight: nt.ProcNode[float]
1926
+
1927
+
1928
+ def interpolate_curves(
1929
+ guide_curves: nt.ProcNode[pt.HairObject],
1930
+ points: nt.ProcNode[nt.Geometry],
1931
+ guide_up: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1932
+ guide_group_id: nt.SocketOrVal[int] = 0,
1933
+ point_up: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
1934
+ point_group_id: nt.SocketOrVal[int] = 0,
1935
+ max_neighbors: nt.SocketOrVal[int] = 4,
1936
+ ) -> InterpolateCurvesResult:
1937
+ """
1938
+ Uses a InterpolateCurves Geometry Node.
1939
+
1940
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/interpolate_curves.html
1941
+ """
1942
+ res = nt.ProcNode.from_nodetype(
1943
+ node_type="GeometryNodeInterpolateCurves",
1944
+ inputs={
1945
+ "Guide Curves": guide_curves,
1946
+ "Guide Up": guide_up,
1947
+ "Guide Group ID": guide_group_id,
1948
+ "Points": points,
1949
+ "Point Up": point_up,
1950
+ "Point Group ID": point_group_id,
1951
+ "Max Neighbors": max_neighbors,
1952
+ },
1953
+ attrs={},
1954
+ )
1955
+
1956
+ return InterpolateCurvesResult(
1957
+ curves=res._output_socket("curves"),
1958
+ closest_index=res._output_socket("closest_index"),
1959
+ closest_weight=res._output_socket("closest_weight"),
1960
+ )
1961
+
1962
+
1963
+ def is_viewport() -> nt.ProcNode[bool]:
1964
+ """
1965
+ Uses a IsViewport Geometry Node.
1966
+
1967
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/is_viewport.html
1968
+ """
1969
+ return nt.ProcNode.from_nodetype(
1970
+ node_type="GeometryNodeIsViewport",
1971
+ inputs={},
1972
+ attrs={},
1973
+ )
1974
+
1975
+
1976
+ def join_geometry(
1977
+ geometries: list[nt.ProcNode[TAnyGeometry]],
1978
+ ) -> nt.ProcNode[TAnyGeometry]:
1979
+ """
1980
+ Uses a JoinGeometry Geometry Node.
1981
+
1982
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/join_geometry.html
1983
+ """
1984
+ return nt.ProcNode.from_nodetype(
1985
+ node_type="GeometryNodeJoinGeometry",
1986
+ inputs={"Geometry": geometries},
1987
+ attrs={},
1988
+ )
1989
+
1990
+
1991
+ def material_selection(
1992
+ material: nt.SocketOrVal[pt.Material] = None,
1993
+ ) -> nt.ProcNode[bool]:
1994
+ """
1995
+ Uses a MaterialSelection Geometry Node.
1996
+
1997
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/material/material_selection.html
1998
+ """
1999
+ return nt.ProcNode.from_nodetype(
2000
+ node_type="GeometryNodeMaterialSelection",
2001
+ inputs={"Material": material},
2002
+ attrs={},
2003
+ )
2004
+
2005
+
2006
+ """
2007
+ TMenuSwitch = TypeVar(
2008
+ "TMenuSwitch",
2009
+ nt.SocketOrVal[bool],
2010
+ nt.SocketOrVal[int],
2011
+ nt.SocketOrVal[pt.Color],
2012
+ nt.SocketOrVal[str],
2013
+ nt.SocketOrVal[float],
2014
+ nt.SocketOrVal[nt.pt.Vector],
2015
+ )
2016
+
2017
+
2018
+ def menu_switch(
2019
+ a: TMenuSwitch = 0,
2020
+ b: TMenuSwitch = 0,
2021
+ menu: Any = "A",
2022
+ active_index: int = 1,
2023
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
2024
+ ) -> nt.ProcNode[TMenuSwitch]:
2025
+
2026
+ if data_type is None:
2027
+ data_type = RuntimeResolveDataType(
2028
+ [
2029
+ NodeDataType.BOOLEAN,
2030
+ NodeDataType.INT,
2031
+ NodeDataType.RGBA,
2032
+ NodeDataType.STRING,
2033
+ NodeDataType.FLOAT,
2034
+ NodeDataType.FLOAT_VECTOR,
2035
+ ],
2036
+ ["A", "B"],
2037
+ )
2038
+ return nt.ProcNode.from_nodetype(
2039
+ node_type="GeometryNodeMenuSwitch",
2040
+ inputs={"A": a, "B": b, "Menu": menu},
2041
+ attrs={
2042
+ "active_index": active_index,
2043
+ "data_type": data_type,
2044
+ },
2045
+ )
2046
+ """
2047
+
2048
+
2049
+ def merge_by_distance(
2050
+ geometry: nt.ProcNode[nt.Geometry],
2051
+ selection: nt.SocketOrVal[bool] = True,
2052
+ distance: nt.SocketOrVal[float] = 0.001,
2053
+ mode: Literal["ALL", "CONNECTED"] = "ALL",
2054
+ ) -> nt.ProcNode[nt.Geometry]:
2055
+ """
2056
+ Uses a MergeByDistance Geometry Node.
2057
+
2058
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/merge_by_distance.html
2059
+ """
2060
+ return nt.ProcNode.from_nodetype(
2061
+ node_type="GeometryNodeMergeByDistance",
2062
+ inputs={"Geometry": geometry, "Selection": selection, "Distance": distance},
2063
+ attrs={"mode": mode},
2064
+ )
2065
+
2066
+
2067
+ def mesh_boolean(
2068
+ mesh_1: nt.ProcNode[nt.Geometry] | None = None,
2069
+ mesh_2: nt.ProcNode[nt.Geometry] | None = None,
2070
+ self_intersection: nt.SocketOrVal[bool] = False,
2071
+ hole_tolerant: nt.SocketOrVal[bool] = False,
2072
+ operation: Literal["INTERSECT", "UNION", "DIFFERENCE"] = "DIFFERENCE",
2073
+ solver: Literal["EXACT", "FLOAT"] = "FLOAT",
2074
+ ) -> nt.ProcNode[pt.MeshObject]:
2075
+ """
2076
+ Uses a MeshBoolean Geometry Node.
2077
+
2078
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/mesh_boolean.html
2079
+ """
2080
+ return nt.ProcNode.from_nodetype(
2081
+ node_type="GeometryNodeMeshBoolean",
2082
+ inputs={
2083
+ "Mesh 1": mesh_1,
2084
+ "Mesh 2": mesh_2,
2085
+ "Self Intersection": self_intersection,
2086
+ "Hole Tolerant": hole_tolerant,
2087
+ },
2088
+ attrs={"operation": operation, "solver": solver},
2089
+ )
2090
+
2091
+
2092
+ def mesh_circle(
2093
+ vertices: nt.SocketOrVal[int] = 32,
2094
+ radius: nt.SocketOrVal[float] = 1.0,
2095
+ fill_type: Literal["NONE", "NGON", "TRIANGLE_FAN"] = "NONE",
2096
+ ) -> nt.ProcNode[pt.MeshObject]:
2097
+ """
2098
+ Uses a MeshCircle Geometry Node.
2099
+
2100
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/mesh_circle.html
2101
+ """
2102
+ return nt.ProcNode.from_nodetype(
2103
+ node_type="GeometryNodeMeshCircle",
2104
+ inputs={"Vertices": vertices, "Radius": radius},
2105
+ attrs={"fill_type": fill_type},
2106
+ )
2107
+
2108
+
2109
+ class MeshResult(NamedTuple):
2110
+ mesh: nt.ProcNode[pt.MeshObject]
2111
+ uv_map: nt.ProcNode[pt.MeshObject]
2112
+
2113
+
2114
+ class MeshConeResult(NamedTuple):
2115
+ mesh: nt.ProcNode[pt.MeshObject]
2116
+ uv_map: nt.ProcNode[pt.MeshObject]
2117
+ top: nt.ProcNode[pt.MeshObject]
2118
+ bottom: nt.ProcNode[pt.MeshObject]
2119
+ side: nt.ProcNode[pt.MeshObject]
2120
+
2121
+
2122
+ def mesh_cone(
2123
+ vertices: nt.SocketOrVal[int] = 32,
2124
+ side_segments: nt.SocketOrVal[int] = 1,
2125
+ fill_segments: nt.SocketOrVal[int] = 1,
2126
+ radius_top: nt.SocketOrVal[float] = 0.0,
2127
+ radius_bottom: nt.SocketOrVal[float] = 1.0,
2128
+ depth: nt.SocketOrVal[float] = 2.0,
2129
+ fill_type: Literal["NONE", "NGON", "TRIANGLE_FAN"] = "NGON",
2130
+ ) -> MeshConeResult:
2131
+ """
2132
+ Uses a MeshCone Geometry Node.
2133
+
2134
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/cone.html
2135
+ """
2136
+ res = nt.ProcNode.from_nodetype(
2137
+ node_type="GeometryNodeMeshCone",
2138
+ inputs={
2139
+ "Vertices": vertices,
2140
+ "Side Segments": side_segments,
2141
+ "Fill Segments": fill_segments,
2142
+ "Radius Top": radius_top,
2143
+ "Radius Bottom": radius_bottom,
2144
+ "Depth": depth,
2145
+ },
2146
+ attrs={"fill_type": fill_type},
2147
+ )
2148
+ return MeshConeResult(
2149
+ mesh=res._output_socket("mesh"),
2150
+ uv_map=res._output_socket("uv_map"),
2151
+ top=res._output_socket("top"),
2152
+ bottom=res._output_socket("bottom"),
2153
+ side=res._output_socket("side"),
2154
+ )
2155
+
2156
+
2157
+ def mesh_cube(
2158
+ size: nt.SocketOrVal[nt.pt.Vector] = (1, 1, 1),
2159
+ vertices_x: nt.SocketOrVal[int] = 2,
2160
+ vertices_y: nt.SocketOrVal[int] = 2,
2161
+ vertices_z: nt.SocketOrVal[int] = 2,
2162
+ ) -> MeshResult:
2163
+ """
2164
+ Uses a MeshCube Geometry Node.
2165
+
2166
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/cube.html
2167
+ """
2168
+ res = nt.ProcNode.from_nodetype(
2169
+ node_type="GeometryNodeMeshCube",
2170
+ inputs={
2171
+ "Size": size,
2172
+ "Vertices X": vertices_x,
2173
+ "Vertices Y": vertices_y,
2174
+ "Vertices Z": vertices_z,
2175
+ },
2176
+ attrs={},
2177
+ )
2178
+ return MeshResult(
2179
+ mesh=res._output_socket("mesh"),
2180
+ uv_map=res._output_socket("uv_map"),
2181
+ )
2182
+
2183
+
2184
+ class MeshCylinderResult(NamedTuple):
2185
+ mesh: nt.ProcNode[pt.MeshObject]
2186
+ top: nt.ProcNode[pt.MeshObject]
2187
+ side: nt.ProcNode[pt.MeshObject]
2188
+ bottom: nt.ProcNode[pt.MeshObject]
2189
+ uv_map: nt.ProcNode[pt.MeshObject]
2190
+
2191
+
2192
+ def mesh_cylinder(
2193
+ vertices: nt.SocketOrVal[int] = 32,
2194
+ side_segments: nt.SocketOrVal[int] = 1,
2195
+ fill_segments: nt.SocketOrVal[int] = 1,
2196
+ radius: nt.SocketOrVal[float] = 1.0,
2197
+ depth: nt.SocketOrVal[float] = 2.0,
2198
+ fill_type: Literal["NONE", "NGON", "TRIANGLE_FAN"] = "NGON",
2199
+ ) -> MeshCylinderResult:
2200
+ """
2201
+ Uses a MeshCylinder Geometry Node.
2202
+
2203
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/cylinder.html
2204
+ """
2205
+ res = nt.ProcNode.from_nodetype(
2206
+ node_type="GeometryNodeMeshCylinder",
2207
+ inputs={
2208
+ "Vertices": vertices,
2209
+ "Side Segments": side_segments,
2210
+ "Fill Segments": fill_segments,
2211
+ "Radius": radius,
2212
+ "Depth": depth,
2213
+ },
2214
+ attrs={"fill_type": fill_type},
2215
+ )
2216
+ return MeshCylinderResult(
2217
+ mesh=res._output_socket("mesh"),
2218
+ top=res._output_socket("top"),
2219
+ side=res._output_socket("side"),
2220
+ bottom=res._output_socket("bottom"),
2221
+ uv_map=res._output_socket("uv_map"),
2222
+ )
2223
+
2224
+
2225
+ def mesh_face_set_boundaries(
2226
+ face_group_id: nt.SocketOrVal[int] = 0,
2227
+ ) -> nt.ProcNode[bool]:
2228
+ """
2229
+ Uses a MeshFaceSetBoundaries Geometry Node.
2230
+
2231
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/face_group_boundaries.html
2232
+ """
2233
+ return nt.ProcNode.from_nodetype(
2234
+ node_type="GeometryNodeMeshFaceSetBoundaries",
2235
+ inputs={"Face Group ID": face_group_id},
2236
+ attrs={},
2237
+ )
2238
+
2239
+
2240
+ def mesh_grid(
2241
+ size_x: nt.SocketOrVal[float] = 1.0,
2242
+ size_y: nt.SocketOrVal[float] = 1.0,
2243
+ vertices_x: nt.SocketOrVal[int] = 3,
2244
+ vertices_y: nt.SocketOrVal[int] = 3,
2245
+ ) -> MeshResult:
2246
+ """
2247
+ Uses a MeshGrid Geometry Node.
2248
+
2249
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/grid.html
2250
+ """
2251
+ res = nt.ProcNode.from_nodetype(
2252
+ node_type="GeometryNodeMeshGrid",
2253
+ inputs={
2254
+ "Size X": size_x,
2255
+ "Size Y": size_y,
2256
+ "Vertices X": vertices_x,
2257
+ "Vertices Y": vertices_y,
2258
+ },
2259
+ attrs={},
2260
+ )
2261
+ return MeshResult(
2262
+ mesh=res._output_socket("mesh"),
2263
+ uv_map=res._output_socket("uv_map"),
2264
+ )
2265
+
2266
+
2267
+ def mesh_icosphere(
2268
+ radius: nt.SocketOrVal[float] = 1.0, subdivisions: nt.SocketOrVal[int] = 1
2269
+ ) -> MeshResult:
2270
+ """
2271
+ Uses a MeshIcoSphere Geometry Node.
2272
+
2273
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/icosphere.html
2274
+ """
2275
+ res = nt.ProcNode.from_nodetype(
2276
+ node_type="GeometryNodeMeshIcoSphere",
2277
+ inputs={"Radius": radius, "Subdivisions": subdivisions},
2278
+ attrs={},
2279
+ )
2280
+ return MeshResult(
2281
+ mesh=res._output_socket("mesh"),
2282
+ uv_map=res._output_socket("uv_map"),
2283
+ )
2284
+
2285
+
2286
+ def mesh_line(
2287
+ start_location: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
2288
+ offset: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 1),
2289
+ count: nt.SocketOrVal[int] = 10,
2290
+ count_mode: Literal["TOTAL", "RESOLUTION"] = "TOTAL",
2291
+ ) -> nt.ProcNode[pt.MeshObject]:
2292
+ """
2293
+ Uses a MeshLine Geometry Node.
2294
+
2295
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/mesh_line.html
2296
+ """
2297
+ return nt.ProcNode.from_nodetype(
2298
+ node_type="GeometryNodeMeshLine",
2299
+ inputs={"Count": count, "Start Location": start_location, "Offset": offset},
2300
+ attrs={"count_mode": count_mode, "mode": "OFFSET"},
2301
+ )
2302
+
2303
+
2304
+ def mesh_line_from_endpoints(
2305
+ start_location: nt.SocketOrVal[nt.pt.Vector],
2306
+ end_location: nt.SocketOrVal[nt.pt.Vector],
2307
+ count: nt.SocketOrVal[int] = 10,
2308
+ count_mode: Literal["TOTAL", "RESOLUTION"] = "TOTAL",
2309
+ ) -> nt.ProcNode[pt.MeshObject]:
2310
+ return nt.ProcNode.from_nodetype(
2311
+ node_type="GeometryNodeMeshLine",
2312
+ inputs={
2313
+ "Count": count,
2314
+ "Start Location": start_location,
2315
+ "Offset": end_location, # 4.2 uses "Offset" key in both cases
2316
+ },
2317
+ attrs={"count_mode": count_mode, "mode": "END_POINTS"},
2318
+ )
2319
+
2320
+
2321
+ def mesh_to_curve(
2322
+ mesh: nt.ProcNode[pt.MeshObject], selection: nt.SocketOrVal[bool] = True
2323
+ ) -> nt.ProcNode[pt.CurveObject]:
2324
+ """
2325
+ Uses a MeshToCurve Geometry Node.
2326
+
2327
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/mesh_to_curve.html
2328
+ """
2329
+ return nt.ProcNode.from_nodetype(
2330
+ node_type="GeometryNodeMeshToCurve",
2331
+ inputs={"Mesh": mesh, "Selection": selection},
2332
+ attrs={},
2333
+ )
2334
+
2335
+
2336
+ def mesh_to_density_grid(
2337
+ mesh: nt.ProcNode[pt.MeshObject],
2338
+ density: nt.SocketOrVal[float] = 1.0,
2339
+ voxel_size: nt.SocketOrVal[float] = 0.3,
2340
+ gradient_width: nt.SocketOrVal[float] = 0.2,
2341
+ ) -> nt.ProcNode:
2342
+ """
2343
+ Uses a MeshToDensityGrid Geometry Node.
2344
+
2345
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/mesh_to_volume.html
2346
+ """
2347
+ return nt.ProcNode.from_nodetype(
2348
+ node_type="GeometryNodeMeshToDensityGrid",
2349
+ inputs={
2350
+ "Mesh": mesh,
2351
+ "Density": density,
2352
+ "Voxel Size": voxel_size,
2353
+ "Gradient Width": gradient_width,
2354
+ },
2355
+ attrs={},
2356
+ )
2357
+
2358
+
2359
+ def mesh_to_points(
2360
+ mesh: nt.ProcNode[pt.MeshObject],
2361
+ selection: nt.SocketOrVal[bool] = True,
2362
+ position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
2363
+ radius: nt.SocketOrVal[float] = 0.05,
2364
+ mode: Literal["VERTICES", "EDGES", "FACES", "CORNERS"] = "VERTICES",
2365
+ ) -> nt.ProcNode[nt.Points]:
2366
+ """
2367
+ Uses a MeshToPoints Geometry Node.
2368
+
2369
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/mesh_to_points.html
2370
+ """
2371
+ return nt.ProcNode.from_nodetype(
2372
+ node_type="GeometryNodeMeshToPoints",
2373
+ inputs={
2374
+ "Mesh": mesh,
2375
+ "Selection": selection,
2376
+ "Position": position,
2377
+ "Radius": radius,
2378
+ },
2379
+ attrs={"mode": mode},
2380
+ )
2381
+
2382
+
2383
+ def mesh_to_sdf_grid(
2384
+ mesh: nt.ProcNode[pt.MeshObject],
2385
+ voxel_size: nt.SocketOrVal[float] = 0.3,
2386
+ band_width: nt.SocketOrVal[int] = 3,
2387
+ ) -> nt.ProcNode:
2388
+ """
2389
+ Uses a MeshToSDFGrid Geometry Node.
2390
+
2391
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/mesh_to_volume.html
2392
+ """
2393
+ return nt.ProcNode.from_nodetype(
2394
+ node_type="GeometryNodeMeshToSDFGrid",
2395
+ inputs={"Mesh": mesh, "Voxel Size": voxel_size, "Band Width": band_width},
2396
+ attrs={},
2397
+ )
2398
+
2399
+
2400
+ def mesh_to_volume(
2401
+ mesh: nt.ProcNode[pt.MeshObject],
2402
+ density: nt.SocketOrVal[float] = 1.0,
2403
+ voxel_amount: nt.SocketOrVal[float] = 64.0,
2404
+ interior_band_width: nt.SocketOrVal[float] = 0.2,
2405
+ resolution_mode: Literal["VOXEL_AMOUNT", "VOXEL_SIZE"] = "VOXEL_AMOUNT",
2406
+ ) -> nt.ProcNode[pt.VolumeObject]:
2407
+ """
2408
+ Uses a MeshToVolume Geometry Node.
2409
+
2410
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/mesh_to_volume.html
2411
+ """
2412
+ return nt.ProcNode.from_nodetype(
2413
+ node_type="GeometryNodeMeshToVolume",
2414
+ inputs={
2415
+ "Mesh": mesh,
2416
+ "Density": density,
2417
+ "Voxel Amount": voxel_amount,
2418
+ "Interior Band Width": interior_band_width,
2419
+ },
2420
+ attrs={"resolution_mode": resolution_mode},
2421
+ )
2422
+
2423
+
2424
+ def mesh_uv_sphere(
2425
+ segments: nt.SocketOrVal[int] = 32,
2426
+ rings: nt.SocketOrVal[int] = 16,
2427
+ radius: nt.SocketOrVal[float] = 1.0,
2428
+ ) -> MeshResult:
2429
+ """
2430
+ Uses a MeshUVSphere Geometry Node.
2431
+
2432
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/primitives/uv_sphere.html
2433
+ """
2434
+ res = nt.ProcNode.from_nodetype(
2435
+ node_type="GeometryNodeMeshUVSphere",
2436
+ inputs={"Segments": segments, "Rings": rings, "Radius": radius},
2437
+ attrs={},
2438
+ )
2439
+ return MeshResult(
2440
+ mesh=res._output_socket("mesh"),
2441
+ uv_map=res._output_socket("uv_map"),
2442
+ )
2443
+
2444
+
2445
+ TObjectInfo = TypeVar("TObjectInfo", pt.MeshObject, pt.CurveObject, pt.VolumeObject)
2446
+
2447
+
2448
+ class ObjectInfoResult(NamedTuple, Generic[TObjectInfo]):
2449
+ geometry: nt.ProcNode[TObjectInfo]
2450
+ transform: nt.ProcNode[pt.Vector]
2451
+ location: nt.ProcNode[pt.Vector]
2452
+ rotation: nt.ProcNode[pt.Vector]
2453
+ scale: nt.ProcNode[pt.Vector]
2454
+
2455
+
2456
+ def object_info(
2457
+ object: nt.SocketOrVal[TObjectInfo],
2458
+ as_instance: nt.SocketOrVal[bool] = False,
2459
+ transform_space: Literal["ORIGINAL", "RELATIVE"] = "ORIGINAL",
2460
+ ) -> ObjectInfoResult[TObjectInfo]:
2461
+ """
2462
+ Uses a ObjectInfo Geometry Node.
2463
+
2464
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/object_info.html
2465
+ """
2466
+ res = nt.ProcNode.from_nodetype(
2467
+ node_type="GeometryNodeObjectInfo",
2468
+ inputs={"Object": object, "As Instance": as_instance},
2469
+ attrs={"transform_space": transform_space},
2470
+ )
2471
+ return ObjectInfoResult(
2472
+ geometry=res._output_socket("geometry"),
2473
+ transform=res._output_socket("transform"),
2474
+ location=res._output_socket("location"),
2475
+ rotation=res._output_socket("rotation"),
2476
+ scale=res._output_socket("scale"),
2477
+ )
2478
+
2479
+
2480
+ def offset_corner_in_face(
2481
+ corner_index: nt.SocketOrVal[int] = 0, offset: nt.SocketOrVal[int] = 0
2482
+ ) -> nt.ProcNode[int]:
2483
+ """
2484
+ Uses a OffsetCornerInFace Geometry Node.
2485
+
2486
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/offset_corner_in_face.html
2487
+ """
2488
+ return nt.ProcNode.from_nodetype(
2489
+ node_type="GeometryNodeOffsetCornerInFace",
2490
+ inputs={"Corner Index": corner_index, "Offset": offset},
2491
+ attrs={},
2492
+ )
2493
+
2494
+
2495
+ class OffsetPointInCurveResult(NamedTuple):
2496
+ is_valid_offset: nt.ProcNode[bool]
2497
+ point_index: nt.ProcNode[int]
2498
+
2499
+
2500
+ def offset_point_in_curve(
2501
+ point_index: nt.SocketOrVal[int] = 0, offset: nt.SocketOrVal[int] = 0
2502
+ ) -> OffsetPointInCurveResult:
2503
+ """
2504
+ Uses a OffsetPointInCurve Geometry Node.
2505
+
2506
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/topology/offset_point_in_curve.html
2507
+ """
2508
+ res = nt.ProcNode.from_nodetype(
2509
+ node_type="GeometryNodeOffsetPointInCurve",
2510
+ inputs={"Point Index": point_index, "Offset": offset},
2511
+ attrs={},
2512
+ )
2513
+ return OffsetPointInCurveResult(
2514
+ is_valid_offset=res._output_socket("is_valid_offset"),
2515
+ point_index=res._output_socket("point_index"),
2516
+ )
2517
+
2518
+
2519
+ def points(
2520
+ count: nt.SocketOrVal[int] = 1,
2521
+ position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
2522
+ radius: nt.SocketOrVal[float] = 0.1,
2523
+ ) -> nt.ProcNode[nt.Points]:
2524
+ """
2525
+ Uses a Points Geometry Node.
2526
+
2527
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/points.html
2528
+ """
2529
+ return nt.ProcNode.from_nodetype(
2530
+ node_type="GeometryNodePoints",
2531
+ inputs={"Count": count, "Position": position, "Radius": radius},
2532
+ attrs={},
2533
+ )
2534
+
2535
+
2536
+ class PointsOfCurveResult(NamedTuple):
2537
+ point_index: nt.ProcNode[int]
2538
+ total: nt.ProcNode[int]
2539
+
2540
+
2541
+ def points_of_curve(
2542
+ curve_index: nt.SocketOrVal[int] = 0,
2543
+ weights: nt.SocketOrVal[float] = 0.0,
2544
+ sort_index: nt.SocketOrVal[int] = 0,
2545
+ ) -> PointsOfCurveResult:
2546
+ """
2547
+ Uses a PointsOfCurve Geometry Node.
2548
+
2549
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/topology/points_of_curve.html
2550
+ """
2551
+ res = nt.ProcNode.from_nodetype(
2552
+ node_type="GeometryNodePointsOfCurve",
2553
+ inputs={
2554
+ "Curve Index": curve_index,
2555
+ "Weights": weights,
2556
+ "Sort Index": sort_index,
2557
+ },
2558
+ attrs={},
2559
+ )
2560
+ return PointsOfCurveResult(
2561
+ point_index=res._output_socket("point_index"),
2562
+ total=res._output_socket("total"),
2563
+ )
2564
+
2565
+
2566
+ def points_to_curves(
2567
+ points: nt.ProcNode[nt.Geometry],
2568
+ curve_group_id: nt.SocketOrVal[int] = 0,
2569
+ weight: nt.SocketOrVal[float] = 0.0,
2570
+ ) -> nt.ProcNode[pt.CurveObject]:
2571
+ """
2572
+ Uses a PointsToCurves Geometry Node.
2573
+
2574
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/points_to_curves.html
2575
+ """
2576
+ return nt.ProcNode.from_nodetype(
2577
+ node_type="GeometryNodePointsToCurves",
2578
+ inputs={"Points": points, "Curve Group ID": curve_group_id, "Weight": weight},
2579
+ attrs={},
2580
+ )
2581
+
2582
+
2583
+ def points_to_sdf_grid(
2584
+ points: nt.ProcNode[nt.Points],
2585
+ radius: nt.SocketOrVal[float] = 0.5,
2586
+ voxel_size: nt.SocketOrVal[float] = 0.3,
2587
+ ) -> nt.ProcNode:
2588
+ """
2589
+ Uses a PointsToSDFGrid Geometry Node.
2590
+
2591
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/points_to_volume.html
2592
+ """
2593
+ return nt.ProcNode.from_nodetype(
2594
+ node_type="GeometryNodePointsToSDFGrid",
2595
+ inputs={"Points": points, "Radius": radius, "Voxel Size": voxel_size},
2596
+ attrs={},
2597
+ )
2598
+
2599
+
2600
+ def points_to_vertices(
2601
+ points: nt.ProcNode[nt.Points], selection: nt.SocketOrVal[bool] = True
2602
+ ) -> nt.ProcNode[pt.MeshObject]:
2603
+ """
2604
+ Uses a PointsToVertices Geometry Node.
2605
+
2606
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/points_to_vertices.html
2607
+ """
2608
+ return nt.ProcNode.from_nodetype(
2609
+ node_type="GeometryNodePointsToVertices",
2610
+ inputs={"Points": points, "Selection": selection},
2611
+ attrs={},
2612
+ )
2613
+
2614
+
2615
+ def points_to_volume(
2616
+ points: nt.ProcNode[nt.Points],
2617
+ density: nt.SocketOrVal[float] = 1.0,
2618
+ voxel_amount: nt.SocketOrVal[float] = 64.0,
2619
+ radius: nt.SocketOrVal[float] = 0.5,
2620
+ resolution_mode: Literal["VOXEL_AMOUNT", "VOXEL_SIZE"] = "VOXEL_AMOUNT",
2621
+ ) -> nt.ProcNode[pt.VolumeObject]:
2622
+ """
2623
+ Uses a PointsToVolume Geometry Node.
2624
+
2625
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/points_to_volume.html
2626
+ """
2627
+ return nt.ProcNode.from_nodetype(
2628
+ node_type="GeometryNodePointsToVolume",
2629
+ inputs={
2630
+ "Points": points,
2631
+ "Density": density,
2632
+ "Voxel Amount": voxel_amount,
2633
+ "Radius": radius,
2634
+ },
2635
+ attrs={"resolution_mode": resolution_mode},
2636
+ )
2637
+
2638
+
2639
+ class ProximityResult(NamedTuple):
2640
+ position: nt.ProcNode[nt.pt.Vector]
2641
+ distance: nt.ProcNode[float]
2642
+ is_valid: nt.ProcNode[bool]
2643
+
2644
+
2645
+ def proximity(
2646
+ geometry: nt.ProcNode[pt.MeshObject],
2647
+ group_id: nt.SocketOrVal[int] = 0,
2648
+ sample_position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
2649
+ sample_group_id: nt.SocketOrVal[int] = 0,
2650
+ target_element: Literal["POINTS", "EDGES", "FACES"] = "FACES",
2651
+ ) -> ProximityResult:
2652
+ """
2653
+ Uses a Proximity Geometry Node.
2654
+
2655
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/sample/geometry_proximity.html
2656
+ """
2657
+ res = nt.ProcNode.from_nodetype(
2658
+ node_type="GeometryNodeProximity",
2659
+ inputs={
2660
+ "Geometry": geometry,
2661
+ "Group ID": group_id,
2662
+ "Sample Position": sample_position,
2663
+ "Sample Group ID": sample_group_id,
2664
+ },
2665
+ attrs={"target_element": target_element},
2666
+ )
2667
+ return ProximityResult(
2668
+ position=res._output_socket("position"),
2669
+ distance=res._output_socket("distance"),
2670
+ is_valid=res._output_socket("is_valid"),
2671
+ )
2672
+
2673
+
2674
+ TRaycast = TypeVar(
2675
+ "TRaycast", nt.SocketOrVal[bool], nt.SocketOrVal[int], nt.SocketOrVal[float]
2676
+ )
2677
+
2678
+
2679
+ class RaycastResult(NamedTuple):
2680
+ attribute: nt.ProcNode[nt.pt.Vector]
2681
+ hit_distance: nt.ProcNode[float]
2682
+ hit_normal: nt.ProcNode[nt.pt.Vector]
2683
+ hit_position: nt.ProcNode[nt.pt.Vector]
2684
+ is_hit: nt.ProcNode[bool]
2685
+
2686
+
2687
+ def raycast(
2688
+ geometry: nt.ProcNode[pt.MeshObject],
2689
+ attribute: TRaycast = 0,
2690
+ ray_direction: nt.SocketOrVal[nt.pt.Vector] = (0, 0, -1),
2691
+ ray_length: nt.SocketOrVal[float] = 100.0,
2692
+ source_position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
2693
+ mapping: Literal["INTERPOLATED", "NEAREST"] = "INTERPOLATED",
2694
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
2695
+ ) -> RaycastResult:
2696
+ """
2697
+ Uses a Raycast Geometry Node.
2698
+
2699
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/sample/raycast.html
2700
+ """
2701
+ if data_type is None:
2702
+ data_type = RuntimeResolveDataType(
2703
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
2704
+ ["Attribute"],
2705
+ )
2706
+ res = nt.ProcNode.from_nodetype(
2707
+ node_type="GeometryNodeRaycast",
2708
+ inputs={
2709
+ "Attribute": attribute,
2710
+ "Ray Direction": ray_direction,
2711
+ "Ray Length": ray_length,
2712
+ "Source Position": source_position,
2713
+ "Target Geometry": geometry,
2714
+ },
2715
+ attrs={
2716
+ "mapping": mapping,
2717
+ "data_type": data_type,
2718
+ },
2719
+ )
2720
+ return RaycastResult(
2721
+ attribute=res._output_socket("attribute"),
2722
+ hit_distance=res._output_socket("hit_distance"),
2723
+ hit_normal=res._output_socket("hit_normal"),
2724
+ hit_position=res._output_socket("hit_position"),
2725
+ is_hit=res._output_socket("is_hit"),
2726
+ )
2727
+
2728
+
2729
+ def realize_instances(
2730
+ geometry: nt.ProcNode[nt.Geometry] | nt.ProcNode[nt.Instances],
2731
+ selection: nt.SocketOrVal[bool] = True,
2732
+ realize_all: nt.SocketOrVal[bool] = True,
2733
+ depth: nt.SocketOrVal[int] = 0,
2734
+ ) -> nt.ProcNode[nt.Geometry]:
2735
+ """
2736
+ Uses a RealizeInstances Geometry Node.
2737
+
2738
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/realize_instances.html
2739
+ """
2740
+ return nt.ProcNode.from_nodetype(
2741
+ node_type="GeometryNodeRealizeInstances",
2742
+ inputs={
2743
+ "Geometry": geometry,
2744
+ "Selection": selection,
2745
+ "Realize All": realize_all,
2746
+ "Depth": depth,
2747
+ },
2748
+ attrs={},
2749
+ )
2750
+
2751
+
2752
+ def remove_attribute(
2753
+ geometry: nt.ProcNode[TAnyGeometry],
2754
+ name: nt.SocketOrVal[str] = "",
2755
+ pattern_mode: Literal["EXACT", "WILDCARD"] = "EXACT",
2756
+ ) -> nt.ProcNode[TAnyGeometry]:
2757
+ """
2758
+ Uses a RemoveAttribute Geometry Node.
2759
+
2760
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/attribute/remove_named_attribute.html
2761
+ """
2762
+ return nt.ProcNode.from_nodetype(
2763
+ node_type="GeometryNodeRemoveAttribute",
2764
+ inputs={"Geometry": geometry, "Name": name},
2765
+ attrs={"pattern_mode": pattern_mode},
2766
+ )
2767
+
2768
+
2769
+ def replace_material(
2770
+ geometry: nt.ProcNode[pt.MeshObject],
2771
+ old: nt.SocketOrVal[pt.Material] | None = None,
2772
+ new: nt.SocketOrVal[pt.Material] | None = None,
2773
+ ) -> nt.ProcNode[pt.MeshObject]:
2774
+ """
2775
+ Uses a ReplaceMaterial Geometry Node.
2776
+
2777
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/material/replace_material.html
2778
+ """
2779
+ return nt.ProcNode.from_nodetype(
2780
+ node_type="GeometryNodeReplaceMaterial",
2781
+ inputs={"Geometry": geometry, "Old": old, "New": new},
2782
+ attrs={},
2783
+ )
2784
+
2785
+
2786
+ def resample_curve_evaluated(
2787
+ curve: nt.ProcNode[pt.CurveObject],
2788
+ selection: nt.SocketOrVal[bool] = True,
2789
+ ) -> nt.ProcNode[pt.CurveObject]:
2790
+ """
2791
+ Uses a ResampleCurve Geometry Node with mode="EVALUATED".
2792
+
2793
+ From Blender docs: Evaluate the spline’s points based on the resolution attribute for NURBS and Bézier splines. Changes nothing for poly splines.
2794
+ https://docs.blender.org/manual/en/latest/modeling/geometry_nodes/curve/operations/resample_curve.html
2795
+ """
2796
+ return nt.ProcNode.from_nodetype(
2797
+ node_type="GeometryNodeResampleCurve",
2798
+ inputs={"Curve": curve, "Selection": selection},
2799
+ attrs={"mode": "EVALUATED"},
2800
+ )
2801
+
2802
+
2803
+ def resample_curve_count(
2804
+ curve: nt.ProcNode[pt.CurveObject],
2805
+ selection: nt.SocketOrVal[bool] = True,
2806
+ count: nt.SocketOrVal[int] = 10,
2807
+ ) -> nt.ProcNode[pt.CurveObject]:
2808
+ """
2809
+ Uses a ResampleCurve Geometry Node with mode="COUNT".
2810
+ https://docs.blender.org/manual/en/latest/modeling/geometry_nodes/curve/operations/resample_curve.html
2811
+ """
2812
+ return nt.ProcNode.from_nodetype(
2813
+ node_type="GeometryNodeResampleCurve",
2814
+ inputs={"Curve": curve, "Selection": selection, "Count": count},
2815
+ attrs={"mode": "COUNT"},
2816
+ )
2817
+
2818
+
2819
+ def resample_curve_length(
2820
+ curve: nt.ProcNode[pt.CurveObject],
2821
+ selection: nt.SocketOrVal[bool] = True,
2822
+ length: nt.SocketOrVal[float] = 1.0,
2823
+ ) -> nt.ProcNode[pt.CurveObject]:
2824
+ """
2825
+ Uses a ResampleCurve Geometry Node with mode="LENGTH".
2826
+ https://docs.blender.org/manual/en/latest/modeling/geometry_nodes/curve/operations/resample_curve.html
2827
+ """
2828
+ return nt.ProcNode.from_nodetype(
2829
+ node_type="GeometryNodeResampleCurve",
2830
+ inputs={"Curve": curve, "Selection": selection, "Length": length},
2831
+ attrs={"mode": "LENGTH"},
2832
+ )
2833
+
2834
+
2835
+ def reverse_curve(
2836
+ curve: nt.ProcNode[pt.CurveObject], selection: nt.SocketOrVal[bool] = True
2837
+ ) -> nt.ProcNode[pt.CurveObject]:
2838
+ """
2839
+ Uses a ReverseCurve Geometry Node.
2840
+
2841
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/reverse_curve.html
2842
+ """
2843
+ return nt.ProcNode.from_nodetype(
2844
+ node_type="GeometryNodeReverseCurve",
2845
+ inputs={"Curve": curve, "Selection": selection},
2846
+ attrs={},
2847
+ )
2848
+
2849
+
2850
+ def rotate_instances(
2851
+ instances: nt.ProcNode[nt.Instances],
2852
+ selection: nt.SocketOrVal[bool] = True,
2853
+ rotation: Any = (0, 0, 0),
2854
+ pivot_point: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
2855
+ local_space: nt.SocketOrVal[bool] = True,
2856
+ ) -> nt.ProcNode[nt.Instances]:
2857
+ """
2858
+ Uses a RotateInstances Geometry Node.
2859
+
2860
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/rotate_instances.html
2861
+ """
2862
+ return nt.ProcNode.from_nodetype(
2863
+ node_type="GeometryNodeRotateInstances",
2864
+ inputs={
2865
+ "Instances": instances,
2866
+ "Selection": selection,
2867
+ "Rotation": rotation,
2868
+ "Pivot Point": pivot_point,
2869
+ "Local Space": local_space,
2870
+ },
2871
+ attrs={},
2872
+ )
2873
+
2874
+
2875
+ def sdf_grid_boolean(
2876
+ grid_1: nt.SocketOrVal[float] = 0.0, grid_2: nt.SocketOrVal[float] = 0.0
2877
+ ) -> nt.ProcNode[nt.Geometry]:
2878
+ """
2879
+ Uses a SDFGridBoolean Geometry Node.
2880
+
2881
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/index.html
2882
+ """
2883
+ return nt.ProcNode.from_nodetype(
2884
+ node_type="GeometryNodeSDFGridBoolean",
2885
+ inputs={"Grid 1": grid_1, "Grid 2": grid_2},
2886
+ attrs={},
2887
+ )
2888
+
2889
+
2890
+ class SampleCurveResult(NamedTuple):
2891
+ normal: nt.ProcNode[nt.pt.Vector]
2892
+ position: nt.ProcNode[nt.pt.Vector]
2893
+ tangent: nt.ProcNode[nt.pt.Vector]
2894
+ value: nt.ProcNode[TAttribute]
2895
+
2896
+
2897
+ def sample_curve(
2898
+ curves: nt.ProcNode[nt.Geometry],
2899
+ curve_index: nt.SocketOrVal[int] = 0,
2900
+ factor: nt.SocketOrVal[float] = 0.0,
2901
+ value: nt.SocketOrVal[TAttribute] | None = None,
2902
+ mode: Literal["FACTOR", "LENGTH"] = "FACTOR",
2903
+ use_all_curves: bool = False,
2904
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
2905
+ ) -> SampleCurveResult:
2906
+ """
2907
+ Uses a SampleCurve Geometry Node.
2908
+
2909
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/sample/sample_curve.html
2910
+ """
2911
+ if data_type is None:
2912
+ data_type = RuntimeResolveDataType(
2913
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
2914
+ ["Value"],
2915
+ )
2916
+ inputs = {
2917
+ "Curves": curves,
2918
+ "Factor": factor,
2919
+ "Value": value,
2920
+ }
2921
+ if not use_all_curves:
2922
+ inputs["Curve Index"] = curve_index
2923
+ res = nt.ProcNode.from_nodetype(
2924
+ node_type="GeometryNodeSampleCurve",
2925
+ inputs=inputs,
2926
+ attrs={
2927
+ "mode": mode,
2928
+ "use_all_curves": use_all_curves,
2929
+ "data_type": data_type,
2930
+ },
2931
+ )
2932
+ return SampleCurveResult(
2933
+ normal=res._output_socket("normal"),
2934
+ position=res._output_socket("position"),
2935
+ tangent=res._output_socket("tangent"),
2936
+ value=res._output_socket("value"),
2937
+ )
2938
+
2939
+
2940
+ def sample_curve_length(
2941
+ curves: nt.ProcNode[nt.Geometry],
2942
+ length: nt.SocketOrVal[float] = 0.0,
2943
+ curve_index: nt.SocketOrVal[int] = 0,
2944
+ value: nt.SocketOrVal[TAttribute] | None = None,
2945
+ use_all_curves: bool = False,
2946
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
2947
+ ) -> SampleCurveResult:
2948
+ """
2949
+ Uses a SampleCurve Geometry Node with LENGTH mode.
2950
+
2951
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/sample/sample_curve.html
2952
+ """
2953
+ if data_type is None:
2954
+ data_type = RuntimeResolveDataType(
2955
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
2956
+ ["Value"],
2957
+ )
2958
+ inputs = {
2959
+ "Curves": curves,
2960
+ "Length": length,
2961
+ "Value": value,
2962
+ }
2963
+ if not use_all_curves:
2964
+ inputs["Curve Index"] = curve_index
2965
+ res = nt.ProcNode.from_nodetype(
2966
+ node_type="GeometryNodeSampleCurve",
2967
+ inputs=inputs,
2968
+ attrs={
2969
+ "mode": "LENGTH",
2970
+ "use_all_curves": use_all_curves,
2971
+ "data_type": data_type,
2972
+ },
2973
+ )
2974
+ return SampleCurveResult(
2975
+ normal=res._output_socket("normal"),
2976
+ position=res._output_socket("position"),
2977
+ tangent=res._output_socket("tangent"),
2978
+ value=res._output_socket("value"),
2979
+ )
2980
+
2981
+
2982
+ '''
2983
+ TSampleGrid = TypeVar(
2984
+ "TSampleGrid",
2985
+ nt.SocketOrVal[bool],
2986
+ nt.SocketOrVal[int],
2987
+ nt.SocketOrVal[float],
2988
+ nt.SocketOrVal[nt.pt.Vector],
2989
+ )
2990
+
2991
+ def sample_grid(
2992
+ grid: TSampleGrid = 0,
2993
+ position: t.SocketOrVal[t.pt.Vector] = (0, 0, 0),
2994
+ interpolation_mode: Literal["NEAREST", "TRILINEAR", "TRIQUADRATIC"] = "TRILINEAR",
2995
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
2996
+ ) -> t.ProcNode:
2997
+ """
2998
+ Uses a SampleGrid Geometry Node.
2999
+
3000
+ TODO: link
3001
+ """
3002
+ if data_type is None:
3003
+ data_type = RuntimeResolveDataType([NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT, NodeDataType.FLOAT_VECTOR], ["Grid"])
3004
+ return t.ProcNode.from_nodetype(
3005
+ node_type="GeometryNodeSampleGrid",
3006
+ inputs={"Grid": grid, "Position": position},
3007
+ attrs={
3008
+ "interpolation_mode": interpolation_mode,
3009
+ "data_type": data_type,
3010
+ },
3011
+ )
3012
+
3013
+
3014
+ TSampleGridIndex = TypeVar(
3015
+ "TSampleGridIndex",
3016
+ t.SocketOrVal[bool],
3017
+ t.SocketOrVal[int],
3018
+ t.SocketOrVal[float],
3019
+ t.SocketOrVal[t.pt.Vector],
3020
+ )
3021
+
3022
+
3023
+ def sample_grid_index(
3024
+ grid: TSampleGridIndex = 0,
3025
+ x: t.SocketOrVal[int] = 0,
3026
+ y: t.SocketOrVal[int] = 0,
3027
+ z: t.SocketOrVal[int] = 0,
3028
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
3029
+ ) -> t.ProcNode:
3030
+ """
3031
+ Uses a SampleGridIndex Geometry Node.
3032
+
3033
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/index.html
3034
+ """
3035
+ if data_type is None:
3036
+ data_type = RuntimeResolveDataType(
3037
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT, NodeDataType.FLOAT_VECTOR],
3038
+ ["Grid"],
3039
+ )
3040
+ return t.ProcNode.from_nodetype(
3041
+ node_type="GeometryNodeSampleGridIndex",
3042
+ inputs={"Grid": grid, "X": x, "Y": y, "Z": z},
3043
+ attrs={
3044
+ "data_type": data_type,
3045
+ },
3046
+ )
3047
+ '''
3048
+
3049
+
3050
+ def sample_index(
3051
+ geometry: nt.ProcNode[TAnyGeometry],
3052
+ index: nt.SocketOrVal[int] = 0,
3053
+ value: nt.ProcNode[TAttribute] | None = None,
3054
+ clamp: bool = False,
3055
+ domain: TDomain = "POINT",
3056
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
3057
+ ) -> nt.ProcNode[TAttribute]:
3058
+ """
3059
+ Uses a SampleIndex Geometry Node.
3060
+
3061
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/sample/sample_index.html
3062
+ """
3063
+ if data_type is None:
3064
+ data_type = RuntimeResolveDataType(
3065
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
3066
+ ["Value"],
3067
+ )
3068
+ return nt.ProcNode.from_nodetype(
3069
+ node_type="GeometryNodeSampleIndex",
3070
+ inputs={"Geometry": geometry, "Index": index, "Value": value},
3071
+ attrs={
3072
+ "clamp": clamp,
3073
+ "domain": domain,
3074
+ "data_type": data_type,
3075
+ },
3076
+ )
3077
+
3078
+
3079
+ def sample_nearest(
3080
+ geometry: nt.ProcNode[nt.Points],
3081
+ sample_position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3082
+ domain: Literal["POINT", "EDGE", "FACE", "CORNER"] = "POINT",
3083
+ ) -> nt.ProcNode[int]:
3084
+ """
3085
+ Uses a SampleNearest Geometry Node.
3086
+
3087
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/sample/sample_nearest.html
3088
+ """
3089
+ return nt.ProcNode.from_nodetype(
3090
+ node_type="GeometryNodeSampleNearest",
3091
+ inputs={"Geometry": geometry, "Sample Position": sample_position},
3092
+ attrs={"domain": domain},
3093
+ )
3094
+
3095
+
3096
+ class SampleResult(NamedTuple, Generic[TAttribute]):
3097
+ value: nt.ProcNode[TAttribute]
3098
+ is_valid: nt.ProcNode[bool]
3099
+
3100
+
3101
+ def sample_nearest_surface(
3102
+ mesh: nt.ProcNode[pt.MeshObject],
3103
+ value: nt.ProcNode[TAttribute] | None = None,
3104
+ group_id: nt.SocketOrVal[int] = 0,
3105
+ sample_group_id: nt.SocketOrVal[int] = 0,
3106
+ sample_position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3107
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
3108
+ ) -> SampleResult[TAttribute]:
3109
+ """
3110
+ Uses a SampleNearestSurface Geometry Node.
3111
+
3112
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/sample/sample_nearest_surface.html
3113
+ """
3114
+ if data_type is None:
3115
+ data_type = RuntimeResolveDataType(
3116
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
3117
+ ["Value"],
3118
+ )
3119
+ res = nt.ProcNode.from_nodetype(
3120
+ node_type="GeometryNodeSampleNearestSurface",
3121
+ inputs={
3122
+ "Group ID": group_id,
3123
+ "Mesh": mesh,
3124
+ "Sample Group ID": sample_group_id,
3125
+ "Sample Position": sample_position,
3126
+ "Value": value,
3127
+ },
3128
+ attrs={
3129
+ "data_type": data_type,
3130
+ },
3131
+ )
3132
+ return SampleResult(
3133
+ is_valid=res._output_socket("is_valid"),
3134
+ value=res._output_socket("value"),
3135
+ )
3136
+
3137
+
3138
+ def sample_uv_surface(
3139
+ mesh: nt.ProcNode[pt.MeshObject],
3140
+ value: nt.ProcNode[TAttribute] | None = None,
3141
+ sample_uv: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3142
+ uv_map: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3143
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
3144
+ ) -> SampleResult[TAttribute]:
3145
+ """
3146
+ Uses a SampleUVSurface Geometry Node.
3147
+
3148
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/sample/sample_uv_surface.html
3149
+ """
3150
+ if data_type is None:
3151
+ data_type = RuntimeResolveDataType(
3152
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
3153
+ ["Value"],
3154
+ )
3155
+ res = nt.ProcNode.from_nodetype(
3156
+ node_type="GeometryNodeSampleUVSurface",
3157
+ inputs={"Mesh": mesh, "Sample UV": sample_uv, "UV Map": uv_map, "Value": value},
3158
+ attrs={
3159
+ "data_type": data_type,
3160
+ },
3161
+ )
3162
+ return SampleResult(
3163
+ is_valid=res._output_socket("is_valid"),
3164
+ value=res._output_socket("value"),
3165
+ )
3166
+
3167
+
3168
+ def scale_elements(
3169
+ geometry: nt.ProcNode[nt.Geometry],
3170
+ selection: nt.SocketOrVal[bool] = True,
3171
+ scale: nt.SocketOrVal[float] = 1.0,
3172
+ center: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3173
+ axis: nt.SocketOrVal[nt.pt.Vector] | None = None,
3174
+ domain: Literal["FACE", "EDGE"] = "FACE",
3175
+ scale_mode: Literal["UNIFORM", "SINGLE_AXIS"] = "UNIFORM",
3176
+ ) -> nt.ProcNode[nt.Geometry]:
3177
+ """
3178
+ Uses a ScaleElements Geometry Node.
3179
+
3180
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/scale_elements.html
3181
+ """
3182
+ inputs = {
3183
+ "Geometry": geometry,
3184
+ "Selection": selection,
3185
+ "Scale": scale,
3186
+ "Center": center,
3187
+ }
3188
+ if scale_mode == "SINGLE_AXIS" and axis is not None:
3189
+ inputs["Axis"] = axis
3190
+ return nt.ProcNode.from_nodetype(
3191
+ node_type="GeometryNodeScaleElements",
3192
+ inputs=inputs,
3193
+ attrs={"domain": domain, "scale_mode": scale_mode},
3194
+ )
3195
+
3196
+
3197
+ def scale_instances(
3198
+ instances: nt.ProcNode[nt.Instances],
3199
+ selection: nt.SocketOrVal[bool] = True,
3200
+ scale: nt.SocketOrVal[nt.pt.Vector] = (1, 1, 1),
3201
+ center: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3202
+ local_space: nt.SocketOrVal[bool] = True,
3203
+ ) -> nt.ProcNode[nt.Instances]:
3204
+ """
3205
+ Uses a ScaleInstances Geometry Node.
3206
+
3207
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/scale_instances.html
3208
+ """
3209
+ return nt.ProcNode.from_nodetype(
3210
+ node_type="GeometryNodeScaleInstances",
3211
+ inputs={
3212
+ "Instances": instances,
3213
+ "Selection": selection,
3214
+ "Scale": scale,
3215
+ "Center": center,
3216
+ "Local Space": local_space,
3217
+ },
3218
+ attrs={},
3219
+ )
3220
+
3221
+
3222
+ def self_object() -> nt.ProcNode[pt.Object]:
3223
+ """
3224
+ Uses a SelfObject Geometry Node.
3225
+
3226
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/self_object.html
3227
+ """
3228
+ return nt.ProcNode.from_nodetype(
3229
+ node_type="GeometryNodeSelfObject",
3230
+ inputs={},
3231
+ attrs={},
3232
+ )
3233
+
3234
+
3235
+ class SeparateComponentsResult(NamedTuple):
3236
+ mesh: nt.ProcNode[pt.MeshObject]
3237
+ curve: nt.ProcNode[pt.CurveObject]
3238
+ point_cloud: nt.ProcNode[nt.Points]
3239
+ volume: nt.ProcNode[pt.VolumeObject]
3240
+ instances: nt.ProcNode[nt.Instances]
3241
+
3242
+
3243
+ def separate_components(
3244
+ geometry: nt.ProcNode[nt.Geometry],
3245
+ ) -> SeparateComponentsResult:
3246
+ """
3247
+ Uses a SeparateComponents Geometry Node.
3248
+
3249
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/separate_components.html
3250
+ """
3251
+ node = nt.ProcNode.from_nodetype(
3252
+ node_type="GeometryNodeSeparateComponents",
3253
+ inputs={"Geometry": geometry},
3254
+ attrs={},
3255
+ )
3256
+ return SeparateComponentsResult(
3257
+ node._output_socket("mesh"),
3258
+ node._output_socket("curve"),
3259
+ node._output_socket("point_cloud"),
3260
+ node._output_socket("volume"),
3261
+ node._output_socket("instances"),
3262
+ )
3263
+
3264
+
3265
+ class SeparateGeometryResult(NamedTuple, Generic[TMeshOrCurve]):
3266
+ selection: nt.ProcNode[TMeshOrCurve]
3267
+ inverted: nt.ProcNode[TMeshOrCurve]
3268
+
3269
+
3270
+ def separate_geometry(
3271
+ geometry: nt.ProcNode[TMeshOrCurve],
3272
+ selection: nt.SocketOrVal[bool] = True,
3273
+ domain: Literal["POINT", "EDGE", "FACE", "CURVE", "INSTANCE", "LAYER"] = "POINT",
3274
+ ) -> SeparateGeometryResult[TMeshOrCurve]:
3275
+ """
3276
+ Uses a SeparateGeometry Geometry Node.
3277
+
3278
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/separate_geometry.html
3279
+ """
3280
+ res = nt.ProcNode.from_nodetype(
3281
+ node_type="GeometryNodeSeparateGeometry",
3282
+ inputs={"Geometry": geometry, "Selection": selection},
3283
+ attrs={"domain": domain},
3284
+ )
3285
+
3286
+ return SeparateGeometryResult(
3287
+ selection=res._output_socket("selection"),
3288
+ inverted=res._output_socket("inverted"),
3289
+ )
3290
+
3291
+
3292
+ def set_curve_handle_positions(
3293
+ curve: nt.ProcNode[pt.CurveObject],
3294
+ selection: nt.SocketOrVal[bool] = True,
3295
+ position: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3296
+ offset: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3297
+ mode: Literal["LEFT", "RIGHT"] = "LEFT",
3298
+ ) -> nt.ProcNode[pt.CurveObject]:
3299
+ """
3300
+ Uses a SetCurveHandlePositions Geometry Node.
3301
+
3302
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_handle_positions.html
3303
+ """
3304
+ return nt.ProcNode.from_nodetype(
3305
+ node_type="GeometryNodeSetCurveHandlePositions",
3306
+ inputs={
3307
+ "Curve": curve,
3308
+ "Selection": selection,
3309
+ "Position": position,
3310
+ "Offset": offset,
3311
+ },
3312
+ attrs={"mode": mode},
3313
+ )
3314
+
3315
+
3316
+ def set_curve_normal(
3317
+ curve: nt.ProcNode[pt.CurveObject],
3318
+ selection: nt.SocketOrVal[bool] = True,
3319
+ mode: Literal["MINIMUM_TWIST", "Z_UP", "FREE"] = "MINIMUM_TWIST",
3320
+ normal: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 1),
3321
+ ) -> nt.ProcNode[pt.CurveObject]:
3322
+ """
3323
+ Uses a SetCurveNormal Geometry Node.
3324
+
3325
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_curve_normal.html
3326
+ """
3327
+ return nt.ProcNode.from_nodetype(
3328
+ node_type="GeometryNodeSetCurveNormal",
3329
+ inputs={"Curve": curve, "Selection": selection, "Normal": normal},
3330
+ attrs={"mode": mode},
3331
+ )
3332
+
3333
+
3334
+ def set_curve_radius(
3335
+ curve: nt.ProcNode[pt.CurveObject],
3336
+ selection: nt.SocketOrVal[bool] = True,
3337
+ radius: nt.SocketOrVal[float] = 0.005,
3338
+ ) -> nt.ProcNode[pt.CurveObject]:
3339
+ """
3340
+ Uses a SetCurveRadius Geometry Node.
3341
+
3342
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_curve_radius.html
3343
+ """
3344
+ return nt.ProcNode.from_nodetype(
3345
+ node_type="GeometryNodeSetCurveRadius",
3346
+ inputs={"Curve": curve, "Selection": selection, "Radius": radius},
3347
+ attrs={},
3348
+ )
3349
+
3350
+
3351
+ def set_curve_tilt(
3352
+ curve: nt.ProcNode[pt.CurveObject],
3353
+ selection: nt.SocketOrVal[bool] = True,
3354
+ tilt: nt.SocketOrVal[float] = 0.0,
3355
+ ) -> nt.ProcNode[pt.CurveObject]:
3356
+ """
3357
+ Uses a SetCurveTilt Geometry Node.
3358
+
3359
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_curve_tilt.html
3360
+ """
3361
+ return nt.ProcNode.from_nodetype(
3362
+ node_type="GeometryNodeSetCurveTilt",
3363
+ inputs={"Curve": curve, "Selection": selection, "Tilt": tilt},
3364
+ attrs={},
3365
+ )
3366
+
3367
+
3368
+ def set_id(
3369
+ geometry: nt.ProcNode[TAnyGeometry],
3370
+ selection: nt.SocketOrVal[bool] = True,
3371
+ id: nt.SocketOrVal[int] = 0,
3372
+ ) -> nt.ProcNode[TAnyGeometry]:
3373
+ """
3374
+ Uses a SetID Geometry Node.
3375
+
3376
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/write/set_id.html
3377
+ """
3378
+ return nt.ProcNode.from_nodetype(
3379
+ node_type="GeometryNodeSetID",
3380
+ inputs={"Geometry": geometry, "Selection": selection, "ID": id},
3381
+ attrs={},
3382
+ )
3383
+
3384
+
3385
+ def set_instance_transform(
3386
+ instances: nt.ProcNode[nt.Instances],
3387
+ transform: nt.SocketOrVal[pt.Matrix] | None = None,
3388
+ selection: nt.SocketOrVal[bool] = True,
3389
+ ) -> nt.ProcNode[nt.Instances]:
3390
+ """
3391
+ Uses a SetInstanceTransform Geometry Node.
3392
+
3393
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/set_instance_transform.html
3394
+ """
3395
+ return nt.ProcNode.from_nodetype(
3396
+ node_type="GeometryNodeSetInstanceTransform",
3397
+ inputs={"Instances": instances, "Selection": selection, "Transform": transform},
3398
+ attrs={},
3399
+ )
3400
+
3401
+
3402
+ def set_material(
3403
+ geometry: nt.ProcNode[pt.MeshObject],
3404
+ material: nt.SocketOrVal[pt.Material] = None,
3405
+ selection: nt.SocketOrVal[bool] = None,
3406
+ ) -> nt.ProcNode[pt.MeshObject]:
3407
+ """
3408
+ Uses a SetMaterial Geometry Node.
3409
+
3410
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/material/set_material.html
3411
+ """
3412
+ return nt.ProcNode.from_nodetype(
3413
+ node_type="GeometryNodeSetMaterial",
3414
+ inputs={"Geometry": geometry, "Selection": selection, "Material": material},
3415
+ attrs={},
3416
+ )
3417
+
3418
+
3419
+ def set_material_index(
3420
+ geometry: nt.ProcNode[pt.MeshObject],
3421
+ selection: nt.SocketOrVal[bool] = True,
3422
+ material_index: nt.SocketOrVal[int] = 0,
3423
+ ) -> nt.ProcNode[pt.MeshObject]:
3424
+ """
3425
+ Uses a SetMaterialIndex Geometry Node.
3426
+
3427
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/material/set_material_index.html
3428
+ """
3429
+ return nt.ProcNode.from_nodetype(
3430
+ node_type="GeometryNodeSetMaterialIndex",
3431
+ inputs={
3432
+ "Geometry": geometry,
3433
+ "Selection": selection,
3434
+ "Material Index": material_index,
3435
+ },
3436
+ attrs={},
3437
+ )
3438
+
3439
+
3440
+ def set_point_radius(
3441
+ points: nt.ProcNode[pt.PointCloudObject],
3442
+ selection: nt.SocketOrVal[bool] = True,
3443
+ radius: nt.SocketOrVal[float] = 0.05,
3444
+ ) -> nt.ProcNode[pt.PointCloudObject]:
3445
+ """
3446
+ Uses a SetPointRadius Geometry Node.
3447
+
3448
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/point/set_point_radius.html
3449
+ """
3450
+ return nt.ProcNode.from_nodetype(
3451
+ node_type="GeometryNodeSetPointRadius",
3452
+ inputs={"Points": points, "Selection": selection, "Radius": radius},
3453
+ attrs={},
3454
+ )
3455
+
3456
+
3457
+ def set_position(
3458
+ geometry: nt.ProcNode[TAnyGeometry],
3459
+ selection: nt.SocketOrVal[bool] = True,
3460
+ position: nt.SocketOrVal[pt.Vector] = (0, 0, 0),
3461
+ offset: nt.SocketOrVal[pt.Vector] = (0, 0, 0),
3462
+ ) -> nt.ProcNode[TAnyGeometry]:
3463
+ """
3464
+ Uses a SetPosition Geometry Node.
3465
+
3466
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/write/set_position.html
3467
+ """
3468
+ return nt.ProcNode.from_nodetype(
3469
+ node_type="GeometryNodeSetPosition",
3470
+ inputs={
3471
+ "Geometry": geometry,
3472
+ "Selection": selection,
3473
+ "Position": position,
3474
+ "Offset": offset,
3475
+ },
3476
+ attrs={},
3477
+ )
3478
+
3479
+
3480
+ def set_shade_smooth(
3481
+ geometry: nt.ProcNode[pt.MeshObject],
3482
+ selection: nt.SocketOrVal[bool] = True,
3483
+ shade_smooth: nt.SocketOrVal[bool] = True,
3484
+ domain: Literal["EDGE", "FACE"] = "FACE",
3485
+ ) -> nt.ProcNode[pt.MeshObject]:
3486
+ """
3487
+ Uses a SetShadeSmooth Geometry Node.
3488
+
3489
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/write/set_shade_smooth.html
3490
+ """
3491
+ return nt.ProcNode.from_nodetype(
3492
+ node_type="GeometryNodeSetShadeSmooth",
3493
+ inputs={
3494
+ "Geometry": geometry,
3495
+ "Selection": selection,
3496
+ "Shade Smooth": shade_smooth,
3497
+ },
3498
+ attrs={"domain": domain},
3499
+ )
3500
+
3501
+
3502
+ def set_spline_cyclic(
3503
+ curve: nt.ProcNode[pt.CurveObject],
3504
+ selection: nt.SocketOrVal[bool] = True,
3505
+ cyclic: nt.SocketOrVal[bool] = False,
3506
+ ) -> nt.ProcNode[pt.CurveObject]:
3507
+ """
3508
+ Uses a SetSplineCyclic Geometry Node.
3509
+
3510
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_spline_cyclic.html
3511
+ """
3512
+ return nt.ProcNode.from_nodetype(
3513
+ node_type="GeometryNodeSetSplineCyclic",
3514
+ inputs={"Geometry": curve, "Selection": selection, "Cyclic": cyclic},
3515
+ attrs={},
3516
+ )
3517
+
3518
+
3519
+ def set_spline_resolution(
3520
+ curve: nt.ProcNode[pt.CurveObject],
3521
+ selection: nt.SocketOrVal[bool] = True,
3522
+ resolution: nt.SocketOrVal[int] = 12,
3523
+ ) -> nt.ProcNode[pt.CurveObject]:
3524
+ """
3525
+ Uses a SetSplineResolution Geometry Node.
3526
+
3527
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/write/set_spline_resolution.html
3528
+ """
3529
+ return nt.ProcNode.from_nodetype(
3530
+ node_type="GeometryNodeSetSplineResolution",
3531
+ inputs={"Geometry": curve, "Selection": selection, "Resolution": resolution},
3532
+ attrs={},
3533
+ )
3534
+
3535
+
3536
+ def sort_elements(
3537
+ geometry: nt.ProcNode[TAnyGeometry],
3538
+ selection: nt.SocketOrVal[bool] = True,
3539
+ group_id: nt.SocketOrVal[int] = 0,
3540
+ sort_weight: nt.SocketOrVal[float] = 0.0,
3541
+ domain: Literal["POINT", "EDGE", "FACE", "CURVE", "INSTANCE"] = "POINT",
3542
+ ) -> nt.ProcNode[TAnyGeometry]:
3543
+ """
3544
+ Uses a SortElements Geometry Node.
3545
+
3546
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/sort_elements.html
3547
+ """
3548
+ return nt.ProcNode.from_nodetype(
3549
+ node_type="GeometryNodeSortElements",
3550
+ inputs={
3551
+ "Geometry": geometry,
3552
+ "Selection": selection,
3553
+ "Group ID": group_id,
3554
+ "Sort Weight": sort_weight,
3555
+ },
3556
+ attrs={"domain": domain},
3557
+ )
3558
+
3559
+
3560
+ class SplineLengthResult(NamedTuple):
3561
+ length: nt.ProcNode[float]
3562
+ point_count: nt.ProcNode[int]
3563
+
3564
+
3565
+ def spline_length() -> SplineLengthResult:
3566
+ """
3567
+ Uses a SplineLength Geometry Node.
3568
+
3569
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/spline_length.html
3570
+ """
3571
+ node = nt.ProcNode.from_nodetype(
3572
+ node_type="GeometryNodeSplineLength",
3573
+ inputs={},
3574
+ attrs={},
3575
+ )
3576
+ return SplineLengthResult(
3577
+ node._output_socket("length"), node._output_socket("point_count")
3578
+ )
3579
+
3580
+
3581
+ class SplineParameterResult(NamedTuple):
3582
+ factor: nt.ProcNode[float]
3583
+ length: nt.ProcNode[float]
3584
+ index: nt.ProcNode[int]
3585
+
3586
+
3587
+ def spline_parameter() -> SplineParameterResult:
3588
+ """
3589
+ Uses a SplineParameter Geometry Node.
3590
+
3591
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/read/spline_parameter.html
3592
+ """
3593
+ node = nt.ProcNode.from_nodetype(
3594
+ node_type="GeometryNodeSplineParameter",
3595
+ inputs={},
3596
+ attrs={},
3597
+ )
3598
+ return SplineParameterResult(
3599
+ node._output_socket("factor"),
3600
+ node._output_socket("length"),
3601
+ node._output_socket("index"),
3602
+ )
3603
+
3604
+
3605
+ def split_edges(
3606
+ mesh: nt.ProcNode[pt.MeshObject], selection: nt.SocketOrVal[bool] = True
3607
+ ) -> nt.ProcNode[pt.MeshObject]:
3608
+ """
3609
+ Uses a SplitEdges Geometry Node.
3610
+
3611
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/split_edges.html
3612
+ """
3613
+ return nt.ProcNode.from_nodetype(
3614
+ node_type="GeometryNodeSplitEdges",
3615
+ inputs={"Mesh": mesh, "Selection": selection},
3616
+ attrs={},
3617
+ )
3618
+
3619
+
3620
+ class SplitToInstancesResult(NamedTuple):
3621
+ instances: nt.ProcNode[nt.Instances]
3622
+ group_id: nt.ProcNode[int]
3623
+
3624
+
3625
+ def split_to_instances(
3626
+ geometry: nt.ProcNode[pt.MeshObject],
3627
+ selection: nt.SocketOrVal[bool] = True,
3628
+ group_id: nt.SocketOrVal[int] = 0,
3629
+ domain: Literal["POINT", "EDGE", "FACE", "CURVE", "INSTANCE", "LAYER"] = "POINT",
3630
+ ) -> SplitToInstancesResult:
3631
+ """
3632
+ Uses a SplitToInstances Geometry Node.
3633
+
3634
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/split_to_instances.html
3635
+ """
3636
+ res = nt.ProcNode.from_nodetype(
3637
+ node_type="GeometryNodeSplitToInstances",
3638
+ inputs={"Geometry": geometry, "Selection": selection, "Group ID": group_id},
3639
+ attrs={"domain": domain},
3640
+ )
3641
+ return SplitToInstancesResult(
3642
+ instances=res._output_socket("instances"),
3643
+ group_id=res._output_socket("group_id"),
3644
+ )
3645
+
3646
+
3647
+ def store_named_attribute(
3648
+ geometry: nt.ProcNode[TMeshOrCurve],
3649
+ name: nt.SocketOrVal[str] = "",
3650
+ selection: nt.SocketOrVal[bool] = True,
3651
+ value: nt.SocketOrVal[TAttribute] | None = None,
3652
+ domain: TDomain = "POINT",
3653
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
3654
+ ) -> nt.ProcNode[TMeshOrCurve]:
3655
+ """
3656
+ Uses a StoreNamedAttribute Geometry Node.
3657
+
3658
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/attribute/store_named_attribute.html
3659
+ """
3660
+ if data_type is None:
3661
+ data_type = RuntimeResolveDataType(
3662
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
3663
+ ["Value"],
3664
+ )
3665
+
3666
+ return nt.ProcNode.from_nodetype(
3667
+ node_type="GeometryNodeStoreNamedAttribute",
3668
+ inputs={
3669
+ "Geometry": geometry,
3670
+ "Name": name,
3671
+ "Selection": selection,
3672
+ "Value": value,
3673
+ },
3674
+ attrs={
3675
+ "domain": domain,
3676
+ "data_type": data_type,
3677
+ },
3678
+ )
3679
+
3680
+
3681
+ def store_named_grid(
3682
+ volume: nt.ProcNode[nt.Geometry],
3683
+ grid: nt.SocketOrVal[float] = 0.0,
3684
+ name: nt.SocketOrVal[str] = "",
3685
+ ) -> nt.ProcNode:
3686
+ """
3687
+ Uses a StoreNamedGrid Geometry Node.
3688
+
3689
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/index.html
3690
+ """
3691
+ return nt.ProcNode.from_nodetype(
3692
+ node_type="GeometryNodeStoreNamedGrid",
3693
+ inputs={"Grid": grid, "Name": name, "Volume": volume},
3694
+ attrs={},
3695
+ )
3696
+
3697
+
3698
+ def string_join(
3699
+ strings: list[nt.SocketOrVal[str]],
3700
+ delimiter: nt.SocketOrVal[str] = "",
3701
+ ) -> nt.ProcNode[str]:
3702
+ """
3703
+ Uses a StringJoin Geometry Node.
3704
+
3705
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/text/join_strings.html
3706
+ """
3707
+ return nt.ProcNode.from_nodetype(
3708
+ node_type="GeometryNodeStringJoin",
3709
+ inputs={"Delimiter": delimiter, "Strings": strings},
3710
+ attrs={},
3711
+ )
3712
+
3713
+
3714
+ class StringToCurvesResult(NamedTuple):
3715
+ curve_instances: nt.ProcNode[nt.Instances]
3716
+ line: nt.ProcNode[pt.CurveObject]
3717
+ pivot_point: nt.ProcNode[nt.pt.Vector]
3718
+
3719
+
3720
+ def string_to_curves(
3721
+ string: nt.SocketOrVal[str],
3722
+ size: nt.SocketOrVal[float] = 1.0,
3723
+ character_spacing: nt.SocketOrVal[float] = 1.0,
3724
+ word_spacing: nt.SocketOrVal[float] = 1.0,
3725
+ line_spacing: nt.SocketOrVal[float] = 1.0,
3726
+ text_box_width: nt.SocketOrVal[float] = 0.0,
3727
+ align_x: Literal["LEFT", "CENTER", "RIGHT", "JUSTIFY", "FLUSH"] = "LEFT",
3728
+ align_y: Literal[
3729
+ "TOP", "TOP_BASELINE", "MIDDLE", "BOTTOM_BASELINE", "BOTTOM"
3730
+ ] = "TOP_BASELINE",
3731
+ overflow: Literal["OVERFLOW", "SCALE_TO_FIT", "TRUNCATE"] = "OVERFLOW",
3732
+ pivot_mode: Literal[
3733
+ "MIDPOINT",
3734
+ "TOP_LEFT",
3735
+ "TOP_CENTER",
3736
+ "TOP_RIGHT",
3737
+ "BOTTOM_LEFT",
3738
+ "BOTTOM_CENTER",
3739
+ "BOTTOM_RIGHT",
3740
+ ] = "BOTTOM_LEFT",
3741
+ ) -> StringToCurvesResult:
3742
+ """
3743
+ Uses a StringToCurves Geometry Node.
3744
+
3745
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/text/string_to_curves.html
3746
+ """
3747
+ res = nt.ProcNode.from_nodetype(
3748
+ node_type="GeometryNodeStringToCurves",
3749
+ inputs={
3750
+ "String": string,
3751
+ "Size": size,
3752
+ "Character Spacing": character_spacing,
3753
+ "Word Spacing": word_spacing,
3754
+ "Line Spacing": line_spacing,
3755
+ "Text Box Width": text_box_width,
3756
+ },
3757
+ attrs={
3758
+ "align_x": align_x,
3759
+ "align_y": align_y,
3760
+ "overflow": overflow,
3761
+ "pivot_mode": pivot_mode,
3762
+ },
3763
+ )
3764
+
3765
+ return StringToCurvesResult(
3766
+ curve_instances=res._output_socket("curve_instances"),
3767
+ line=res._output_socket("line"),
3768
+ pivot_point=res._output_socket("pivot_point"),
3769
+ )
3770
+
3771
+
3772
+ def subdivide_curve(
3773
+ curve: nt.ProcNode[pt.CurveObject], cuts: nt.SocketOrVal[int] = 1
3774
+ ) -> nt.ProcNode[pt.CurveObject]:
3775
+ """
3776
+ Uses a SubdivideCurve Geometry Node.
3777
+
3778
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/subdivide_curve.html
3779
+ """
3780
+ return nt.ProcNode.from_nodetype(
3781
+ node_type="GeometryNodeSubdivideCurve",
3782
+ inputs={"Curve": curve, "Cuts": cuts},
3783
+ attrs={},
3784
+ )
3785
+
3786
+
3787
+ def subdivide_mesh(
3788
+ mesh: nt.ProcNode[pt.MeshObject], level: nt.SocketOrVal[int] = 1
3789
+ ) -> nt.ProcNode[pt.MeshObject]:
3790
+ """
3791
+ Uses a SubdivideMesh Geometry Node.
3792
+
3793
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/subdivide_mesh.html
3794
+ """
3795
+ return nt.ProcNode.from_nodetype(
3796
+ node_type="GeometryNodeSubdivideMesh",
3797
+ inputs={"Mesh": mesh, "Level": level},
3798
+ attrs={},
3799
+ )
3800
+
3801
+
3802
+ def subdivision_surface(
3803
+ mesh: nt.ProcNode[pt.MeshObject],
3804
+ level: nt.SocketOrVal[int] = 1,
3805
+ edge_crease: nt.SocketOrVal[float] = 0.0,
3806
+ vertex_crease: nt.SocketOrVal[float] = 0.0,
3807
+ boundary_smooth: Literal["PRESERVE_CORNERS", "ALL"] = "ALL",
3808
+ uv_smooth: Literal[
3809
+ "NONE",
3810
+ "PRESERVE_CORNERS",
3811
+ "PRESERVE_CORNERS_AND_JUNCTIONS",
3812
+ "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE",
3813
+ "PRESERVE_BOUNDARIES",
3814
+ "SMOOTH_ALL",
3815
+ ] = "PRESERVE_BOUNDARIES",
3816
+ ) -> nt.ProcNode[pt.MeshObject]:
3817
+ """
3818
+ Uses a SubdivisionSurface Geometry Node.
3819
+
3820
+ See: http://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/operations/mesh/subdivision_surface.html
3821
+ """
3822
+ return nt.ProcNode.from_nodetype(
3823
+ node_type="GeometryNodeSubdivisionSurface",
3824
+ inputs={
3825
+ "Mesh": mesh,
3826
+ "Level": level,
3827
+ "Edge Crease": edge_crease,
3828
+ "Vertex Crease": vertex_crease,
3829
+ },
3830
+ attrs={"boundary_smooth": boundary_smooth, "uv_smooth": uv_smooth},
3831
+ )
3832
+
3833
+
3834
+ _SWITCH_DATA_TYPES = [
3835
+ NodeDataType.BOOLEAN,
3836
+ NodeDataType.INT,
3837
+ NodeDataType.FLOAT,
3838
+ NodeDataType.FLOAT_VECTOR,
3839
+ NodeDataType.ROTATION,
3840
+ NodeDataType.FLOAT_MATRIX,
3841
+ NodeDataType.STRING,
3842
+ NodeDataType.RGBA,
3843
+ NodeDataType.OBJECT,
3844
+ # NodeDataType.IMAGE, # TODO verify support
3845
+ NodeDataType.GEOMETRY,
3846
+ NodeDataType.COLLECTION,
3847
+ # NodeDataType.TEXTURE, # TODO verify support
3848
+ NodeDataType.MATERIAL,
3849
+ ]
3850
+
3851
+ '''
3852
+
3853
+ class Tool3DCursorResult(NamedTuple):
3854
+ location: t.ProcNode[pt.Vector]
3855
+ rotation: t.ProcNode[pt.Vector]
3856
+
3857
+ def tool3_d_cursor() -> Tool3DCursorResult:
3858
+ """
3859
+ Uses a Tool3DCursor Geometry Node.
3860
+
3861
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/3d_cursor.html
3862
+ """
3863
+ node = t.ProcNode.from_nodetype(
3864
+ node_type="GeometryNodeTool3DCursor",
3865
+ inputs={},
3866
+ attrs={},
3867
+ )
3868
+ return Tool3DCursorResult(node._output_socket("location"), node._output_socket("rotation"))
3869
+
3870
+
3871
+ class ToolActiveElementResult(NamedTuple):
3872
+ index: t.ProcNode[int]
3873
+ exists: t.ProcNode[bool]
3874
+
3875
+
3876
+ def tool_active_element(domain: TDomain = "POINT") -> ToolActiveElementResult:
3877
+ """
3878
+ Uses a ToolActiveElement Geometry Node.
3879
+
3880
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/active_element.html
3881
+ """
3882
+ node = t.ProcNode.from_nodetype(
3883
+ node_type="GeometryNodeToolActiveElement",
3884
+ inputs={},
3885
+ attrs={"domain": domain},
3886
+ )
3887
+ return ToolActiveElementResult(node._output_socket("index"), node._output_socket("exists"))
3888
+
3889
+
3890
+ class ToolFaceSetResult(NamedTuple):
3891
+ face_set: t.ProcNode[int]
3892
+ exists: t.ProcNode[bool]
3893
+
3894
+
3895
+ def tool_face_set() -> ToolFaceSetResult:
3896
+ """
3897
+ Uses a ToolFaceSet Geometry Node.
3898
+
3899
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/read/face_set.html
3900
+ """
3901
+ node = t.ProcNode.from_nodetype(
3902
+ node_type="GeometryNodeToolFaceSet",
3903
+ inputs={},
3904
+ attrs={},
3905
+ )
3906
+ return ToolFaceSetResult(node._output_socket("face_set"), node._output_socket("exists"))
3907
+
3908
+
3909
+ class ToolMousePositionResult(NamedTuple):
3910
+ mouse_x: t.ProcNode[float]
3911
+ mouse_y: t.ProcNode[float]
3912
+ region_width: t.ProcNode[int]
3913
+ region_height: t.ProcNode[int]
3914
+
3915
+
3916
+ def tool_mouse_position() -> ToolMousePositionResult:
3917
+ """
3918
+ Uses a ToolMousePosition Geometry Node.
3919
+
3920
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/mouse_position.html
3921
+ """
3922
+ node = t.ProcNode.from_nodetype(
3923
+ node_type="GeometryNodeToolMousePosition",
3924
+ inputs={},
3925
+ attrs={},
3926
+ )
3927
+ return ToolMousePositionResult(
3928
+ node._output_socket("mouse_x"), node._output_socket("mouse_y"), node._output_socket("region_width"), node._output_socket("region_height")
3929
+ )
3930
+
3931
+
3932
+ def tool_selection() -> t.ProcNode:
3933
+ """
3934
+ Uses a ToolSelection Geometry Node.
3935
+
3936
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/read/selection.html
3937
+ """
3938
+ return t.ProcNode.from_nodetype(
3939
+ node_type="GeometryNodeToolSelection",
3940
+ inputs={},
3941
+ attrs={},
3942
+ )
3943
+
3944
+
3945
+ def tool_set_face_set(
3946
+ mesh: t.ProcNode[pt.MeshObject],
3947
+ selection: t.SocketOrVal[bool] = True,
3948
+ face_set: t.SocketOrVal[int] = 0,
3949
+ ) -> t.ProcNode:
3950
+ """
3951
+ Uses a ToolSetFaceSet Geometry Node.
3952
+
3953
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/write/set_face_set.html
3954
+ """
3955
+ return t.ProcNode.from_nodetype(
3956
+ node_type="GeometryNodeToolSetFaceSet",
3957
+ inputs={"Mesh": mesh, "Selection": selection, "Face Set": face_set},
3958
+ attrs={},
3959
+ )
3960
+
3961
+
3962
+ def tool_set_selection(
3963
+ geometry: t.ProcNode[t.Geometry],
3964
+ selection: t.SocketOrVal[bool] = True,
3965
+ domain: TDomain = "POINT",
3966
+ ) -> t.ProcNode:
3967
+ """
3968
+ Uses a ToolSetSelection Geometry Node.
3969
+
3970
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/write/set_selection.html
3971
+ """
3972
+ return t.ProcNode.from_nodetype(
3973
+ node_type="GeometryNodeToolSetSelection",
3974
+ inputs={"Geometry": geometry, "Selection": selection},
3975
+ attrs={"domain": domain},
3976
+ )
3977
+ '''
3978
+
3979
+
3980
+ def transform(
3981
+ geometry: nt.ProcNode[TMeshOrCurve],
3982
+ translation: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
3983
+ rotation: Any = (0, 0, 0),
3984
+ scale: nt.SocketOrVal[nt.pt.Vector] = (1, 1, 1),
3985
+ ) -> nt.ProcNode[TMeshOrCurve]:
3986
+ """
3987
+ Uses a Transform Geometry Node.
3988
+
3989
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/transform_geometry.html
3990
+ """
3991
+ return nt.ProcNode.from_nodetype(
3992
+ node_type="GeometryNodeTransform",
3993
+ inputs={
3994
+ "Geometry": geometry,
3995
+ "Translation": translation,
3996
+ "Rotation": rotation,
3997
+ "Scale": scale,
3998
+ },
3999
+ attrs={"mode": "COMPONENTS"},
4000
+ )
4001
+
4002
+
4003
+ def transform_by_matrix(
4004
+ geometry: nt.ProcNode[TMeshOrCurve],
4005
+ matrix: nt.SocketOrVal[pt.Matrix],
4006
+ ):
4007
+ return nt.ProcNode.from_nodetype(
4008
+ node_type="GeometryNodeTransformByMatrix",
4009
+ inputs={
4010
+ "Geometry": geometry,
4011
+ "Matrix": matrix,
4012
+ },
4013
+ attrs={"mode": "MATRIX"},
4014
+ )
4015
+
4016
+
4017
+ def translate_instances(
4018
+ instances: nt.ProcNode[nt.Instances],
4019
+ selection: nt.SocketOrVal[bool] = True,
4020
+ translation: nt.SocketOrVal[nt.pt.Vector] = (0, 0, 0),
4021
+ local_space: nt.SocketOrVal[bool] = True,
4022
+ ) -> nt.ProcNode[nt.Instances]:
4023
+ """
4024
+ Uses a TranslateInstances Geometry Node.
4025
+
4026
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/instances/translate_instances.html
4027
+ """
4028
+ return nt.ProcNode.from_nodetype(
4029
+ node_type="GeometryNodeTranslateInstances",
4030
+ inputs={
4031
+ "Instances": instances,
4032
+ "Selection": selection,
4033
+ "Translation": translation,
4034
+ "Local Space": local_space,
4035
+ },
4036
+ attrs={},
4037
+ )
4038
+
4039
+
4040
+ def triangulate(
4041
+ mesh: nt.ProcNode[pt.MeshObject],
4042
+ selection: nt.SocketOrVal[bool] = True,
4043
+ minimum_vertices: nt.SocketOrVal[int] = 4,
4044
+ ngon_method: Literal["BEAUTY", "CLIP"] = "BEAUTY",
4045
+ quad_method: Literal[
4046
+ "BEAUTY", "FIXED", "FIXED_ALTERNATE", "SHORTEST_DIAGONAL", "LONGEST_DIAGONAL"
4047
+ ] = "SHORTEST_DIAGONAL",
4048
+ ) -> nt.ProcNode[pt.MeshObject]:
4049
+ """
4050
+ Uses a Triangulate Geometry Node.
4051
+
4052
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/operations/triangulate.html
4053
+ """
4054
+ return nt.ProcNode.from_nodetype(
4055
+ node_type="GeometryNodeTriangulate",
4056
+ inputs={
4057
+ "Mesh": mesh,
4058
+ "Selection": selection,
4059
+ "Minimum Vertices": minimum_vertices,
4060
+ },
4061
+ attrs={"ngon_method": ngon_method, "quad_method": quad_method},
4062
+ )
4063
+
4064
+
4065
+ def trim_curve(
4066
+ curve: nt.ProcNode[pt.CurveObject],
4067
+ selection: nt.SocketOrVal[bool] = True,
4068
+ start: nt.SocketOrVal[float] = 0.0,
4069
+ end: nt.SocketOrVal[float] = 1.0,
4070
+ mode: Literal["FACTOR", "LENGTH"] = "FACTOR",
4071
+ ) -> nt.ProcNode[pt.CurveObject]:
4072
+ """
4073
+ Uses a TrimCurve Geometry Node.
4074
+
4075
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/operations/trim_curve.html
4076
+ """
4077
+ return nt.ProcNode.from_nodetype(
4078
+ node_type="GeometryNodeTrimCurve",
4079
+ inputs={"Curve": curve, "Selection": selection, "Start": start, "End": end},
4080
+ attrs={"mode": mode},
4081
+ )
4082
+
4083
+
4084
+ def uv_pack_islands(
4085
+ uv: nt.SocketOrVal[pt.Vector] = (0, 0, 0),
4086
+ selection: nt.SocketOrVal[bool] = True,
4087
+ margin: nt.SocketOrVal[float] = 0.001,
4088
+ rotate: nt.SocketOrVal[bool] = True,
4089
+ ) -> nt.ProcNode[pt.Vector]:
4090
+ """
4091
+ Uses a UVPackIslands Geometry Node.
4092
+
4093
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/uv/pack_uv_islands.html
4094
+ """
4095
+ return nt.ProcNode.from_nodetype(
4096
+ node_type="GeometryNodeUVPackIslands",
4097
+ inputs={"UV": uv, "Selection": selection, "Margin": margin, "Rotate": rotate},
4098
+ attrs={},
4099
+ )
4100
+
4101
+
4102
+ def uv_unwrap(
4103
+ selection: nt.SocketOrVal[bool] = True,
4104
+ seam: nt.SocketOrVal[bool] = False,
4105
+ margin: nt.SocketOrVal[float] = 0.001,
4106
+ fill_holes: nt.SocketOrVal[bool] = True,
4107
+ method: Literal["ANGLE_BASED", "CONFORMAL"] = "ANGLE_BASED",
4108
+ ) -> nt.ProcNode[pt.Vector]:
4109
+ """
4110
+ Uses a UVUnwrap Geometry Node.
4111
+
4112
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/uv/uv_unwrap.html
4113
+ """
4114
+ return nt.ProcNode.from_nodetype(
4115
+ node_type="GeometryNodeUVUnwrap",
4116
+ inputs={
4117
+ "Selection": selection,
4118
+ "Seam": seam,
4119
+ "Margin": margin,
4120
+ "Fill Holes": fill_holes,
4121
+ },
4122
+ attrs={"method": method},
4123
+ )
4124
+
4125
+
4126
+ def vertex_of_corner(corner_index: nt.SocketOrVal[int] = 0) -> nt.ProcNode[int]:
4127
+ """
4128
+ Uses a VertexOfCorner Geometry Node.
4129
+
4130
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/mesh/topology/vertex_of_corner.html
4131
+ """
4132
+ return nt.ProcNode.from_nodetype(
4133
+ node_type="GeometryNodeVertexOfCorner",
4134
+ inputs={"Corner Index": corner_index},
4135
+ attrs={},
4136
+ )
4137
+
4138
+
4139
+ TViewer = TypeVar(
4140
+ "TViewer", nt.SocketOrVal[bool], nt.SocketOrVal[int], nt.SocketOrVal[float]
4141
+ )
4142
+
4143
+
4144
+ '''
4145
+ def viewer(
4146
+ geometry: t.ProcNode[t.Geometry],
4147
+ value: TViewer = 0,
4148
+ domain: TDomain = "AUTO",
4149
+ data_type: NodeDataType | RuntimeResolveDataType | None = None,
4150
+ ) -> t.ProcNode:
4151
+ """
4152
+ Uses a Viewer Geometry Node.
4153
+
4154
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/output/viewer.html
4155
+ """
4156
+ if data_type is None:
4157
+ data_type = RuntimeResolveDataType(
4158
+ [NodeDataType.BOOLEAN, NodeDataType.INT, NodeDataType.FLOAT],
4159
+ ["Value"],
4160
+ )
4161
+ return t.ProcNode.from_nodetype(
4162
+ node_type="GeometryNodeViewer",
4163
+ inputs={"Geometry": geometry, "Value": value},
4164
+ attrs={
4165
+ "domain": domain,
4166
+ "data_type": data_type,
4167
+ },
4168
+ )
4169
+ '''
4170
+
4171
+
4172
+ class ViewportTransformResult(NamedTuple):
4173
+ projection: nt.ProcNode
4174
+ view: nt.ProcNode
4175
+ is_orthographic: nt.ProcNode[bool]
4176
+
4177
+
4178
+ def viewport_transform() -> ViewportTransformResult:
4179
+ """
4180
+ Uses a ViewportTransform Geometry Node.
4181
+
4182
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/scene/viewport_transform.html
4183
+ """
4184
+ node = nt.ProcNode.from_nodetype(
4185
+ node_type="GeometryNodeViewportTransform",
4186
+ inputs={},
4187
+ attrs={},
4188
+ )
4189
+ return ViewportTransformResult(
4190
+ node._output_socket("projection"),
4191
+ node._output_socket("view"),
4192
+ node._output_socket("is_orthographic"),
4193
+ )
4194
+
4195
+
4196
+ def volume_cube(
4197
+ density: nt.SocketOrVal[float] = 1.0,
4198
+ background: nt.SocketOrVal[float] = 0.0,
4199
+ min: nt.SocketOrVal[nt.pt.Vector] = (-1, -1, -1),
4200
+ max: nt.SocketOrVal[nt.pt.Vector] = (1, 1, 1),
4201
+ resolution_x: nt.SocketOrVal[int] = 32,
4202
+ resolution_y: nt.SocketOrVal[int] = 32,
4203
+ resolution_z: nt.SocketOrVal[int] = 32,
4204
+ ) -> nt.ProcNode[pt.VolumeObject]:
4205
+ """
4206
+ Uses a VolumeCube Geometry Node.
4207
+
4208
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/primitives/volume_cube.html
4209
+ """
4210
+ return nt.ProcNode.from_nodetype(
4211
+ node_type="GeometryNodeVolumeCube",
4212
+ inputs={
4213
+ "Density": density,
4214
+ "Background": background,
4215
+ "Min": min,
4216
+ "Max": max,
4217
+ "Resolution X": resolution_x,
4218
+ "Resolution Y": resolution_y,
4219
+ "Resolution Z": resolution_z,
4220
+ },
4221
+ attrs={},
4222
+ )
4223
+
4224
+
4225
+ def volume_to_mesh(
4226
+ volume: nt.ProcNode[pt.VolumeObject],
4227
+ threshold: nt.SocketOrVal[float] = 0.1,
4228
+ adaptivity: nt.SocketOrVal[float] = 0.0,
4229
+ resolution_mode: Literal["GRID", "VOXEL_AMOUNT", "VOXEL_SIZE"] = "GRID",
4230
+ ) -> nt.ProcNode[pt.MeshObject]:
4231
+ """
4232
+ Uses a VolumeToMesh Geometry Node.
4233
+
4234
+ See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/volume/operations/volume_to_mesh.html
4235
+ """
4236
+ return nt.ProcNode.from_nodetype(
4237
+ node_type="GeometryNodeVolumeToMesh",
4238
+ inputs={"Volume": volume, "Threshold": threshold, "Adaptivity": adaptivity},
4239
+ attrs={"resolution_mode": resolution_mode},
4240
+ )