经纬志
首页 / luma.gl / API 文档

Program

先看结论

v9 里没有 Program 这个类。着色器编译与管线链接被拆成 Shader 与 RenderPipeline,日常绘制再由 Model 封装。 这一页说明它为什么消失,以及旧代码怎么迁移。

最后验证 2026-11-03 · luma.gl 9.4 · 更新 2026-10-27 · 引用本文
v8v9 对应物说明
Program RenderPipeline 把顶点与片元着色器链接成可绘制的管线
Program 的 vs / fs 字符串 device.createShader({ stage, source }) 着色器先编译为独立的 Shader 对象
Program 的 attributes bufferLayout 用格式字符串声明,不依赖 WebGL 的属性位置
Program 的 uniforms 绑定与 shaderInputs uniform 通过缓冲区绑定,适配 WebGPU
Model(v8) Model(v9) 仍是高层绘制入口,但构造签名改为 (device, props)

为什么去掉 Program

WebGPU 的渲染管线是不可变对象:深度、混合、图元类型、附件格式都在创建时固定, 改动要新建管线。WebGL 的 program 只是一个着色器链接结果,状态在其他地方设置。 两种模型的差异太大,用一个 Program 同时抽象两边,会不断泄漏后端细节。

v9 的做法是把「着色器」与「管线」分开:着色器负责编译,管线负责把着色器、 顶点布局与固定状态组合起来。WebGL 后端的管线可以在参数变化时内部重建, 对外仍是同一套接口。

创建着色器与管线

const vs = device.createShader({
  stage: 'vertex',
  source: [
    '#version 300 es',
    'in vec3 positions;',
    'void main() {',
    '  gl_Position = vec4(positions, 1.0);',
    '}'
  ].join('\n')
});

const fs = device.createShader({
  stage: 'fragment',
  source: [
    '#version 300 es',
    'precision highp float;',
    'out vec4 fragColor;',
    'void main() {',
    '  fragColor = vec4(0.35, 0.80, 0.62, 1.0);',
    '}'
  ].join('\n')
});

const pipeline = device.createRenderPipeline({
  vs: vs,
  fs: fs,
  topology: 'triangle-list',
  bufferLayout: [
    { name: 'positions', stepMode: 'vertex', format: 'float32x3' }
  ],
  parameters: {
    depthWriteEnabled: true,
    depthCompare: 'less-equal'
  }
});

着色器编译是异步的。生产环境可以先检查 shader.compilationStatus,或等待 shader.asyncCompilationStatus,再把管线投入绘制, 避免首帧出现空洞。

实际绘制仍建议用 Model

直接操作管线要自己管理顶点数组、绑定组与渲染通道状态,代码很快就会变得冗长。 Model 已经把这些封装好,并且在参数变化时自动重建管线。 只有需要精细控制管线状态、或实现自定义图层基类时,才需要直接接触 RenderPipeline。

const model = new Model(device, {
  vs: vsSource,
  fs: fsSource,
  attributes: { positions: positions },
  bufferLayout: [
    { name: 'positions', stepMode: 'vertex', format: 'float32x3' }
  ],
  vertexCount: 3,
  topology: 'triangle-list'
});

const pass = device.beginRenderPass({ clearColor: [0.05, 0.07, 0.1, 1] });
model.draw(pass);
pass.end();

迁移检查清单

  • 把 new Program(gl, {...}) 改为 Model 或 createRenderPipeline,不要继续寻找 createProgram。
  • 把 attributes 的位置索引改为 bufferLayout 的格式声明。
  • 把 uniform 更新从 program.setUniforms 迁到绑定或 shaderInputs。
  • 把 program.draw 迁到 model.draw(renderPass), 绘制需要显式开渲染通道。

看到旧教程先看版本。v8 的 Program、Geometry 的 GPU 缓冲、 AnimationLoop 的自动设备创建,在 v9 里都不成立。 按旧代码逐行翻译,通常会在第一处就停在「is not a constructor」。

引用本文

经纬志(2026)。《Program》。https://www.jingweizhi.com/lumagl/api/program.html(访问日期 2026-11-03)。