Caustics

  • Caustics
    Caustics
  • Sandbox Caustics
    Sandbox Caustics

Caustics are swirls of light that appear when light passes through transmissive surfaces. This component uses a raymarching technique to project caustics onto a catcher plane. It is based on github/N8python/caustics.

type CausticsProps = JSX.IntrinsicElements['group'] & {
  /** How many frames it will render, set it to Infinity for runtime, default: 1 */
  frames?: number
  /** Enables visual cues to help you stage your scene, default: false */
  debug?: boolean
  /** Will display caustics only and skip the models, default: false */
  causticsOnly: boolean
  /** Will include back faces and enable the backsideIOR prop, default: false */
  backside: boolean
  /** The IOR refraction index, default: 1.1 */
  ior?: number
  /** The IOR refraction index for back faces (only available when backside is enabled), default: 1.1 */
  backsideIOR?: number
  /** The texel size, default: 0.3125 */
  worldRadius?: number
  /** Intensity of the prjected caustics, default: 0.05 */
  intensity?: number
  /** Caustics color, default: white */
  color?: ReactThreeFiber.Color
  /** Buffer resolution, default: 2048 */
  resolution?: number
  /** Camera position, it will point towards the contents bounds center, default: [5, 5, 5] */
  lightSource?: [x: number, y: number, z: number] | React.MutableRefObject<THREE.Object3D>
}

It will create a transparent plane that blends the caustics of the objects it receives into your scene. It will only render once and not take resources any longer!

Make sure to use the debug flag to help you stage your contents. Like ContactShadows and AccumulativeShadows the plane faces Y up. It is recommended to use leva to configue the props above as some can be micro fractional depending on the models (intensity, worldRadius, ior and backsideIOR especially).

<Caustics debug backside lightSource={[2.5, 5, -2.5]}>
  <Bottle />
  <WineGlass>
</Caustics>

Sometimes you want to combine caustics for even better visuals, or if you want to emulate multiple lightsources. Use the causticsOnly flag in such cases and it will use the model inside only for calculations. Since all loaders in Fiber should be cached there is no expense or memory overhead doing this.

<Caustics backside lightSource={[2.5, 5, -2.5]} >
  <WineGlass />
</Caustics>
<Caustics causticsOnly backside lightSource={[-2.5, 5, 2.5]} ior={0.79} worldRadius={0.0124}>
  <WineGlass />
</Caustics>

The light source can either be defined by prop or by reference. Use the latter if you want to control the light source, for instance in order to move or animate it. Runtime caustics with frames set to Infinity, a low resolution and no backside can be feasible.

const lightSource = useRef()

<Caustics frames={Infinity} resolution={256} lightSource={lightSource} >
  <WineGlass />
</Caustics>
<object3d ref={lightSource} position={[2.5, 5, -2.5]} />