RaymarchedSculpt
The scoped block form. Inside smoothUnion(k:) { … }, bare mesh calls (drawSphere, drawCapsule, drawCone, …) are captured as fields and melt into one traced surface.
- Run
swift run --package-path Examples Example-3D-Raymarching-RaymarchedSculpt- Source
- Examples/3D/Raymarching/RaymarchedSculpt/Sketch.swift
import Ollin
import Foundation
// The scoped block form of the 3D SDF combinators: inside `smoothUnion(k:) { … }` the bare
// mesh primitives (`drawSphere`, `drawCapsule`, `drawCone`, …) are captured as fields and
// melted into one sphere-traced surface instead of drawn as separate solids. Each call's
// own `fill` becomes that lobe's color, so they blend across the seams. The transform stack
// works inside the block (a primitive drawn under `translate`/`rotate` lands there in the
// merged field), so this is a little blob creature posed with `withState`.
@main
final class RaymarchedSculpt: Sketch {
override func draw() {
raymarchResolution(0.35) // a heavier sculpted field, so traced below the default half-res
background(Color(hex: 0x101418))
let t = time
cameraShowcase(.turntable(period: .tau / 0.4), target: Vector3(0, 0.2, 0), radius: 6.0,
elevation: 0.25, fieldOfView: .pi / 4, near: 0.1, far: 40)
directionalLight(.white, direction: Vector3(-0.5, 0.8, 0.4),
intensity: 1.2, softness: 0.3)
ambientLight(Color(white: 0.18))
material(.jade)
let wobble = sin(t * 2) * 0.12
// Everything inside melts together: body + head + two arms + a hat, each posed with
// the transform stack, each its own color blending at the smooth-union seams.
smoothUnion(k: 0.35) {
fill(Color(hex: 0x3ad6c5))
withState { translate(0, -0.6, 0); drawSphere(radius: 0.95) } // body
withState { translate(0, 0.7, 0); drawSphere(radius: 0.62) } // head
fill(Color(hex: 0xffb84d))
withState {
translate(-0.9, -0.4, 0); rotateZ(0.6 + wobble)
drawCapsule(radius: 0.16, height: 0.7) // left arm
}
withState {
translate(0.9, -0.4, 0); rotateZ(-0.6 - wobble)
drawCapsule(radius: 0.16, height: 0.7) // right arm
}
fill(Color(hex: 0xff5d73))
withState { translate(0, 1.5, 0); drawCone(radius: 0.45, height: 0.7) } // hat
}
}
}