经纬志
首页 / luma.gl / 使用示例

离屏渲染

两趟渲染:第一趟画进 256×256 的帧缓冲,第二趟把该帧缓冲的颜色附件当纹理采样到屏幕。 这是后期处理、拾取与多通道合成的共同骨架。

luma.gl 9.4 · 更新 2026-10-28
源码与运行效果
运行效果

说明

Framebuffer 把两张纹理绑成渲染目标:颜色附件负责出图,深度附件负责遮挡。 第一趟通道传 framebuffer,视口随之变成 256×256; 第二趟不传,画到画布,颜色附件即可作为普通纹理传入 bindings。

屏幕上那块四边形每帧按 CPU 算出的角度旋转,纹理内容每帧都由第一趟重新生成, 所以旋转时能看到画面是实时的离屏结果,而不是一张静态图片。

项目取值说明
离屏尺寸256 × 256由帧缓冲的宽高决定
颜色附件rgba8unorm用途 SAMPLE | RENDER | COPY_DST
深度附件device.preferredDepthFormat用途 RENDER
绘制调用2 趟各 1 次场景与合成各一个模型
绑定名uScene合成着色器里的 sampler2D
清除clearColor + clearDepth深度每帧回到 1

两趟通道

const offscreen = device.beginRenderPass({
  framebuffer: fbo,
  clearColor: [0.02, 0.04, 0.07, 1],
  clearDepth: 1
});
sceneModel.draw(offscreen);
offscreen.end();

const screen = device.beginRenderPass({ clearColor: [0.04, 0.06, 0.09, 1] });
composite.draw(screen);
screen.end();

两个通道必须先后结束,不能嵌套:end() 会恢复进入通道前的状态栈, 中间插入另一个 beginRenderPass 会让状态互相覆盖。

附件用途要一次给全

颜色纹理要同时带 SAMPLE 与 RENDER。 只给 RENDER,WebGL 后端仍可能采样成功,但 WebGPU 会直接判定不可采样, 同一份代码换后端就黑屏。用途在创建时固定,事后无法追加。

const colorTex = device.createTexture({
  width: 256,
  height: 256,
  format: 'rgba8unorm',
  usage: Texture.SAMPLE | Texture.RENDER | Texture.COPY_DST,
  sampler: { minFilter: 'linear', magFilter: 'linear', mipmapFilter: 'none' }
});

const fbo = device.createFramebuffer({
  width: 256,
  height: 256,
  colorAttachments: [colorTex],
  depthStencilAttachment: depthTex
});

视口由谁决定

没给 parameters.viewport 时,通道自动取目标尺寸: 画到帧缓冲用帧缓冲的宽高,画到画布用绘制缓冲的宽高。 手工指定视口只在做分屏或小地图时才需要,写死像素值会让页面缩放后错位。

GIS 里的对应场景

拾取缓冲区是最常见的用法:第一趟把要素编号编码成颜色画进离屏纹理, 点击时按坐标回读一个像素即可知道命中了谁。 地形晕渲、阴影图、抗锯齿的历史帧也走同一条路径。

不要在同一帧里同时读写同一张纹理。 把帧缓冲的颜色附件绑定为采样源、又准备画回该帧缓冲,会形成反馈回路, 多数驱动会给出未定义结果。合成一趟必须画到另一个目标。