@threlte/extras
useFBO
useFBO
(Framebuffer Object) is a port of drei’s useFBO that creates a THREE.WebGLRenderTarget.
Framebuffer objects are useful when you want to render a scene to something other than the canvas. In ThreeJS, you do this by rendering the scene to a RenderTarget. The render target has a texture property that can be used for various things such as postprocessing effects or applying the texture to something in the scene.
<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, useThrelte } from '@threlte/core'
import { OrbitControls, Sky, useFBO, useGltf } from '@threlte/extras'
import {
CameraHelper,
Group,
Mesh,
MeshStandardMaterial,
PerspectiveCamera,
PlaneGeometry
} from 'three'
const gltf = useGltf('/models/Duck.glb')
const { renderer, scene } = useThrelte()
const fbo = useFBO({
size: {
width: 1024,
height: 2048
}
})
const group = new Group()
const cameraMeshHeight = 1
const cameraRotationRadius = 5
// create the plane and other camera in the script tag so that we don't have to bind to the ref and worry about `undefined` cases
const rotatingCamera = new PerspectiveCamera(40, 1, 2, 8)
const helper = new CameraHelper(rotatingCamera)
const planeMesh = new Mesh(new PlaneGeometry(), new MeshStandardMaterial({ map: fbo.texture }))
planeMesh.position.setZ(-1 * (cameraMeshHeight + cameraRotationRadius))
planeMesh.scale.setScalar(10)
let time = 0
useTask((delta) => {
time += delta * 0.2
const c = Math.cos(time)
const s = Math.sin(time)
rotatingCamera.position.set(cameraRotationRadius * c, 2 * c * s, cameraRotationRadius * s)
rotatingCamera.lookAt(group.position)
planeMesh.visible = false
helper.visible = false
const lastRenderTarget = renderer.getRenderTarget()
renderer.setRenderTarget(fbo)
renderer.render(scene, rotatingCamera)
helper.visible = true
planeMesh.visible = true
renderer.setRenderTarget(lastRenderTarget)
})
</script>
<T.PerspectiveCamera
position.x={5}
position.y={5}
position.z={10}
makeDefault
>
<OrbitControls />
</T.PerspectiveCamera>
<T.AmbientLight />
<Sky />
<T
is={rotatingCamera}
manual
/>
<T
is={helper}
attach={scene}
/>
<T is={planeMesh} />
<T is={group}>
<T.Group position.y={-1}>
{#await gltf then { scene }}
<T is={scene} />
{/await}
</T.Group>
</T>
Options
useFBO
’s options object extends Three.RenderTargetOptions
. The additional properties are listed below.
size
size
is used to set the width
and height
of the render target.
If size
is not provided, the target’s size is set to the size of the canvas and it will follow any updates to the size.
const { size } = useThrelte()
// use `size`'s width and height
const target = useFBO()
assert(target.width === size.current.width)
assert(target.height === size.current.height)
If size
is provided, the width
and height
of the texture are taken from size
.
const size = { width: 512, height: 512 }
const target = useFBO({ size })
assert(target.width === size.width)
assert(target.height === size.height)
width
and height
both default to 1
if they are not found on the size
object.
const size = { width: 512 }
const target = useFBO({ size })
assert(target.width === size.width)
assert(target.height === 1)
const size = { height: 512 }
const target = useFBO({ size })
assert(target.width === 1)
assert(target.height === size.height)
const size = {}
const target = useFBO({ size })
assert(target.width === 1)
assert(target.height === 1)
depth
depth
is used to assign a DepthTexture to the depthTexture
property of the render target. It can either be a boolean, “size” object, or DepthTexture
instance. By default, depth
is set to false
and a depth texture is not created. When depth
is used, the scene’s depth is rendered to the depthTexture
of the render target.
If depth
is set to true
, a depth texture is created and sized to match the size of the render target, after an appropriate size has been given to the render target.
const { size } = useThrelte()
const target = useFBO({ depth: true })
assert(target.depthTexture.image.width === size.current.width)
assert(target.depthTexture.image.height === size.current.height)
If depth
is a depth texture instance, it is assigned to the depthTexture
property of the returned render target.
const depthTexture = new DepthTexture(512, 512)
const target = useFBO({ depth: depthTexture })
assert(target.depthTexture === depthTexture)
If depth
is set to a “size” object, the depth texture size is set the width
and height
of the object.
const depth = { width: 512, height: 512 }
const target = useFBO({ depth })
assert(target.depthTexture.image.width === depth.width)
assert(target.depthTexture.image.height === depth.height)
width
and height
default to 1
if they are not found on the depth
object.
const depth = { width: 512 }
const target = useFBO({ depth })
assert(target.depthTexture.image.width === depth.width)
assert(target.depthTexture.image.height === 1)
const depth = { height: 512 }
const target = useFBO({ depth })
assert(target.depthTexture.image.width === 1)
assert(target.depthTexture.image.height === depth.height)
const depth = {}
const target = useFBO({ depth })
assert(target.depthTexture.image.width === 1)
assert(target.depthTexture.image.height === 1)