# Making Worlds Feel Alive with Procedural Systems in Blender
## Abstract
This hands-on class is focused on progressively building a simple space traffic system, using proceduralism. The two main building blocks of this system are the spaceship generator and the traffic paths. The goal of the system is to provide a believable behavior for the ships, making the background of a scene feel alive.
The spaceship generator will use procedural geometry modifications to achieve a variety of sci-fi looking vessels, using common geometry manipulation techniques, and simple shapes using boolean operations.
The traffic paths will be a simulation driven particle system, exposing parameters such as density, speed, etc.
While the spaceship system will be used as a practical example, the concepts are more generally applicable to similar scenarios.
There is no requirement of previous experience with the Geometry Nodes system, while a base level familiarity with Blender is encouraged to follow along.
## Files
[Files are here.](https://drive.google.com/drive/folders/192oUAFUdoQRXgPXEu4dJAbJtnICpgiAm?usp=sharing)
## Shortcuts Cheatsheet
- Move selected nodes: `G`
- Viewer: `CTRL + SHIFT + LMB`
- Add node: `SHIFT + A` -> search
- Add node from socket: `LMB drag + let go` -> search
- Mute node: `M`
- Frame: `F`
- Rename: `F2`
- Add reroute node: `SHIFT + RMB drag`
- Cut links: `CTRL + RMB drag`
- Mute links: `CTRL + ALT + RMB drag`
- Toggle Maximize Editor: `CTRL + Spacebar`
## STEP by STEP guide
### I. Spaceship Generator

#### 1. Base Layer


<details>
- scatter points on base plane (`Distribute Points on Faces`)
- create collection with set of base meshes
- instance base meshes on the generated points (`Collection Info`, `Instance on Points`)
- enable `Separate Children` and `Pick Instance`
- merge instances into one mesh (`Mesh Boolean` - Union, Manifold)
- expose `Seed` as modifier input (drag link and search for `Group Input`)
</details>
#### 2. Rotate + Bisect

<details>
- after Base Layer
- rotate randomly (`Transform Geometry`; `Random Value` - Vector)
- use `Seed` input from modifier as `ID` to generate single value
- create cube mesh for intersection (`Cube` - size 200; `Transform Geometry` - `X = -100`)
- generate difference mesh ('Mesh Boolean' - Difference, Manifold)
- delete inside faces (`Delete Geometry` - Face; `Capture Attribute` - Face)
- Capture a `True` boolean on the cube before intersectionand use the captured result as selection for deleting faces after
</details>
#### 3. Mirror

<details>
- at the end of the node-tree
- flip mesh on X axis (`Transform Geometry` - `Scale = [-1,1,1]`)
- join with original (`Join Geometry`)
</details>
#### 4. Subtraction Layer

<details>
- after the Base Layer, before Rotate + Bisect
- scatter base meshes on base layer mesh (`Distribute Points on Faces`; `Instance on Points`)
- use same instances as before
- enable `Pick Instance` as before
- subtract from base layer mesh (`Mesh Boolean` - Difference, Manifold)
</details>
#### 5. Greeble

<details>
- after Rotate + Bisect
- extrude random faces (`Extrude Mesh` - Offset = 0; `Random Value` - Boolean, Probability = 0.5)
- scale extruded faces down (`Scale Elements` - Scale = 0.9)
- `Top` as selection
- extrude again with random offset (`Extrude Mesh`; `Random Value`)
- previous `Top` as selection
- random value as `Offset Scale`
- range negative to positive (e.g. 0.05)
- repeat whole process
- add repeat zone
- integrate geometry data flow into the repeat zone
- use repeat iteration index as Seed for randomization
- don't use side faces for further extrusion
- `Side` from 1st extrusion `Or` `Side` from 2nd extrusion
- `Not`
- `And`
- pass result into new repeat output
- make that repeat input `True` and pass into second `And` input
</details>
#### 6. Wires

<details>
- after Rotate + Bisect in parallel to Greeble
- generate convex hull (`Convex Hull`)
- convert to curves (`Mesh to Curve`)
- create tubes from curves (`Curve to Mesh` - Scale = 0.002; `Curve Circle` - Resolution = 4)
- circle as profile curve
- add sagging deformation
- `Subdivide Curve` between `Mesh to Curve` and `Curve to Mesh` (Cuts = 20)
- Deform using `Set Position`
- `Spline Parameter` - `Factor` into `Float Curve` into `Combine XYZ` - `Z` into `Offset`
- float curve points: `[[0,0], [0.5, 0.25], [1, 0]]`
- `Scale` the offset vector by `-0.5`
- turn each edge into its own curve (`Duplicate Elements` - Edge)
- use a random selection (`Random Value` - Boolean, Probability = 0.5)
- `Scale` the sagging offset vector by `Spline Length`
- assign different materials to main and wires geometry
- join with main mesh (`Geometry to Instance`)
</details>
### II. Spaceship Zoo

<details>
- create `Grid`
- generate spaceship for each point of the grid
- add `For Each Element` zone
- connect grid to zone input
- add spaceship generator node-group in zone and connect to group geometry input and zone geometry ouput
- connect zone index to seed
- move each to its grid point position
- convert `Geometry to Instance`
- `Transform Geometry` of instance
- add `Position` to zone inputs
- use position of the point inside the zone for the translation
- make seed dependant on modifier input
- add `Hash Value` node to zone `Index`
- expose `Seed` input to group inputs
- name each spaceship geometry by its used seed
- convert hashed `Value to String`
- `Set Geometry Name` from that string
- `Join Strings` with new `String` ('Spaceship ')
- store used seed as attribute
- pass hash result as attribute on zone output geometry
- set attribute domain to `Instance` in zone node properties
- add `Store Named Attribute` (Integer, Instance) outside of zone
- connect hash attribute to value
- give attribute name 'seed'
</details>
### III. Spaceship Swarm

#### 0. Starting Curve

<details>
- create curve
- set cyclic
- set resolution to `64`
</details>
#### 1. Create Points

<details>
- `Points` node
- expose `Count`
- randomize `Set ID`
- `Index` into `Hash Value`
- `Sample Curve` for random position per point
- `Random Value` into `Factor`
- `Position` into `Points` `Position`
- expose `Seed`
</details>
#### 2. Instancing

<details>
- get input instances
- `Object Info` of spaceship object
- extract individual spaceship instances
- `Separate Components` - `Instances`
- reset instance positions
- `Set Position` to `Vector` [0,0,0]
- `Instance on Points` - `Pick Instances` = `True`
- `Align Rotation to Vector` - `Y` into `Rotation`
- use sampled curve `Tangent` as alignment `Vector` (for now)
</details>
#### 3. Basic Simulation Setup

<details>
- add `Simulation` zone
- add `Set Position` node
- add `Velocity` vector to simulation
- `Scale` velocity by `Delta Time` and use as `Offset`
- accelerate every frame with constant force
- `Add` to velocity and pass it to the simulation output
- `Scale` constant `Vector` by `Delta Time` and plug into `Add`
</details>
#### 4. Curve Sampling

<details>
- `Sample Index` - `Vector` on curve
- `Curve to Points` - `Evaluated`
- `Sample Nearest` as `Index` for `Sample Index`
- `Tangent` as `Value` input
- duplicate to sample `Position` as well
</details>
#### 5. Speed Alignment

<details>
- `Scale` sampled curve tangent randomly
- `Random Value` between `20` and `50` as different target speed per point
- `Mix` (`Factor` = `.1`) into `Velocity` to align to target speed along curve
</details>
#### 6. Curve Attraction

<details>
- `Subtract` `Position` from Nearest Curve Position
- `Scale` by its `Length` to the `Power` of `2`
- use result as acceleration force
</details>
#### 7. Evade Neighbors

<details>
- duplicate 'Curve Attraction' setup
- instead of nearest curve tangent, use `Evaluate at Index` of `Position` at `Index of Nearest`
- invert strength falloff
- `Divide` `25` by (existing) `Length`
- `Add` result to total forces
</details>
#### 8. Clamping

<details>
- `Normalize` total force vector
- `Scale` by its `Length` clamped by `Smooth Minimum` with `100`
</details>