move_and_scale = compose(
translate(3, 3, 0),
scale(0.5),
)
cube = box(2)
cube
| set_material('blue')
| render
cube
| move_and_scale
| set_material('red')
| render
box(8) | render;
(sphere(radius=5, resolution=4) + v3(8, 8, -4)) | render
light_pos = v3(10, 13, -10)
sphere(radius=0.5, resolution=4)
| trans(light_pos * 1.1)
| set_material('light_marker')
| render
dir_light(intensity=25, color=0xff00ff)
| trans(light_pos)
| render
0..10
-> || { sphere(radius=1.15, resolution=2) | trans(randv(-3, 3)) }
| union
| connected_components
-> |component: mesh, i: int| { component | set_material(str(i)) }
| render
// pick 50,000 random points within 1 unit of the origin
points = 0..100000000
-> || { randv(0, 1) }
| filter(|v| len(v) < 1)
| take(50000)
// Create a mesh bounded by the convex hull of all those
// points. This is the smallest convex shape that contains
// all of the points.
points
| convex_hull
| render
a = box(size=8)
b = icosphere(radius=5, resolution=5)
// subtract the space inside the sphere from the cube
core = sub(a, b)
// You can also just use `-` instead. The following is
// equivalent to the previous:
core = a - b
core | render
spiral = |count, height_factor, radius, resolution| {
0..count -> |i| {
t = i * (1. / resolution)
vec3(
sin(t) * radius,
i * height_factor,
cos(t) * radius
)
}
}
spiral(count=400, height_factor=0.1, radius=5.5, resolution=4)
| extrude_pipe(radius=0.5, resolution=8, close_ends=true)
| render
// demo of `extrude_pipe` with a dynamic radius for each
// vertex of the pipe's rings
resolution = 12
get_radius = |segment_ix: int, center: vec3| {
0..resolution
-> |i| {
if segment_ix % 12 < 6 {
if i % 2 == 0 { 2 } else { 1 }
} else {
0.5
}
}
}
0..78
-> |i| { vec3(i * 0.15, 0, 0) }
| extrude_pipe(resolution=resolution, radius=get_radius)
| simplify(tolerance=0.1)
| render
// create a path defining the outline of a circle
circle_path = 0..100 -> |i| {
t = i / 100
vec3(cos(t * pi * 2), 0, sin(t * pi * 2))
}
// fill the outline into a flat mesh
circle = fan_fill(
circle_path,
// flip the direction the triangles are facing so that
// it is visible when looking from the top down
flipped=true
)
circle | render
a = cylinder(radius=6, height=20, radial_segments=20)
b = icosphere(radius=10, resolution=5)
// only keep the area that exists inside both the sphere
// and the cylinder, kind of like cutting out the core
// of an apple
core = intersect(a, b)
// `intersect` also has a dedicated operator. The
// following is equivalent to the previous:
core = a & b
core | render
// generate a 3D matrix of cubes filling all the space
0..10 -> |y_ix| {
y = y_ix - 5
0..10 -> |x_ix| {
x = x_ix - 5
0..10 -> |z_ix| {
z = z_ix - 5
box(0.9) | trans(x, y, z)
}
}
}
| flatten
| flatten
-> |cube| {
has_hit = cube
| intersects_ray(
ray_origin=v3(-10, -10, -5),
ray_direction=vec3(1, 1, 0.5)
)
if has_hit {
return cube
}
cube
| scale(0.2)
| set_material('red')
}
| render
cubes: mesh = 0..10
-> |i| {
box(1)
| trans(0, i * 1.5, 0)
| rot(0, i * 0.2, 0)
}
| join
cubes | render
// builds a cube mesh from scratch
verts = [
v3(-1, -1, -1),
v3(1, -1, -1),
v3(1, 1, -1),
v3(-1, 1, -1),
v3(-1, -1, 1),
v3(1, -1, 1),
v3(1, 1, 1),
v3(-1, 1, 1)
]
indices = [
0, 2, 1, 0, 3, 2,
4, 5, 6, 4, 6, 7,
0, 1, 5, 0, 5, 4,
2, 3, 7, 2, 7, 6,
0, 7, 3, 0, 4, 7,
1, 2, 6, 1, 6, 5,
]
mesh(verts, indices) | render
base = torus_knot_path(
radius=12, tube_radius=7, p=3, q=4, point_count=400
)
| extrude_pipe(
radius=2, resolution=12, connect_ends=true
)
| set_material('base')
base | render
surface_points = base
| point_distribute(count=500)
-> |pos: vec3| {
icosphere(radius=0.6, resolution=1) | trans(pos)
}
surface_points | render
box(5)
| trans(5, 0, 0)
// This requires a material called "red" to have been
// defined in the material editor for the scene.
//
// This can be found in the hamburger menu next to the
// home button.
| set_material('red')
| render
icosphere(radius=3, resolution=4)
| trans(-5, 0, 0)
// same for this one
| set_material('blue')
| render
shape = box(10, 5, 10)
| union(cyl(radius=4, height=8, radial_segments=40))
pieces: seq = shape
| split_by_plane(
plane_normal=vec3(1, -1, 1),
plane_offset=0
)
pieces = pieces -> |piece: mesh, i: int| {
if i == 0 {
piece | set_material('red')
} else {
piece | set_material('blue') | trans(0, 1, 0)
}
}
render(pieces)
height_segments = 40
resolution = 100
radius = 5
// creates a sequence of contours which encode the profile
// of the shape we're building from bottom to top
contours = 0..height_segments -> |y_ix| {
0..resolution -> |i| {
t = i / resolution
// bulge the radius out, but at a different spot
// depending on how far up the shape we are
radius = radius + sin(y_ix * 0.5 + t * pi * 4) * 4
// construct a path tracing the radius of the shape
// at this height, basing it off the parametric
// equation for a circle
vec3(
cos(t * pi * 2) * radius,
y_ix * 2.25,
sin(t * pi * 2) * radius
)
}
}
// join the contours into a closed 3D mesh by connecting
// them with a strip of triangles between each one.
contours
// default options shown
| stitch_contours(closed=true, cap_ends=true)
| render
c = cyl(radius=6, height=20, radial_segments=40)
// sequence of steps deltas to talk along the surface of
// the mesh
path = 0..20 -> || v2(3, 1);
surface_points: seq = trace_geodesic_path(
path,
c,
full_path=false,
start_pos_local_space=v3(10, -8, 0)
)
// cut out a cube from the surface of the mesh at each
// step of the walk
fold(
c,
|c: mesh, pt: vec3| c - (box(2) + pt),
surface_points
) | render
// adds a red directional light to better show off the
// carved out sections
dir_light(intensity=12, color=v3(1,0.3,0.1))
| trans(40, 20, -10)
| render
box(1) | render
box(1)
| translate(0, 2, 0)
| render
// you can also use a shorthand for translating meshes
box(1) + vec3(2, 0, 0) | render
icosphere(radius=8, resolution=4)
// the position of each vertex in the mesh is set to
// whatever this function returns.
| warp(|pos: vec3, normal: vec3| {
if pos.y >= 0 {
return pos
}
// elongate and distort the bottom half of the sphere
vec3(
pos.x + sin(pos.y) * 1.5,
pos.y * 2,
pos.z + sin(pos.y) * 1.5
)
})
| render
// warp also has a dedicated shorthand operator. The
// following two statements are equivalent:
box(4) | warp(|pos| pos * 2)
box(4) -> |pos| pos * 2
lissajous_knot_path(
amp=vec3(18),
freq=vec3(3, 5, 7),
phase=vec3(0,pi/2,pi/5),
count=500
)
| extrude_pipe(radius=1,connect_ends=true, resolution=8)
| render
path = torus_knot_path(
radius=5, tube_radius=2, p=3, q=4, point_count=400
)
path
| extrude_pipe(radius=1, resolution=12,
connect_ends=true)
| simplify(tolerance=0.05)
| render
grid(size=300, divisions=300)
-> |v| {
noise = fbm(octaves=8, pos=v*0.01, lacunarity=1.8)
vec3(v.x, noise * 36, v.z)
}
| render
build_smooth_path = |smoothing: num| {
// this is essentially applying a low-pass filter
dirs = scan(
initial=normalize(randv(-1, 1)),
fn=|acc, _| {
new_dir = mix(1 - smoothing, acc, randv(-1, 1))
normalize(new_dir)
},
sequence=0..100
)
scan(
initial=vec3(0),
fn=|pos, dir| pos + dir,
sequence=dirs
)
}
smooth_path = build_smooth_path(0.75)
random_path = build_smooth_path(0)
smooth_path
| extrude_pipe(radius=0.2, resolution=8)
| set_material('red')
| render
random_path
| extrude_pipe(radius=0.2, resolution=8)
| set_material('blue')
| render