fbo
import { ChangeDetectionStrategy, Component } from '@angular/core';import { SobaWrapper } from '@soba/wrapper.ts';import { NgtCanvas, provideNgtRenderer } from 'angular-three/dom';import { SceneGraph } from './scene-graph';
@Component({ selector: 'app-fbo', template: ` <ngt-canvas [camera]="{ position: [0, 0, 5], fov: 50 }"> <app-soba-wrapper *canvasContent [grid]="false"> <app-scene-graph /> </app-soba-wrapper> </ngt-canvas> `, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'fbo-demo relative block h-full' }, imports: [NgtCanvas, SobaWrapper, SceneGraph],})export default class Fbo { static clientProviders = [provideNgtRenderer()];}import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, ElementRef, computed, viewChild,} from '@angular/core';import { NgtArgs, NgtPortal, NgtPortalContent, beforeRender } from 'angular-three';import { NgtsPerspectiveCamera } from 'angular-three-soba/cameras';import { fbo } from 'angular-three-soba/misc';import * as THREE from 'three';
@Component({ selector: 'app-spinning-content', template: ` <ngt-mesh #mesh> <ngt-torus-knot-geometry *args="[0.5, 0.15, 128, 32]" /> <ngt-mesh-normal-material /> </ngt-mesh> `, schemas: [CUSTOM_ELEMENTS_SCHEMA], changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgtArgs],})export class SpinningContent { private meshRef = viewChild<ElementRef<THREE.Mesh>>('mesh');
constructor() { beforeRender(({ delta }) => { const mesh = this.meshRef()?.nativeElement; if (mesh) { mesh.rotation.x += delta; mesh.rotation.y += delta * 0.5; } }); }}
@Component({ selector: 'app-scene-graph', template: ` <!-- Off-screen camera for FBO rendering --> <ngts-perspective-camera [options]="{ position: [0, 0, 3], makeDefault: false }" />
<!-- Portal scene rendered to FBO --> <ngt-portal [container]="portalScene()"> <ng-template portalContent> <ngt-color *args="['#1a1a2e']" attach="background" /> <ngt-ambient-light [intensity]="0.5" /> <ngt-point-light [position]="[5, 5, 5]" [intensity]="Math.PI" /> <app-spinning-content /> </ng-template> </ngt-portal>
<!-- Display FBO texture on a box --> <ngt-mesh [rotation]="[0, Math.PI / 6, 0]"> <ngt-box-geometry *args="[2, 2, 2]" /> <ngt-mesh-basic-material [map]="target.texture" /> </ngt-mesh> `, schemas: [CUSTOM_ELEMENTS_SCHEMA], changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgtArgs, NgtPortal, NgtPortalContent, NgtsPerspectiveCamera, SpinningContent],})export class SceneGraph { protected readonly Math = Math;
private cameraRef = viewChild(NgtsPerspectiveCamera);
portalScene = computed(() => new THREE.Scene()); target = fbo(() => ({ width: 512, height: 512, settings: { samples: 4 } }));
constructor() { beforeRender(({ gl }) => { const camera = this.cameraRef()?.cameraRef()?.nativeElement; const scene = this.portalScene(); if (camera && scene) { gl.setRenderTarget(this.target); gl.render(scene, camera); gl.setRenderTarget(null); } }); }}fbo creates a WebGLRenderTarget (Frame Buffer Object) for off-screen rendering. The FBO is automatically sized to the canvas dimensions if width/height are not specified, and is disposed on component destroy.
Usage
import { fbo } from 'angular-three-soba/misc';import { beforeRender } from 'angular-three';
@Component({...})class MyComponent { // Basic usage - sized to canvas renderTarget = fbo();
// Custom size with multisampling target = fbo(() => ({ width: 512, height: 512, settings: { samples: 4 } }));
constructor() { // Render to FBO beforeRender(({ gl, scene, camera }) => { gl.setRenderTarget(this.target); gl.render(scene, camera); gl.setRenderTarget(null); }); }}NgtsFBOParams
| Property | Type | Description |
|---|---|---|
width | number | Width in pixels. Defaults to canvas width × device pixel ratio |
height | number | Height in pixels. Defaults to canvas height × device pixel ratio |
settings | RenderTargetOptions | THREE.js render target options |
Settings Options
| Property | Type | Default | Description |
|---|---|---|---|
samples | number | 0 | Samples for MSAA |
depth | boolean | false | Render scene depth into buffer.depthTexture |
depthBuffer | boolean | true | Include a depth buffer |
stencilBuffer | boolean | false | Include a stencil buffer |
injectFBO is deprecated. Use fbo instead.
Arguments
| name | type | description | required |
|---|---|---|---|
| params | () => NgtsFBOParams | Signal returning FBO configuration with width, height, and settings | no |
| options | { injector?: Injector } | Optional configuration object with injector | no |
Returns
| type | description |
|---|---|
| THREE.WebGLRenderTarget | A WebGLRenderTarget for off-screen rendering |
Creates a WebGLRenderTarget (Frame Buffer Object) for off-screen rendering. The FBO is automatically sized to the canvas dimensions if width/height are not specified, and is disposed on component destroy.
import { fbo } from 'angular-three-soba/misc';import { beforeRender } from 'angular-three';
@Component({...})class MyComponent { // Basic usage - sized to canvas renderTarget = fbo();
// Custom size with multisampling target = fbo(() => ({ width: 512, height: 512, settings: { samples: 4 }, }));
constructor() { // Render to FBO beforeRender(({ gl, scene, camera }) => { gl.setRenderTarget(this.target); gl.render(scene, camera); gl.setRenderTarget(null); }); }}Signature
Section titled “Signature”function fbo( params: () => NgtsFBOParams = () => ({}), { injector }: { injector?: Injector } = {},): THREE.WebGLRenderTarget;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
params | () => NgtsFBOParams | Signal of FBO configuration |
injector | Injector (optional) | Custom injector for dependency injection |
NgtsFBOParams
Section titled “NgtsFBOParams”| Property | Type | Description |
|---|---|---|
width | number | Width in pixels. Defaults to canvas width × device pixel ratio |
height | number | Height in pixels. Defaults to canvas height × device pixel ratio |
settings | RenderTargetOptions | THREE.js render target options (see below) |
RenderTargetOptions
Section titled “RenderTargetOptions”| Property | Type | Default | Description |
|---|---|---|---|
samples | number | 0 | Samples for MSAA. Set to 0 to disable |
depth | boolean | false | Render scene depth into buffer.depthTexture |
depthBuffer | boolean | true | Include a depth buffer |
stencilBuffer | boolean | false | Include a stencil buffer |
generateMipmaps | boolean | true | Generate mipmaps for the FBO texture |
wrapS | Wrapping | - | Wrapping mode for s-coordinate |
wrapT | Wrapping | - | Wrapping mode for t-coordinate |
magFilter | TextureFilter | - | Magnification filter |
minFilter | TextureFilter | - | Minification filter |
format | PixelFormat | - | Internal format of the color buffer |
type | TextureDataType | - | Data type of the color buffer |
anisotropy | number | - | Anisotropic filtering level |
depthTexture | DepthTexture | - | Custom DepthTexture instance |
colorSpace | ColorSpace | - | Color space of the FBO texture |
Return Value
Section titled “Return Value”Returns a THREE.WebGLRenderTarget that can be used for off-screen rendering.
NgtsFBO Directive
Section titled “NgtsFBO Directive”A structural directive that renders a part of your scene into an FBO using ng-template. Provides the created WebGLRenderTarget as implicit context to the template.
<ng-template [fbo]="{ width: 512, height: 512 }" let-target> <!-- target is the WebGLRenderTarget --> <ngt-mesh> <ngt-plane-geometry /> <ngt-mesh-basic-material [map]="target.texture" /> </ngt-mesh></ng-template>With Multisampling
Section titled “With Multisampling”<ng-template [fbo]="{ width: 1024, height: 1024, samples: 4 }" let-target> <ngt-mesh> <ngt-box-geometry /> <ngt-mesh-standard-material [map]="target.texture" /> </ngt-mesh></ng-template>