threlte logo
@threlte/extras

<MeshRefractionMaterial>

To use this component you need to install the seperate library three-mesh-bvh, please run npm install three-mesh-bvh before adding this component to your project.

This material may not work reliably on some devices or browsers. We’re investigating possible fixes.

This component is a port of drei’s <MeshRefractionMaterial> component, a convincing Glass/Diamond refraction material.

<script lang="ts">
  import { Canvas } from '@threlte/core'
  import Scene from './Scene.svelte'
</script>

<div>
  <Canvas>
    <Scene />
  </Canvas>
</div>

<style>
  div {
    height: 100%;
  }
</style>
<script lang="ts">
  import { Mesh } from 'three'
  import { T, useLoader } from '@threlte/core'
  import { useGltf, MeshRefractionMaterial, useDraco } from '@threlte/extras'

  import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'

  let { ...props } = $props()

  type GLTFResult = {
    nodes: {
      Diamond_1_0: Mesh
    }
    materials: {}
  }

  const dracoLoader = useDraco()
  const gltf = useGltf<GLTFResult>('/models/diamond/dflat.glb', { dracoLoader })
  const env = useLoader(RGBELoader).load('/hdr/aerodynamics_workshop_1k.hdr')
</script>

{#await gltf then { nodes }}
  <T.Mesh
    castShadow
    receiveShadow
    geometry={nodes.Diamond_1_0.geometry}
    {...props}
  >
    {#await env then e}
      <MeshRefractionMaterial
        envMap={e}
        fresnel={0.5}
        ior={2.75}
        aberrationStrength={0.04}
        bounces={3}
        color={'#ffdddd'}
      />
    {/await}
  </T.Mesh>
{/await}
<script lang="ts">
  import { T } from '@threlte/core'
  import { OrbitControls, Grid, Float } from '@threlte/extras'
  import Diamond from './Diamond.svelte'
</script>

<Float
  floatIntensity={5}
  rotationIntensity={1}
  rotationSpeed={[0, 0, 0]}
>
  <Diamond
    scale={3}
    position.y={2}
  />
</Float>

<T.PerspectiveCamera
  makeDefault
  position.y={7}
  position.z={-8}
  fov={90}
>
  <OrbitControls
    enableDamping
    autoRotate
    enablePan={false}
    enableZoom={false}
  />
</T.PerspectiveCamera>

<Grid
  cellColor={'#46536b'}
  sectionThickness={0}
  infiniteGrid
  cellSize={5}
/>

Examples

Basic Example

You can either pass in a texture to use as the environment:

RefractionWithTexture.svelte
<script lang="ts">
  import { T, useLoader } from '@threlte/core'
  import { MeshRefractionMaterial } from '@threlte/extras'
  import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'

  const env = useLoader(RGBELoader).load('/hdr/aerodynamics_workshop_1k.hdr')
</script>

{#await env then texture}
  <T.Mesh>
    <MeshRefractionMaterial envMap={texture} />
    <T.IcosahedronGeometry args={[4, 0]} />
  </T.Mesh>
{/await}

or you can use a cube camera to generate the environment:

RefractionWithCubeCamera.svelte
<script lang="ts">
  import { T, useThrelte, useTask } from '@threlte/core'
  import { MeshRefractionMaterial } from '@threlte/extras'
  import { WebGLCubeRenderTarget, CubeCamera } from 'three'

  let renderTarget: WebGLCubeRenderTarget = new WebGLCubeRenderTarget(128)
  let cubeCamera: CubeCamera = new CubeCamera(0.1, 100, renderTarget)

  const { scene, renderer } = useThrelte()

  useTask(() => {
    if (cubeCamera) {
      cubeCamera.update(renderer, scene)
    }
  })
</script>

<T.Mesh>
  <MeshRefractionMaterial envMap={renderTarget.texture} />
  <T.IcosahedronGeometry args={[4, 0]} />
</T.Mesh>

Component Signature

<MeshRefractionMaterial> extends <T . ShaderMaterial> and supports all its props, slot props, bindings and events.

Props

name
type
required
default
description

envMap
CubeTexture | Texture
yes

aberrationStrength
number
no
0.0
RGB shift intensity, can be expensive

bounces
number
no
2
Number of ray-cast bounces, it can be expensive to have too many

color
ColorRepresentation
no
white

fastChrome
boolean
no
true
If this is on it uses fewer ray casts for the RGB shift sacrificing physical accuracy

fresnel
number
no
0.0
Fresnel (strip light)

ior
number
no
2.4
Refraction index