Add mdbook

This commit is contained in:
Carson Katri 2022-11-15 12:59:28 -05:00
commit 146e83f8ae
56 changed files with 817 additions and 9 deletions

View file

@ -0,0 +1,119 @@
# City Builder
In this tutorial we'll create a dense grid of buildings, then cut away from them to place roads with curves. We'll also make use of a [generator](../api/advanced-scripting/generators.md) to combine the buildings with the roads.
![](./city_builder.gif)
## Setting Up
Create a Bezier Curve object. You can enter edit mode and delete the default curve it creates.
Then create a new script. Setting up an [external editor](../setup/external-editing.md) is recommended.
Import Geometry Script, and create a basic tree builder function. We'll add a few arguments to configure the buildings.
```python
from geometry_script import *
@tree("City Builder")
def city_builder(
geometry: Geometry,
seed: Int,
road_width: Float = 0.25,
size_x: Float = 5, size_y: Float = 5, density: Float = 10,
building_size_min: Vector = (0.1, 0.1, 0.2),
building_size_max: Vector = (0.3, 0.3, 1),
):
return geometry
```
Run the script to create the tree, then add a *Geometry Nodes* modifier to your curve object and select the *City Builger* node group.
## Buildings
Let's start with the buildings. We'll distribute points on a grid with `size_x` and `size_y`.
```python
def city_builder(...):
building_points = grid(size_x=size_x, size_y=size_y).distribute_points_on_faces(density=density, seed=seed).points
return building_points
```
Next, we'll instance cubes on these points to serve as our buildings. We move the cube object up half its height so the buildings sit flat on the grid, and scale them randomly between the min and max sizes.
```python
def city_builder(...):
...
return building_points.instance_on_points(
instance=cube().transform(translation=(0, 0, 0.5)),
scale=random_value(data_type='FLOAT_VECTOR', min=building_size_min, max=building_size_max, seed=seed),
)
```
## Roads
Using `curve_to_mesh`, we can turn the input curve into a flat mesh. We'll use the `yield` keyword to join the curve mesh and the building mesh automatically. Change the `building_points.instance_on_points` line to use `yield` for this to work.
```python
def city_builder(...):
yield geometry.curve_to_mesh(profile_curve=curve_line(
start=combine_xyz(x=road_width * -0.5),
end=combine_xyz(x=road_width * 0.5)
))
...
yield building_points.instance_on_points(...)
```
But now the buildings are overlapping the road. We need to remove any point that falls within the road curve. We'll use `geometry_proximity` and `delete_geometry` to find and remove these invalid points.
```python
def city_builder(...):
...
building_points = ...
road_points = geometry.curve_to_points(mode='EVALUATED').points
building_points = building_points.delete_geometry(
domain='POINT',
selection=geometry_proximity(target_element='POINTS', target=road_points, source_position=position()).distance < road_width
)
...
```
## Drawing Roads
Enter edit mode and select the *Draw* tool. Simply draw roads onto your city to see the buildings and meshes update.
![](./city_builder.gif)
## Final Script
```python
from geometry_script import *
@tree("City Builder")
def city_builder(
geometry: Geometry,
seed: Int,
road_width: Float = 0.25,
size_x: Float = 5, size_y: Float = 5, density: Float = 10,
building_size_min: Vector = (0.1, 0.1, 0.2),
building_size_max: Vector = (0.3, 0.3, 1),
):
# Road mesh
yield geometry.curve_to_mesh(profile_curve=curve_line(
start=combine_xyz(x=road_width * -0.5),
end=combine_xyz(x=road_width * 0.5)
))
# Building points
building_points = grid(size_x=size_x, size_y=size_y).distribute_points_on_faces(density=density, seed=seed).points
road_points = geometry.curve_to_points(mode='EVALUATED').points
# Delete points within the curve
building_points = building_points.delete_geometry(
domain='POINT',
selection=geometry_proximity(target_element='POINTS', target=road_points, source_position=position()).distance < road_width
)
# Building instances
yield building_points.instance_on_points(
instance=cube().transform(translation=(0, 0, 0.5)),
scale=random_value(data_type='FLOAT_VECTOR', min=building_size_min, max=building_size_max, seed=seed),
)
```
## Generated Node Tree
![](./city_builder_nodes.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

View file

@ -0,0 +1,109 @@
# Voxelize
This tutorial walks you through creating a script that turns any mesh into voxels.
> This tutorial requires Blender 3.4+ for the *Distribute Points In Volume* node.
## Setting Up
Create a base mesh. I'll be using a Monkey primitive.
![](./monkey.png)
Next, create a new script. Setting up an [external editor](../setup/external-editing.md) is recommended.
Import Geometry Script, and create a basic tree builder function. We'll add a `geometry` argument and annotate it with the `Geometry` type to receive our base mesh (in this case, a monkey).
```python
from geometry_script import *
@tree("Voxelize")
def voxelize(geometry: Geometry):
return geometry
```
Run the script to create the tree, then add a *Geometry Nodes* modifier to your mesh and select the *Voxelize* node group.
![](./voxelize_modifier.png)
## Arguments
Add a new argument `resolution: Float`. Give it a default value of `0.2`. This value will be used throughout the script to configure spacing and voxel density.
```python
def voxelize(geometry: Geometry, resolution: Float = 0.2):
...
```
## Mesh to Volume
We want to convert the mesh to a hollow volume, so only the outside of the mesh has voxel instances. This will improve the performance of our script.
Use the `mesh_to_volume` function on the base mesh to convert it to a volume.
```python
def voxelize(geometry: Geometry, resolution: Float = 0.2):
return geometry.mesh_to_volume( # Hollow mesh volume
interior_band_width=resolution,
fill_volume=False
)
```
![](./monkey_volume.png)
## Volume to Points
Next, we need to create points to instance each voxel cube on. Use `distribute_points_in_volume` with the mode set to `DENSITY_GRID` to create a uniform distribution of points.
```python
def voxelize(geometry: Geometry, resolution: Float = 0.2):
return geometry.mesh_to_volume(
interior_band_width=resolution,
fill_volume=False
).distribute_points_in_volume( # Uniform grid distribution
mode='DENSITY_GRID',
spacing=resolution
)
```
![](./monkey_points.png)
## Instance Cubes
Finally, use `instance_on_points` with a cube of size `resolution` to instance a cube on each point created from our mesh.
```python
def voxelize(geometry: Geometry, resolution: Float = 0.2):
return geometry.mesh_to_volume(
interior_band_width=resolution,
fill_volume=False
).distribute_points_in_volume(
mode='DENSITY_GRID',
spacing=resolution
).instance_on_points( # Cube instancing
instance=cube(size=resolution)
)
```
![](./monkey_voxels.png)
You can lower the resolution to get smaller, more detailed voxels, or raise it to get larger voxels.
## Final Script
```python
# NOTE: This example requires Blender 3.4+
from geometry_script import *
@tree("Voxelize")
def voxelize(geometry: Geometry, resolution: Float = 0.2):
return geometry.mesh_to_volume(
interior_band_width=resolution,
fill_volume=False
).distribute_points_in_volume(
mode='DENSITY_GRID',
spacing=resolution
).instance_on_points(
instance=cube(size=resolution)
)
```
## Generated Node Tree
![](./voxelize_nodes.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB