01 / Physical simulation Research in progress

WaveGratingA research rendererfor iridescent colors in Blender.

A CD, a banknote hologram, and a holographic Pokémon card show iridescent colors, which change as you tilt them. Cycles, the renderer in the free 3D program Blender, treats light as rays and can't compute these colors. I'm building WaveGrating, a research renderer that treats light as waves, to compute them. The code stays private while the research is in progress.

Role
Project lead
Built
September 2026 to now
Software
Python, PyTorch, CUDA, Blender
Runs on
Windows 11 with an RTX 3090 graphics card
A CD as it tiltsGrating equation
A CD under a lamp, tilted 40 degrees. Two bands of color run along its radius on opposite sides of the center, and their colors depend on the tilt.
An illustration computed with the grating equation for tracks 1.6 µm apart, orders one to three.

A CD's colors come from light waves adding up, which ray renderers don't compute.

A CD, up closeGrating equation
Why a CD shows a rainbowWhite light reaches a CD's tracks at 50 degrees, and most of it reflects like a mirror. The tracks are 1.6 micrometers apart. At that spacing, each wavelength leaves the first diffraction order at its own angle, from red at 19 degrees to violet at 31 degrees. An eye at 29 degrees sees blue light at 450 nanometers. At 25 degrees, it sees green at 549 nanometers, and at 21 degrees, red at 652 nanometers. The colored band on the disc moves with the eye. A renderer that treats light as rays computes only the mirror reflection, so it shows no rainbow. Computed with the grating equation for the positions drawn. EYE SEES450 nm549 nm652 nmNO COLOR WHITE LIGHT50°MIRRORREFLECTIONFIRST ORDERCD TRACKS, 1.6 µm APARTSPOT

WaveGrating is built to compute these colors by treating light as waves.

Drawn for this page with the grating equation, with the tracks enlarged and first order only.

Why rays miss these colors, in technical terms

Path tracers such as Cycles treat light as rays that carry brightness. That works for most scenes. A path tracer can't compute the colors of a CD, a banknote hologram, a holographic card, or a Morpho butterfly's wing. Those colors come from interference: waves add with their phase before anything becomes bright.

A grating shader can imitate the look. WaveGrating tries to compute the colors and to state how accurate the result is. The drawing labels each color with its wavelength in nanometers (nm): blue at 450 nm, green at 549 nm, and red at 652 nm.

Wave optics / interference
Coherent waves form an interference patternTwo slits emit wavefronts with the same phase. The detector brightness follows the difference in path length from the two slits. This simplified concept diagram was drawn for this page. LIGHT2 SLITSINTENSITYCOHERENT INPUTINTERFERENCE

Concept diagram.

The physics runs in a separate program, outside Blender.

How a scene travels from Blender to resultsSimplified

Blender only describes the scene, and every physics step runs in the worker.

The numerical core, in technical terms

Blender is only the authoring tool. The scene leaves Blender as a strict, versioned file in SI units, and unknown keys are rejected. An isolated Python worker runs the numerical core, so no physics runs inside Blender's own Python.

The worker has a NumPy reference core that uses double-precision complex numbers. GPU operators use PyTorch and CUDA, and TORCWA handles periodic structures such as gratings. pySCATMECH and Meep give independent checks. A written physics contract sets the units and phase conventions, and it fixes the order of operations. The worker saves raw results apart from the preview.

Five design choices keep every result measured and every change reviewed.

What each design choice doesFive choices

Every result is measured against a reference. Every change comes with its evidence, and nothing merges automatically.

How each choice works, in technical terms

Measure only after adding fields. Coherent paths are combined as complex fields before any power is measured, so the power is |a₁ + a₂|². The cross term makes the fringes and the colors. A test guards this order. Light that is mutually incoherent is added as power, and only after each part travels on its own.

Compare speed only at matched error. A faster route counts only when it reaches the same measurement error as the accurate reference, which always stays in the code. GPU work and caches need measured evidence before they are added.

Pass on measured error alone. A run passes only on its measured error. Phase fitting, energy normalization, clipping signed data, and threshold changes never count toward a pass, and every run stays in the record.

Put AI models under written contracts. One AI model leads the numerical design and review. Other agents, including a local model on my DGX Spark, get bounded work packages. Each package lists the files the agent may change and the checks it must pass. Every change is a pull request that cites its specification and evidence, and nothing merges automatically.

Keep Blender's Python out of the physics. Only a standard-library schema crosses into the worker. Exact decimal strings are the authority, and a float copy in Blender is for display only.

Independent references agree with WaveGrating.

Checks and measurements on an RTX 3090Measured

Tests and speed

  • 23regression checks, all passing
  • 2.2–⁠4.5×faster at the same error1024 × 1024 grid
  • 3.9–⁠7.7×faster at the same error2048 × 2048 grid

Difference from two independent references

  • SCATMECH2.6 × 10−11
  • Rayleigh–Sommerfeld9.1 × 10−5 to 1.6 × 10−3

Smaller means closer agreement. Each labeled step on the scale is 1,000 times larger than the one before it.

All 23 checks pass, the fast methods match the reference's error, and two independent methods agree.

Measurement details, in technical terms

The regression suite of 23 checks passes. The speed tests ran on an RTX 3090. At matched measurement error, the windowed GPU routes ran 2.2 to 4.5 times faster than the full-grid reference on a 1024 × 1024 grid. On a 2048 × 2048 grid, they ran 3.9 to 7.7 times faster. An independent Rayleigh–Sommerfeld reference agrees at the detector to within 9.1 × 10⁻⁵ to 1.6 × 10⁻³.

The test grating is one-dimensional, with 200 Fourier harmonics on each side of zero. On it, WaveGrating and an independent SCATMECH reference agree to 2.6 × 10⁻¹¹. The reflected powers are stable to 6 × 10⁻⁸.

The roadmap leads to complete renders in Blender.

  • An independent finite-element check of the light field at a repeating surface.
  • Light that arrives at an angle to the grooves, called conical incidence, and patterns that repeat in two directions.
  • Complete renders of CDs, banknote holograms, and holographic cards.
  • WaveGrating objects inside ordinary Cycles scenes.

Contact

Get in touch.

I'm open to full-time AI product engineering roles.

Email hello@shayanbianconi.com or see more of my work on GitHub.

Email me