threlte logo
@threlte/extras

useFBO

useFBO (Framebuffer Object) is a hook that creates a THREE.WebGLRenderTarget. This is a port of drei’s useFBO hook.

Framebuffer objects are useful for cases where you want to render a scene but not display it. For example, rendering a scene to a framebuffer then passing that to a fragment shader as a uniform. You can read more about WebGLRenderTarget’s here.

<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 { interactivity, OrbitControls, Sky, useFBO } from '@threlte/extras'

  import { Mesh, PerspectiveCamera, Vector2 } from 'three'

  interactivity()

  const { camera, renderer, scene, size } = useThrelte()

  // render scene at a lower resolution
  const renderTarget = useFBO($size.width * 0.5, $size.height * 0.5, {
    samples: 4
  })

  // change aspect ratio of the texture because we are putting it on a circle so w and h are the same
  const aspect = new Vector2($size.height / $size.width, 1).normalize()
  renderTarget.texture.repeat.set(aspect.x, aspect.y)
  renderTarget.texture.offset.x = -0.5 * (aspect.x - 1)
  renderTarget.texture.offset.y = -0.5 * (aspect.y - 1)

  let fboPreviewMesh: Mesh

  let knotRotation = 0

  useTask((delta) => {
    knotRotation += delta
    if (!fboPreviewMesh) return
    const cam = $camera as PerspectiveCamera

    fboPreviewMesh.visible = false
    renderer.setRenderTarget(renderTarget)
    renderer.render(scene, cam)

    fboPreviewMesh.visible = true
    renderer.setRenderTarget(null)
  })
</script>

<T.PerspectiveCamera
  makeDefault
  position={[5, 1, 5]}
>
  <OrbitControls />
</T.PerspectiveCamera>

<Sky />

<T.Mesh
  rotation.x={knotRotation}
  rotation.z={knotRotation}
>
  <T.TorusKnotGeometry />
  <T.MeshStandardMaterial />
</T.Mesh>

<T.Mesh
  position.z={-5}
  position.x={-0.1}
  bind:ref={fboPreviewMesh}
>
  <T.PlaneGeometry args={[5, 5]} />
  <T.MeshBasicMaterial
    map={renderTarget.texture}
    color="#CCFFCC"
  />
</T.Mesh>

Options

type UseFBOOptions = {
  /** Defines the count of MSAA samples. Can only be used with WebGL 2. Default: 0 */
  samples?: number
  /** If set, the scene depth will be rendered into buffer.depthTexture. Default: false */
  depth?: boolean
} & THREE.WebGLRenderTargetOptions

export function useFBO(
  /** Width in pixels, or options (will render fullscreen by default) */
  width?: number | UseFBOOptions,
  /** Height in pixels */
  height?: number,
  /**Options */
  options?: UseFBOOptions
): THREE.WebGLRenderTarget