首页 / 专栏 / Cesium / viewer.scene.requestRender

viewer.scene.requestRender

  • 发布时间: 2026-02-12 09:19:01
  • 相关标签: cesium requestRender
  • 简介: 你想要深入了解 viewer.scene.requestRender() 这个方法,我会从它的作用、原理、使用场景和最佳实践等方面为你做全面讲解,帮你彻底掌握这个关键方法。

一、核心概念:requestRender() 是什么?

在 Cesium 中,viewer.scene.requestRender() 是触发场景重新渲染的核心方法。

1. 基础定义

Cesium 的场景渲染默认是按需渲染(不是每一帧都无脑渲染):

  • 当相机移动、实体位置变化、时间推进等「主动操作」发生时,Cesium 会自动触发渲染;
  • 当你做了「Cesium 无法自动感知」的修改(比如手动修改几何体顶点、自定义材质参数、非 Cesium 原生事件驱动的属性变化),就需要手动调用 requestRender() 告诉 Cesium:“场景变了,该重新画一帧了”。

2. 底层原理

  • Cesium 内部维护一个「渲染请求标记」,requestRender() 会将这个标记置为 true
  • Cesium 的渲染循环(requestAnimationFrame 驱动)每帧都会检查这个标记:
    • 如果为 true:执行渲染流程(更新场景状态 → 绘制图元 → 输出到画布),然后将标记置为 false
    • 如果为 false:跳过渲染,节省性能。

二、使用场景:什么时候需要调用?

1. 必须调用的场景(核心)

以下操作修改了场景,但 Cesium 无法自动检测,必须手动触发渲染:

// 示例1:手动修改自定义几何体的顶点数据
const primitive = viewer.scene.primitives.add(new Cesium.Primitive({
  geometryInstances: new Cesium.GeometryInstance({
    geometry: new Cesium.BoxGeometry({
      vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
      minimum: new Cesium.Cartesian3(-100000, -100000, -100000),
      maximum: new Cesium.Cartesian3(100000, 100000, 100000)
    })
  }),
  appearance: new Cesium.PerInstanceColorAppearance()
}));

// 手动修改几何体顶点(Cesium 无法感知这个修改)
primitive.geometryInstances.geometry.attributes.position.value[0] = 200000;
// 必须调用 requestRender() 才能看到修改后的效果
viewer.scene.requestRender();

// 示例2:自定义材质参数更新
const material = new Cesium.Material({
  fabric: {
    type: 'Color',
    uniforms: {
      color: new Cesium.Color(1, 0, 0, 1)
    }
  }
});
// 修改材质颜色(非 Cesium 自动触发的修改)
material.uniforms.color = new Cesium.Color(0, 1, 0, 1);
viewer.scene.requestRender(); // 触发渲染才能看到颜色变化

2. 不需要调用的场景(Cesium 自动处理)

以下操作 Cesium 会自动触发渲染,无需手动调用:

  • 相机操作:viewer.camera.flyTo()viewer.camera.setView()
  • 实体/图元增删:viewer.entities.add()viewer.scene.primitives.remove()
  • 时间变化:viewer.clock.tick()(Cesium 内部自动调用);
  • 交互操作:鼠标拖拽地球、缩放、旋转。

3. 进阶场景:批量修改后统一触发

如果有大量修改操作(比如循环修改1000个实体属性),不要每次修改都调用 requestRender(),而是批量修改完成后调用一次,避免性能浪费:

// 反例:性能差(触发1000次渲染请求)
for (let i = 0; i < 1000; i++) {
  entities[i].position = new Cesium.Cartesian3(i * 1000, 0, 0);
  viewer.scene.requestRender(); // 错误:频繁调用
}

// 正例:性能优(仅触发1次渲染请求)
for (let i = 0; i < 1000; i++) {
  entities[i].position = new Cesium.Cartesian3(i * 1000, 0, 0);
}
viewer.scene.requestRender(); // 正确:批量修改后调用

三、进阶知识点:requestRender() 的细节

1. 重复调用的幂等性

多次调用 requestRender() 不会重复触发多次渲染,而是合并为一次:

// 连续调用3次,最终只会触发1次渲染
viewer.scene.requestRender();
viewer.scene.requestRender();
viewer.scene.requestRender();

原理:Cesium 内部会先检查「渲染请求标记」,如果已经是 true,则直接返回,不会重复标记。

2. 与 render() 的区别

  • requestRender()异步触发渲染(加入下一帧渲染队列),非阻塞,是推荐用法;
  • scene.render()同步立即触发渲染,阻塞主线程,可能导致卡顿,仅在特殊场景(如截图)使用:
    // 截图场景(需要立即渲染最新状态)
    viewer.scene.requestRender(); // 标记需要渲染
    viewer.scene.render(); // 立即执行渲染(确保截图是最新的)
    const canvas = viewer.canvas;
    const dataUrl = canvas.toDataURL('image/png'); // 获取截图
    

3. 禁用自动渲染后的手动控制

如果通过 scene.requestRenderMode = Cesium.RequestRenderMode.MANUAL 禁用自动渲染,所有渲染都必须手动调用 requestRender()

// 禁用自动渲染(仅在性能极度敏感场景使用)
viewer.scene.requestRenderMode = Cesium.RequestRenderMode.MANUAL;
viewer.scene.maximumRenderTimeChange = Infinity;

// 此时任何修改都需要手动触发渲染
viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(116, 39),
  point: { pixelSize: 10 }
});
viewer.scene.requestRender(); // 必须调用才能看到实体

// 相机移动后也需要手动调用
viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(116, 39, 10000) });
viewer.scene.requestRender();

四、常见坑点与避坑指南

  1. 坑点1:修改自定义着色器/材质参数后没效果 → 忘记调用 requestRender()
    ✅ 解决:修改后立即调用 requestRender()

  2. 坑点2:频繁调用导致性能下降 → 循环中每次修改都调用;
    ✅ 解决:批量修改后统一调用一次。

  3. 坑点3:误以为 requestRender() 是同步渲染 → 调用后立即截图得到旧画面;
    ✅ 解决:截图前先调用 requestRender(),再调用 scene.render() 同步渲染。

总结

  1. viewer.scene.requestRender() 的核心作用是手动触发 Cesium 场景重新渲染,仅在 Cesium 无法自动感知修改时使用;
  2. 最佳实践:批量修改后统一调用,避免频繁调用;重复调用不会重复渲染,无需担心;
  3. 区分 requestRender()(异步,推荐)和 scene.render()(同步,仅特殊场景用),禁用自动渲染后必须手动调用。

同分类推荐