Render Targets and Views

This guide assumes you already have a scene rendering from First Scene. Here, we focus on where the camera renders and how to split output.

What You Will Add

Step 1: Import Render Target APIs

import {
  CanvasTarget,
  ImageRenderTarget,
  ViewRectangle,
  Texture,
  TextureType,
  TextureFormat,
  Camera
} from "webgl";

Use CanvasTarget for on-screen output. Use ImageRenderTarget for offscreen passes.

Step 2: Create a Canvas Target (Most Common)

const canvasTarget = new CanvasTarget(canvas);
const camera = new Camera(canvasTarget);

This is the default path for rendering directly to the page.

Step 3: Render a Scene to the Canvas Target

renderer.render([object, camera], device);

If your scene is blank, first confirm the camera uses the expected target.

Step 4: Create an Offscreen Image Target

const imageTarget = new ImageRenderTarget({
  width: 1024,
  height: 1024,
  color: [
    new Texture({
      type: TextureType.Texture2D,
      format: TextureFormat.RGBA8Unorm,
      width: 1024,
      height: 1024
    })
  ],
  internalDepthStencil: TextureFormat.Depth24PlusStencil8
});

This creates a texture-backed target you can render into.

Step 5: Render Offscreen with a Dedicated Camera

const offscreenCamera = new Camera(imageTarget);
renderer.render([offscreenObject, offscreenCamera], device);

Use a separate camera when offscreen pass framing differs from main pass.

Step 6: Use Offscreen Output as a Texture

const screenObject = new MeshMaterial3D(
  mesh,
  new BasicMaterial({ mainTexture: imageTarget.color[0] })
);

renderer.render([screenObject, camera], device);

This is the core pattern for mirrors, portals, and postprocessing chains.

Step 7: Split Canvas with Viewports

Use multiple CanvasTarget instances on the same canvas.

const leftTarget = new CanvasTarget(canvas);
const rightTarget = new CanvasTarget(canvas);

leftTarget.viewport.offset.set(0, 0);
leftTarget.viewport.size.set(0.5, 1);

rightTarget.viewport.offset.set(0.5, 0);
rightTarget.viewport.size.set(0.5, 1);

Viewport values are normalized (0 to 1) relative to full canvas size.

Step 8: Bind Cameras to Each View and Render

const leftCamera = new Camera(leftTarget);
const rightCamera = new Camera(rightTarget);

renderer.render([scene, leftCamera], device);
renderer.render([scene, rightCamera], device);

This gives independent camera views in a single canvas.

Step 9: Use Scissor for Hard Split/Masking

leftTarget.scissor = new ViewRectangle();
rightTarget.scissor = new ViewRectangle();

leftTarget.scissor.offset.set(0, 0);
leftTarget.scissor.size.set(0.5, 1);

rightTarget.scissor.offset.set(0.5, 0);
rightTarget.scissor.size.set(0.5, 1);

Scissor restricts actual draw area, useful for editor layouts and split bars.

Resize Rule for Multi-View Scenes

Keep canvas size and camera projection in sync on resize. For split views, compute aspect per view region (not full canvas).

Reference Examples