RaymarchedEnvironment
Raymarched fields lit by an environment. They get the same image-based lighting and traced reflections the meshes get.
- Run
swift run --package-path Examples Example-3D-Raymarching-RaymarchedEnvironment- Source
- Examples/3D/Raymarching/RaymarchedEnvironment/Sketch.swift
import Ollin
import Foundation
/// Raymarched fields lit by an environment: the same image-based lighting the meshes get.
///
/// `environment(_:)` alone lights the scene, and the sphere-traced fields take their
/// ambient from it exactly as the rasterized meshes do. A physically-based field gathers
/// the split-sum ambient (the polished-metal melt reflects the sky) while the stylized
/// materials take the diffuse irradiance. The mesh spheres beside each field carry the
/// same material, so field and mesh read as one consistently lit scene.
@main
final class RaymarchedEnvironment: Sketch {
override func draw() {
background(Color(hex: 0x0B0C12))
toneMap(.aces)
cameraShowcase(.turntable(period: .tau / 0.22), target: Vector3(0, 0.1, 0), radius: 9.5,
elevation: 0.16, fieldOfView: .pi / 4.2)
// The environment is the only light, drifting so the reflections move across
// the metal and the irradiance shifts on the matte forms.
environment(.sunset.rotated(time * 0.08))
let t = time
// A polished-metal melt: the split-sum ambient fills it with the sky's reflection.
withState {
material(.polishedMetal)
fill(Color(white: 0.95))
let melt = SDF3D.torus(radius: 1.15, tube: 0.42)
.smoothUnion(.sphere(radius: 0.62).at(0, sin(t * 0.9) * 0.9, 0), k: 0.55)
drawSDF3D(melt.rotatedX(0.5 * .pi).at(-2.4, 0.4, 0))
}
// A matte melt in the standard material: the diffuse irradiance is its ambient,
// so its two colors stay warm under the sunset instead of going black.
withState {
material(.matte)
let melt = SDF3D.sphere(radius: 0.95).colored(Color(hex: 0x3ad6c5))
.smoothUnion(.octahedron(radius: 1.05)
.at(0.9, 0.75 + sin(t * 1.3) * 0.25, 0)
.colored(Color(hex: 0xffb84d)), k: 0.6)
drawSDF3D(melt.at(2.2, 0.2, 0))
}
// Mesh parity: the same two materials on rasterized spheres, sharing the frame
// with the fields under the one environment.
withState {
translate(-0.1, -1.4, 1.6)
material(.polishedMetal)
fill(Color(white: 0.95))
drawSphere(radius: 0.55)
}
withState {
translate(1.0, -1.5, 1.9)
material(.matte)
fill(Color(hex: 0x3ad6c5))
drawSphere(radius: 0.45)
}
}
}