<Mask>
Masks use the stencil buffer to cut out areas of the screen. This component is a port of drei’s <Mask> component.
The Mask component requires Three.js to render with a stencil buffer. As of r163, stencil is set to
false by default. To enable the stencil buffer, set it in your canvas’s renderer: <Canvas createRenderer={(canvas)=>{return new WebGLRenderer({canvas,stencil: true })}}>. In prior versions the default is true already.
<script lang="ts"> import { Canvas } from '@threlte/core' import Scene from './Scene.svelte' import { WebGLRenderer } from 'three'</script>
<div> <Canvas createRenderer={(canvas) => { return new WebGLRenderer({ canvas, stencil: true }) }} > <Scene /> </Canvas></div>
<style> div { height: 100%; }</style><script lang="ts"> import { T } from '@threlte/core' import { OrbitControls, Grid, Float, TransformControls, Mask, useMask } from '@threlte/extras' import { Pane, Checkbox, List } from 'svelte-tweakpane-ui'
let inverse = $state(true) let move = $state(false) let id = $state<1 | 2 | 3>(1)
const torusStencil = $derived(useMask(1, inverse)) const boxStencil = $derived(useMask(2, inverse)) const icoStencil = $derived(useMask(3, inverse))</script>
<Pane title="Mask" position="fixed"> <Checkbox bind:value={inverse} label="inverse" /> <List bind:value={id} label="target" options={{ torus: 1, box: 2, ico: 3 }} /> <Checkbox bind:value={move} label="move" /></Pane>
<T.PerspectiveCamera makeDefault position={[3, 4, 15]} fov={15}> <OrbitControls enableDamping target={[0, 0.5, 0]} /></T.PerspectiveCamera>
<T.Group position={[0, 1, 2]}> {#snippet children({ ref })} <Mask {id}> <T.CircleGeometry args={[0.65]} /> <T.MeshBasicMaterial /> </Mask> <T.Mesh> <T.RingGeometry args={[0.6, 0.7, 50]} /> <T.MeshBasicMaterial /> </T.Mesh> {#if move} <TransformControls object={ref} showZ={false} /> {/if} {/snippet}</T.Group>
<T.DirectionalLight intensity={3} position.x={5} position.y={10}/><T.AmbientLight intensity={0.6} />
<Grid gridSize={[8, 8]} cellColor="#46536b" position.y={-0.3} sectionThickness={0} fadeDistance={50}/>
<Float floatIntensity={1} floatingRange={[0, 1]}> <T.Mesh position={[0, 0.3, 0]}> <T.TorusKnotGeometry args={[0.5, 0.15, 100, 12, 2, 3]} /> <T.MeshStandardMaterial color="#F85122" {...torusStencil} /> </T.Mesh></Float>
<Float floatIntensity={1} floatingRange={[0, 0.5]}> <T.Mesh position.y={0.5} position={[-1.5, 0, -2]} > <T.BoxGeometry /> <T.MeshStandardMaterial color="#0059BA" {...boxStencil} /> </T.Mesh></Float>
<Float floatIntensity={1} floatingRange={[0, 0.5]}> <T.Mesh position={[1.5, 0.3, -2]} scale={0.8} > <T.IcosahedronGeometry /> <T.MeshStandardMaterial color="#F8EBCE" {...icoStencil} /> </T.Mesh></Float>First you need to define a mask, give it the shape that you want.
<Mask id={1}> <T.PlaneGeometry /> <T.MeshBasicMaterial /></Mask>Now refer to it with the useMask hook and the same id, your content will now be masked out by the geometry defined above.
<script lang="ts"> import { useMask } from '@threlte/extras' const stencil = useMask(1)</script>
<T.Mesh> <T.TorusKnotGeometry /> <T.MeshStandardMaterial {...stencil} /></T.Mesh>You can build compound masks with multiple shapes by re-using an id. You can also use the mask as a normal mesh by providing colorWrite and depthWrite props.
<Mask position={[-1, 0, 0]} id={1}> <T.PlaneGeometry /> <T.MeshBasicMaterial /></Mask><Mask colorWrite depthWrite position={[1, 0, 0]} id={1}> <T.CircleGeometry /> <T.MeshBasicMaterial /></Mask>Invert masks individually by providing a 2nd boolean argument to the useMask hook.
const stencil = useMask(1, true)