MeshTransmissionMaterial

  • MeshTransmissionMaterial
    MeshTransmissionMaterial

An improved THREE.MeshPhysicalMaterial. It acts like a normal PhysicalMaterial in terms of transmission support, thickness, ior, roughness, etc., but has chromatic aberration, noise-based roughness blur, (primitive) anisotropic blur support, and unlike the original it can "see" other transmissive or transparent objects which leads to improved visuals.

Although it should be faster than MPM keep in mind that it can still be expensive as it causes an additional render pass of the scene. Low samples and low resolution will make it faster. If you use roughness consider using a tiny resolution, for instance 32x32 pixels, it will still look good but perform much faster.

For performance and visual reasons the host mesh gets removed from the render-stack temporarily. If you have other objects that you don't want to see reflected in the material just add them to the parent mesh as children.

type MeshTransmissionMaterialProps = JSX.IntrinsicElements['meshPhysicalMaterial'] & {
  /* Transmission, default: 1 */
  transmission?: number
  /* Thickness (refraction), default: 0 */
  thickness?: number
  /** Backside thickness (when backside is true), default: 0 */
  backsideThickness?: number
  /* Roughness (blur), default: 0 */
  roughness?: number
  /* Chromatic aberration, default: 0.03 */
  chromaticAberration?: number
  /* Anisotropy, default: 0.1 */
  anisotropicBlur?: number
  /* Distortion, default: 0 */
  distortion?: number
  /* Distortion scale, default: 0.5 */
  distortionScale?: number
  /* Temporal distortion (speed of movement), default: 0.0 */
  temporalDistortion?: number
  /** The scene rendered into a texture (use it to share a texture between materials), default: null  */
  buffer?: THREE.Texture
  /** transmissionSampler, you can use the threejs transmission sampler texture that is
   *  generated once for all transmissive materials. The upside is that it can be faster if you
   *  use multiple MeshPhysical and Transmission materials, the downside is that transmissive materials
   *  using this can't see other transparent or transmissive objects nor do you have control over the
   *  buffer and its resolution, default: false */
  transmissionSampler?: boolean
  /** Render the backside of the material (more cost, better results), default: false */
  backside?: boolean
  /** Resolution of the local buffer, default: undefined (fullscreen) */
  resolution?: number
  /** Resolution of the local buffer for backfaces, default: undefined (fullscreen) */
  backsideResolution?: number
  /** Refraction samples, default: 6 */
  samples?: number
  /** Buffer scene background (can be a texture, a cubetexture or a color), default: null */
  background?: THREE.Texture
}
return (
  <mesh geometry={geometry} {...props}>
    <MeshTransmissionMaterial />

If each material rendering the scene on its own is too expensive you can share a buffer texture. Either by enabling transmissionSampler which would use the threejs-internal buffer that MeshPhysicalMaterials use. This might be faster, the downside is that no transmissive material can "see" other transparent or transmissive objects.

<mesh geometry={torus}>
  <MeshTransmissionMaterial transmissionSampler />
</mesh>
<mesh geometry={sphere}>
  <MeshTransmissionMaterial transmissionSampler />
</mesh>

Or, by passing a texture to buffer manually, for instance using useFBO.

const buffer = useFBO()
useFrame((state) => {
  state.gl.setRenderTarget(buffer)
  state.gl.render(state.scene, state.camera)
  state.gl.setRenderTarget(null)
})
return (
  <>
    <mesh geometry={torus}>
      <MeshTransmissionMaterial buffer={buffer.texture} />
    </mesh>
    <mesh geometry={sphere}>
      <MeshTransmissionMaterial buffer={buffer.texture} />
    </mesh>

Or a PerspectiveCamera.

<PerspectiveCamera makeDefault fov={75} position={[10, 0, 15]} resolution={1024}>
  {(texture) => (
    <>
      <mesh geometry={torus}>
        <MeshTransmissionMaterial buffer={texture} />
      </mesh>
      <mesh geometry={sphere}>
        <MeshTransmissionMaterial buffer={texture} />
      </mesh>
    </>
  )}

This would mimic the default MeshPhysicalMaterial behaviour, these materials won't "see" one another, but at least they would pick up on everything else, including transmissive or transparent objects.