@threlte/extras
<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 params: <Canvas rendererParameters={{ stencil: true }}>
. In prior versions the default is true
already. <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 { T, useTask } from '@threlte/core'
import { OrbitControls, Grid, Float, TransformControls, Mask, useMask } from '@threlte/extras'
import { Pane, Checkbox, List } from 'svelte-tweakpane-ui'
let rotation = 0
let inverse = true
let move = false
let target: 1 | 2 | 3 = 1
let torusStencil: any = useMask(1, true)
let boxStencil: any = useMask(2, true)
let icoStencil: any = useMask(3, true)
const settingsChanged = () => {
if (inverse) {
torusStencil = useMask(1, true)
boxStencil = useMask(2, true)
icoStencil = useMask(3, true)
} else {
torusStencil = target === 1 ? useMask(1, false) : {}
boxStencil = target === 2 ? useMask(2, false) : {}
icoStencil = target === 3 ? useMask(3, false) : {}
}
}
$: {
settingsChanged()
inverse
target
}
useTask(() => {
rotation -= 0.001
})
</script>
<Pane
title="Mask"
position="fixed"
>
<Checkbox
bind:value={inverse}
label="inverse"
/>
<List
bind:value={target}
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]}
let:ref
>
<Mask id={target}>
<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}
</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}
sectionColor="#ffffff"
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]}
rotation={[rotation, 128, rotation]}
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)