Comapring the API

How does the API compare to other existing solutions?

geonodes

‘Hello World’

The hello world example from geonodes readme: https://github.com/al1brn/geonodes

from nodebpy import geometry as g

with g.tree("Hello World") as tree:
    height = tree.inputs.float("Height", 3.0)
    omega = tree.inputs.float("Omega", 2.0)

    with g.Frame("Computing the wave"):
        pos = g.Position().o.position
        distance = g.Math.square_root(pos.x**2 + pos.y**2)
        z = height * g.Math.sine(distance * omega) / distance

    with g.Frame("Point offset & smooth"):
        mesh = (
            g.Grid(20, 20, 200, 200)
            >> g.SetPosition(offset=g.CombineXYZ(z=z))
            >> g.SetShadeSmooth.face()
        )

    mesh >> tree.outputs.geometry("Mesh")
from geonodes import *

with GeoNodes("Hello World"):
    height = 3
    omega  = 2

    grid = Mesh.Grid(vertices_x=200, vertices_y=200, size_x=20, size_y=20)
    with Layout("Computing the wave"):
        pos = nd.position
        distance = gnmath.sqrt(pos.x**2 + pos.y**2)
        z = height*gnmath.sin(distance*omega)/distance

    with Layout("Point offset and smoothness"):
        grid.offset = (0, 0, z)
        grid.faces.smooth = True

    grid.out()

geometry-script

README Demo

from nodebpy import geometry as g

with g.tree("Repeat Grid") as tree:
    geometry = tree.inputs.geometry("Geometry")
    width = tree.inputs.integer("Width")
    height = tree.inputs.integer("Height")

    (
        g.Grid(width, height, vertices_x=width, vertices_y=height)
        >> g.MeshToPoints()
        >> g.InstanceOnPoints(instance=geometry)
        >> tree.outputs.geometry("Instances")
    )
from geometry_script import *

@tree("Repeat Grid")
def repeat_grid(geometry: Geometry, width: Int, height: Int):
    g = grid(
        size_x=width, size_y=height,
        vertices_x=width, vertices_y=height
    ).mesh.mesh_to_points()
    return g.instance_on_points(instance=geometry)

Primitive Shapes

from nodebpy import geometry as g

with g.tree("Primitive Shapes") as tree:
    join =  g.JoinGeometry([g.Cube(), g.UVSphere(), g.Cylinder()])
    join >> tree.outputs.geometry("Result")
@tree("Primitive Shapes")
def primitive_shapes():
    yield cube()
    yield uv_sphere()
    yield cylinder().mesh

Voxelise

Example script found here.

from nodebpy import geometry as g

with g.tree("Voxelise") as tree:
    geo = tree.inputs.geometry("Geometry")
    resolution = tree.inputs.float("Resolution", 0.2)

    (
        geo
        >> g.MeshToVolume(interior_band_width=resolution)
        >> g.DistributePointsInVolume(mode="Grid", spacing=resolution)
        >> g.InstanceOnPoints(instance=g.Cube(size=resolution))
        >> tree.outputs.geometry("Result")
    )
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=DistributePointsInVolume.Mode.DENSITY_GRID,
        spacing=resolution
    ).instance_on_points(
        instance=cube(size=resolution)
    )

City Builder

Example script found here.

from nodebpy import geometry as g

with g.tree("Voxelise") as tree:
    geo = tree.inputs.geometry("Geometry")
    seed = tree.inputs.integer("Seed")
    road_width = tree.inputs.float("Road Width", 0.25)
    size_x = tree.inputs.float("Size X", 5.0)
    size_y = tree.inputs.float("Size Y", 5.0)
    density = tree.inputs.float("Density", 10.0)
    building_size_min = tree.inputs.vector("Building Size Min", (0.1, 0.1, 0.2))
    building_size_max = tree.inputs.vector("Building Size Max", (0.3, 0.3, 1.0))

    curve_mesh = geo >> g.CurveToMesh(
        profile_curve=g.CurveLine(
            start=g.CombineXYZ(x=road_width * -0.5),
            end=g.CombineXYZ(x=road_width * 0.5),
        ),
    )

    building_points = g.Grid(size_x, size_y) >> g.DistributePointsOnFaces(
        density=density, seed=seed
    )

    road_points = geo >> g.CurveToPoints(mode="EVALUATED")
    building_points = g.DeleteGeometry.point(
        building_points,
        selection=g.GeometryProximity(
            target_element="POINTS",
            target=road_points,
            source_position=g.Position().o.position,
        ).o.distance
        < road_width,
    )

    buildings = building_points >> g.InstanceOnPoints(
        instance=g.Cube() >> g.TransformGeometry(translation=(0, 0, 0.5)),
        scale=g.RandomValue.vector(
            min=building_size_min, max=building_size_max, seed=seed
        ),
    )

    g.JoinGeometry((curve_mesh, buildings)) >> tree.outputs.geometry("Result")
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=CurveToPoints.Mode.EVALUATED).points
    # Delete points within the curve
    building_points = building_points.delete_geometry(
        domain=DeleteGeometry.Domain.POINT,
        selection=geometry_proximity(
            target_element=GeometryProximity.TargetElement.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=RandomValue.DataType.FLOAT_VECTOR,
            min=building_size_min,
            max=building_size_max,
            seed=seed,
        ),
    )