Add mdbook
3
book/src/api/advanced-scripting.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Advanced Scripting
|
||||
|
||||
Now that we've covered the basics, let's take a look at some more advanced scripting techniques.
|
||||
BIN
book/src/api/advanced-scripting/cube_grid.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
30
book/src/api/advanced-scripting/generators.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Generators
|
||||
|
||||
Python has support for [generators](https://wiki.python.org/moin/Generators) using the `yield` keyword.
|
||||
|
||||
Geometry Script tree functions can be represented as generators to output multiple values. If every generated value is `Geometry`, the values are automatically connected to a *Join Geometry* node and output as a single mesh.
|
||||
|
||||
```python
|
||||
@tree("Primitive Shapes")
|
||||
def primitive_shapes():
|
||||
yield cube()
|
||||
yield uv_sphere()
|
||||
yield cylinder().mesh
|
||||
```
|
||||
|
||||

|
||||
|
||||
However, if any of the outputs is not `Geometry`, separate sockets are created for each output.
|
||||
|
||||
```python
|
||||
@tree("Primitive Shapes and Integer")
|
||||
def primitive_shapes():
|
||||
yield cube()
|
||||
yield uv_sphere()
|
||||
yield cylinder().mesh
|
||||
yield 5 # Not a geometry socket type
|
||||
```
|
||||
|
||||

|
||||
|
||||
> The first output is always displayed when using a *Geometry Nodes* modifier. Ensure it is a `Geometry` socket type, unless you are using the function as a node group.
|
||||
BIN
book/src/api/advanced-scripting/geometry_generator.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
book/src/api/advanced-scripting/instance_grid.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
book/src/api/advanced-scripting/mixed_generator.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
25
book/src/api/advanced-scripting/node-groups.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Node Groups
|
||||
|
||||
A Geometry Script can have more than one tree function. Each tree function is a node group, and tree functions can be used in other tree functions to create *Node Group* nodes.
|
||||
|
||||
```python
|
||||
@tree("Instance Grid")
|
||||
def instance_grid(instance: Geometry):
|
||||
""" Instance the input geometry on a grid """
|
||||
return grid().mesh_to_points().instance_on_points(instance=instance)
|
||||
|
||||
@tree("Cube Grid")
|
||||
def cube_grid():
|
||||
""" Create a grid of cubes """
|
||||
return instance_grid(instance=cube(size=0.2))
|
||||
```
|
||||
|
||||
The *Cube Grid* tree uses the *Instance Grid* node group by calling the `instance_grid` function:
|
||||
|
||||

|
||||
|
||||
The *Instance Grid* node group uses the passed in `instance` argument to create a grid of instances:
|
||||
|
||||

|
||||
|
||||
This concept can scale to complex interconnected node trees, while keeping everything neatly organized in separate functions.
|
||||
5
book/src/api/basics.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Basics
|
||||
Creating Geometry Scripts can be as easy or complex as you want for your project.
|
||||
Throughout this guide, scripts will be displayed alongside the generated nodes to provide context on how a script relates to the underlying nodes.
|
||||
|
||||
Setting up an editor for [external editing](../setup/external-editing.md) is recommended when writing scripts, but [internal editing inside Blender](../setup/internal-editing-basics.md) will suffice for the simple examples shown here.
|
||||
BIN
book/src/api/basics/capture_attribute_node.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
book/src/api/basics/cube_node.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
book/src/api/basics/cube_tree.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
book/src/api/basics/cube_tree_int.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
book/src/api/basics/cube_tree_mesh_to_volume.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
book/src/api/basics/cube_tree_modifier.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
book/src/api/basics/cube_tree_size.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
book/src/api/basics/cube_tree_size_compare.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
book/src/api/basics/cube_tree_size_components.png
Normal file
|
After Width: | Height: | Size: 261 KiB |
BIN
book/src/api/basics/cube_tree_size_double.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
book/src/api/basics/cube_tree_size_input.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
38
book/src/api/basics/modules.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Modules
|
||||
|
||||
The first step when writing is script is importing the `geometry_script` module. There a are a few ways of doing this:
|
||||
|
||||
## Import All Names (Recommended)
|
||||
This will import every type and function available into your script. It can make it easy to discover what's available with code completion, and makes the scripts more terse.
|
||||
```python
|
||||
from geometry_script import *
|
||||
|
||||
cube(...) # Available globally
|
||||
my_geo: Geometry # All types available as well
|
||||
```
|
||||
|
||||
## Import Specific Names
|
||||
This will import only the specified names from the module:
|
||||
```python
|
||||
from geometry_script import cube, Geometry
|
||||
|
||||
cube(...) # Available from import
|
||||
my_geo: Geometry
|
||||
```
|
||||
|
||||
## Namespaced Import
|
||||
This will import every type and function, and place them behind the namespace. You can use the module name, or provide your own.
|
||||
```python
|
||||
import geometry_script
|
||||
|
||||
geometry_script.cube(...) # Prefix with the namespace
|
||||
my_geo: geometry_script.Geometry
|
||||
```
|
||||
```python
|
||||
import geometry_script as gs
|
||||
|
||||
gs.cube(...) # Prefix with the custom name
|
||||
my_geo: gs.Geometry
|
||||
```
|
||||
|
||||
Now that you have Geometry Script imported in some way, let's create a tree.
|
||||
BIN
book/src/api/basics/open_documentation.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
124
book/src/api/basics/sockets.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# Sockets
|
||||
Because scripts are converted to Geometry Node trees, you typically cannot use default Python types as arguments. In some cases, they will be automatically converted for you, but in general you will be dealing with socket types.
|
||||
|
||||
## What is a socket?
|
||||
A socket is any input or output on a node. Take the *Cube* node for example:
|
||||
|
||||

|
||||
|
||||
This node has 4 input sockets, and 1 output socket.
|
||||
|
||||
* Input Sockets
|
||||
* Size: `Vector`
|
||||
* Vertices X: `Int`
|
||||
* Vertices Y: `Int`
|
||||
* Vertices Z: `Int`
|
||||
* Output Sockets
|
||||
* Mesh: `Geometry`
|
||||
|
||||
A socket does not represent a value itself. For example, the `Size` socket does not necessarily represent the value `(1, 1, 1)`. Instead, it can be connected to another node as an input, giving it a dynamic value.
|
||||
|
||||
When we write scripts, we typically deal with socket types, not concrete values like `(1, 1, 1)`. Take this script for example:
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
return cube(size=size)
|
||||
```
|
||||
|
||||
The `size` argument creates a input socket with the type `Vector`. This is then connected to the `size` socket of the *Cube* node.
|
||||
|
||||

|
||||
|
||||
Our script does not run every time the node tree is evaluated. It only runs once to create the node tree. Therefore, we have no way of knowing what value `size` has when the script runs, because it is dynamic.
|
||||
|
||||
## What sockets *can* do
|
||||
|
||||
Sockets are great for passing values between nodes. A socket type like `Geometry` does not represent concrete vertices, edges, and faces. Instead, it represents the input or output socket of a node. This lets us use it to create connections between different nodes, by passing the output of one node to the input of another.
|
||||
|
||||
## What sockets *cannot* do
|
||||
|
||||
Sockets cannot be read for their concrete value. A `Float` socket type does not equal `5` or `10` or `3.14` to our script. It only represents the socket of a node. If you try to `print(...)` a socket, you will receive a generic reference type with no underlying value.
|
||||
|
||||
## Why use sockets?
|
||||
|
||||
You might be wondering, "if you can't access the value of a socket, what can you do with it?"
|
||||
|
||||
Geometry Script provides many helpful additions that make working with sockets about as easy as working with a concrete value.
|
||||
|
||||
## Socket Math
|
||||
|
||||
Socket types can be used to perform math operations. The proper *Math* node will be created automatically for you, so you can focus on writing a script and not thinking about sockets. If you use `Float` or `Int` it will create a *Math* node, and if you use a `Vector` it will create a *Vector Math* node.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
doubled = size * (2, 2, 2) # Multiply each component by 2
|
||||
return cube(size=doubled)
|
||||
```
|
||||

|
||||
|
||||
Several common math operations are available, such as:
|
||||
* Add (`socket + 2`)
|
||||
* Subtract (`socket - 2`)
|
||||
* Multiply (`socket * 2`)
|
||||
* Divide (`socket / 2`)
|
||||
* Modulo (`socket % 2`)
|
||||
|
||||
## Socket Comparison
|
||||
|
||||
Socket types can be compared with Python comparison operators. A *Compare* node will be created with the correct inputs and options specified.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
show_cube = size > (2, 2, 2) # Check if each component is greater than 2
|
||||
return cube(size=show_cube)
|
||||
```
|
||||

|
||||
|
||||
Several common comparison operators are supported, such as:
|
||||
* Equal To (`socket == 2`)
|
||||
* Not Equal To (`socket != 2`)
|
||||
* Less Than (`socket < 2`)
|
||||
* Less Than Or Equal To (`socket <= 2`)
|
||||
* Greater Than (`socket > 2`)
|
||||
* Greater Than Or Equal To (`socket >= 2`)
|
||||
|
||||
## Vector Component Properties
|
||||
|
||||
While the `Vector` type does not equate to three concrete components, such as `(1, 2, 3)`, you can still access the `x`, `y`, and `z` components as sockets. A *Separate XYZ* node will be created with the correct inputs and outputs specified.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
height = size.z # Access the Z component
|
||||
# Multiply the height by 2 but leave the other components unchanged.
|
||||
return cube(size=combine_xyz(x=size.x, y=size.y, z=height * 2))
|
||||
```
|
||||
|
||||
For each component access, a *Separate XYZ* node is created.
|
||||
|
||||

|
||||
|
||||
## Chained Calls
|
||||
|
||||
Any node function can be called on a socket type. This will automatically connect the socket to the first input of the node.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
return cube(size=size).mesh_to_volume()
|
||||
```
|
||||
|
||||
The output of the *Cube* node (a `Geometry` socket type) is connected to the first input of the *Mesh to Volume* node.
|
||||
|
||||

|
||||
|
||||
The same script without chaining calls is written more verbosely as:
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
return mesh_to_volume(mesh=cube(size=size))
|
||||
```
|
||||
80
book/src/api/basics/tree-functions.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# Tree Functions
|
||||
|
||||
Node trees are created by decorating a function with `@tree`. Let's try creating a simple tree function.
|
||||
|
||||
> The code samples for the rest of the book assume you are importing all names with `from geometry_script import *`. However, if you are using a namespaced import, simply prefix the functions and types with `geometry_script` or your custom name.
|
||||
|
||||
```python
|
||||
@tree
|
||||
def cube_tree():
|
||||
...
|
||||
```
|
||||
|
||||
By default, the name of your function will be used as the name of the generated node tree. However, you can specify a custom name by passing a string to `@tree`:
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree():
|
||||
...
|
||||
```
|
||||
|
||||
## Group Output
|
||||
Every node tree is **required** to return `Geometry` as the first output. Let's try returning a simple cube.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree():
|
||||
return cube()
|
||||
```
|
||||
|
||||
Here we call the `cube(...)` function, which creates a *Cube* node and connects it to the *Group Output*.
|
||||
|
||||

|
||||
|
||||
You can also return multiple values. However, `Geometry` must always be returned first for a tree to be valid.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree():
|
||||
return cube(), 5
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Group Input
|
||||
All arguments in a tree function must be annotated with a valid socket type. These types are provided by Geometry Script, and are not equivalent to Python's built-in types. Let's add a size argument to our Cube Tree.
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector):
|
||||
return cube(size=size)
|
||||
```
|
||||
|
||||
This creates a *Size* socket on the *Group Input* node and connects it to our cube.
|
||||
|
||||

|
||||
|
||||
The option is available on the Geometry Nodes modifier.
|
||||
|
||||

|
||||
|
||||
The available socket types match those in the UI. Here are some common ones:
|
||||
|
||||
* `Geometry`
|
||||
* `Float`
|
||||
* `Int`
|
||||
* `Vector`
|
||||
|
||||
> You *cannot* use Python's built-in types in place of these socket types.
|
||||
|
||||
In the next chapter, we'll take a closer look at how socket types work, and what you can and cannot do with them.
|
||||
|
||||
### Default Values
|
||||
You can specify a default for any argument, and it will be set on the modifier when added:
|
||||
|
||||
```python
|
||||
@tree("Cube Tree")
|
||||
def cube_tree(size: Vector = (1, 1, 1)):
|
||||
return cube(size=size)
|
||||
```
|
||||

|
||||
111
book/src/api/basics/using-nodes.md
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
# Using Nodes
|
||||
|
||||
Node functions are automatically generated for the Blender version you are using. This means every node will be available from geometry script.
|
||||
|
||||
This means that when future versions of Blender add new nodes, they will all be available in Geometry Script without updating the add-on.
|
||||
|
||||
To see all of the node functions available in your Blender version, open the *Geometry Script* menu in the *Text Editor* and click *Open Documentation*.
|
||||
|
||||

|
||||
|
||||
This will open the automatically generated docs page with a list of every available node and it's inputs and outputs.
|
||||
|
||||
## How nodes are mapped
|
||||
All nodes are mapped to functions in the same way, so even without the documentation you can decifer what a node will equate to. Using an [IDE with code completion](../../setup/external-editing.md) makes this even easier.
|
||||
|
||||
The general process is:
|
||||
1. Convert the node name to snake case.
|
||||
2. Add a keyword argument (in snake case) for each property and input.
|
||||
3. If the node has a single output, return the socket type, otherwise return an object with properties for each output name.
|
||||
|
||||
> Properties and inputs are different types of argument. A property is a value that cannot be connected to a socket. These are typically enums (displayed in the UI as a dropdown), with specific string values expected. Check the documentation for a node to see what the possible values are for a property.
|
||||
|
||||
Let's take a look at two nodes as an example.
|
||||
|
||||
### Cube
|
||||
|
||||

|
||||
|
||||
1. Name: `Cube` -> `cube`
|
||||
2. Keyword Arguments
|
||||
* `size: Vector`
|
||||
* `vertices_x: Int`
|
||||
* `vertices_y: Int`
|
||||
* `vertices_z: Int`
|
||||
3. Return `Geometry`
|
||||
|
||||
The node can now be used as a function:
|
||||
|
||||
```python
|
||||
cube() # All arguments are optional
|
||||
cube(size=(1, 1, 1), vertices_x=3) # Optionally specify keyword arguments
|
||||
cube_geo: Geometry = cube() # Returns a Geometry socket type
|
||||
```
|
||||
|
||||
The generated documentation will show the signature, result type, and [chain syntax](./sockets.md#chained-calls).
|
||||
|
||||
#### Signature
|
||||
```python
|
||||
cube(
|
||||
size: VectorTranslation,
|
||||
vertices_x: Int,
|
||||
vertices_y: Int,
|
||||
vertices_z: Int
|
||||
)
|
||||
```
|
||||
|
||||
#### Result
|
||||
```python
|
||||
mesh: Geometry
|
||||
```
|
||||
|
||||
#### Chain Syntax
|
||||
```python
|
||||
size: VectorTranslation = ...
|
||||
size.cube(...)
|
||||
```
|
||||
|
||||
### Capture Attribute
|
||||
|
||||

|
||||
|
||||
1. Name `Capture Attribute` -> `capture_attribute`
|
||||
2. Keyword Arguments
|
||||
* Properties
|
||||
* `data_type: Literal['FLOAT', 'INT', 'FLOAT_VECTOR', 'FLOAT_COLOR', 'BYTE_COLOR', 'STRING', 'BOOLEAN', 'FLOAT2', 'INT8']`
|
||||
* `domain: Literal['POINT', 'EDGE', 'FACE', 'CORNER', 'CURVE', 'INSTANCE']`
|
||||
* Inputs
|
||||
* `geometry: Geometry`
|
||||
* `value: Vector | Float | Color | Bool | Int`
|
||||
3. Return `{ geometry: Geometry, attribute: Int }`
|
||||
|
||||
The node can now be used as a function:
|
||||
|
||||
```python
|
||||
result = capture_attribute(data_type='BOOLEAN', geometry=cube_geo) # Specify a property and an input
|
||||
result.geometry # Access the geometry
|
||||
result.attribute # Access the attribute
|
||||
```
|
||||
|
||||
The generated documentation will show the signature, result type, and [chain syntax](./sockets.md#chained-calls).
|
||||
|
||||
#### Signature
|
||||
```python
|
||||
capture_attribute(
|
||||
data_type: Literal['FLOAT', 'INT', 'FLOAT_VECTOR', 'FLOAT_COLOR', 'BYTE_COLOR', 'STRING', 'BOOLEAN', 'FLOAT2', 'INT8'],
|
||||
domain: Literal['POINT', 'EDGE', 'FACE', 'CORNER', 'CURVE', 'INSTANCE'],
|
||||
geometry: Geometry,
|
||||
value: Vector | Float | Color | Bool | Int
|
||||
)
|
||||
```
|
||||
|
||||
#### Result
|
||||
```python
|
||||
{ geometry: Geometry, attribute: Int }
|
||||
```
|
||||
|
||||
#### Chain Syntax
|
||||
```python
|
||||
geometry: Geometry = ...
|
||||
geometry.capture_attribute(...)
|
||||
```
|
||||