nodebpy 0.2.0__py3-none-any.whl → 0.3.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.
nodebpy/nodes/grid.py CHANGED
@@ -1,59 +1,103 @@
1
- import bpy
2
- from typing_extensions import Literal
1
+ from typing import Literal
3
2
 
4
- from nodebpy.builder import NodeBuilder, SocketLinker
3
+ import bpy
5
4
 
6
- from .types import (
7
- LINKABLE,
5
+ from ..builder import NodeBuilder, SocketLinker
6
+ from ..types import (
8
7
  TYPE_INPUT_BOOLEAN,
9
8
  TYPE_INPUT_GEOMETRY,
10
- TYPE_INPUT_GRID,
11
9
  TYPE_INPUT_INT,
10
+ TYPE_INPUT_MENU,
12
11
  TYPE_INPUT_STRING,
12
+ TYPE_INPUT_MATRIX,
13
13
  TYPE_INPUT_VALUE,
14
14
  TYPE_INPUT_VECTOR,
15
- _AdvectGridIntegration,
16
- _GridDataTypes,
17
15
  )
18
16
 
19
17
 
20
- class DistributePointsInGrid(NodeBuilder):
21
- """Generate points inside a volume grid"""
18
+ class AdvectGrid(NodeBuilder):
19
+ """Move grid values through a velocity field using numerical integration. Supports multiple integration schemes for different accuracy and performance trade-offs"""
22
20
 
23
- name = "GeometryNodeDistributePointsInGrid"
24
- node: bpy.types.GeometryNodeDistributePointsInGrid
21
+ _bl_idname = "GeometryNodeGridAdvect"
22
+ node: bpy.types.GeometryNodeGridAdvect
25
23
 
26
24
  def __init__(
27
25
  self,
28
- grid: LINKABLE = None,
29
- mode: Literal["DENSITY_RANDOM", "DENSITY_GRID"] = "DENSITY_RANDOM",
30
- **kwargs,
26
+ grid: TYPE_INPUT_VALUE = 0.0,
27
+ velocity: TYPE_INPUT_VECTOR = None,
28
+ time_step: TYPE_INPUT_VALUE = 1.0,
29
+ integration_scheme: TYPE_INPUT_MENU = "Runge-Kutta 3",
30
+ limiter: TYPE_INPUT_MENU = "Clamp",
31
+ *,
32
+ data_type: Literal["FLOAT", "INT", "VECTOR"] = "FLOAT",
31
33
  ):
32
34
  super().__init__()
33
35
  key_args = {
34
36
  "Grid": grid,
37
+ "Velocity": velocity,
38
+ "Time Step": time_step,
39
+ "Integration Scheme": integration_scheme,
40
+ "Limiter": limiter,
35
41
  }
36
- self.mode = mode
37
- key_args.update(kwargs)
42
+ self.data_type = data_type
38
43
  self._establish_links(**key_args)
39
44
 
40
45
  @classmethod
41
- def grid(
46
+ def float(
42
47
  cls,
43
- grid: LINKABLE,
44
- spacing: TYPE_INPUT_VECTOR = (0.3, 0.3, 0.3),
45
- threshold: TYPE_INPUT_VALUE = 0.1,
46
- ) -> "DistributePointsInGrid":
47
- return cls(grid=grid, Spacing=spacing, Threshold=threshold, mode="DENSITY_GRID")
48
+ grid: TYPE_INPUT_VALUE = 0.0,
49
+ velocity: TYPE_INPUT_VECTOR = None,
50
+ time_step: TYPE_INPUT_VALUE = 1.0,
51
+ integration_scheme: TYPE_INPUT_MENU = "Runge-Kutta 3",
52
+ limiter: TYPE_INPUT_MENU = "Clamp",
53
+ ) -> "AdvectGrid":
54
+ """Create Advect Grid with operation 'Float'."""
55
+ return cls(
56
+ data_type="FLOAT",
57
+ grid=grid,
58
+ velocity=velocity,
59
+ time_step=time_step,
60
+ integration_scheme=integration_scheme,
61
+ limiter=limiter,
62
+ )
48
63
 
49
64
  @classmethod
50
- def random(
65
+ def integer(
51
66
  cls,
52
- grid: LINKABLE,
53
- density: TYPE_INPUT_VALUE = 1.0,
54
- seed: TYPE_INPUT_INT = 0,
55
- ) -> "DistributePointsInGrid":
56
- return cls(grid=grid, Density=density, Seed=seed, mode="DENSITY_RANDOM")
67
+ grid: TYPE_INPUT_INT = 0,
68
+ velocity: TYPE_INPUT_VECTOR = None,
69
+ time_step: TYPE_INPUT_VALUE = 1.0,
70
+ integration_scheme: TYPE_INPUT_MENU = "Runge-Kutta 3",
71
+ limiter: TYPE_INPUT_MENU = "Clamp",
72
+ ) -> "AdvectGrid":
73
+ """Create Advect Grid with operation 'Integer'."""
74
+ return cls(
75
+ data_type="INT",
76
+ grid=grid,
77
+ velocity=velocity,
78
+ time_step=time_step,
79
+ integration_scheme=integration_scheme,
80
+ limiter=limiter,
81
+ )
82
+
83
+ @classmethod
84
+ def vector(
85
+ cls,
86
+ grid: TYPE_INPUT_VECTOR = None,
87
+ velocity: TYPE_INPUT_VECTOR = None,
88
+ time_step: TYPE_INPUT_VALUE = 1.0,
89
+ integration_scheme: TYPE_INPUT_MENU = "Runge-Kutta 3",
90
+ limiter: TYPE_INPUT_MENU = "Clamp",
91
+ ) -> "AdvectGrid":
92
+ """Create Advect Grid with operation 'Vector'."""
93
+ return cls(
94
+ data_type="VECTOR",
95
+ grid=grid,
96
+ velocity=velocity,
97
+ time_step=time_step,
98
+ integration_scheme=integration_scheme,
99
+ limiter=limiter,
100
+ )
57
101
 
58
102
  @property
59
103
  def i_grid(self) -> SocketLinker:
@@ -61,66 +105,70 @@ class DistributePointsInGrid(NodeBuilder):
61
105
  return self._input("Grid")
62
106
 
63
107
  @property
64
- def i_density(self) -> SocketLinker:
65
- """Input socket: Density"""
66
- return self._input("Density")
108
+ def i_velocity(self) -> SocketLinker:
109
+ """Input socket: Velocity"""
110
+ return self._input("Velocity")
67
111
 
68
112
  @property
69
- def i_seed(self) -> SocketLinker:
70
- """Input socket: Seed"""
71
- return self._input("Seed")
113
+ def i_time_step(self) -> SocketLinker:
114
+ """Input socket: Time Step"""
115
+ return self._input("Time Step")
72
116
 
73
117
  @property
74
- def o_points(self) -> SocketLinker:
75
- """Output socket: Points"""
76
- return self._output("Points")
118
+ def i_integration_scheme(self) -> SocketLinker:
119
+ """Input socket: Integration Scheme"""
120
+ return self._input("Integration Scheme")
77
121
 
78
122
  @property
79
- def mode(self) -> Literal["DENSITY_RANDOM", "DENSITY_GRID"]:
80
- return self.node.mode
123
+ def i_limiter(self) -> SocketLinker:
124
+ """Input socket: Limiter"""
125
+ return self._input("Limiter")
81
126
 
82
- @mode.setter
83
- def mode(self, value: Literal["DENSITY_RANDOM", "DENSITY_GRID"]):
84
- self.node.mode = value
127
+ @property
128
+ def o_grid(self) -> SocketLinker:
129
+ """Output socket: Grid"""
130
+ return self._output("Grid")
85
131
 
132
+ @property
133
+ def data_type(self) -> Literal["FLOAT", "INT", "VECTOR"]:
134
+ return self.node.data_type
86
135
 
87
- class DistributePointsInVolume(NodeBuilder):
88
- """Generate points inside a volume"""
136
+ @data_type.setter
137
+ def data_type(self, value: Literal["FLOAT", "INT", "VECTOR"]):
138
+ self.node.data_type = value
89
139
 
90
- name = "GeometryNodeDistributePointsInVolume"
91
- node: bpy.types.GeometryNodeDistributePointsInVolume
140
+
141
+ class DistributePointsInGrid(NodeBuilder):
142
+ """Generate points inside a volume grid"""
143
+
144
+ _bl_idname = "GeometryNodeDistributePointsInGrid"
145
+ node: bpy.types.GeometryNodeDistributePointsInGrid
92
146
 
93
147
  def __init__(
94
148
  self,
95
- volume: TYPE_INPUT_GEOMETRY = None,
96
- mode: Literal["Random", "Grid"] = "Random",
97
- **kwargs,
149
+ grid: TYPE_INPUT_VALUE = 0.0,
150
+ density: TYPE_INPUT_VALUE = 1.0,
151
+ seed: TYPE_INPUT_INT = 0,
152
+ spacing: TYPE_INPUT_VECTOR = None,
153
+ threshold: TYPE_INPUT_VALUE = 0.1,
154
+ *,
155
+ mode: Literal["DENSITY_RANDOM", "DENSITY_GRID"] = "DENSITY_RANDOM",
98
156
  ):
99
157
  super().__init__()
100
158
  key_args = {
101
- "Volume": volume,
102
- "Mode": mode,
159
+ "Grid": grid,
160
+ "Density": density,
161
+ "Seed": seed,
162
+ "Spacing": spacing,
163
+ "Threshold": threshold,
103
164
  }
104
- key_args.update(kwargs)
165
+ self.mode = mode
105
166
  self._establish_links(**key_args)
106
167
 
107
- @classmethod
108
- def grid(
109
- cls,
110
- volume: TYPE_INPUT_GEOMETRY = None,
111
- density: TYPE_INPUT_VALUE = 1.0,
112
- seed: TYPE_INPUT_INT = 0,
113
- ):
114
- return cls(volume=volume, Density=density, Seed=seed, mode="Grid")
115
-
116
- @classmethod
117
- def random(
118
- cls,
119
- volume: TYPE_INPUT_GEOMETRY = None,
120
- spacing: TYPE_INPUT_VECTOR = (0.3, 0.3, 0.3),
121
- threshold: TYPE_INPUT_VALUE = 0.1,
122
- ):
123
- return cls(volume=volume, Space=spacing, Threshold=threshold, mode="Random")
168
+ @property
169
+ def i_grid(self) -> SocketLinker:
170
+ """Input socket: Grid"""
171
+ return self._input("Grid")
124
172
 
125
173
  @property
126
174
  def i_density(self) -> SocketLinker:
@@ -147,122 +195,137 @@ class DistributePointsInVolume(NodeBuilder):
147
195
  """Output socket: Points"""
148
196
  return self._output("Points")
149
197
 
198
+ @property
199
+ def mode(self) -> Literal["DENSITY_RANDOM", "DENSITY_GRID"]:
200
+ return self.node.mode
150
201
 
151
- class FieldToGrid(NodeBuilder):
152
- """Create new grids by evaluating new values on an existing volume grid topology
153
-
154
- New socket items for field evaluation are first created from *args then **kwargs to give specific names to the items.
155
-
156
- Data types are inferred automatically from the closest compatible data type.
202
+ @mode.setter
203
+ def mode(self, value: Literal["DENSITY_RANDOM", "DENSITY_GRID"]):
204
+ self.node.mode = value
157
205
 
158
- Inputs:
159
- -------
160
- topology: LINKABLE
161
- The grid which contains the topology to evaluate the different fields on.
162
- data_type: _GridDataTypes = "FLOAT"
163
- The data type of the grid to evaluate on. Possible values are "FLOAT", "INT", "VECTOR", "BOOLEAN".
164
- *args: TYPE_INPUT_VALUE | TYPE_INPUT_VECTOR | TYPE_INPUT_INT | TYPE_INPUT_BOOLEAN
165
- The fields to evaluate on the grid.
166
- **kwargs: dict[str, TYPE_INPUT_VALUE | TYPE_INPUT_VECTOR | TYPE_INPUT_INT | TYPE_INPUT_GEOMETRY]
167
- The key-value pairs of the fields to evaluate on the grid. Keys will be used as the name of the socket.
168
206
 
169
- """
207
+ class DistributePointsInVolume(NodeBuilder):
208
+ """Generate points inside a volume"""
170
209
 
171
- name = "GeometryNodeFieldToGrid"
172
- node: bpy.types.GeometryNodeFieldToGrid
173
- _socket_data_types = ("FLOAT", "VALUE", "INT", "VECTOR", "BOOLEAN")
174
- _default_input_id = "Topology"
210
+ _bl_idname = "GeometryNodeDistributePointsInVolume"
211
+ node: bpy.types.GeometryNodeDistributePointsInVolume
175
212
 
176
213
  def __init__(
177
214
  self,
178
- *args: TYPE_INPUT_GRID,
179
- topology: TYPE_INPUT_GRID = None,
180
- data_type: _GridDataTypes = "FLOAT",
181
- **kwargs: TYPE_INPUT_GRID,
215
+ volume: TYPE_INPUT_GEOMETRY = None,
216
+ mode: TYPE_INPUT_MENU = "Random",
217
+ density: TYPE_INPUT_VALUE = 1.0,
218
+ seed: TYPE_INPUT_INT = 0,
219
+ spacing: TYPE_INPUT_VECTOR = None,
220
+ threshold: TYPE_INPUT_VALUE = 0.1,
182
221
  ):
183
222
  super().__init__()
184
- self.data_type = data_type
185
223
  key_args = {
186
- "Topology": topology,
224
+ "Volume": volume,
225
+ "Mode": mode,
226
+ "Density": density,
227
+ "Seed": seed,
228
+ "Spacing": spacing,
229
+ "Threshold": threshold,
187
230
  }
188
- key_args.update(self._add_inputs(*args, **kwargs)) # type: ignore
231
+
189
232
  self._establish_links(**key_args)
190
233
 
191
- def _add_socket( # type: ignore
192
- self,
193
- name: str,
194
- type: _GridDataTypes = "FLOAT",
195
- default_value: float | int | str | None = None,
196
- ):
197
- item = self.node.grid_items.new(socket_type=type, name=name)
198
- if default_value is not None:
199
- try:
200
- self.node.inputs[item.name].default_value = default_value # type: ignore
201
- except TypeError as e:
202
- raise ValueError(
203
- f"Invalid default value for {type}: {default_value}"
204
- ) from e
205
- return self.node.inputs[item.name]
206
-
207
- def capture(self, *args, **kwargs) -> list[SocketLinker]:
208
- outputs = {
209
- name: self.node.outputs[name] for name in self._add_inputs(*args, **kwargs)
210
- }
234
+ @property
235
+ def i_volume(self) -> SocketLinker:
236
+ """Input socket: Volume"""
237
+ return self._input("Volume")
211
238
 
212
- return [SocketLinker(x) for x in outputs.values()]
239
+ @property
240
+ def i_mode(self) -> SocketLinker:
241
+ """Input socket: Mode"""
242
+ return self._input("Mode")
213
243
 
214
244
  @property
215
- def outputs(self) -> dict[str, SocketLinker]:
216
- return {
217
- item.name: SocketLinker(self.node.outputs[item.name])
218
- for item in self.node.grid_items
219
- }
245
+ def i_density(self) -> SocketLinker:
246
+ """Input socket: Density"""
247
+ return self._input("Density")
220
248
 
221
249
  @property
222
- def inputs(self) -> dict[str, SocketLinker]:
223
- return {
224
- item.name: SocketLinker(self.node.inputs[item.name])
225
- for item in self.node.grid_items
226
- }
250
+ def i_seed(self) -> SocketLinker:
251
+ """Input socket: Seed"""
252
+ return self._input("Seed")
227
253
 
228
254
  @property
229
- def i_topology(self) -> SocketLinker:
230
- """Input socket: Topology"""
231
- return self._input("Topology")
255
+ def i_spacing(self) -> SocketLinker:
256
+ """Input socket: Spacing"""
257
+ return self._input("Spacing")
232
258
 
233
259
  @property
234
- def data_type(
235
- self,
236
- ) -> _GridDataTypes:
237
- return self.node.data_type # type: ignore
260
+ def i_threshold(self) -> SocketLinker:
261
+ """Input socket: Threshold"""
262
+ return self._input("Threshold")
238
263
 
239
- @data_type.setter
240
- def data_type(
241
- self,
242
- value: _GridDataTypes,
243
- ):
244
- self.node.data_type = value
264
+ @property
265
+ def o_points(self) -> SocketLinker:
266
+ """Output socket: Points"""
267
+ return self._output("Points")
245
268
 
246
269
 
247
270
  class GetNamedGrid(NodeBuilder):
248
271
  """Get volume grid from a volume geometry with the specified name"""
249
272
 
250
- name = "GeometryNodeGetNamedGrid"
273
+ _bl_idname = "GeometryNodeGetNamedGrid"
251
274
  node: bpy.types.GeometryNodeGetNamedGrid
252
- _default_input_id = "Volume"
253
275
 
254
276
  def __init__(
255
277
  self,
256
278
  volume: TYPE_INPUT_GEOMETRY = None,
257
279
  name: TYPE_INPUT_STRING = "",
258
280
  remove: TYPE_INPUT_BOOLEAN = True,
259
- data_type: _GridDataTypes = "FLOAT",
281
+ *,
282
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
260
283
  ):
261
284
  super().__init__()
262
285
  key_args = {"Volume": volume, "Name": name, "Remove": remove}
263
286
  self.data_type = data_type
264
287
  self._establish_links(**key_args)
265
288
 
289
+ @classmethod
290
+ def float(
291
+ cls,
292
+ volume: TYPE_INPUT_GEOMETRY = None,
293
+ name: TYPE_INPUT_STRING = "",
294
+ remove: TYPE_INPUT_BOOLEAN = True,
295
+ ) -> "GetNamedGrid":
296
+ """Create Get Named Grid with operation 'Float'."""
297
+ return cls(data_type="FLOAT", volume=volume, name=name, remove=remove)
298
+
299
+ @classmethod
300
+ def integer(
301
+ cls,
302
+ volume: TYPE_INPUT_GEOMETRY = None,
303
+ name: TYPE_INPUT_STRING = "",
304
+ remove: TYPE_INPUT_BOOLEAN = True,
305
+ ) -> "GetNamedGrid":
306
+ """Create Get Named Grid with operation 'Integer'."""
307
+ return cls(data_type="INT", volume=volume, name=name, remove=remove)
308
+
309
+ @classmethod
310
+ def boolean(
311
+ cls,
312
+ volume: TYPE_INPUT_GEOMETRY = None,
313
+ name: TYPE_INPUT_STRING = "",
314
+ remove: TYPE_INPUT_BOOLEAN = True,
315
+ ) -> "GetNamedGrid":
316
+ """Create Get Named Grid with operation 'Boolean'."""
317
+ return cls(data_type="BOOLEAN", volume=volume, name=name, remove=remove)
318
+
319
+ @classmethod
320
+ def vector(
321
+ cls,
322
+ volume: TYPE_INPUT_GEOMETRY = None,
323
+ name: TYPE_INPUT_STRING = "",
324
+ remove: TYPE_INPUT_BOOLEAN = True,
325
+ ) -> "GetNamedGrid":
326
+ """Create Get Named Grid with operation 'Vector'."""
327
+ return cls(data_type="VECTOR", volume=volume, name=name, remove=remove)
328
+
266
329
  @property
267
330
  def i_volume(self) -> SocketLinker:
268
331
  """Input socket: Volume"""
@@ -289,100 +352,24 @@ class GetNamedGrid(NodeBuilder):
289
352
  return self._output("Grid")
290
353
 
291
354
  @property
292
- def data_type(
293
- self,
294
- ) -> _GridDataTypes:
295
- return self.node.data_type # type: ignore
355
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
356
+ return self.node.data_type
296
357
 
297
358
  @data_type.setter
298
- def data_type(
299
- self,
300
- value: _GridDataTypes,
301
- ):
302
- self.node.data_type = value
303
-
304
-
305
- class AdvectGrid(NodeBuilder):
306
- """Move grid values through a velocity field using numerical integration. Supports multiple integration schemes for different accuracy and performance trade-offs"""
307
-
308
- name = "GeometryNodeGridAdvect"
309
- node: bpy.types.GeometryNodeGridAdvect
310
- _socket_data_types = ["FLOAT", "VALUE", "INT", "VECTOR"]
311
-
312
- def __init__(
313
- self,
314
- grid: TYPE_INPUT_VALUE = None,
315
- velocity: TYPE_INPUT_VECTOR = None,
316
- time_step: TYPE_INPUT_VALUE = 1.0,
317
- *,
318
- integration_scheme: _AdvectGridIntegration = "Runge-Kutta 3",
319
- limiter: Literal["None", "Clamp", "Revert"] = "Clamp",
320
- data_type: Literal["FLOAT", "INT", "VECTOR"] = "FLOAT",
321
- ):
322
- super().__init__()
323
- key_args = {
324
- "Grid": grid,
325
- "Velocity": velocity,
326
- "Time Step": time_step,
327
- "Integration Scheme": integration_scheme,
328
- "Limiter": limiter,
329
- }
330
- self.data_type = data_type
331
- self._establish_links(**key_args)
332
-
333
- @property
334
- def i_grid(self) -> SocketLinker:
335
- """Input socket: Grid"""
336
- return self._input("Grid")
337
-
338
- @property
339
- def i_velocity(self) -> SocketLinker:
340
- """Input socket: Velocity"""
341
- return self._input("Velocity")
342
-
343
- @property
344
- def i_time_step(self) -> SocketLinker:
345
- """Input socket: Time Step"""
346
- return self._input("Time Step")
347
-
348
- @property
349
- def i_integration_scheme(self) -> SocketLinker:
350
- """Input socket: Integration Scheme"""
351
- return self._input("Integration Scheme")
352
-
353
- @property
354
- def i_limiter(self) -> SocketLinker:
355
- """Input socket: Limiter"""
356
- return self._input("Limiter")
357
-
358
- @property
359
- def o_grid(self) -> SocketLinker:
360
- """Output socket: Grid"""
361
- return self._output("Grid")
362
-
363
- @property
364
- def data_type(
365
- self,
366
- ) -> Literal["FLOAT", "INT", "VECTOR"]:
367
- return self.node.data_type # type: ignore
368
-
369
- @data_type.setter
370
- def data_type(
371
- self,
372
- value: Literal["FLOAT", "INT", "VECTOR"],
373
- ):
359
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
374
360
  self.node.data_type = value
375
361
 
376
362
 
377
363
  class GridCurl(NodeBuilder):
378
364
  """Calculate the magnitude and direction of circulation of a directional vector grid"""
379
365
 
380
- name = "GeometryNodeGridCurl"
366
+ _bl_idname = "GeometryNodeGridCurl"
381
367
  node: bpy.types.GeometryNodeGridCurl
382
368
 
383
369
  def __init__(self, grid: TYPE_INPUT_VECTOR = None):
384
370
  super().__init__()
385
371
  key_args = {"Grid": grid}
372
+
386
373
  self._establish_links(**key_args)
387
374
 
388
375
  @property
@@ -399,12 +386,13 @@ class GridCurl(NodeBuilder):
399
386
  class GridDivergence(NodeBuilder):
400
387
  """Calculate the flow into and out of each point of a directional vector grid"""
401
388
 
402
- name = "GeometryNodeGridDivergence"
389
+ _bl_idname = "GeometryNodeGridDivergence"
403
390
  node: bpy.types.GeometryNodeGridDivergence
404
391
 
405
392
  def __init__(self, grid: TYPE_INPUT_VECTOR = None):
406
393
  super().__init__()
407
394
  key_args = {"Grid": grid}
395
+
408
396
  self._establish_links(**key_args)
409
397
 
410
398
  @property
@@ -421,12 +409,13 @@ class GridDivergence(NodeBuilder):
421
409
  class GridGradient(NodeBuilder):
422
410
  """Calculate the direction and magnitude of the change in values of a scalar grid"""
423
411
 
424
- name = "GeometryNodeGridGradient"
412
+ _bl_idname = "GeometryNodeGridGradient"
425
413
  node: bpy.types.GeometryNodeGridGradient
426
414
 
427
- def __init__(self, grid: TYPE_INPUT_VALUE = None):
415
+ def __init__(self, grid: TYPE_INPUT_VALUE = 0.0):
428
416
  super().__init__()
429
417
  key_args = {"Grid": grid}
418
+
430
419
  self._establish_links(**key_args)
431
420
 
432
421
  @property
@@ -443,17 +432,40 @@ class GridGradient(NodeBuilder):
443
432
  class GridInfo(NodeBuilder):
444
433
  """Retrieve information about a volume grid"""
445
434
 
446
- name = "GeometryNodeGridInfo"
435
+ _bl_idname = "GeometryNodeGridInfo"
447
436
  node: bpy.types.GeometryNodeGridInfo
448
437
 
449
438
  def __init__(
450
- self, grid: TYPE_INPUT_GRID = None, data_type: _GridDataTypes = "FLOAT"
439
+ self,
440
+ grid: TYPE_INPUT_VALUE = 0.0,
441
+ *,
442
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
451
443
  ):
452
444
  super().__init__()
453
445
  key_args = {"Grid": grid}
454
446
  self.data_type = data_type
455
447
  self._establish_links(**key_args)
456
448
 
449
+ @classmethod
450
+ def float(cls, grid: TYPE_INPUT_VALUE = 0.0) -> "GridInfo":
451
+ """Create Grid Info with operation 'Float'."""
452
+ return cls(data_type="FLOAT", grid=grid)
453
+
454
+ @classmethod
455
+ def integer(cls, grid: TYPE_INPUT_INT = 0) -> "GridInfo":
456
+ """Create Grid Info with operation 'Integer'."""
457
+ return cls(data_type="INT", grid=grid)
458
+
459
+ @classmethod
460
+ def boolean(cls, grid: TYPE_INPUT_BOOLEAN = False) -> "GridInfo":
461
+ """Create Grid Info with operation 'Boolean'."""
462
+ return cls(data_type="BOOLEAN", grid=grid)
463
+
464
+ @classmethod
465
+ def vector(cls, grid: TYPE_INPUT_VECTOR = None) -> "GridInfo":
466
+ """Create Grid Info with operation 'Vector'."""
467
+ return cls(data_type="VECTOR", grid=grid)
468
+
457
469
  @property
458
470
  def i_grid(self) -> SocketLinker:
459
471
  """Input socket: Grid"""
@@ -470,28 +482,24 @@ class GridInfo(NodeBuilder):
470
482
  return self._output("Background Value")
471
483
 
472
484
  @property
473
- def data_type(
474
- self,
475
- ) -> _GridDataTypes:
476
- return self.node.data_type # type: ignore
485
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
486
+ return self.node.data_type
477
487
 
478
488
  @data_type.setter
479
- def data_type(
480
- self,
481
- value: _GridDataTypes,
482
- ):
489
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
483
490
  self.node.data_type = value
484
491
 
485
492
 
486
493
  class GridLaplacian(NodeBuilder):
487
494
  """Compute the divergence of the gradient of the input grid"""
488
495
 
489
- name = "GeometryNodeGridLaplacian"
496
+ _bl_idname = "GeometryNodeGridLaplacian"
490
497
  node: bpy.types.GeometryNodeGridLaplacian
491
498
 
492
- def __init__(self, grid: TYPE_INPUT_VALUE = None):
499
+ def __init__(self, grid: TYPE_INPUT_VALUE = 0.0):
493
500
  super().__init__()
494
501
  key_args = {"Grid": grid}
502
+
495
503
  self._establish_links(**key_args)
496
504
 
497
505
  @property
@@ -505,23 +513,21 @@ class GridLaplacian(NodeBuilder):
505
513
  return self._output("Laplacian")
506
514
 
507
515
 
508
- class PruneGrid(NodeBuilder):
509
- """Make the storage of a volume grid more efficient by collapsing data into tiles or inner nodes"""
516
+ class GridToMesh(NodeBuilder):
517
+ """Generate a mesh on the "surface" of a volume grid"""
510
518
 
511
- name = "GeometryNodeGridPrune"
512
- node: bpy.types.GeometryNodeGridPrune
519
+ _bl_idname = "GeometryNodeGridToMesh"
520
+ node: bpy.types.GeometryNodeGridToMesh
513
521
 
514
522
  def __init__(
515
523
  self,
516
- grid: TYPE_INPUT_GRID = None,
517
- *,
518
- mode: Literal["Inactive", "Threshold", "SDF"] = "Threshold",
519
- threshold: TYPE_INPUT_VALUE = 0.01,
520
- data_type: _GridDataTypes = "FLOAT",
524
+ grid: TYPE_INPUT_VALUE = 0.0,
525
+ threshold: TYPE_INPUT_VALUE = 0.1,
526
+ adaptivity: TYPE_INPUT_VALUE = 0.0,
521
527
  ):
522
528
  super().__init__()
523
- key_args = {"Grid": grid, "Mode": mode, "Threshold": threshold}
524
- self.data_type = data_type
529
+ key_args = {"Grid": grid, "Threshold": threshold, "Adaptivity": adaptivity}
530
+
525
531
  self._establish_links(**key_args)
526
532
 
527
533
  @property
@@ -529,135 +535,266 @@ class PruneGrid(NodeBuilder):
529
535
  """Input socket: Grid"""
530
536
  return self._input("Grid")
531
537
 
532
- @property
533
- def i_mode(self) -> SocketLinker:
534
- """Input socket: Mode"""
535
- return self._input("Mode")
536
-
537
538
  @property
538
539
  def i_threshold(self) -> SocketLinker:
539
540
  """Input socket: Threshold"""
540
541
  return self._input("Threshold")
541
542
 
542
543
  @property
543
- def o_grid(self) -> SocketLinker:
544
- """Output socket: Grid"""
545
- return self._output("Grid")
544
+ def i_adaptivity(self) -> SocketLinker:
545
+ """Input socket: Adaptivity"""
546
+ return self._input("Adaptivity")
546
547
 
547
548
  @property
548
- def data_type(
549
- self,
550
- ) -> _GridDataTypes:
551
- return self.node.data_type # type: ignore
549
+ def o_mesh(self) -> SocketLinker:
550
+ """Output socket: Mesh"""
551
+ return self._output("Mesh")
552
552
 
553
- @data_type.setter
554
- def data_type(
553
+
554
+ class MeshToDensityGrid(NodeBuilder):
555
+ """Create a filled volume grid from a mesh"""
556
+
557
+ _bl_idname = "GeometryNodeMeshToDensityGrid"
558
+ node: bpy.types.GeometryNodeMeshToDensityGrid
559
+
560
+ def __init__(
555
561
  self,
556
- value: _GridDataTypes,
562
+ mesh: TYPE_INPUT_GEOMETRY = None,
563
+ density: TYPE_INPUT_VALUE = 1.0,
564
+ voxel_size: TYPE_INPUT_VALUE = 0.3,
565
+ gradient_width: TYPE_INPUT_VALUE = 0.2,
557
566
  ):
558
- self.node.data_type = value
567
+ super().__init__()
568
+ key_args = {
569
+ "Mesh": mesh,
570
+ "Density": density,
571
+ "Voxel Size": voxel_size,
572
+ "Gradient Width": gradient_width,
573
+ }
559
574
 
575
+ self._establish_links(**key_args)
560
576
 
561
- class VoxelizeGrid(NodeBuilder):
562
- """Remove sparseness from a volume grid by making the active tiles into voxels"""
577
+ @property
578
+ def i_mesh(self) -> SocketLinker:
579
+ """Input socket: Mesh"""
580
+ return self._input("Mesh")
563
581
 
564
- name = "GeometryNodeGridVoxelize"
565
- node: bpy.types.GeometryNodeGridVoxelize
582
+ @property
583
+ def i_density(self) -> SocketLinker:
584
+ """Input socket: Density"""
585
+ return self._input("Density")
586
+
587
+ @property
588
+ def i_voxel_size(self) -> SocketLinker:
589
+ """Input socket: Voxel Size"""
590
+ return self._input("Voxel Size")
591
+
592
+ @property
593
+ def i_gradient_width(self) -> SocketLinker:
594
+ """Input socket: Gradient Width"""
595
+ return self._input("Gradient Width")
596
+
597
+ @property
598
+ def o_density_grid(self) -> SocketLinker:
599
+ """Output socket: Density Grid"""
600
+ return self._output("Density Grid")
601
+
602
+
603
+ class MeshToSDFGrid(NodeBuilder):
604
+ """Create a signed distance volume grid from a mesh"""
605
+
606
+ _bl_idname = "GeometryNodeMeshToSDFGrid"
607
+ node: bpy.types.GeometryNodeMeshToSDFGrid
566
608
 
567
609
  def __init__(
568
- self, grid: TYPE_INPUT_GRID = None, data_type: _GridDataTypes = "FLOAT"
610
+ self,
611
+ mesh: TYPE_INPUT_GEOMETRY = None,
612
+ voxel_size: TYPE_INPUT_VALUE = 0.3,
613
+ band_width: TYPE_INPUT_INT = 3,
569
614
  ):
570
615
  super().__init__()
571
- key_args = {"Grid": grid}
572
- self.data_type = data_type
616
+ key_args = {"Mesh": mesh, "Voxel Size": voxel_size, "Band Width": band_width}
617
+
573
618
  self._establish_links(**key_args)
574
619
 
575
620
  @property
576
- def i_grid(self) -> SocketLinker:
577
- """Input socket: Grid"""
578
- return self._input("Grid")
621
+ def i_mesh(self) -> SocketLinker:
622
+ """Input socket: Mesh"""
623
+ return self._input("Mesh")
579
624
 
580
625
  @property
581
- def o_grid(self) -> SocketLinker:
582
- """Output socket: Grid"""
583
- return self._output("Grid")
626
+ def i_voxel_size(self) -> SocketLinker:
627
+ """Input socket: Voxel Size"""
628
+ return self._input("Voxel Size")
584
629
 
585
630
  @property
586
- def data_type(
587
- self,
588
- ) -> _GridDataTypes:
589
- return self.node.data_type # type: ignore
631
+ def i_band_width(self) -> SocketLinker:
632
+ """Input socket: Band Width"""
633
+ return self._input("Band Width")
590
634
 
591
- @data_type.setter
592
- def data_type(
593
- self,
594
- value: _GridDataTypes,
595
- ):
596
- self.node.data_type = value
635
+ @property
636
+ def o_sdf_grid(self) -> SocketLinker:
637
+ """Output socket: SDF Grid"""
638
+ return self._output("SDF Grid")
597
639
 
598
640
 
599
- class VolumeCube(NodeBuilder):
600
- """Generate a dense volume with a field that controls the density at each grid voxel based on its position"""
641
+ class MeshToVolume(NodeBuilder):
642
+ """Create a fog volume with the shape of the input mesh's surface"""
601
643
 
602
- name = "GeometryNodeVolumeCube"
603
- node: bpy.types.GeometryNodeVolumeCube
644
+ _bl_idname = "GeometryNodeMeshToVolume"
645
+ node: bpy.types.GeometryNodeMeshToVolume
604
646
 
605
647
  def __init__(
606
648
  self,
649
+ mesh: TYPE_INPUT_GEOMETRY = None,
607
650
  density: TYPE_INPUT_VALUE = 1.0,
608
- background: TYPE_INPUT_VALUE = 0.0,
609
- min: TYPE_INPUT_VECTOR = (-1.0, -1.0, -1.0),
610
- max: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
611
- resolution_x: TYPE_INPUT_INT = 32,
612
- resolution_y: TYPE_INPUT_INT = 32,
613
- resolution_z: TYPE_INPUT_INT = 32,
651
+ resolution_mode: TYPE_INPUT_MENU = "Amount",
652
+ voxel_size: TYPE_INPUT_VALUE = 0.3,
653
+ voxel_amount: TYPE_INPUT_VALUE = 64.0,
654
+ interior_band_width: TYPE_INPUT_VALUE = 0.2,
614
655
  ):
615
656
  super().__init__()
616
657
  key_args = {
658
+ "Mesh": mesh,
617
659
  "Density": density,
618
- "Background": background,
619
- "Min": min,
620
- "Max": max,
621
- "Resolution X": resolution_x,
622
- "Resolution Y": resolution_y,
623
- "Resolution Z": resolution_z,
660
+ "Resolution Mode": resolution_mode,
661
+ "Voxel Size": voxel_size,
662
+ "Voxel Amount": voxel_amount,
663
+ "Interior Band Width": interior_band_width,
624
664
  }
665
+
625
666
  self._establish_links(**key_args)
626
667
 
668
+ @property
669
+ def i_mesh(self) -> SocketLinker:
670
+ """Input socket: Mesh"""
671
+ return self._input("Mesh")
672
+
627
673
  @property
628
674
  def i_density(self) -> SocketLinker:
629
675
  """Input socket: Density"""
630
676
  return self._input("Density")
631
677
 
632
678
  @property
633
- def i_background(self) -> SocketLinker:
634
- """Input socket: Background"""
635
- return self._input("Background")
679
+ def i_resolution_mode(self) -> SocketLinker:
680
+ """Input socket: Resolution Mode"""
681
+ return self._input("Resolution Mode")
636
682
 
637
683
  @property
638
- def i_min(self) -> SocketLinker:
639
- """Input socket: Min"""
640
- return self._input("Min")
684
+ def i_voxel_size(self) -> SocketLinker:
685
+ """Input socket: Voxel Size"""
686
+ return self._input("Voxel Size")
641
687
 
642
688
  @property
643
- def i_max(self) -> SocketLinker:
644
- """Input socket: Max"""
645
- return self._input("Max")
689
+ def i_voxel_amount(self) -> SocketLinker:
690
+ """Input socket: Voxel Amount"""
691
+ return self._input("Voxel Amount")
646
692
 
647
693
  @property
648
- def i_resolution_x(self) -> SocketLinker:
649
- """Input socket: Resolution X"""
650
- return self._input("Resolution X")
694
+ def i_interior_band_width(self) -> SocketLinker:
695
+ """Input socket: Interior Band Width"""
696
+ return self._input("Interior Band Width")
651
697
 
652
698
  @property
653
- def i_resolution_y(self) -> SocketLinker:
654
- """Input socket: Resolution Y"""
655
- return self._input("Resolution Y")
699
+ def o_volume(self) -> SocketLinker:
700
+ """Output socket: Volume"""
701
+ return self._output("Volume")
702
+
703
+
704
+ class PointsToSDFGrid(NodeBuilder):
705
+ """Create a signed distance volume grid from points"""
706
+
707
+ _bl_idname = "GeometryNodePointsToSDFGrid"
708
+ node: bpy.types.GeometryNodePointsToSDFGrid
709
+
710
+ def __init__(
711
+ self,
712
+ points: TYPE_INPUT_GEOMETRY = None,
713
+ radius: TYPE_INPUT_VALUE = 0.5,
714
+ voxel_size: TYPE_INPUT_VALUE = 0.3,
715
+ ):
716
+ super().__init__()
717
+ key_args = {"Points": points, "Radius": radius, "Voxel Size": voxel_size}
718
+
719
+ self._establish_links(**key_args)
656
720
 
657
721
  @property
658
- def i_resolution_z(self) -> SocketLinker:
659
- """Input socket: Resolution Z"""
660
- return self._input("Resolution Z")
722
+ def i_points(self) -> SocketLinker:
723
+ """Input socket: Points"""
724
+ return self._input("Points")
725
+
726
+ @property
727
+ def i_radius(self) -> SocketLinker:
728
+ """Input socket: Radius"""
729
+ return self._input("Radius")
730
+
731
+ @property
732
+ def i_voxel_size(self) -> SocketLinker:
733
+ """Input socket: Voxel Size"""
734
+ return self._input("Voxel Size")
735
+
736
+ @property
737
+ def o_sdf_grid(self) -> SocketLinker:
738
+ """Output socket: SDF Grid"""
739
+ return self._output("SDF Grid")
740
+
741
+
742
+ class PointsToVolume(NodeBuilder):
743
+ """Generate a fog volume sphere around every point"""
744
+
745
+ _bl_idname = "GeometryNodePointsToVolume"
746
+ node: bpy.types.GeometryNodePointsToVolume
747
+
748
+ def __init__(
749
+ self,
750
+ points: TYPE_INPUT_GEOMETRY = None,
751
+ density: TYPE_INPUT_VALUE = 1.0,
752
+ resolution_mode: TYPE_INPUT_MENU = "Amount",
753
+ voxel_size: TYPE_INPUT_VALUE = 0.3,
754
+ voxel_amount: TYPE_INPUT_VALUE = 64.0,
755
+ radius: TYPE_INPUT_VALUE = 0.5,
756
+ ):
757
+ super().__init__()
758
+ key_args = {
759
+ "Points": points,
760
+ "Density": density,
761
+ "Resolution Mode": resolution_mode,
762
+ "Voxel Size": voxel_size,
763
+ "Voxel Amount": voxel_amount,
764
+ "Radius": radius,
765
+ }
766
+
767
+ self._establish_links(**key_args)
768
+
769
+ @property
770
+ def i_points(self) -> SocketLinker:
771
+ """Input socket: Points"""
772
+ return self._input("Points")
773
+
774
+ @property
775
+ def i_density(self) -> SocketLinker:
776
+ """Input socket: Density"""
777
+ return self._input("Density")
778
+
779
+ @property
780
+ def i_resolution_mode(self) -> SocketLinker:
781
+ """Input socket: Resolution Mode"""
782
+ return self._input("Resolution Mode")
783
+
784
+ @property
785
+ def i_voxel_size(self) -> SocketLinker:
786
+ """Input socket: Voxel Size"""
787
+ return self._input("Voxel Size")
788
+
789
+ @property
790
+ def i_voxel_amount(self) -> SocketLinker:
791
+ """Input socket: Voxel Amount"""
792
+ return self._input("Voxel Amount")
793
+
794
+ @property
795
+ def i_radius(self) -> SocketLinker:
796
+ """Input socket: Radius"""
797
+ return self._input("Radius")
661
798
 
662
799
  @property
663
800
  def o_volume(self) -> SocketLinker:
@@ -665,66 +802,76 @@ class VolumeCube(NodeBuilder):
665
802
  return self._output("Volume")
666
803
 
667
804
 
668
- class SDFGridBoolean(NodeBuilder):
669
- """Cut, subtract, or join multiple SDF volume grid inputs"""
805
+ class PruneGrid(NodeBuilder):
806
+ """Make the storage of a volume grid more efficient by collapsing data into tiles or inner nodes"""
670
807
 
671
- name = "GeometryNodeSDFGridBoolean"
672
- node: bpy.types.GeometryNodeSDFGridBoolean
808
+ _bl_idname = "GeometryNodeGridPrune"
809
+ node: bpy.types.GeometryNodeGridPrune
673
810
 
674
811
  def __init__(
675
- self, *, operation: Literal["INTERSECT", "UNION", "DIFFERENCE"] = "DIFFERENCE"
812
+ self,
813
+ grid: TYPE_INPUT_VALUE = 0.0,
814
+ mode: TYPE_INPUT_MENU = "Threshold",
815
+ threshold: TYPE_INPUT_VALUE = 0.01,
816
+ *,
817
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
676
818
  ):
677
819
  super().__init__()
678
- self.operation = operation
820
+ key_args = {"Grid": grid, "Mode": mode, "Threshold": threshold}
821
+ self.data_type = data_type
822
+ self._establish_links(**key_args)
679
823
 
680
824
  @classmethod
681
- def intersect(
825
+ def float(
682
826
  cls,
683
- *args: LINKABLE,
684
- ) -> "SDFGridBoolean":
685
- node = cls(operation="INTERSECT")
686
- for arg in args:
687
- if arg is None:
688
- continue
689
- node._link_from(arg, "Grid 2")
690
- return node
827
+ grid: TYPE_INPUT_VALUE = 0.0,
828
+ mode: TYPE_INPUT_MENU = "Threshold",
829
+ threshold: TYPE_INPUT_VALUE = 0.01,
830
+ ) -> "PruneGrid":
831
+ """Create Prune Grid with operation 'Float'."""
832
+ return cls(data_type="FLOAT", grid=grid, mode=mode, threshold=threshold)
691
833
 
692
834
  @classmethod
693
- def union(
835
+ def integer(
694
836
  cls,
695
- *args: LINKABLE,
696
- ) -> "SDFGridBoolean":
697
- node = cls(operation="UNION")
698
- for arg in args:
699
- if arg is None:
700
- continue
701
- node._link_from(arg, "Grid 2")
702
- return node
837
+ grid: TYPE_INPUT_INT = 0,
838
+ mode: TYPE_INPUT_MENU = "Threshold",
839
+ threshold: TYPE_INPUT_INT = 0,
840
+ ) -> "PruneGrid":
841
+ """Create Prune Grid with operation 'Integer'."""
842
+ return cls(data_type="INT", grid=grid, mode=mode, threshold=threshold)
843
+
844
+ @classmethod
845
+ def boolean(
846
+ cls, grid: TYPE_INPUT_BOOLEAN = False, mode: TYPE_INPUT_MENU = "Threshold"
847
+ ) -> "PruneGrid":
848
+ """Create Prune Grid with operation 'Boolean'."""
849
+ return cls(data_type="BOOLEAN", grid=grid, mode=mode)
703
850
 
704
851
  @classmethod
705
- def difference(
852
+ def vector(
706
853
  cls,
707
- *args: LINKABLE,
708
- grid_1: LINKABLE,
709
- ) -> "SDFGridBoolean":
710
- """Create SDF Grid Boolean with operation 'Difference'."""
711
- node = cls(operation="DIFFERENCE")
712
- node._link_from(grid_1, "Grid 1")
713
- for arg in args:
714
- if arg is None:
715
- continue
716
- node._link_from(arg, "Grid 2")
717
- return node
854
+ grid: TYPE_INPUT_VECTOR = None,
855
+ mode: TYPE_INPUT_MENU = "Threshold",
856
+ threshold: TYPE_INPUT_VECTOR = None,
857
+ ) -> "PruneGrid":
858
+ """Create Prune Grid with operation 'Vector'."""
859
+ return cls(data_type="VECTOR", grid=grid, mode=mode, threshold=threshold)
860
+
861
+ @property
862
+ def i_grid(self) -> SocketLinker:
863
+ """Input socket: Grid"""
864
+ return self._input("Grid")
718
865
 
719
866
  @property
720
- def i_grid_1(self) -> SocketLinker:
721
- """Input socket: Grid 1"""
722
- return self._input("Grid 1")
867
+ def i_mode(self) -> SocketLinker:
868
+ """Input socket: Mode"""
869
+ return self._input("Mode")
723
870
 
724
871
  @property
725
- def i_grid_2(self) -> SocketLinker:
726
- """Input socket: Grid 2"""
727
- return self._input("Grid 2")
872
+ def i_threshold(self) -> SocketLinker:
873
+ """Input socket: Threshold"""
874
+ return self._input("Threshold")
728
875
 
729
876
  @property
730
877
  def o_grid(self) -> SocketLinker:
@@ -732,23 +879,28 @@ class SDFGridBoolean(NodeBuilder):
732
879
  return self._output("Grid")
733
880
 
734
881
  @property
735
- def operation(self) -> Literal["INTERSECT", "UNION", "DIFFERENCE"]:
736
- return self.node.operation
882
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
883
+ return self.node.data_type
737
884
 
738
- @operation.setter
739
- def operation(self, value: Literal["INTERSECT", "UNION", "DIFFERENCE"]):
740
- self.node.operation = value
885
+ @data_type.setter
886
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
887
+ self.node.data_type = value
741
888
 
742
889
 
743
890
  class SDFGridFillet(NodeBuilder):
744
891
  """Round off concave internal corners in a signed distance field. Only affects areas with negative principal curvature, creating smoother transitions between surfaces"""
745
892
 
746
- name = "GeometryNodeSDFGridFillet"
893
+ _bl_idname = "GeometryNodeSDFGridFillet"
747
894
  node: bpy.types.GeometryNodeSDFGridFillet
748
895
 
749
- def __init__(self, grid: TYPE_INPUT_VALUE = None, iterations: TYPE_INPUT_INT = 1):
896
+ def __init__(
897
+ self,
898
+ grid: TYPE_INPUT_VALUE = 0.0,
899
+ iterations: TYPE_INPUT_INT = 1,
900
+ ):
750
901
  super().__init__()
751
902
  key_args = {"Grid": grid, "Iterations": iterations}
903
+
752
904
  self._establish_links(**key_args)
753
905
 
754
906
  @property
@@ -770,12 +922,17 @@ class SDFGridFillet(NodeBuilder):
770
922
  class SDFGridLaplacian(NodeBuilder):
771
923
  """Apply Laplacian flow smoothing to a signed distance field. Computationally efficient alternative to mean curvature flow, ideal when combined with SDF normalization"""
772
924
 
773
- name = "GeometryNodeSDFGridLaplacian"
925
+ _bl_idname = "GeometryNodeSDFGridLaplacian"
774
926
  node: bpy.types.GeometryNodeSDFGridLaplacian
775
927
 
776
- def __init__(self, grid: TYPE_INPUT_VALUE = None, iterations: TYPE_INPUT_INT = 1):
928
+ def __init__(
929
+ self,
930
+ grid: TYPE_INPUT_VALUE = 0.0,
931
+ iterations: TYPE_INPUT_INT = 1,
932
+ ):
777
933
  super().__init__()
778
934
  key_args = {"Grid": grid, "Iterations": iterations}
935
+
779
936
  self._establish_links(**key_args)
780
937
 
781
938
  @property
@@ -797,17 +954,18 @@ class SDFGridLaplacian(NodeBuilder):
797
954
  class SDFGridMean(NodeBuilder):
798
955
  """Apply mean (box) filter smoothing to a signed distance field. Fast separable averaging filter for general smoothing of the distance field"""
799
956
 
800
- name = "GeometryNodeSDFGridMean"
957
+ _bl_idname = "GeometryNodeSDFGridMean"
801
958
  node: bpy.types.GeometryNodeSDFGridMean
802
959
 
803
960
  def __init__(
804
961
  self,
805
- grid: TYPE_INPUT_VALUE = None,
962
+ grid: TYPE_INPUT_VALUE = 0.0,
806
963
  width: TYPE_INPUT_INT = 1,
807
964
  iterations: TYPE_INPUT_INT = 1,
808
965
  ):
809
966
  super().__init__()
810
967
  key_args = {"Grid": grid, "Width": width, "Iterations": iterations}
968
+
811
969
  self._establish_links(**key_args)
812
970
 
813
971
  @property
@@ -834,16 +992,17 @@ class SDFGridMean(NodeBuilder):
834
992
  class SDFGridMeanCurvature(NodeBuilder):
835
993
  """Apply mean curvature flow smoothing to a signed distance field. Evolves the surface based on its mean curvature, naturally smoothing high-curvature regions more than flat areas"""
836
994
 
837
- name = "GeometryNodeSDFGridMeanCurvature"
995
+ _bl_idname = "GeometryNodeSDFGridMeanCurvature"
838
996
  node: bpy.types.GeometryNodeSDFGridMeanCurvature
839
997
 
840
998
  def __init__(
841
999
  self,
842
- grid: TYPE_INPUT_VALUE = None,
1000
+ grid: TYPE_INPUT_VALUE = 0.0,
843
1001
  iterations: TYPE_INPUT_INT = 1,
844
1002
  ):
845
1003
  super().__init__()
846
1004
  key_args = {"Grid": grid, "Iterations": iterations}
1005
+
847
1006
  self._establish_links(**key_args)
848
1007
 
849
1008
  @property
@@ -865,17 +1024,18 @@ class SDFGridMeanCurvature(NodeBuilder):
865
1024
  class SDFGridMedian(NodeBuilder):
866
1025
  """Apply median filter to a signed distance field. Reduces noise while preserving sharp features and edges in the distance field"""
867
1026
 
868
- name = "GeometryNodeSDFGridMedian"
1027
+ _bl_idname = "GeometryNodeSDFGridMedian"
869
1028
  node: bpy.types.GeometryNodeSDFGridMedian
870
1029
 
871
1030
  def __init__(
872
1031
  self,
873
- grid: TYPE_INPUT_VALUE = None,
1032
+ grid: TYPE_INPUT_VALUE = 0.0,
874
1033
  width: TYPE_INPUT_INT = 1,
875
1034
  iterations: TYPE_INPUT_INT = 1,
876
1035
  ):
877
1036
  super().__init__()
878
1037
  key_args = {"Grid": grid, "Width": width, "Iterations": iterations}
1038
+
879
1039
  self._establish_links(**key_args)
880
1040
 
881
1041
  @property
@@ -902,12 +1062,17 @@ class SDFGridMedian(NodeBuilder):
902
1062
  class SDFGridOffset(NodeBuilder):
903
1063
  """Offset a signed distance field surface by a world-space distance. Dilates (positive) or erodes (negative) while maintaining the signed distance property"""
904
1064
 
905
- name = "GeometryNodeSDFGridOffset"
1065
+ _bl_idname = "GeometryNodeSDFGridOffset"
906
1066
  node: bpy.types.GeometryNodeSDFGridOffset
907
1067
 
908
- def __init__(self, grid: TYPE_INPUT_VALUE = 0.0, distance: TYPE_INPUT_VALUE = 0.1):
1068
+ def __init__(
1069
+ self,
1070
+ grid: TYPE_INPUT_VALUE = 0.0,
1071
+ distance: TYPE_INPUT_VALUE = 0.1,
1072
+ ):
909
1073
  super().__init__()
910
1074
  key_args = {"Grid": grid, "Distance": distance}
1075
+
911
1076
  self._establish_links(**key_args)
912
1077
 
913
1078
  @property
@@ -929,23 +1094,76 @@ class SDFGridOffset(NodeBuilder):
929
1094
  class SampleGrid(NodeBuilder):
930
1095
  """Retrieve values from the specified volume grid"""
931
1096
 
932
- name = "GeometryNodeSampleGrid"
1097
+ _bl_idname = "GeometryNodeSampleGrid"
933
1098
  node: bpy.types.GeometryNodeSampleGrid
934
1099
 
935
1100
  def __init__(
936
1101
  self,
937
- grid: TYPE_INPUT_VALUE = None,
1102
+ grid: TYPE_INPUT_VALUE = 0.0,
938
1103
  position: TYPE_INPUT_VECTOR = None,
939
- interpolation: Literal["Trilinear", "Triquadratic", "Nearest Neighbor"]
940
- | bpy.types.NodeSocketMenu = "Trilinear",
1104
+ interpolation: TYPE_INPUT_MENU = "Trilinear",
941
1105
  *,
942
- data_type: _GridDataTypes = "FLOAT",
1106
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
943
1107
  ):
944
1108
  super().__init__()
945
1109
  key_args = {"Grid": grid, "Position": position, "Interpolation": interpolation}
946
1110
  self.data_type = data_type
947
1111
  self._establish_links(**key_args)
948
1112
 
1113
+ @classmethod
1114
+ def float(
1115
+ cls,
1116
+ grid: TYPE_INPUT_VALUE = 0.0,
1117
+ position: TYPE_INPUT_VECTOR = None,
1118
+ interpolation: TYPE_INPUT_MENU = "Trilinear",
1119
+ ) -> "SampleGrid":
1120
+ """Create Sample Grid with operation 'Float'."""
1121
+ return cls(
1122
+ data_type="FLOAT", grid=grid, position=position, interpolation=interpolation
1123
+ )
1124
+
1125
+ @classmethod
1126
+ def integer(
1127
+ cls,
1128
+ grid: TYPE_INPUT_INT = 0,
1129
+ position: TYPE_INPUT_VECTOR = None,
1130
+ interpolation: TYPE_INPUT_MENU = "Trilinear",
1131
+ ) -> "SampleGrid":
1132
+ """Create Sample Grid with operation 'Integer'."""
1133
+ return cls(
1134
+ data_type="INT", grid=grid, position=position, interpolation=interpolation
1135
+ )
1136
+
1137
+ @classmethod
1138
+ def boolean(
1139
+ cls,
1140
+ grid: TYPE_INPUT_BOOLEAN = False,
1141
+ position: TYPE_INPUT_VECTOR = None,
1142
+ interpolation: TYPE_INPUT_MENU = "Trilinear",
1143
+ ) -> "SampleGrid":
1144
+ """Create Sample Grid with operation 'Boolean'."""
1145
+ return cls(
1146
+ data_type="BOOLEAN",
1147
+ grid=grid,
1148
+ position=position,
1149
+ interpolation=interpolation,
1150
+ )
1151
+
1152
+ @classmethod
1153
+ def vector(
1154
+ cls,
1155
+ grid: TYPE_INPUT_VECTOR = None,
1156
+ position: TYPE_INPUT_VECTOR = None,
1157
+ interpolation: TYPE_INPUT_MENU = "Trilinear",
1158
+ ) -> "SampleGrid":
1159
+ """Create Sample Grid with operation 'Vector'."""
1160
+ return cls(
1161
+ data_type="VECTOR",
1162
+ grid=grid,
1163
+ position=position,
1164
+ interpolation=interpolation,
1165
+ )
1166
+
949
1167
  @property
950
1168
  def i_grid(self) -> SocketLinker:
951
1169
  """Input socket: Grid"""
@@ -967,39 +1185,78 @@ class SampleGrid(NodeBuilder):
967
1185
  return self._output("Value")
968
1186
 
969
1187
  @property
970
- def data_type(
971
- self,
972
- ) -> _GridDataTypes:
973
- return self.node.data_type # type: ignore
1188
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
1189
+ return self.node.data_type
974
1190
 
975
1191
  @data_type.setter
976
- def data_type(
977
- self,
978
- value: _GridDataTypes,
979
- ):
1192
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
980
1193
  self.node.data_type = value
981
1194
 
982
1195
 
983
1196
  class SampleGridIndex(NodeBuilder):
984
1197
  """Retrieve volume grid values at specific voxels"""
985
1198
 
986
- name = "GeometryNodeSampleGridIndex"
1199
+ _bl_idname = "GeometryNodeSampleGridIndex"
987
1200
  node: bpy.types.GeometryNodeSampleGridIndex
988
1201
 
989
1202
  def __init__(
990
1203
  self,
991
- grid: TYPE_INPUT_VALUE = None,
1204
+ grid: TYPE_INPUT_VALUE = 0.0,
992
1205
  x: TYPE_INPUT_INT = 0,
993
1206
  y: TYPE_INPUT_INT = 0,
994
1207
  z: TYPE_INPUT_INT = 0,
995
1208
  *,
996
- data_type: _GridDataTypes = "FLOAT",
1209
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
997
1210
  ):
998
1211
  super().__init__()
999
1212
  key_args = {"Grid": grid, "X": x, "Y": y, "Z": z}
1000
1213
  self.data_type = data_type
1001
1214
  self._establish_links(**key_args)
1002
1215
 
1216
+ @classmethod
1217
+ def float(
1218
+ cls,
1219
+ grid: TYPE_INPUT_VALUE = 0.0,
1220
+ x: TYPE_INPUT_INT = 0,
1221
+ y: TYPE_INPUT_INT = 0,
1222
+ z: TYPE_INPUT_INT = 0,
1223
+ ) -> "SampleGridIndex":
1224
+ """Create Sample Grid Index with operation 'Float'."""
1225
+ return cls(data_type="FLOAT", grid=grid, x=x, y=y, z=z)
1226
+
1227
+ @classmethod
1228
+ def integer(
1229
+ cls,
1230
+ grid: TYPE_INPUT_INT = 0,
1231
+ x: TYPE_INPUT_INT = 0,
1232
+ y: TYPE_INPUT_INT = 0,
1233
+ z: TYPE_INPUT_INT = 0,
1234
+ ) -> "SampleGridIndex":
1235
+ """Create Sample Grid Index with operation 'Integer'."""
1236
+ return cls(data_type="INT", grid=grid, x=x, y=y, z=z)
1237
+
1238
+ @classmethod
1239
+ def boolean(
1240
+ cls,
1241
+ grid: TYPE_INPUT_BOOLEAN = False,
1242
+ x: TYPE_INPUT_INT = 0,
1243
+ y: TYPE_INPUT_INT = 0,
1244
+ z: TYPE_INPUT_INT = 0,
1245
+ ) -> "SampleGridIndex":
1246
+ """Create Sample Grid Index with operation 'Boolean'."""
1247
+ return cls(data_type="BOOLEAN", grid=grid, x=x, y=y, z=z)
1248
+
1249
+ @classmethod
1250
+ def vector(
1251
+ cls,
1252
+ grid: TYPE_INPUT_VECTOR = None,
1253
+ x: TYPE_INPUT_INT = 0,
1254
+ y: TYPE_INPUT_INT = 0,
1255
+ z: TYPE_INPUT_INT = 0,
1256
+ ) -> "SampleGridIndex":
1257
+ """Create Sample Grid Index with operation 'Vector'."""
1258
+ return cls(data_type="VECTOR", grid=grid, x=x, y=y, z=z)
1259
+
1003
1260
  @property
1004
1261
  def i_grid(self) -> SocketLinker:
1005
1262
  """Input socket: Grid"""
@@ -1026,23 +1283,18 @@ class SampleGridIndex(NodeBuilder):
1026
1283
  return self._output("Value")
1027
1284
 
1028
1285
  @property
1029
- def data_type(
1030
- self,
1031
- ) -> _GridDataTypes:
1032
- return self.node.data_type # type: ignore
1286
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
1287
+ return self.node.data_type
1033
1288
 
1034
1289
  @data_type.setter
1035
- def data_type(
1036
- self,
1037
- value: _GridDataTypes,
1038
- ):
1290
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
1039
1291
  self.node.data_type = value
1040
1292
 
1041
1293
 
1042
1294
  class SetGridBackground(NodeBuilder):
1043
1295
  """Set the background value used for inactive voxels and tiles"""
1044
1296
 
1045
- name = "GeometryNodeSetGridBackground"
1297
+ _bl_idname = "GeometryNodeSetGridBackground"
1046
1298
  node: bpy.types.GeometryNodeSetGridBackground
1047
1299
 
1048
1300
  def __init__(
@@ -1050,13 +1302,41 @@ class SetGridBackground(NodeBuilder):
1050
1302
  grid: TYPE_INPUT_VALUE = 0.0,
1051
1303
  background: TYPE_INPUT_VALUE = 0.0,
1052
1304
  *,
1053
- data_type: _GridDataTypes = "FLOAT",
1305
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
1054
1306
  ):
1055
1307
  super().__init__()
1056
1308
  key_args = {"Grid": grid, "Background": background}
1057
1309
  self.data_type = data_type
1058
1310
  self._establish_links(**key_args)
1059
1311
 
1312
+ @classmethod
1313
+ def float(
1314
+ cls, grid: TYPE_INPUT_VALUE = 0.0, background: TYPE_INPUT_VALUE = 0.0
1315
+ ) -> "SetGridBackground":
1316
+ """Create Set Grid Background with operation 'Float'."""
1317
+ return cls(data_type="FLOAT", grid=grid, background=background)
1318
+
1319
+ @classmethod
1320
+ def integer(
1321
+ cls, grid: TYPE_INPUT_INT = 0, background: TYPE_INPUT_INT = 0
1322
+ ) -> "SetGridBackground":
1323
+ """Create Set Grid Background with operation 'Integer'."""
1324
+ return cls(data_type="INT", grid=grid, background=background)
1325
+
1326
+ @classmethod
1327
+ def boolean(
1328
+ cls, grid: TYPE_INPUT_BOOLEAN = False, background: TYPE_INPUT_BOOLEAN = False
1329
+ ) -> "SetGridBackground":
1330
+ """Create Set Grid Background with operation 'Boolean'."""
1331
+ return cls(data_type="BOOLEAN", grid=grid, background=background)
1332
+
1333
+ @classmethod
1334
+ def vector(
1335
+ cls, grid: TYPE_INPUT_VECTOR = None, background: TYPE_INPUT_VECTOR = None
1336
+ ) -> "SetGridBackground":
1337
+ """Create Set Grid Background with operation 'Vector'."""
1338
+ return cls(data_type="VECTOR", grid=grid, background=background)
1339
+
1060
1340
  @property
1061
1341
  def i_grid(self) -> SocketLinker:
1062
1342
  """Input socket: Grid"""
@@ -1073,37 +1353,60 @@ class SetGridBackground(NodeBuilder):
1073
1353
  return self._output("Grid")
1074
1354
 
1075
1355
  @property
1076
- def data_type(
1077
- self,
1078
- ) -> _GridDataTypes:
1079
- return self.node.data_type # type: ignore
1356
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
1357
+ return self.node.data_type
1080
1358
 
1081
1359
  @data_type.setter
1082
- def data_type(
1083
- self,
1084
- value: _GridDataTypes,
1085
- ):
1360
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
1086
1361
  self.node.data_type = value
1087
1362
 
1088
1363
 
1089
1364
  class SetGridTransform(NodeBuilder):
1090
1365
  """Set the transform for the grid from index space into object space."""
1091
1366
 
1092
- name = "GeometryNodeSetGridTransform"
1367
+ _bl_idname = "GeometryNodeSetGridTransform"
1093
1368
  node: bpy.types.GeometryNodeSetGridTransform
1094
1369
 
1095
1370
  def __init__(
1096
1371
  self,
1097
1372
  grid: TYPE_INPUT_VALUE = 0.0,
1098
- transform: LINKABLE | None = None,
1373
+ transform: TYPE_INPUT_MATRIX = None,
1099
1374
  *,
1100
- data_type: _GridDataTypes = "FLOAT",
1375
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
1101
1376
  ):
1102
1377
  super().__init__()
1103
1378
  key_args = {"Grid": grid, "Transform": transform}
1104
1379
  self.data_type = data_type
1105
1380
  self._establish_links(**key_args)
1106
1381
 
1382
+ @classmethod
1383
+ def float(
1384
+ cls, grid: TYPE_INPUT_VALUE = 0.0, transform: TYPE_INPUT_MATRIX = None
1385
+ ) -> "SetGridTransform":
1386
+ """Create Set Grid Transform with operation 'Float'."""
1387
+ return cls(data_type="FLOAT", grid=grid, transform=transform)
1388
+
1389
+ @classmethod
1390
+ def integer(
1391
+ cls, grid: TYPE_INPUT_INT = 0, transform: TYPE_INPUT_MATRIX = None
1392
+ ) -> "SetGridTransform":
1393
+ """Create Set Grid Transform with operation 'Integer'."""
1394
+ return cls(data_type="INT", grid=grid, transform=transform)
1395
+
1396
+ @classmethod
1397
+ def boolean(
1398
+ cls, grid: TYPE_INPUT_BOOLEAN = False, transform: TYPE_INPUT_MATRIX = None
1399
+ ) -> "SetGridTransform":
1400
+ """Create Set Grid Transform with operation 'Boolean'."""
1401
+ return cls(data_type="BOOLEAN", grid=grid, transform=transform)
1402
+
1403
+ @classmethod
1404
+ def vector(
1405
+ cls, grid: TYPE_INPUT_VECTOR = None, transform: TYPE_INPUT_MATRIX = None
1406
+ ) -> "SetGridTransform":
1407
+ """Create Set Grid Transform with operation 'Vector'."""
1408
+ return cls(data_type="VECTOR", grid=grid, transform=transform)
1409
+
1107
1410
  @property
1108
1411
  def i_grid(self) -> SocketLinker:
1109
1412
  """Input socket: Grid"""
@@ -1125,23 +1428,18 @@ class SetGridTransform(NodeBuilder):
1125
1428
  return self._output("Grid")
1126
1429
 
1127
1430
  @property
1128
- def data_type(
1129
- self,
1130
- ) -> _GridDataTypes:
1131
- return self.node.data_type # type: ignore
1431
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
1432
+ return self.node.data_type
1132
1433
 
1133
1434
  @data_type.setter
1134
- def data_type(
1135
- self,
1136
- value: _GridDataTypes,
1137
- ):
1435
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
1138
1436
  self.node.data_type = value
1139
1437
 
1140
1438
 
1141
1439
  class StoreNamedGrid(NodeBuilder):
1142
1440
  """Store grid data in a volume geometry with the specified name"""
1143
1441
 
1144
- name = "GeometryNodeStoreNamedGrid"
1442
+ _bl_idname = "GeometryNodeStoreNamedGrid"
1145
1443
  node: bpy.types.GeometryNodeStoreNamedGrid
1146
1444
 
1147
1445
  def __init__(
@@ -1150,13 +1448,53 @@ class StoreNamedGrid(NodeBuilder):
1150
1448
  name: TYPE_INPUT_STRING = "",
1151
1449
  grid: TYPE_INPUT_VALUE = 0.0,
1152
1450
  *,
1153
- data_type: Literal["FLOAT", "VECTOR_FLOAT", "INT", "BOOLEAN"] = "FLOAT",
1451
+ data_type: Literal["BOOLEAN", "FLOAT", "INT", "VECTOR_FLOAT"] = "FLOAT",
1154
1452
  ):
1155
1453
  super().__init__()
1156
1454
  key_args = {"Volume": volume, "Name": name, "Grid": grid}
1157
1455
  self.data_type = data_type
1158
1456
  self._establish_links(**key_args)
1159
1457
 
1458
+ @classmethod
1459
+ def boolean(
1460
+ cls,
1461
+ volume: TYPE_INPUT_GEOMETRY = None,
1462
+ name: TYPE_INPUT_STRING = "",
1463
+ grid: TYPE_INPUT_BOOLEAN = False,
1464
+ ) -> "StoreNamedGrid":
1465
+ """Create Store Named Grid with operation 'Boolean'."""
1466
+ return cls(data_type="BOOLEAN", volume=volume, name=name, grid=grid)
1467
+
1468
+ @classmethod
1469
+ def float(
1470
+ cls,
1471
+ volume: TYPE_INPUT_GEOMETRY = None,
1472
+ name: TYPE_INPUT_STRING = "",
1473
+ grid: TYPE_INPUT_VALUE = 0.0,
1474
+ ) -> "StoreNamedGrid":
1475
+ """Create Store Named Grid with operation 'Float'."""
1476
+ return cls(data_type="FLOAT", volume=volume, name=name, grid=grid)
1477
+
1478
+ @classmethod
1479
+ def integer(
1480
+ cls,
1481
+ volume: TYPE_INPUT_GEOMETRY = None,
1482
+ name: TYPE_INPUT_STRING = "",
1483
+ grid: TYPE_INPUT_INT = 0,
1484
+ ) -> "StoreNamedGrid":
1485
+ """Create Store Named Grid with operation 'Integer'."""
1486
+ return cls(data_type="INT", volume=volume, name=name, grid=grid)
1487
+
1488
+ @classmethod
1489
+ def vector(
1490
+ cls,
1491
+ volume: TYPE_INPUT_GEOMETRY = None,
1492
+ name: TYPE_INPUT_STRING = "",
1493
+ grid: TYPE_INPUT_VECTOR = None,
1494
+ ) -> "StoreNamedGrid":
1495
+ """Create Store Named Grid with operation 'Vector'."""
1496
+ return cls(data_type="VECTOR_FLOAT", volume=volume, name=name, grid=grid)
1497
+
1160
1498
  @property
1161
1499
  def i_volume(self) -> SocketLinker:
1162
1500
  """Input socket: Volume"""
@@ -1178,39 +1516,130 @@ class StoreNamedGrid(NodeBuilder):
1178
1516
  return self._output("Volume")
1179
1517
 
1180
1518
  @property
1181
- def data_type(
1182
- self,
1183
- ) -> Literal["FLOAT", "VECTOR_FLOAT", "INT", "BOOLEAN"]:
1184
- return self.node.data_type # type: ignore
1519
+ def data_type(self) -> Literal["BOOLEAN", "FLOAT", "INT", "VECTOR_FLOAT"]:
1520
+ return self.node.data_type
1185
1521
 
1186
1522
  @data_type.setter
1187
- def data_type(
1523
+ def data_type(self, value: Literal["BOOLEAN", "FLOAT", "INT", "VECTOR_FLOAT"]):
1524
+ self.node.data_type = value
1525
+
1526
+
1527
+ class VolumeCube(NodeBuilder):
1528
+ """Generate a dense volume with a field that controls the density at each grid voxel based on its position"""
1529
+
1530
+ _bl_idname = "GeometryNodeVolumeCube"
1531
+ node: bpy.types.GeometryNodeVolumeCube
1532
+
1533
+ def __init__(
1188
1534
  self,
1189
- value: Literal["FLOAT", "VECTOR_FLOAT", "INT", "BOOLEAN"],
1535
+ density: TYPE_INPUT_VALUE = 1.0,
1536
+ background: TYPE_INPUT_VALUE = 0.0,
1537
+ min: TYPE_INPUT_VECTOR = None,
1538
+ max: TYPE_INPUT_VECTOR = None,
1539
+ resolution_x: TYPE_INPUT_INT = 32,
1540
+ resolution_y: TYPE_INPUT_INT = 32,
1541
+ resolution_z: TYPE_INPUT_INT = 32,
1190
1542
  ):
1191
- self.node.data_type = value
1543
+ super().__init__()
1544
+ key_args = {
1545
+ "Density": density,
1546
+ "Background": background,
1547
+ "Min": min,
1548
+ "Max": max,
1549
+ "Resolution X": resolution_x,
1550
+ "Resolution Y": resolution_y,
1551
+ "Resolution Z": resolution_z,
1552
+ }
1192
1553
 
1554
+ self._establish_links(**key_args)
1193
1555
 
1194
- class GridToMesh(NodeBuilder):
1195
- """Generate a mesh on the "surface" of a volume grid"""
1556
+ @property
1557
+ def i_density(self) -> SocketLinker:
1558
+ """Input socket: Density"""
1559
+ return self._input("Density")
1560
+
1561
+ @property
1562
+ def i_background(self) -> SocketLinker:
1563
+ """Input socket: Background"""
1564
+ return self._input("Background")
1565
+
1566
+ @property
1567
+ def i_min(self) -> SocketLinker:
1568
+ """Input socket: Min"""
1569
+ return self._input("Min")
1570
+
1571
+ @property
1572
+ def i_max(self) -> SocketLinker:
1573
+ """Input socket: Max"""
1574
+ return self._input("Max")
1575
+
1576
+ @property
1577
+ def i_resolution_x(self) -> SocketLinker:
1578
+ """Input socket: Resolution X"""
1579
+ return self._input("Resolution X")
1580
+
1581
+ @property
1582
+ def i_resolution_y(self) -> SocketLinker:
1583
+ """Input socket: Resolution Y"""
1584
+ return self._input("Resolution Y")
1585
+
1586
+ @property
1587
+ def i_resolution_z(self) -> SocketLinker:
1588
+ """Input socket: Resolution Z"""
1589
+ return self._input("Resolution Z")
1590
+
1591
+ @property
1592
+ def o_volume(self) -> SocketLinker:
1593
+ """Output socket: Volume"""
1594
+ return self._output("Volume")
1196
1595
 
1197
- name = "GeometryNodeGridToMesh"
1198
- node: bpy.types.GeometryNodeGridToMesh
1596
+
1597
+ class VolumeToMesh(NodeBuilder):
1598
+ """Generate a mesh on the "surface" of a volume"""
1599
+
1600
+ _bl_idname = "GeometryNodeVolumeToMesh"
1601
+ node: bpy.types.GeometryNodeVolumeToMesh
1199
1602
 
1200
1603
  def __init__(
1201
1604
  self,
1202
- grid: TYPE_INPUT_VALUE = 0.0,
1605
+ volume: TYPE_INPUT_GEOMETRY = None,
1606
+ resolution_mode: TYPE_INPUT_MENU = "Grid",
1607
+ voxel_size: TYPE_INPUT_VALUE = 0.3,
1608
+ voxel_amount: TYPE_INPUT_VALUE = 64.0,
1203
1609
  threshold: TYPE_INPUT_VALUE = 0.1,
1204
1610
  adaptivity: TYPE_INPUT_VALUE = 0.0,
1205
1611
  ):
1206
1612
  super().__init__()
1207
- key_args = {"Grid": grid, "Threshold": threshold, "Adaptivity": adaptivity}
1613
+ key_args = {
1614
+ "Volume": volume,
1615
+ "Resolution Mode": resolution_mode,
1616
+ "Voxel Size": voxel_size,
1617
+ "Voxel Amount": voxel_amount,
1618
+ "Threshold": threshold,
1619
+ "Adaptivity": adaptivity,
1620
+ }
1621
+
1208
1622
  self._establish_links(**key_args)
1209
1623
 
1210
1624
  @property
1211
- def i_grid(self) -> SocketLinker:
1212
- """Input socket: Grid"""
1213
- return self._input("Grid")
1625
+ def i_volume(self) -> SocketLinker:
1626
+ """Input socket: Volume"""
1627
+ return self._input("Volume")
1628
+
1629
+ @property
1630
+ def i_resolution_mode(self) -> SocketLinker:
1631
+ """Input socket: Resolution Mode"""
1632
+ return self._input("Resolution Mode")
1633
+
1634
+ @property
1635
+ def i_voxel_size(self) -> SocketLinker:
1636
+ """Input socket: Voxel Size"""
1637
+ return self._input("Voxel Size")
1638
+
1639
+ @property
1640
+ def i_voxel_amount(self) -> SocketLinker:
1641
+ """Input socket: Voxel Amount"""
1642
+ return self._input("Voxel Amount")
1214
1643
 
1215
1644
  @property
1216
1645
  def i_threshold(self) -> SocketLinker:
@@ -1226,3 +1655,59 @@ class GridToMesh(NodeBuilder):
1226
1655
  def o_mesh(self) -> SocketLinker:
1227
1656
  """Output socket: Mesh"""
1228
1657
  return self._output("Mesh")
1658
+
1659
+
1660
+ class VoxelizeGrid(NodeBuilder):
1661
+ """Remove sparseness from a volume grid by making the active tiles into voxels"""
1662
+
1663
+ _bl_idname = "GeometryNodeGridVoxelize"
1664
+ node: bpy.types.GeometryNodeGridVoxelize
1665
+
1666
+ def __init__(
1667
+ self,
1668
+ grid: TYPE_INPUT_VALUE = 0.0,
1669
+ *,
1670
+ data_type: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"] = "FLOAT",
1671
+ ):
1672
+ super().__init__()
1673
+ key_args = {"Grid": grid}
1674
+ self.data_type = data_type
1675
+ self._establish_links(**key_args)
1676
+
1677
+ @classmethod
1678
+ def float(cls, grid: TYPE_INPUT_VALUE = 0.0) -> "VoxelizeGrid":
1679
+ """Create Voxelize Grid with operation 'Float'."""
1680
+ return cls(data_type="FLOAT", grid=grid)
1681
+
1682
+ @classmethod
1683
+ def integer(cls, grid: TYPE_INPUT_INT = 0) -> "VoxelizeGrid":
1684
+ """Create Voxelize Grid with operation 'Integer'."""
1685
+ return cls(data_type="INT", grid=grid)
1686
+
1687
+ @classmethod
1688
+ def boolean(cls, grid: TYPE_INPUT_BOOLEAN = False) -> "VoxelizeGrid":
1689
+ """Create Voxelize Grid with operation 'Boolean'."""
1690
+ return cls(data_type="BOOLEAN", grid=grid)
1691
+
1692
+ @classmethod
1693
+ def vector(cls, grid: TYPE_INPUT_VECTOR = None) -> "VoxelizeGrid":
1694
+ """Create Voxelize Grid with operation 'Vector'."""
1695
+ return cls(data_type="VECTOR", grid=grid)
1696
+
1697
+ @property
1698
+ def i_grid(self) -> SocketLinker:
1699
+ """Input socket: Grid"""
1700
+ return self._input("Grid")
1701
+
1702
+ @property
1703
+ def o_grid(self) -> SocketLinker:
1704
+ """Output socket: Grid"""
1705
+ return self._output("Grid")
1706
+
1707
+ @property
1708
+ def data_type(self) -> Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]:
1709
+ return self.node.data_type
1710
+
1711
+ @data_type.setter
1712
+ def data_type(self, value: Literal["FLOAT", "INT", "BOOLEAN", "VECTOR"]):
1713
+ self.node.data_type = value