threlte logo
@threlte/extras

<ContactShadows>

This component is a port of drei’s <ContactShadows> component.

A contact shadow implementation, facing upwards (positive Y) by default. scale can be a positive number or a 2D array (x: number, y: number]).

<ContactShadows
  opacity={1}
  scale={10}
  blur={1}
  far={10}
  resolution={256}
  color="#000000"
/>

Since this is a rather expensive effect you can limit the amount of frames it renders when your objects are static. For instance making it render only once:

<ContactShadows frames={1} />

Use the binding refresh to manually refresh the shadows:

<script>
  let refresh

  const onSomeEvent = () => {
    if (refresh) refresh()
  }
</script>

<ContactShadows
  bind:refresh
  frames={0}
/>

Currently it has the same limitations of drei’s version: It yields unexpected results if moved on the x or the z axis.

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

<div class="relative h-full w-full bg-white/90">
  <Canvas>
    <Scene />
  </Canvas>
</div>
<script lang="ts">
  import { T, useFrame } from '@threlte/core'
  import { ContactShadows, Environment, Float, OrbitControls } from '@threlte/extras'
  import {
    BoxGeometry,
    Color,
    IcosahedronGeometry,
    MeshStandardMaterial,
    TorusKnotGeometry
  } from 'three'

  let pos = {
    x: 0
  }
  useFrame(() => {
    pos.x = Math.sin(Date.now() / 2000)
  })
</script>

<Environment
  path="/hdr/"
  files="shanghai_riverside_1k.hdr"
/>

<T.PerspectiveCamera
  makeDefault
  position={[-10, 10, 10]}
  fov={25}
>
  <OrbitControls
    enabled={false}
    autoRotate
    autoRotateSpeed={0.5}
    target.y={1}
  />
</T.PerspectiveCamera>

<T.DirectionalLight
  intensity={0.8}
  position.x={5}
  position.y={10}
/>
<T.AmbientLight intensity={0.2} />

<T.GridHelper
  args={[10, 10]}
  position.y={-0.001}
/>

<ContactShadows
  scale={10}
  blur={2}
  far={2.5}
  opacity={0.5}
/>

<Float
  floatIntensity={1}
  floatingRange={[0, 1]}
>
  <T.Mesh
    position.y={1.2}
    position.z={-0.75}
    geometry={new BoxGeometry(1, 1, 1)}
    material={new MeshStandardMaterial({
      color: new Color('#0059BA')
    })}
  />
</Float>

<Float
  floatIntensity={1}
  floatingRange={[0, 1]}
>
  <T.Mesh
    position={[1.2, 1.5, 0.75]}
    rotation.x={5}
    rotation.y={71}
    geometry={new TorusKnotGeometry(0.5, 0.15, 100, 12, 2, 3)}
    material={new MeshStandardMaterial({
      color: new Color('#F85122')
    })}
  />
</Float>

<Float
  floatIntensity={1}
  floatingRange={[0, 1]}
>
  <T.Mesh
    position={[-1.4, 1.5, 0.75]}
    rotation={[-5, 128, 10]}
    geometry={new IcosahedronGeometry(1, 0)}
    material={new MeshStandardMaterial({
      color: new Color('#F8EBCE')
    })}
  />
</Float>

Example

<script lang="ts">
  import { ContactShadows } from 'threlte/extras'
</script>

<ContactShadows
  scale={10}
  blur={2}
  far={2.5}
  opacity={0.5}
/>

Component Signature

<ContactShadows> extends <T.Group> and supports all its props, slot props, bindings and events.

Props

name
type
required

blur
number
no

color
THREE.ColorRepresentation
no

depthWrite
boolean
no

far
number
no

frames
number
no

height
number
no

opacity
number
no

resolution
number
no

scale
number | [x: number, y: number]
no

smooth
boolean
no

width
number
no

Bindings

name
type

refresh
() => void