# A Painting Made of Light

Kochu Studio optical experiment EX03, from Iana Kochu’s *The Listener*. The study uses a clear simulated plate to concentrate uniform white light into the painting’s central curl.

## Scene

A 2 × 2 directional area emitter at world Y = +5 sends parallel rays along −Y. The dielectric plate has index of refraction 1.50 in air, a square entrance face at Y = +0.18, and a nominal exit face at Y = 0. The outer vertices stay on the exit plane to meet the four flat side walls. Positive height displaces the exit downstream. The solved height ranges from −0.049394 to +0.034077 scene units. The receiver is a unit-reflectance diffuse plane at Y = −7. The camera faces it straight on and sees a centered square of width 2.08 scene units. All positions and the 49 probe paths per plate state come from this same geometry.

The target is a hand-traced and smoothed outline derived from the [original painting photo](../../assets/the-listener.jpg). It keeps the wide blue curl, treats the orange interior as a dark opening, and drops the background, other shapes and signature. The target is used in the loss and the renderer receives only the light source, surfaces, and camera. The flat control has the same lamp, plate entrance, sides, and camera. The receiver has a uniform white material for both traces.

## Method and fit

Adapted from the [official Mitsuba caustics optimization notebook](https://mitsuba.readthedocs.io/en/latest/src/inverse_rendering/caustics_optimization.html). Mitsuba 3.9.1 and Dr.Jit 1.5.0 ran on the `metal_ad_mono` backend on macOS arm64. The `ptracer` integrator follows light from the emitter through the two interfaces. The training loop used 320 Adam updates, 32 samples per pixel per forward and gradient pass for the first three quarters and 64 for the last quarter. The latent height grid grew from 12² to 24² to 48² at steps 80 and 192. The resulting 65 × 65 vertex mesh has interpolated shading normals. Validation rendered a new seed at 1,024 spp for both plate states.

| Measurement | Flat | Optimized |
| --- | ---: | ---: |
| Pearson pixel correlation to target | 0.193 | 0.990 |
| Root mean squared error after mean normalization | 0.971 | 0.142 |
| Intersection over union of bright pixels | 0% | 95.8% |
| Mean linear receiver value | 0.2170 | 0.1522 |

RMSE compares each image and target after dividing by its own mean. IoU compares the receiver region above 1.35 times its mean to the target region above 0.57 on the target’s 0.14–1 scale. Optimized mean in the crop is 70.2% of the flat result. The PNGs use one exposure and sRGB encoding. The target’s display mean is set to the flat plate’s mean before encoding. `data.npz` keeps the native linear arrays for separate analysis.

This is a geometric optics simulation with an ideal directional source and dielectric interfaces. The scene suppresses reflected paths, retains Fresnel transmission weighting, and omits scattering, absorption, dispersion and source divergence. Mesh shading normals interpolate across the triangles. Physical fabrication, alignment and finish could change the pattern. `concept.png` is a separate generated illustration of an imagined installation using the painting photo as a reference.

## Reproduce

From this directory, with `uv` and Python 3.13 available:

```sh
scratch=$(mktemp -d "${TMPDIR:-/tmp}/kochu-caustic.XXXXXX")
uv venv --python 3.13 "$scratch/venv"
uv pip install --python "$scratch/venv/bin/python" mitsuba==3.9.1 drjit==1.5.0 numpy==2.5.4 pillow==13.0.0
"$scratch/venv/bin/python" solve.py --output "$scratch/run"
```

Metal is the verified backend. The CLI accepts `--variant llvm_ad_mono` for machines with a Dr.Jit-compatible LLVM library. The LLVM backend was unavailable on the verification host. An independent Metal replay reached 0.990 correlation, 0.143 normalized RMSE and 96.3% IoU. Replays can vary slightly. The browser study reads only local assets and uses Canvas to display the traced ray probes and the mesh. Serve the Kochu Studio prototype root over HTTP and visit `/light-experiments/painting-made-of-light/`.

- [Target](target.png), [flat receiver](flat.png), [optimized receiver](optimized.png), [heightmap](heightmap.png), and [cover](cover.png).
- [Entrance and sides OBJ](plate-entrance.obj), [flat exit PLY](plate-flat.ply), and [optimized exit PLY](plate-exit.ply). Use the entrance and sides with either exit mesh.
- [Raw linear images and height field](data.npz), [browser geometry and ray probes](surface.json), and [exact run parameters and metrics](results.json).
