CesiumJS PrimitiveAPI 高级着色入门-使用 GLSL 着色器

CesiumJS 是一个非常强大的开源 JavaScript 库,用于在 web 浏览器中创建 3D 地球仪和 2D 地图。它提供了丰富的API,允许开发者构建复杂的地理空间可视化应用。在 CesiumJS 中,PrimitiveAPI 允许你以较低级别的方式渲染几何体,如点、线和多边形等,这为自定义着色和渲染效果提供了可能。

CesiumJS PrimitiveAPI 高级着色入门-使用 GLSL 着色器

明确一个定义,在 Primitive API 中应用着色器,实际上是给 AppearancevertexShaderSourcefragmentShaderSourceMaterial 中的 fabric.source 设置着色器代码,它们所能控制的层级不太一样。但是他们的共同目的都是为了 Geometry 服务的,它们会随着 CesiumJS 的每帧 update 过程,创建 ShaderProgram,创建 DrawCommand,最终去到 WebGL 的底层渲染中。

3D模型在线预览提供多种低代码平台3D模型在线预览解决方案,实现了将多种3D模型格式无缝集成到低代码业务表单中。这意味着用户可以在不离开低代码平台的情况下,直接查看和操作3D模型,极大地提升了数据可视化的效果和用户交互体验。

使用 GLSL 着色器

为 Fabric 材质添加自定义着色代码 - Fabric 材质的本质

有了之前的 fabric.uniformsfabric.materialsfabric.components 基础,你可能迫不及待想写自定义着色器代码了。需要知道的一点是,有了 fabric.source,就不兼容 fabric.components 了,只能二选一。

关于 fabric.uniforms,它的所有键名都可以在着色器代码中作为 GLSL Uniform 变量使用;关于 fabric.materials,它的所有键名都可以在着色器代码中作为 GLSL 变量使用,也就是一个计算完成的 czm_material 结构体变量。

编写 fabric.source,实际上就是写一个函数,它必须返回一个 czm_material 结构体,且输入一些特定的、当前片元的信息:

czm_material 已经在之前提及过了,它包含了实时渲染所需的一些基本材质参数。而 materialInput 这个变量,它是 czm_materialInput 类型的结构体,定义如下:

其中:

  • s - 一维纹理坐标
  • st - 二维纹理坐标
  • str - 三维纹理坐标。注意,materialInput.str.st 不一定就是 materialInput.st,也不能保证 materialInput.st.s == materialInput.s,例如对于椭球体而言,s 是底部到顶部的纹理坐标,st 是经纬度,str 可能是范围框的轴向值,这要参考源代码
  • tangentToEyeMatrix - 片元切线空间到眼坐标系的转换矩阵,用于法线计算等
  • positionToEyeEC - 片元坐标到观察坐标系(眼坐标系)原点的向量,模长为片元到原点的距离,单位是米,可以用于反射或者折射计算
  • normalEC - 可用于凹凸映射、反射、折射计算中的眼睛坐标系下的标准化法线

那个 czm_getDefaultMaterial 函数就是获取默认的材质结构,这个函数很简单:

有了上面这些基础,你就可以在这个 czm_getMaterial() 函数体里写你想要的片元着色内容了,注意任意 CesiumJS 的内置变量、自动 Uniform、结构体、内置函数都可以用。

社区实现案例 - 泛光墙体和流动线材质

有了上一节的基础,我们直接参考网上的一些案例。

其用到的渐变纹理可以是任意的一个横向颜色至透明的渐变 png:

效果:

文中还介绍了 Entity 使用自定义 MaterialProperty 的方法,实际上底层也是 Material

详细的完整封装调用就不列举了,需要有 Entity API 的使用经验,不在本篇范围。想知道 Property 是如何调用底层的,也需要自己研究 EntityAPI 的底层。

直接定义外观对象的两个着色器

fabric.source 只能作用于材质的片元着色,当然也可以通过编写外观对象的两个着色器实现更大自由。

默认情况下,MaterialAppearance 的顶点着色器与片元着色器是这样的:

顶点着色器调用 czm_computePosition() 函数将 position3DHighposition3DLow 合成为 vec4 的模型坐标,然后乘以 czm_modelViewProjectionRelativeToEye 这个内置的矩阵,得到裁剪坐标。然后是片元着色器:

如果想完全定制 Primitive 的着色行为,需要十分熟悉你所定制的 Geometry 的 VertexBuffer,也要控制好两大着色器之间相互传递的值。

源码中如何合并着色器

这段要讲讲源码,定位到 Primitive.prototype.update() 方法:

使用 createShaderProgram 函数会用到外观对象。

总之,外观的两个着色器也仅仅是 CesiumJS 这个庞大的着色器系统中的一部分,仍有非常多的状态需要添加到着色器对象(ShaderProgram)上。

CesiumJS PrimitiveAPI 高级着色入门-索引

CesiumJS PrimitiveAPI 高级着色入门-参数化几何

CesiumJS PrimitiveAPI 高级着色入门-外观材质

CesiumJS PrimitiveAPI 高级着色入门-使用 GLSL 着色器

CesiumJS PrimitiveAPI 高级着色入门-底层知识

NSDT场景编辑器 | NSDT 数字孪生 | GLTF在线编辑器 | 3D模型在线转换 | UnrealSynth虚幻合成数据生成器 | 3D模型自动纹理化工具
2023 power by nsdt©鄂ICP备2023000829号