Add repeat zone support

pull/35/head
Carson Katri 2023-11-11 14:43:12 -05:00 zatwierdzone przez Carson Katri
rodzic e3befbefc9
commit da99654edb
6 zmienionych plików z 117 dodań i 4 usunięć

Wyświetl plik

@ -0,0 +1,51 @@
import bpy
import inspect
import typing
def repeat_zone(block: typing.Callable):
"""
Create a repeat input/output block.
> Only available in Blender 4.0+.
"""
def wrapped(*args, **kwargs):
from geometry_script.api.node_mapper import OutputsList, set_or_create_link
from geometry_script.api.state import State
from geometry_script.api.types import Type, socket_class_to_data_type
signature = inspect.signature(block)
# setup zone
repeat_in = State.current_node_tree.nodes.new(bpy.types.GeometryNodeRepeatInput.__name__)
repeat_out = State.current_node_tree.nodes.new(bpy.types.GeometryNodeRepeatOutput.__name__)
repeat_in.pair_with_output(repeat_out)
# clear state items
for item in repeat_out.repeat_items:
repeat_out.repeat_items.remove(item)
# link the iteration count
set_or_create_link(args[0], repeat_in.inputs[0])
# create state items from block signature
repeat_items = {}
for param in signature.parameters.values():
repeat_items[param.name] = (param.annotation, param.default, None, None)
for i, arg in enumerate(repeat_items.items()):
repeat_out.repeat_items.new(socket_class_to_data_type(arg[1][0].socket_type), arg[0].replace('_', ' ').title())
# skip the first index, which is reserved for the iteration count
i = i + 1
set_or_create_link(kwargs[arg[0]] if arg[0] in kwargs else args[i], repeat_in.inputs[i])
step = block(*[Type(o) for o in repeat_in.outputs[:-1]])
if isinstance(step, Type):
step = (step,)
for i, result in enumerate(step):
set_or_create_link(result, repeat_out.inputs[i])
if len(repeat_out.outputs[:-1]) == 1:
return Type(repeat_out.outputs[0])
else:
return OutputsList({o.name.lower().replace(' ', '_'): Type(o) for o in repeat_out.outputs[:-1]})
return wrapped

Wyświetl plik

@ -6,6 +6,8 @@ def simulation_zone(block: typing.Callable):
""" """
Create a simulation input/output block. Create a simulation input/output block.
In Blender 4.0+, you must return a boolean value for the "Skip" argument as the first element in the return tuple.
> Only available in Blender 3.6+. > Only available in Blender 3.6+.
""" """
def wrapped(*args, **kwargs): def wrapped(*args, **kwargs):
@ -37,7 +39,7 @@ def simulation_zone(block: typing.Callable):
if isinstance(step, Type): if isinstance(step, Type):
step = (step,) step = (step,)
for i, result in enumerate(step): for i, result in enumerate(step):
State.current_node_tree.links.new(result._socket, simulation_out.inputs[i]) set_or_create_link(result, simulation_out.inputs[i])
if len(simulation_out.outputs[:-1]) == 1: if len(simulation_out.outputs[:-1]) == 1:
return Type(simulation_out.outputs[0]) return Type(simulation_out.outputs[0])

Wyświetl plik

@ -11,6 +11,7 @@ from .static.attribute import *
from .static.curve import * from .static.curve import *
from .static.expression import * from .static.expression import *
from .static.input_group import * from .static.input_group import *
from .static.repeat import *
from .static.sample_mode import * from .static.sample_mode import *
from .static.simulation import * from .static.simulation import *
from .arrange import _arrange from .arrange import _arrange

Wyświetl plik

@ -23,7 +23,8 @@
- [Boolean Math](./api/advanced-scripting/boolean-math.md) - [Boolean Math](./api/advanced-scripting/boolean-math.md)
- [Curves](./api/advanced-scripting/curves.md) - [Curves](./api/advanced-scripting/curves.md)
- [Drivers](./api/advanced-scripting/drivers.md) - [Drivers](./api/advanced-scripting/drivers.md)
- [Simulation](./api/advanced-scripting/simulation.md) - [Simulation Zones](./api/advanced-scripting/simulation-zones.md)
- [Repeat Zones](./api/advanced-scripting/repeat-zones.md)
# Tutorials # Tutorials

Wyświetl plik

@ -0,0 +1,42 @@
# Repeat Zones
Blender 4.0 introduced repeat zones.
Using a *Repeat Input* and *Repeat Output* node, you can loop a block of nodes for a specific number of iterations.
You must use the `@repeat_zone` decorator to create these special linked nodes.
```python
from geometry_script import *
@tree
def test_loop(geometry: Geometry):
@repeat_zone
def doubler(value: Float):
return value * 2
return points(count=doubler(5, 1)) # double the input value 5 times.
```
The function should modify the input values and return them in the same order.
When calling the repeat zone, pass the *Iterations* argument first, then any other arguments the function accepts.
For example:
```python
def doubler(value: Float) -> Float
```
would be called as:
```python
doubler(iteration_count, value)
```
When a repeat zone has multiple arguments, return a tuple from the zone.
```python
@repeat_zone
def multi_doubler(value1: Float, value2: Float):
return (value1 * 2, value2 * 2)
```

Wyświetl plik

@ -1,4 +1,4 @@
# Simulation # Simulation Zones
Blender 3.6 includes simulation nodes. Blender 3.6 includes simulation nodes.
@ -19,4 +19,20 @@ def test_sim(geometry: Geometry):
The first argument should always be `delta_time`. Any other arguments must also be returned as a tuple with their modified values. The first argument should always be `delta_time`. Any other arguments must also be returned as a tuple with their modified values.
Each frame, the result from the previous frame is passed into the zone's inputs. Each frame, the result from the previous frame is passed into the zone's inputs.
The initial call to `my_sim` in `test_sim` provides the initial values for the simulation. The initial call to `my_sim` in `test_sim` provides the initial values for the simulation.
## Blender 4.0+
A "Skip" argument was added to the *Simulation Output* node in Blender 4.0.
Return a boolean value first from any simulation zone to determine whether the step should be skipped.
The simplest way to migrate existing node trees is by adding `False` to the return tuple.
```python
@simulation_zone
def my_sim(delta_time, geometry: Geometry, value: Float):
return (False, geometry, value)
```
You can pass any boolean value as the skip output.