Custom effects
If you plan to use custom effects, make sure to expose the effect itself as a primitive!
r3f never disposes objects rendered via <primitive object={...}> (their state may be owned outside
React), so effects rendered this way must dispose themselves - use the useDispose hook exported by
this library for that.
import { useMemo } from 'react'
import { PixelationEffect } from 'postprocessing'
import { useDispose } from '@react-three/postprocessing'
export function Pixelation({ granularity = 5, ref }) {
const effect = useMemo(() => new PixelationEffect(granularity), [granularity])
useDispose(effect)
return <primitive ref={ref} object={effect} />
}
For effects that aren't present in postprocessing you should extend the Effect class:
import { useMemo } from 'react'
import { Uniform } from 'three'
import { Effect } from 'postprocessing'
import { useDispose } from '@react-three/postprocessing'
const fragmentShader = `some_shader_code`
// Effect implementation
class MyCustomEffectImpl extends Effect {
constructor({ param = 0.1 } = {}) {
super('MyCustomEffect', fragmentShader, {
uniforms: new Map([['param', new Uniform(param)]]),
})
}
update(renderer, inputBuffer, deltaTime) {
// read/write per-frame state on `this` (e.g. this.uniforms.get('param').value = ...),
// never on a module-level variable - that would be shared across every instance
}
}
// Effect component
export function MyCustomEffect({ param, ref }) {
const effect = useMemo(() => new MyCustomEffectImpl({ param }), [param])
useDispose(effect)
return <primitive ref={ref} object={effect} />
}