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 { Group } from 'three'
  import {
    T,
    type Props,
    type Events,
    type Slots,
    forwardEventHandlers,
    useLoader
  } from '@threlte/core'
  import { useGltf, MeshRefractionMaterial } from '@threlte/extras'

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

  type $$Props = Props<THREE.Group>
  type $$Events = Events<THREE.Group>
  type $$Slots = Slots<THREE.Group> & { fallback: {}; error: { error: any } }

  export const ref = new Group()

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

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

  const component = forwardEventHandlers()
</script>

<T
  is={ref}
  dispose={false}
  {...$$restProps}
  bind:this={$component}
>
  {#await gltf}
    <slot name="fallback" />
  {:then gltf}
    <T.Mesh
      castShadow
      receiveShadow
      geometry={gltf.nodes.Diamond_1_0.geometry}
    >
      {#await env then e}
        <MeshRefractionMaterial
          envMap={e}
          fresnel={0.5}
          ior={2.75}
          aberrationStrength={0.04}
          bounces={3}
          color={'#ffdddd'}
        />
      {/await}
    </T.Mesh>
  {:catch error}
    <slot
      name="error"
      {error}
    />
  {/await}
  <slot {ref} />
</T>
<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}
  on:create={({ ref }) => {
    ref.lookAt(0, 0, 0)
  }}
>
  <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