Cesium 顶点着色器的数据来源

书接上文,上文我们重点介绍了片元着色器的数据来源,这次我们来详细解析一下在 Cesium 中编写自定义着色器(特别是顶点着色器)时,可以使用的数据来源。

Cesium 为自定义着色器提供了丰富的数据输入,让你能够基于原始模型的几何信息、材质、外观以及 Cesium 特有的上下文(如时间、位置)来修改顶点。

这些数据主要通过着色器的 attributesuniformsvaryings 来传递。

1. 顶点属性

顶点属性是逐顶点 的数据,它们来自原始的 3D 模型(如 glTF)或 Cesium 原生图元(如 Cesium3DTileset, Model, Primitive)。在自定义着色器中,你可以通过 attributes 对象来访问它们。

以下是一些最常用和最重要的顶点属性:

属性名 类型 描述
position vec3 模型的顶点坐标(模型空间) 。这是最关键的属性,修改它可以直接改变顶点的位置,实现动画、扭曲等效果。
normal vec3 顶点法线(模型空间) 。用于光照计算。如果你移动了顶点,通常也需要相应地重新计算或变换法线。
texCoord vec2 第一套纹理坐标。用于从纹理中采样颜色、高度图等。
texCoord1 vec2 第二套纹理坐标(如果模型有的话)。
color vec4 顶点颜色。通常是 RGBA 格式。
batchId float 批次ID 。主要用于 Cesium3DTileset,用于区分同一个瓦片内不同对象的标识符,常与 czm_batchTable 配合使用。

示例代码:在自定义着色器中访问属性

arduino 复制代码
const vertexShader = `
  // 将属性从 JavaScript 作用域传递到 GLSL 作用域
  in vec3 position;
  in vec3 normal;
  in vec2 texCoord;

  void vertexMain() {
    // 示例1:让模型在Y轴上上下波动
    float offset = sin(position.x * 10.0) * 0.1; // 基于x坐标的正弦波
    vec3 modifiedPosition = position + vec3(0.0, offset, 0.0);

    // 将修改后的位置赋值给内置变量
    positionMC = modifiedPosition; // positionMC 是 Cesium 约定的输出变量,表示模型空间坐标

    // 示例2:将纹理坐标传递给片元着色器(如果需要)
    v_texCoord = texCoord;

    // 示例3:传递法线(如果片元着色器需要计算光照)
    v_normal = normal;
  }
`;

// 在 CustomShader 中配置
const customShader = new Cesium.CustomShader({
  vertexShader: vertexShader,
  // 定义我们使用了哪些属性
  attributes: {
    position: new Cesium.Attribute("vec3"),
    normal: new Cesium.Attribute("vec3"),
    texCoord: new Cesium.Attribute("vec2"),
  },
  // 定义要传递给片元着色器的 Varyings
  varyings: {
    v_texCoord: new Cesium.Varying("vec2"),
    v_normal: new Cesium.Varying("vec3"),
  },
});

2. Uniforms

Uniforms 是全局常量 ,对于所有顶点和片元都是相同的值。它们可以来自 Cesium 自动提供的 czm_ 系列内置变量,也可以是你自己定义的。

A. 内置 Uniforms (Cesium Provided)

Cesium 提供了一个庞大的内置 Uniform 库,以 czm_ 为前缀。它们在 cesium_modules 中自动可用。

常用内置 Uniforms 举例:

Uniform 名 类型 描述
czm_frame float 当前的帧号。可用于与时间相关的动画。
czm_model mat4 模型矩阵。将模型空间坐标转换为世界坐标。
czm_modelView mat4 模型视图矩阵。将模型空间坐标转换为眼睛坐标(相机空间)。
czm_projection mat4 投影矩阵。将眼睛坐标转换为裁剪坐标。
czm_modelViewProjection mat4 模型视图投影矩阵。将模型空间坐标直接转换为裁剪坐标。
czm_worldToModel mat4 世界坐标到模型坐标的逆矩阵。
czm_encodedCameraPositionMCD vec4 相机在模型空间中的编码位置,用于高精度渲染。

示例代码:使用内置 Uniform 进行变换

ini 复制代码
void vertexMain() {
  // 标准变换:将模型空间坐标转换为裁剪坐标
  positionMC = position;
  positionWC = (czm_model * vec4(position, 1.0)).xyz; // 世界坐标
  gl_Position = czm_modelViewProjection * vec4(position, 1.0);
}

B. 自定义 Uniforms

你可以定义自己的 Uniforms,并在运行时从 JavaScript 更新它们的值。

示例代码:自定义时间 Uniform

ini 复制代码
const vertexShader = `
  uniform float u_time;
  uniform float u_speed;
  uniform float u_amplitude;

  in vec3 position;

  void vertexMain() {
    // 使用自定义的 Uniforms 来控制波动效果
    float offset = sin(position.x * u_speed + u_time) * u_amplitude;
    vec3 modifiedPosition = position + vec3(0.0, offset, 0.0);
    positionMC = modifiedPosition;
  }
`;

const customShader = new Cesium.CustomShader({
  vertexShader: vertexShader,
  uniforms: {
    u_time: {
      type: Cesium.UniformType.FLOAT,
      value: 0.0,
    },
    u_speed: {
      type: Cesium.UniformType.FLOAT,
      value: 5.0,
    },
    u_amplitude: {
      type: Cesium.UniformType.FLOAT,
      value: 0.2,
    },
  },
  // ... 其他配置
});

// 在渲染循环中更新 uniform
viewer.scene.preRender.addEventListener(function (scene, time) {
  customShader.setUniform("u_time", Cesium.JulianDate.toDate(time).getTime() / 1000.0);
});

3. Varyings

Varyings 本身不是数据来源 ,而是数据从顶点着色器传递到片元着色器的通道。你在顶点着色器中计算出的、需要在片元着色器中使用的逐顶点数据,必须通过 Varyings 来传递。

关键点:

  • 在顶点着色器中写入 Varying。
  • 在片元着色器中读取同一个 Varying(它会经过光栅化插值)。
  • 必须在 CustomShadervaryings 配置中声明。

示例:

上面的第一个代码示例已经展示了如何定义和使用 v_texCoordv_normal 这两个 varyings。

4. 特殊数据源

A. 纹理 (Textures as Uniforms)

你可以将纹理(如高度图、噪声图)作为 Uniform 传入,并在顶点着色器中采样。虽然顶点着色器通常不大量采样纹理,但这是一个非常强大的技术,常用于:

  • 顶点置换:使用高度图或噪声图来偏移顶点位置。
  • 动态地形

示例代码:使用噪声纹理

ini 复制代码
uniform sampler2D u_noiseTexture;
in vec3 position;
in vec2 texCoord;

void vertexMain() {
  // 采样噪声纹理(注意:texCoord 可能需要在模型表面展开)
  vec4 noise = texture(u_noiseTexture, texCoord * 5.0); // 缩放纹理坐标
  // 使用噪声的r通道来偏移y轴
  vec3 modifiedPosition = position + vec3(0.0, noise.r * 0.5, 0.0);
  positionMC = modifiedPosition;
}

在 JavaScript 中,你需要将 u_noiseTexture 定义为一个 UniformType.SAMPLER_2D 并为其设置一个图像资源。

B. 批次表 (Batch Table)

对于 3D Tiles,batchId 属性可以与 czm_batchTable 函数结合,来获取每个要素的特定属性。

ini 复制代码
in float batchId;

void vertexMain() {
  // 从批次表中获取一个名为 "Height" 的属性
  float height = czm_batchTable_getProperty(batchId, "Height");
  // 使用这个属性来影响顶点
  vec3 modifiedPosition = position;
  modifiedPosition.y += height;
  positionMC = modifiedPosition;
}

总结

Cesium 顶点着色器的数据来源非常丰富,可以归纳为:

类别 关键点 主要用途
Attributes 逐顶点,来自原始模型 获取每个顶点的位置、法线、UV等基础信息。
Built-in Uniforms 全局,Cesium 自动提供 进行坐标变换、获取时间、相机位置等上下文信息。
Custom Uniforms 全局,由开发者定义 从 JavaScript 端传入控制参数(如时间、强度、颜色)。
Textures 作为 Uniform 传入 提供复杂的、基于图像的数据来影响顶点(如高度图、噪声)。
Batch Table 通过 batchId 属性访问 在 3D Tiles 中,根据要素ID获取其属性数据。
Varyings 顶点到片元的桥梁 将顶点着色器的计算结果(如新的法线、自定义数据)传递给片元着色器。
相关推荐
玉宇夕落3 小时前
🌌用CSS3打造“星球大战”片头:前端是代码界的导演,让文字在星空中翻滚
前端·javascript
colorFocus3 小时前
Promise与async/await的接口串联和并联
前端·javascript
Happy coder3 小时前
【avalonia教程】17mvvm简介、command
前端·javascript·vue.js
老前端的功夫4 小时前
Webpack 优化:你的构建速度其实还能快10倍
前端·javascript
Lsx_4 小时前
ECharts 全局触发click点击事件(柱状图、折线图增大点击范围)
前端·javascript·echarts
不吃香菜的猪4 小时前
构建时变量注入:Vite 环境下 SCSS 与 JavaScript 的变量同步机制
前端·javascript·scss
一枚前端小能手4 小时前
🚀 Node.js 25重磅发布!快来看看吧
前端·javascript·node.js
濑户川4 小时前
Vue3 项目创建指南(Vue-CLI vs Vite 对比)
前端·javascript·vue.js
Mintopia4 小时前
🌌 元宇宙 Web 场景中,AIGC 驱动的虚拟内容生成技术
前端·javascript·aigc