Liquid glass logo

               
by
Published Aug 31, 2026 at 22:45
Open In Editor


Real-time refractive glass, aiming to match a Blender/Cycles render of the same scene rather than approximate it. It's the hero of benedettimartin.com.

How it works

The mesh is a closed GLTF solid (13,076 tris, consistent winding, two separate bodies). Everything else happens in one CustomShader_v2.

Layer peeling instead of a cubemap fake. Four float render targets hold the distance to each successive surface along the view ray, at canvas x 2 (the bmescalaw / bmescalah multiply ops set that factor). The fragment shader refracts at the front face, then marches ~28 steps through those layers to find where the ray actually leaves the glass, applies Snell at each interface, and does that for up to 3 bounces. Total internal reflection is handled per bounce.

Dispersion is six wavelengths, not an RGB offset - the refraction IOR is 1.40 / 1.45 / 1.50, and the dispersion port scales the spread. Fresnel uses the Glass BSDF's 1.7. Roughness 0.008. Absorption is 0, because the source .blend doesn't absorb.

Lighting is an EXR environment through PbrEnvironmentLight plus an equirect-to-cubemap skybox, and one analytic area light that can follow the camera. Output goes through an AgX Medium High Contrast tonemap to match Blender's view transform.

Adaptive supersampling lives inside the shader. main() calls the shading function with sub-pixel offsets built from dFdx/dFdy of the interpolated attributes - exact for flat faces, and this logo is all flat faces. Samples are averaged after the tonemap, which is what actually makes a 2x render look better. It takes two samples at opposite corners first and pays for the other two only where those two disagree by more than aaUmbral: about 9% of the logo edge-on, under 1% from inside, and indistinguishable from always paying four.

debugView exposes ~23 diagnostic views - path length, how many planes the march found, TIR, the edge-darkening mask and its terms, raw bounce count, surface curvature. At 0 the shader is the production one, bit for bit.

What got solved along the way

  • The "grain" was aliasing, not broken reconstruction. The test that settled it: render at 2560x1600 and downscale - the detail survives, the grain doesn't. Nothing was broken; it was undersampled.
  • Two artifacts, two different levers. Speckle on the edges is shading aliasing and needs samples per pixel. The comb pattern in the internal veins is the march alternating between 2 and 3 planes texel by texel, and needs layer resolution. That matters for framerate, because the expensive lever is not the one that fixed the thing that bothered us most: at 2x layers the comb is gone with a single sample.
  • Work that was computed and thrown away, now removed: the normal read four layers and used two; the environment was sampled every pixel - atan, acos, fetch and pow, six times - even when mixed at weight zero; an absorption exponential was evaluated with absorption at zero.

What's missing

  • Filaments. Thin, almost dotted dark lines cross the glass faces diagonally, following no edge of the geometry, visible from above. They predate everything above - not dispersion, not the supersampling, not the 2x layers - and only became noticeable once the rest got clean. Suspect is the march or the peeling, not the sampling.
  • Performance. ~21 fps with the camera inside the glass at 1920 on the previous revision, four samples always; the adaptive version halves the shading there but hasn't been measured live yet. The big unused lever is packing the four layer distances into one RGBA texture - right now every march step reads between 2 and 4 textures just to ask "am I inside?", and the march dominates the frame.
  • Memory. Four RGBA32F at 2x canvas is 250 MB at 1280x800 and 507 MB at 1920x1080. It grows with the square of the scale and with the screen, so it needs a resolution-dependent cap. 1.5x isn't enough and 16-bit is noisier.
  • The blacks are faked. edgeDark darkens grazing angles by hand. In Cycles that black is real - the refracted image of the room. The right fix is to delete the term and let the geometry produce it.
  • The cloud plane from the .blend isn't in the patch yet. It's the largest remaining difference against the reference, mostly in saturation.

Ask for full access if you want to open it up and poke at it.

Licence: All Rights Reserved

The author retains all the copyright on this work, please contact the author before using or remixing this work.
 



More patches made by cables users





what is cables?


Cables is a tool for creating beautiful interactive content. With an easy to navigate interface and real time visuals, it allows for rapid prototyping and fast adjustments.

cables is free to use!

Register