kopia lustrzana https://github.com/carson-katri/geometry-script
Change capture/transfer behavior
rodzic
a360f26fde
commit
f50fa922be
|
@ -169,8 +169,11 @@ class Type(metaclass=_TypeMeta):
|
||||||
|
|
||||||
def capture(self, value, **kwargs):
|
def capture(self, value, **kwargs):
|
||||||
data_type = socket_type_to_data_type(value._socket.type)
|
data_type = socket_type_to_data_type(value._socket.type)
|
||||||
captured = self.capture_attribute(data_type=data_type, value=value, **kwargs)
|
geometry, attribute = self.capture_attribute(data_type=data_type, value=value, **kwargs)
|
||||||
return lambda **kwargs: captured.geometry.transfer_attribute(data_type=data_type, attribute=captured.attribute, **kwargs)
|
return geometry, attribute
|
||||||
|
def transfer(self, attribute, **kwargs):
|
||||||
|
data_type = socket_type_to_data_type(attribute._socket.type)
|
||||||
|
return self.transfer_attribute(data_type=data_type, attribute=attribute, **kwargs)
|
||||||
|
|
||||||
for standard_socket in list(filter(lambda x: 'NodeSocket' in x, dir(bpy.types))):
|
for standard_socket in list(filter(lambda x: 'NodeSocket' in x, dir(bpy.types))):
|
||||||
name = standard_socket.replace('NodeSocket', '')
|
name = standard_socket.replace('NodeSocket', '')
|
||||||
|
|
|
@ -1,66 +1,48 @@
|
||||||
# Attributes
|
# Attributes
|
||||||
|
|
||||||
An important concept in Geometry Nodes is attributes. Many trees transfer attributes between geometry, using a combination of *Capture Attribute* and *Transfer Attribute*.
|
An important concept in Geometry Nodes is attributes. Many trees capture attributes or transfer them from one geometry to another.
|
||||||
|
|
||||||
Unfortunately, it takes quite a bit of code to use this common pattern.
|
When using these methods, the `data_type` argument must be correctly specified for the transfer to work as intended.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@tree("Skin")
|
@tree("Skin")
|
||||||
def skin():
|
def skin():
|
||||||
# Create a cube
|
# Create a cube
|
||||||
c = cube()
|
c = cube()
|
||||||
# Capture the position
|
|
||||||
cube_position_attribute = c.capture_attribute(
|
|
||||||
data_type=CaptureAttribute.DataType.FLOAT_VECTOR,
|
|
||||||
value=position()
|
|
||||||
)
|
|
||||||
# Create a sphere
|
# Create a sphere
|
||||||
sphere = uv_sphere()
|
sphere = uv_sphere()
|
||||||
# Transfer the position to the sphere
|
# Transfer the position to the sphere
|
||||||
transferred_position = cube_position_attribute.geometry.transfer_attribute(
|
transferred_position = c.transfer_attribute(
|
||||||
data_type=TransferAttribute.DataType.FLOAT_VECTOR,
|
data_type=TransferAttribute.DataType.FLOAT_VECTOR,
|
||||||
attribute=cube_position_attribute.attribute
|
attribute=position()
|
||||||
)
|
)
|
||||||
# Make the sphere conform to the shape of the cube
|
# Make the sphere conform to the shape of the cube
|
||||||
return sphere.set_position(position=transferred_position)
|
return sphere.set_position(position=transferred_position)
|
||||||
```
|
```
|
||||||
|
|
||||||
Thankfully, a convenient `capture(...)` method is available on `Geometry`, which simplifies this function quite a bit.
|
To improve the usability of these nodes, `capture(...)` and `transfer(...)` methods are provided on `Geometry` that simply take the attribute and any other optional arguments.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@tree("Skin")
|
@tree("Skin")
|
||||||
def skin():
|
def skin():
|
||||||
# Create a cube
|
# Create a cube
|
||||||
c = cube()
|
c = cube()
|
||||||
# Capture the position
|
|
||||||
cube_position = c.capture(position())
|
|
||||||
# Create a sphere
|
# Create a sphere
|
||||||
sphere = uv_sphere()
|
sphere = uv_sphere()
|
||||||
# Make the sphere conform to the shape of the cube
|
# Make the sphere conform to the shape of the cube
|
||||||
return sphere.set_position(position=cube_position())
|
return sphere.set_position(position=c.transfer(position()))
|
||||||
```
|
```
|
||||||
|
|
||||||
## How it Works
|
The same is available for `capture(...)`.
|
||||||
|
|
||||||
Internally, `capture(...)` works just like the more manual approach.
|
|
||||||
|
|
||||||
1. Capture the attribute from the source
|
|
||||||
|
|
||||||
In the example above, we capture the `position()` from the cube.
|
|
||||||
The data type is automatically inferred from the input. If you want to customize other options, simply pass them as keyword arguments to `capture(...)`.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
cube_position = c.capture(position())
|
geometry_with_attribute, attribute = c.capture(position())
|
||||||
cube_position = c.capture(position(), domain=CaptureAttribute.Domain.FACE) # Optionally pass other arguments available on `capture_attribute`.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Transfer the attribute to the target
|
> You must use the `Geometry` returned from `capture(...)` for the anonymous attribute it creates to be usable.
|
||||||
|
|
||||||
`capture(...)` returns another function that calls `transfer_attribute` with the correct arguments passed automatically.
|
Any additional keyword arguments can be passed as normal.
|
||||||
Call this returned function (which we store in the variable `cube_position`) to transfer the attribute.
|
|
||||||
In this example we also set the transferred cube position back onto the sphere.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
sphere.set_position(position=cube_position())
|
c.transfer(position(), mapping=TransferAttribute.Mapping.INDEX)
|
||||||
sphere.set_position(position=cube_position(mapping=TransferAttribute.Mapping.NEAREST)) # Optionally pass other arguments available on `transfer_attribute`.
|
|
||||||
```
|
```
|
Ładowanie…
Reference in New Issue