-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor simulation API to use
simulation_zone
decorator
- Loading branch information
1 parent
467ae71
commit 63a7516
Showing
4 changed files
with
76 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,46 @@ | ||
import bpy | ||
import inspect | ||
import typing | ||
|
||
class SimulationInput: | ||
class DeltaTime: pass | ||
class ElapsedTime: pass | ||
|
||
def simulation(block: typing.Callable[typing.Any, 'Geometry']): | ||
def simulation_zone(block: typing.Callable): | ||
""" | ||
Create a simulation input/output block. | ||
> Only available in the `geometry-node-simulation` branch of Blender 3.5. | ||
> Only available in Blender 3.6+. | ||
""" | ||
def wrapped(geometry: 'Geometry', *args, **kwargs): | ||
from geometry_script import simulation_input, simulation_output | ||
simulation_in = simulation_input(geometry=geometry) | ||
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) | ||
for key, value in signature.parameters.items(): | ||
match value.annotation: | ||
case SimulationInput.DeltaTime: | ||
kwargs[key] = simulation_in.delta_time | ||
case SimulationInput.ElapsedTime: | ||
kwargs[key] = simulation_in.elapsed_time | ||
return simulation_output(geometry=block(simulation_in.geometry, *args, **kwargs)).geometry | ||
|
||
# setup zone | ||
simulation_in = State.current_node_tree.nodes.new(bpy.types.GeometryNodeSimulationInput.__name__) | ||
simulation_out = State.current_node_tree.nodes.new(bpy.types.GeometryNodeSimulationOutput.__name__) | ||
simulation_in.pair_with_output(simulation_out) | ||
|
||
# clear state items | ||
for item in simulation_out.state_items: | ||
simulation_out.state_items.remove(item) | ||
|
||
# create state items from block signature | ||
state_items = {} | ||
for param in [*signature.parameters.values()][1:]: | ||
state_items[param.name] = (param.annotation, param.default, None, None) | ||
for i, arg in enumerate(state_items.items()): | ||
simulation_out.state_items.new(socket_class_to_data_type(arg[1][0].socket_type), arg[0].replace('_', ' ').title()) | ||
set_or_create_link(kwargs[arg[0]] if arg[0] in kwargs else args[i], simulation_in.inputs[i]) | ||
|
||
step = block(*[Type(o) for o in simulation_in.outputs[:-1]]) | ||
|
||
if isinstance(step, Type): | ||
step = (step,) | ||
for i, result in enumerate(step): | ||
State.current_node_tree.links.new(result._socket, simulation_out.inputs[i]) | ||
|
||
if len(simulation_out.outputs[:-1]) == 1: | ||
return Type(simulation_out.outputs[0]) | ||
else: | ||
return OutputsList({o.name.lower().replace(' ', '_'): Type(o) for o in simulation_out.outputs[:-1]}) | ||
return wrapped |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,22 @@ | ||
# Simulation | ||
|
||
> This API is subject to change as future builds of Blender with simulation nodes are released. | ||
The `geometry-nodes-simulation` branch of Blender 3.5 includes support for "simulation nodes". | ||
Blender 3.6 includes simulation nodes. | ||
|
||
Using a *Simulation Input* and *Simulation Output* node, you can create effects that change over time. | ||
|
||
As a convenience, the `@simulation` decorator is provided to make simulation node blocks easier to create. | ||
As a convenience, the `@simulation_zone` decorator is provided to make simulation node blocks easier to create. | ||
|
||
```python | ||
@simulation | ||
def move_over_time( | ||
geometry: Geometry, # the first input must be `Geometry` | ||
speed: Float, | ||
dt: SimulationInput.DeltaTime, # Automatically passes the delta time on any argument annotated with `SimulationInput.DeltaTime`. | ||
elapsed: SimulationInput.ElapsedTime, # Automatically passes the elapsed time | ||
) -> Geometry: | ||
return geometry.set_position( | ||
offset=combine_xyz(x=speed) | ||
) | ||
``` | ||
from geometry_script import * | ||
|
||
Every frame the argument `geometry` will be set to the geometry from the previous frame. This allows the offset to accumulate over time. | ||
@tree | ||
def test_sim(geometry: Geometry): | ||
@simulation_zone | ||
def my_sim(delta_time, geometry: Geometry, value: Float): | ||
return (geometry, value) | ||
return my_sim(geometry, 0.26).value | ||
``` | ||
|
||
The `SimulationInput.DeltaTime`/`SimulationInput.ElapsedTime` types mark arguments that should be given the outputs from the *Simulation Input* node. | ||
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. | ||
The initial call to `my_sim` in `test_sim` provides the initial values for the simulation. |