PathTraceGlassDemo.kt
src/jvmMain/kotlin/afield/graphics/scene/fabricated/PathTraceGlassDemo.kt · 66 lines
package afield.graphics.scene.fabricated
import afield.graphics.vulkan.Renderer
import afield.graphics.vulkan.util.Camera
import afield.math.linalg.Vector3f
All four of the path tracer's glass materials in one scene: clear, absorbing, frosted, and a thin pane.
public/docs/path_tracing.md prints this scene as its glass figure and
dev_docs/agents/transcripts/path_tracing_glass.yaml launches it, so what the file builds is
what those two are written about. Left to right: a sphere of PathTraceMaterial.glass(), one
given an attenuationColor, one given a roughness of 0.32, and a quad of thinGlass.
Most of the geometry here is background, since what a transparent material shows is mostly
whatever is behind it. The floor is a checkerboard of 0.55-unit tiles and the wall behind the
spheres is eighteen horizontal stripes, both built from the same two diffuse greys, one ten times
the reflectance of the other. Each material moves that pattern its own way: refraction displaces
the stripes, absorption tints them by how far the ray travelled inside the solid, roughness
scatters them, and the thin pane leaves their positions where they are, because thinGlass
transmits per crossing and has no thickness to refract across.
The returned renderer is set to ten bounces rather than the default five, because a ray that
enters and leaves a sphere has spent two of them before reaching anything else, and to an
exposure of 1.5 for a floor this dark. With no environmentPath the light is a constant white
environment of radiance one; a path is read by PathTraceEnvironment.fromFile, which takes EXR,
Radiance and ordinary image files.
object PathTraceGlassDemo
Clear glass, absorbing green glass, frosted glass and a thin blue pane, from left to right.
object PathTraceGlassDemo {
fun install(renderer: Renderer, environmentPath: String? = null, width: Int = 640, height: Int = 360): PathTracingRenderer
Builds the scene, points a camera at it and installs a PathTracingRenderer under
renderer, returning it so a box can blitToScreen or reconfigure it.
fun install(renderer: Renderer, environmentPath: String? = null, width: Int = 640, height: Int = 360): PathTracingRenderer {
val scene=PathTraceScene()
val dark=scene.material(PathTraceMaterial.diffuse(0.055f,0.055f,0.055f))
val light=scene.material(PathTraceMaterial.diffuse(0.55f,0.55f,0.55f))
for (x in -10 until 10) for (z in -6 until 8) {
val a=x*0.55f; val b=z*0.55f; val m=if ((x+z) and 1 == 0) light else dark
scene.quad(Vector3f(a,0f,b),Vector3f(a,0f,b+0.55f),Vector3f(a+0.55f,0f,b+0.55f),Vector3f(a+0.55f,0f,b),m)
}
// Narrow stripes reveal refraction and frosting against a common background.
for (i in 0 until 18) {
val y=i*0.18f
scene.quad(Vector3f(-6f,y,-2.5f),Vector3f(6f,y,-2.5f),Vector3f(6f,y+0.18f,-2.5f),
Vector3f(-6f,y+0.18f,-2.5f),if (i and 1 == 0) light else dark)
}
val clear=scene.material(PathTraceMaterial.glass())
val green=scene.material(PathTraceMaterial.glass(attenuationColor=Vector3f(0.45f,0.9f,0.65f)))
val frosted=scene.material(PathTraceMaterial.glass(roughness=0.32f))
val sheet=scene.material(PathTraceMaterial.thinGlass(tint=Vector3f(0.65f,0.85f,1f)))
scene.sphere(Vector3f(-2.7f,0.8f,0f),0.8f,clear,48,24)
scene.sphere(Vector3f(-0.9f,0.8f,0f),0.8f,green,48,24)
scene.sphere(Vector3f(0.9f,0.8f,0f),0.8f,frosted,48,24)
scene.quad(Vector3f(2f,0.05f,0.1f),Vector3f(3.4f,0.05f,0.1f),Vector3f(3.4f,1.7f,0.1f),Vector3f(2f,1.7f,0.1f),sheet)
val camera=Camera(renderer).also { it.at.set(0f,2.7f,9.5f); it.target.set(0f,0.8f,0f); it.p.fov=0.52 }
return PathTracingRenderer(renderer,scene,environmentPath?.let(PathTraceEnvironment::fromFile)
?: PathTraceEnvironment.constant(),width,height,camera).also {
it.maxBounces=10; it.exposure=1.5f; it.install()
}
}
}