Postprocessing
Outline
Implements the Outline postprocessing pass. Vanilla threejs example here
An outlined cube loops through a maze, with a different outline color when the object is hidden.
<script lang="ts">
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
</script>
<Canvas>
<Scene />
</Canvas>
<script lang="ts">
import { useThrelte, useRender } from '@threlte/core'
import {
EffectComposer,
EffectPass,
RenderPass,
OutlineEffect,
BlendFunction
} from 'postprocessing'
export let selectedMesh: THREE.Mesh
const { scene, renderer, camera, size } = useThrelte()
const composer = new EffectComposer(renderer)
const setupEffectComposer = (camera: THREE.Camera, selectedMesh: THREE.Mesh) => {
composer.removeAllPasses()
composer.addPass(new RenderPass(scene, camera))
const outlineEffect = new OutlineEffect(scene, camera, {
blendFunction: BlendFunction.ALPHA,
edgeStrength: 100,
pulseSpeed: 0.0,
visibleEdgeColor: 0xffffff,
hiddenEdgeColor: 0x9900ff,
xRay: true,
blur: true
})
if (selectedMesh !== undefined) {
outlineEffect.selection.add(selectedMesh)
}
composer.addPass(new EffectPass(camera, outlineEffect))
}
$: setupEffectComposer($camera, selectedMesh)
$: composer.setSize($size.width, $size.height)
useRender((_, delta) => {
composer.render(delta)
})
</script>
<script>
import { T } from '@threlte/core'
</script>
<T.Mesh position={[6, 2, 4]} rotation.y={Math.PI / 2}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[7, 4, 1]} />
</T.Mesh>
<T.Mesh position={[-6, 2, 4]} rotation.y={Math.PI / 2}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[7, 4, 1]} />
</T.Mesh>
<T.Mesh position={[-4, 2, 0]}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[5, 4, 1]} />
</T.Mesh>
<T.Mesh position={[4, 2, 0]}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[5, 4, 1]} />
</T.Mesh>
<T.Mesh position={[-3, 2, 7]}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[7, 4, 1]} />
</T.Mesh>
<T.Mesh position={[5, 2, 7]}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[3, 4, 1]} />
</T.Mesh>
<T.Mesh position={[-1, 2, 3.5]}>
<T.MeshStandardMaterial color="silver" />
<T.BoxGeometry args={[10, 4, 1]} />
</T.Mesh>
<script lang="ts">
import { onMount } from 'svelte'
import { quadInOut } from 'svelte/easing'
import { tweened } from 'svelte/motion'
import { T } from '@threlte/core'
import { OrbitControls, Grid } from '@threlte/extras'
import Maze from './Maze.svelte'
import CustomRenderer from './CustomRenderer.svelte'
const route = [
[0, 1, -3],
[0, 1, 1.5],
[4.7, 1, 1.5],
[4.7, 1, 5],
[2, 1, 5],
[2, 1, 9],
[8, 1, 9],
[8, 1, -3]
]
let routeIndex = 0
let cubePosition = tweened(route[routeIndex], {
duration: 400,
easing: quadInOut,
})
let outlinedCube: THREE.Mesh
onMount(() => {
const interval = setInterval(nextCubePosition, 500)
return () => {
clearInterval(interval)
}
})
const nextCubePosition = () => {
if (routeIndex < route.length - 1) {
routeIndex++
} else {
routeIndex = 0
}
cubePosition.set(route[routeIndex])
}
</script>
<Maze />
<T.Mesh position={$cubePosition} bind:ref={outlinedCube}>
<T.MeshToonMaterial color="gold" />
<T.BoxGeometry />
</T.Mesh>
<CustomRenderer selectedMesh={outlinedCube} />
<T.PerspectiveCamera
makeDefault
position={[0, 6, -10]}
fov={15}
zoom={0.2}
>
<OrbitControls enableZoom={true} enableDamping target={[0, 0, 5]}/>
</T.PerspectiveCamera>
<T.DirectionalLight
intensity={0.8}
position.x={5}
position.y={10}
/>
<T.AmbientLight intensity={0.2} />
<Grid
gridSize={18}
position={[0, -0.001, 5]}
cellColor="#ffffff"
sectionColor="#ffffff"
sectionThickness={0}
fadeDistance={25}
/>
How it works
- in
Scene.svelte
- bind the mesh we want to outline, and pass it as prop
selectedMesh
toCustomRenderer
component
- bind the mesh we want to outline, and pass it as prop
- Postprocessing is performed within
CustomRenderer
component- we use ‘postprocessing’ library from the pmndrs team
- call
EffectComposer
on threlte’srender
function, to return a newrender
function - then run our own render loop with this new render function, using
useRender
from threlte - our function
setupEffectComposer
adds the required RenderPass, and OutlinePass to the composer, specifically to our mesh - this function will re-run if
selectedMesh
changes (not done in this example currently)
- animation of the cube is done with
svelte/motion
inScene.svelte