Skip to content
转载】浅谈CesiumJS+WebGL融合引擎渲染

 在WebGL环境下,将不同的3D引擎(如Cesium、Three.js、Babylon.js等)融合在同一个场景中的方法有多种,每种方法都有其特定的优缺点,适用于不同的场景和需求,这里主要提供一些思路和可行性,具体需要开发者完善。本文仅为个人观点和实践,感兴趣可以自行尝试研究,当然好的方案也不只这几种。

01

WebGL基础概述

WebGL 的渲染管线是一套由硬件加速的逐步流水线,每一阶段的任务与输入/输出十分明确,整体流程如下:

  1. 顶点着色器阶段

    • 接收顶点数据(例如顶点位置、法线、纹理坐标等)。

    • 通过顶点着色器计算顶点的变换,完成模型矩阵、视图矩阵、投影矩阵的乘积计算,输出裁剪坐标(Clip Space)。

    • 输出:裁剪坐标(带有齐次坐标,gl_Position)。

  2. 裁剪与视锥体剔除

    • 依据裁剪坐标裁剪出视锥体外的顶点,避免多余计算。
  3. 光栅化阶段

    • 将裁剪空间坐标转化为屏幕上的像素(片段)。

    • 根据顶点插值计算片段的属性值(如颜色、纹理坐标等)。

  4. 片段着色器阶段

    • 使用片段着色器对光栅化生成的片段逐一着色,结合纹理、光照、材质计算最终颜色值。

    • 片段着色器还会输出深度值(Z 值)。

  5. 深度与模板测试、混合

    • 深度测试决定是否绘制当前片段(依据深度缓冲)。

    • 模板测试、混合等会进一步处理透明度与叠加关系。

  6. 帧缓冲写入

    • 最终颜色值、深度值等被写入帧缓冲(FBO),完成渲染。

WebGL 使用齐次坐标系统(4D),通过矩阵变换实现坐标系的转换,核心流程如下:

  1. 模型矩阵(Model Matrix)
    定义模型从局部坐标系世界坐标系 的变换(旋转、平移、缩放)。

  2. 视图矩阵(View Matrix)
    定义从世界坐标系相机视角坐标系 的变换。视图矩阵通常是相机变换的逆矩阵。

  3. 投影矩阵(Projection Matrix)
    定义从相机视角坐标系裁剪坐标系 的变换,包括正交投影或透视投影。

  4. 视口变换(Viewport Transform)
    将裁剪空间坐标(NDC,[-1, 1])映射到屏幕坐标系。

02

WebGL功能对比

以下是CesiumThree.jsBabylon.js坐标系深度缓冲渲染分类透明度处理场景规模后处理 等方面的基本对比表格:

特性CesiumThree.jsBabylon.js
坐标系
球心笛卡尔坐标系(ECEF),即地球中心坐标系

|

右手坐标系(X:向右,Y:向上,Z:向外)

|

右手坐标系(X:向右,Y:向上,Z:向前)

| | 深度缓冲 |

对数深度缓冲(Log Depth Buffer)

|

线性深度缓冲(Linear Depth Buffer)

|

线性深度缓冲(Linear Depth Buffer)

| | 渲染分类 |

11个Pass(包括不透明、透明、环境、地形3dtiles等)

|

不透明和半透明物体分类渲染,手动深度排序

|

不透明和半透明物体分类渲染,手动深度排序

| | 透明度处理 |

使用OIT(Order Independent Transparency)

|

使用深度排序算法,支持多种混合模式(Alpha Blending)

|

使用深度排序算法,支持多种混合模式(Alpha Blending)

| | 场景规模 |

支持全球级大场景,具有高效的空间剔除(Quadtree/Octree)

|

支持中小型场景,较适合桌面和Web应用

|

支持中小型场景,较适合桌面和Web应用

| | 后处理 |

高级后处理效果(FXAA、HDR、Bloom等)

|

支持多种后处理效果(如FXAA、Bloom、SSR)

|

支持多种后处理效果(如FXAA、Bloom、Motion Blur等)

|

1.坐标系

  • Cesium

    使用球心笛卡尔坐标系(ECEF),即地球中心坐标系。在这种坐标系下,所有的坐标都是相对于地球中心的,这使得它能够在全球范围内处理 3D 数据,适用于大规模地理空间应用。

  • Three.js

    Babylon.js 使用的是右手坐标系,这是图形学中最常见的坐标系。在这种坐标系中,X 轴指向右,Y 轴指向上,Z 轴指向观察者(Three.js)或离开观察者(Babylon.js)。

  • 结合点:在Cesium中结合需要统一坐标系和顶点数据,在转换到上面的webgl坐标系的视图坐标系中需要保持位置正确,同时也需要保证大场景精度需要加入RTC和RTE机制。

2.深度缓冲

  • Cesium

    使用对数深度缓冲(Log Depth Buffer),可以解决大场景深度精度不足的问题。在渲染大范围的场景时,传统的线性深度缓冲会导致远距离的深度信息丢失,使用对数深度缓冲可以有效提高远距的深度分辨率,避免深度冲突。

  • Three.js

    Babylon.js 默认使用线性深度缓冲,其中深度值在[0, 1] 范围内,随着物体离相机的距离增加,深度值的分辨率逐渐降低。它们也可以通过启用对数深度缓冲(Log Depth)来优化远距离深度分辨率,特别是在渲染大场景时。

  • 结合点:Cesium支持Lod Depth和多视锥两种绘制,默认使用Lod Depth。第一种渲染场景深度结合时需要统一重写深度支持Cesium的LogDepth,第二种直接换到多视锥模式 ,Cesium多视锥按视距分割成多个工作视锥统计渲染场景,虽然能不用重写深度解决大场景深度问题但也会增加额外DC开销。

3.渲染分类

  • Cesium

    采用了精细化的11 个渲染 Pass,分别处理环境光、天空盒、地形、3d瓦片、透明物体、不透明物体等不同类别的渲染。每个 Pass 负责不同的渲染目标,例如深度缓冲、颜色缓冲、阴影、光照等。

  • Three.js

    Babylon.js 通常将渲染分为不透明物体和半透明物体两个主要分类。在透明物体的渲染上,透明物体需要进行深度排序,以保证它们正确地显示在场景中。

  • 结合点:结合Cesium可以通过自定义Pass流程加入融合引擎的渲染类别,一般分为不透明和半透明物体渲染,这里渲染半透明物体可以直接在Cesium的PASS 7(不透明物体)完成之后渲染自定义的Pass流程。

4.半透明处理

  • Cesium

    使用OIT(Order Independent Transparency) 技术来处理半透明物体的渲染。OIT 是一种不依赖渲染顺序的透明度处理方法,可以有效地解决多重透明物体渲染中的顺序问题,从而得到正确的视觉效果。

  • Three.js

    Babylon.js 采用深度排序算法,先渲染不透明物体,再渲染透明物体。在渲染透明物体时,通常需要禁用深度写入,仅进行深度测试,并按从远到近的顺序对透明物体进行排序。

  • 结合点:渲染半透明一直都是各引擎的难点,很多半透明渲染算法:α混合,深度排序,深度剥离,OIT,Abuffer..等等但都各有优缺点,所以选择适合引擎的半透明算法才是最优解,这里主要是Cesium结合,所渲染半透明可以选择Pass 8沿用Cesium的OIT机制。

5.场景规模

  • Cesium

    设计上支持全球级大场景,尤其适合地理信息系统(GIS)和大规模 3D 地图应用。它使用空间分层剔除 技术(如 Quadtree、Octree)来高效管理和渲染大范围的场景,确保即使在全球范围内也能流畅地渲染。

  • Three.js

    Babylon.js 适用于中小型的场景,尤其适合在 Web、桌面应用中使用。它们并没有像 Cesium 那样设计专门的全局场景管理,通常用于游戏、虚拟现实和其他小范围的 3D 可视化。

6.后处理

  • Cesium

    提供了丰富的后处理效果,包括FXAAHDR(高动态范围)、BloomSSAO(屏幕空间环境光遮蔽)等,适合用于处理大规模场景中的视觉效果。

  • Three.js

    Babylon.js 也支持类似的后处理效果,能够进行FXAABloomMotion BlurSSR(屏幕空间反射)等效果。它们的后处理管线非常灵活,支持通过自定义材质和效果来实现更多特效。

03

浅谈Cesium融合

在WebGL环境下,将不同的3D引擎(如Cesium、Three.js、Babylon.js等)融合在同一个场景中的方法有多种,每种方法都有其特定的优缺点,适用于不同的场景和需求,这里主要提供一些思路和可行性,具体需要开发者完善。

1.从WebGL层面融合

这种方案的核心思想是在Cesium的渲染流程完成后,在它渲染完不透明物体和半透明物体的前后,插入其他引擎(如Three.js)渲染的物体。具体流程如下:

  • 渲染顺序:Cesium渲染主场景的几何和不透明物体。在完成这些渲染之后,不透明物体已经被渲染到帧缓冲区中,接下来进行半透明物体的渲染。在此时,可以插入Three.js的渲染,先渲染Three.js的固态(不透明)物体,然后再使用Cesium的OIT(Order-Independent Transparency)技术渲染半透明物体。
  • 半透明物体的渲染:Cesium的OIT技术通过多次渲染并排序半透明物体来处理遮挡问题,这时Three.js渲染的物体已经插入到了合适的位置,能够正确参与透明物体的计算。

优点是:

  • 较少修改引擎内部结构:基本上是在现有引擎之间插入渲染步骤,兼容性较好。
  • 灵活性:可以根据不同的需求灵活插入不同的渲染过程。

缺点是:

  • 渲染性能:可能会因为多次渲染、合成过程导致性能开销较大,特别是在渲染复杂场景时。
  • 深度遮挡问题:可能需要小心处理深度信息,以确保不同引擎的物体正确遮挡

Cesium+3DGS渲染

图片

Cesium+OpenVDB体素渲染

图片

Cesium+VFX粒子系统

图片

Cesium+Twgl.js渲染Demo

图片

开源地址:

https://gitee.com/m3d/cesium.js--twgl.js

2.从API层面融合

从API层面的融合是通过将Three.js的Mesh对象转换成Cesium的DrawCommand来实现。DrawCommand是Cesium的渲染接口,允许将渲染指令直接传递到WebGL上下文进行渲染。

具体步骤如下:

  • 将Three.js的Mesh转换为DrawCommand:首先需要将Three.js中的几何体(Geometry)和材质(Material),纹理(Texture)转换为Cesium支持的格式,例如将Three.js的BufferGeometry转换为Cesium的Geometry,材质则需要映射到Cesium的相应材质类型(如Cesium.Material或Cesium.ShaderMaterial)。

  • 创建DrawCommand:Cesium的DrawCommand代表了一个渲染单元,包括了需要绘制的几何数据、材质、着色器等。通过将Three.js转换为Cesium支持的格式后,可以将其作为一个DrawCommand加入到Cesium的渲染队列中。

  • 集成渲染管线:所有的渲染过程,包括Three.js的物体、Cesium的物体,都通过Cesium的DrawCommand渲染管线进行调度。这样做的好处是能充分利用Cesium的渲染优势(如高效的地理空间处理和深度优化)同时不失去Three.js的灵活性。

优点是:

  • 高效统一渲染管线:通过DrawCommand的标准化接口,能在Cesium的渲染系统中统一管理所有物体的渲染。
  • 可扩展性强:不需要修改现有引擎的核心逻辑,可以方便地增加更多的渲染物体(例如其他引擎的物体)。

缺点是:

  • 复杂的转换过程:需要将Three.js的对象映射到Cesium支持的格式,特别是处理复杂的几何和材质时可能比较麻烦,而且每个引擎都有优化机制,处理不好适得其反。
  • 潜在的性能瓶颈:尽管通过DrawCommand可以获得一定的性能优化,但大量的Mesh转换和材质转换操作可能会带来性能损失。

Cesium+Three.js GPUWater渲染

图片

Cesium+PBR灯光渲染

图片

Cesium+PBR+后处理渲染

图片

3.深度共享融合

利用Cesium默认提供colorTexture和depthTexture来进行深度重建和着色,如能提供GBuffer信息融合效果会更完善,这里以GBuffer提供深度信息融合为例,由于Cesium默认不支持GBuffer这里以引擎A和引擎B举例:

通过两个引擎之间共享GBuffer(几何缓冲区)信息来解决深度冲突的问题。具体来说,GBuffer是渲染过程中的一种中间缓冲区,存储了物体的颜色、法线、深度等信息。在这两种引擎之间共享GBuffer,可以避免在不同引擎之间的深度冲突。

步骤如下:

  • 渲染引擎A的GBuffer:首先,在引擎A(例如Cesium)中完成场景的渲染,并将几何信息(颜色、法线、深度等)输出到GBuffer。

  • 共享深度信息:引擎B(如Three.js)在渲染之前,通过从引擎A的GBuffer中读取深度信息,重建A引擎的深度值,并对齐自己的渲染深度缓冲区。这意味着在引擎B中绘制物体时,可以根据A引擎的深度信息来正确遮挡物体。

  • 分别渲染:两套引擎可以各自渲染自己的物体,但每个引擎渲染时都会使用共享的深度信息,避免了深度冲突。

优点是:

  • 解决深度遮蔽问题:通过共享深度信息,能够有效避免两个引擎之间的深度冲突。
  • 灵活性高:每个引擎依然可以独立工作,适用于需要将不同引擎结合的复杂场景。

缺点是:

  • 内存开销大:为了共享深度信息,必须保留两套缓冲区和两套场景资源,而且每个引擎的机制不同,优化手段也不同,这会导致内存消耗倍增,尤其是在大型场景下。
  • 渲染性能问题:每次渲染之前都需要读取其他引擎的GBuffer或缓冲区信息,计算深度写入深度等,可能会带来一定的性能开销。

Cesium+M3D for WebGPU渲染

图片

图片

图片

这些方法各有特点,具体使用哪种方法要根据应用场景来决定:

  • WebGL层面融合:适合快速实现,不需要太多修改引擎本身,适用于深度渲染的场景。
  • API层面融合: 可以更深入地集成两个引擎,性能优化空间较大,但需要处理引擎间的接口转换。
  • 深度共享:方法适用于对深度遮挡要求较高的场景,但需要权衡内存开销和性能问题。

上文仅供参考,如果其他意见请保留。

本文转自 https://mp.weixin.qq.com/s/TPUeRFh2zNw5SGvg97XUqQ,如有侵权,请联系删除。

Updated at: