diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 6d50d52..6f928eb 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -22,10 +22,11 @@ - [Attributes](./api/advanced-scripting/attributes.md) - [Boolean Math](./api/advanced-scripting/boolean-math.md) - [Item Nodes](./api/advanced-scripting/item-nodes.md) - - [Repeat Zones](./api/advanced-scripting/repeat-zones.md) - - [Simulation Zones](./api/advanced-scripting/simulation-zones.md) - - [For Each Element Zones](./api/advanced-scripting/for-each-zones.md) - - [Closure Zones](./api/advanced-scripting/closure-zones.md) + - [Zones](./api/advanced-scripting/zones.md) + - [Repeat Zones](./api/advanced-scripting/repeat-zones.md) + - [Simulation Zones](./api/advanced-scripting/simulation-zones.md) + - [For Each Element Zones](./api/advanced-scripting/for-each-zones.md) + - [Closure Zones](./api/advanced-scripting/closure-zones.md) - [Shaders and Compositing](./api/advanced-scripting/shaders-and-compositing.md) # Tutorials diff --git a/book/src/api/advanced-scripting/zones.md b/book/src/api/advanced-scripting/zones.md new file mode 100644 index 0000000..3bab087 --- /dev/null +++ b/book/src/api/advanced-scripting/zones.md @@ -0,0 +1,59 @@ +# Zones + +A zone is a region of a node tree between a pair of input and output nodes, such as *Repeat Input* and *Repeat Output*. The nodes inside the zone are evaluated differently from the rest of the tree: repeated, run once per frame, run once per element, or packaged up to be evaluated later. + +Geometry Script has a decorator for each kind of zone: + +| Zone | Decorator | Runs its nodes | Works in | +|---|---|---|---| +| [Repeat](./repeat-zones.md) | `@repeat_zone` | A set number of times, feeding each result into the next iteration | Geometry Nodes, shaders | +| [Simulation](./simulation-zones.md) | `@simulation_zone` | Once per frame, starting from the previous frame's result | Geometry Nodes | +| [For Each Element](./for-each-zones.md) | `@for_each_element(domain=...)` | Once for each point, face, or other element of a geometry | Geometry Nodes | +| [Closure](./closure-zones.md) | `@closure_zone` | Whenever the closure is evaluated | Geometry Nodes, shaders | + +## Writing a Zone + +The decorated function is the body of the zone. Its parameters become the zone's items, and the values it returns are connected to the zone's output node: + +```python +@repeat_zone +def grow(geometry: Geometry, size: float): + bigger = transform_geometry(geometry=geometry, scale=(1.1, 1.1, 1.1)).geometry + return bigger, size * 1.1 +``` + +* Each parameter's annotation sets the item's socket type, just like the inputs of a [tree function](../basics/tree-functions.md#group-input). Without an annotation, the type is inferred from the value passed in. +* Return one value per item, in the same order as the parameters. You can also return a dictionary keyed by parameter name. +* Some parameter names are special, and receive a value from the zone instead of being an item: `iteration` in a repeat zone, `delta_time` in a simulation zone, and `index` and `element` in a for-each zone. + +## Using a Zone + +Call the decorated function inside a tree function to add the zone to the tree. Pass the initial value of each item, positionally or by name, along with any settings of the zone itself, such as `iterations=` or `skip=`: + +```python +@tree("Growing Cube") +def growing_cube(steps: int = 4): + result = grow(cube().mesh, 1.0, iterations=steps) + return result.geometry, result.size +``` + +A zone with a single item returns that socket directly. A zone with several items returns a named tuple with a field per item. For-each and closure zones return their own kinds of results, described on their pages. + +Each call adds a new zone, so the same decorated function can be used several times, in one tree or in many. Zones can only be called while a tree is being built. + +A zone can also be defined inside the tree function that uses it, which lets its body use the tree's inputs directly: + +```python +@tree("Spiral") +def spiral(count: int = 12, turn: float = 0.5): + @repeat_zone + def step(geometry: Geometry, iteration: int): + point = points(position=(math_(operation="COSINE", value=iteration * turn).value, + math_(operation="SINE", value=iteration * turn).value, + iteration * 0.1)).points + return join_geometry(geometry=[geometry, point]).geometry + + return step(points(count=0).points, iterations=count) +``` + +The next pages cover each kind of zone in detail. diff --git a/book/src/api/basics/cube_tree_size_compare.png b/book/src/api/basics/cube_tree_size_compare.png deleted file mode 100644 index f6ce58d..0000000 Binary files a/book/src/api/basics/cube_tree_size_compare.png and /dev/null differ diff --git a/book/src/api/basics/tree-functions.md b/book/src/api/basics/tree-functions.md index 358391b..6b24d29 100644 --- a/book/src/api/basics/tree-functions.md +++ b/book/src/api/basics/tree-functions.md @@ -20,6 +20,8 @@ def cube_tree(): Running the script again rebuilds the tree in place. Modifiers using the tree keep their input values, and if the script raises an error, the previous version of the tree is left untouched. +The nodes are laid out for you each time the tree is built, in columns that flow from the *Group Input* on the left to the *Group Output* on the right, with each zone's nodes kept together. Shader and compositor groups, materials and worlds are arranged the same way. + ## Group Output The values you return become the outputs of the tree. Let's try returning a simple cube. diff --git a/book/src/images/ide_docs.png b/book/src/images/ide_docs.png deleted file mode 100644 index 52f255c..0000000 Binary files a/book/src/images/ide_docs.png and /dev/null differ diff --git a/book/src/images/vscode_code_completion.png b/book/src/images/vscode_code_completion.png deleted file mode 100644 index a22099c..0000000 Binary files a/book/src/images/vscode_code_completion.png and /dev/null differ diff --git a/book/src/introduction.md b/book/src/introduction.md index f8474ec..983ca0b 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -1,13 +1,13 @@ # Introduction **Geometry Script** is a scripting API for Blender's Geometry Nodes. -It makes complicated node trees more managable and easy to share. +It makes complicated node trees more manageable and easy to share. * [Full coverage of nodes](./api/basics/using-nodes.md) available in your Blender version * Clean, easy to use [Python API](./api/basics.md) * Typed node functions generated from your Blender version, with [errors that say what to change](./api/basics/using-nodes.md) * External [IDE integration](./setup/external-editing.md) for better completions and hot reload -* [Repeat, simulation, for-each and closure zones](./api/advanced-scripting/repeat-zones.md) +* [Repeat, simulation, for-each and closure zones](./api/advanced-scripting/zones.md) Here's a simple example of what's possible with a short script: diff --git a/book/src/setup/agent-tools.md b/book/src/setup/agent-tools.md index 3180f04..7ef6b73 100644 --- a/book/src/setup/agent-tools.md +++ b/book/src/setup/agent-tools.md @@ -12,8 +12,8 @@ agent.run("/path/to/Repeat Grid.py", object="Cube") ``` ``` -built 'Repeat Grid': 14 nodes; in (Geometry: Geometry, Columns: Int = 3, Rows: Int = 3, Spacing X: Float = 0, Spacing Y: Float = 0) -> out (Result: Geometry) -object 'Cube': instances 9; instance positions (-2, -2, 0)..(2, 2, 0) +built 'Repeat Grid': 14 nodes; in (Geometry: Geometry, Columns: Int = 3, Rows: Int = 3, Spacing X: Float = 0.5, Spacing Y: Float = 0.5) -> out (Result: Geometry) +object 'Cube': instances 9; instance positions (-2.5, -2.5, 0)..(2.5, 2.5, 0) ``` Shader groups, materials, worlds and compositor groups are reported too: diff --git a/book/src/setup/external-editing.md b/book/src/setup/external-editing.md index a79aab7..f5188d5 100644 --- a/book/src/setup/external-editing.md +++ b/book/src/setup/external-editing.md @@ -22,9 +22,21 @@ Every node function in Geometry Script is generated with full type hints: its ke ![A screenshot of the Python > Analysis: Extra Paths setting with the path pasted in](../images/vscode_extra_paths.png) -5. Create a new Python file, such as `Repeat Grid.py` and start writing a script. As you type, you should get helpful suggestions for every available node. - -![A screenshot of a script with the documentation for `instance_on_points` appearing as the user types.](../images/vscode_code_completion.png) +5. Create a new Python file, such as `Repeat Grid.py` and start writing a script. As you type, you should get helpful suggestions for every available node. Hovering a node function shows its signature and description, for example: + +```python +def instance_on_points( + *, + points: Geometry | Socket[Geometry] | None = None, + selection: bool | Field[bool] | Socket[bool | Field[bool]] = True, + instance: Geometry | Socket[Geometry] | None = None, + pick_instance: bool | Field[bool] | Socket[bool | Field[bool]] = False, + instance_index: int | Field[int] | Socket[int | Field[int]] = 0, + rotation: Rotation | Field[Rotation] | Socket[Rotation | Field[Rotation]] = (0.0, 0.0, 0.0), + scale: Vector | Field[Vector] | Socket[Vector | Field[Vector]] = (1.0, 1.0, 1.0), +) -> GeometryNodeInstanceOnPointsOutputs: + 'Generate a reference to geometry at each of the input points, without duplicating its underlying data' +``` > For completions of `bpy` itself, install [`fake-bpy-module`](https://github.com/nutti/fake-bpy-module) into the Python environment your editor uses. diff --git a/book/src/setup/installation.md b/book/src/setup/installation.md index 47e9436..06e4442 100644 --- a/book/src/setup/installation.md +++ b/book/src/setup/installation.md @@ -29,11 +29,6 @@ Blender asks to allow online access if it's off, then offers to add the Geometry 2. Open *Blender* > *Preferences* > *Get Extensions* 3. Open the dropdown at the top right, choose *Install from Disk...* and select the downloaded ZIP file -## From Blender Market -1. After [purchasing the add-on](https://www.blendermarket.com/), download the ZIP file -2. Open *Blender* > *Preferences* > *Get Extensions* -3. Open the dropdown at the top right, choose *Install from Disk...* and select the downloaded ZIP file - ## Building it yourself To build the extension for a Blender version that has no published ZIP, clone the repository and run: diff --git a/examples/Repeat Grid.py b/examples/Repeat Grid.py index b5614c2..4306cd0 100644 --- a/examples/Repeat Grid.py +++ b/examples/Repeat Grid.py @@ -5,8 +5,8 @@ def repeat_grid( geometry: Geometry, columns: int = 3, rows: int = 3, - spacing_x: float = 0.0, - spacing_y: float = 0.0, + spacing_x: float = 0.5, + spacing_y: float = 0.5, ): # Measure the geometry's bounds bounds = bounding_box(geometry=geometry)