在 Cesium 中,Material
是一个强大的工具,用于定义几何体外观。它允许开发者通过 顶点着色器(Vertex Shader)和 片段着色器(Fragment Shader)实现自定义效果。以下将从 Material 架构、着色器编程、以及 GPU 与 CPU 数据传递 等方面进行详解。
1. Cesium 的 Material 架构
在 Cesium 中,Material
是通过 GLSL 代码(WebGL 的着色器语言)实现的。Cesium 提供了一些预定义的 Material 类型(例如 ColorMaterialProperty
),也允许用户定义自定义着色器。
Material 的构成
- 顶点着色器(Vertex Shader):处理每个顶点的逻辑,计算顶点的变换(位置、法线等)。
- 片段着色器(Fragment Shader):处理每个片元的逻辑,定义像素的颜色、纹理等属性。
- Uniforms:从 CPU 向 GPU 传递的全局数据,通常是不变的值(如时间、模型矩阵)。
- Varyings:从顶点着色器传递到片段着色器的中间数据,用于共享信息。
- Attributes:每个顶点的数据(如位置、法线、颜色等)。
2. 自定义 Material 示例
以下是创建一个动态颜色渐变 Material 的示例。
// 创建自定义材质
const customMaterial = new Cesium.Material({fabric: {type: 'CustomMaterial', // 自定义类型名uniforms: {u_time: 0.0, // 时间参数(Uniform)u_color1: new Cesium.Color(1.0, 0.0, 0.0, 1.0), // 起始颜色u_color2: new Cesium.Color(0.0, 0.0, 1.0, 1.0), // 结束颜色},source: `// 顶点着色器代码czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);float mixRatio = abs(sin(u_time)); // 动态变化的混合因子material.diffuse = mix(u_color1.rgb, u_color2.rgb, mixRatio); // 颜色渐变material.alpha = 1.0; // 不透明return material;}`,},
});// 创建带自定义材质的实体
viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(0, 0, 0),ellipsoid: {radii: new Cesium.Cartesian3(500000.0, 500000.0, 500000.0),material: customMaterial, // 应用自定义材质},
});// 更新时间参数
viewer.clock.onTick.addEventListener(() => {customMaterial.uniforms.u_time += viewer.clock.deltaTime;
});
代码说明
fabric
定义了材质结构。uniforms
是从 CPU 传递到 GPU 的参数,支持动态更新。source
是 GLSL 着色器代码,定义了颜色渐变逻辑。
3. 顶点着色器详解
顶点着色器的主要作用是处理顶点数据并计算最终的顶点位置。
关键点
- 输入:
attributes
:顶点属性,如位置、法线、纹理坐标。uniforms
:全局常量参数。
- 输出:
gl_Position
:顶点在屏幕上的位置。varyings
:传递给片段着色器的数据。
示例
attribute vec3 position;
attribute vec3 normal;uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;varying vec3 vNormal;void main() {gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);vNormal = normal;
}
4. 片段着色器详解
片段着色器负责计算每个像素的颜色。
关键点
- 输入:
varyings
:从顶点着色器传递的数据。uniforms
:全局参数。
- 输出:
gl_FragColor
:最终片元颜色。
示例
varying vec3 vNormal;uniform vec3 lightDirection;void main() {float brightness = max(dot(normalize(vNormal), normalize(lightDirection)), 0.0);gl_FragColor = vec4(vec3(brightness), 1.0);
}
5. GPU 和 CPU 之间的数据传递
Cesium 提供了友好的接口来传递数据:
-
Uniforms:
- 用于传递全局数据,如时间、颜色、纹理等。
- 在
Material
中通过uniforms
字段定义。 - 动态更新方法:
customMaterial.uniforms.u_time = newValue;
-
Attributes:
- 每个顶点的数据,如位置、法线。
- Cesium 自动处理基本的顶点数据,但你也可以通过
Geometry
自定义。
-
Textures:
- Cesium 支持将纹理传递给 GPU,通常通过 Uniform 实现。
- 示例:
const texture = new Cesium.Texture({context: viewer.scene.context,source: imageElement, }); customMaterial.uniforms.u_texture = texture;
6. 着色器编程中的关键概念
1. 模型-视图-投影矩阵
- 用于将世界坐标系的顶点转换到屏幕坐标系。
- Cesium 自动为大多数几何体处理这些矩阵。
2. 法线和光照
- 在顶点着色器中计算法线,并传递给片段着色器以实现光照效果。
3. 颜色混合
- 使用 GLSL 的
mix
函数,可以实现颜色渐变或插值。
4. 动态效果
- 利用时间参数(
u_time
)可以实现波浪、脉冲等动态视觉效果。
7. 实现复杂效果的技巧
1. 多纹理混合
将多个纹理通过自定义逻辑混合,创建复杂的表面外观。
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float mixRatio;void main() {vec4 color1 = texture2D(texture1, gl_TexCoord[0].st);vec4 color2 = texture2D(texture2, gl_TexCoord[0].st);gl_FragColor = mix(color1, color2, mixRatio);
}
2. 法线贴图
使用法线贴图来模拟复杂的表面细节。
总结
- 顶点着色器:处理顶点位置,计算中间数据。
- 片段着色器:处理像素颜色,定义最终的视觉效果。
- GPU-CPU 数据传递:通过 Uniforms 和 Attributes 实现,Cesium 提供了友好的接口。
通过以上知识,可以在 Cesium 中实现丰富的自定义渲染效果!
Cesium 的后处理(Post-Processing)阶段是指在场景渲染完成后,对已经生成的帧缓冲区(Frame Buffer)进行处理,以添加视觉效果。常见的后处理效果包括 泛光、景深、色调映射、抗锯齿、模糊 等。
Cesium 支持后处理的实现主要通过 PostProcessStage,同时允许开发者自定义后处理管线。
1. 后处理的基础架构
渲染管线
Cesium 的渲染分为以下几个阶段:
- 几何阶段:将 3D 场景的几何数据通过顶点着色器和片段着色器渲染到帧缓冲区。
- 光照阶段:应用光照模型计算像素颜色。
- 后处理阶段:对帧缓冲区的结果应用额外的效果。
后处理的实现方式
Cesium 的后处理通过以下方式实现:
- 使用
PostProcessStage
对帧缓冲区中的像素进行操作。 - 使用
PostProcessStageComposite
将多个后处理阶段组合成一个管线。
2. Cesium 内置的后处理效果
Cesium 提供了一些常见的后处理效果:
1. 泛光(Bloom)
为高亮部分添加光晕效果。
const bloom = viewer.scene.postProcessStages.bloom;
bloom.enabled = true;
bloom.threshold = 0.8; // 高亮阈值
bloom.intensity = 2.0; // 光晕强度
2. 景深(Depth of Field)
模糊远处或近处的对象,模拟相机对焦效果。
const depthOfField = Cesium.PostProcessStageLibrary.createDepthOfFieldStage();
viewer.scene.postProcessStages.add(depthOfField);
depthOfField.enabled = true;
depthOfField.uniforms.focalDistance = 200.0; // 对焦距离
depthOfField.uniforms.delta = 1.5; // 模糊强度
depthOfField.uniforms.sigma = 2.0;
depthOfField.uniforms.stepSize = 5.0;
3. 色调映射(Tonemapping)
调整场景的亮度和对比度。
const tonemapping = Cesium.PostProcessStageLibrary.createTonemappingStage();
viewer.scene.postProcessStages.add(tonemapping);
tonemapping.enabled = true;
tonemapping.uniforms.brightness = 1.2; // 亮度
4. FXAA 抗锯齿
通过快速近似抗锯齿算法减少锯齿。
const fxaa = Cesium.PostProcessStageLibrary.createFXAA();
viewer.scene.postProcessStages.add(fxaa);
fxaa.enabled = true;
3. 自定义后处理效果
Cesium 允许通过自定义 GLSL 着色器创建新的后处理效果。
示例:实现灰度效果
将场景渲染为灰度图像。
const grayScaleStage = new Cesium.PostProcessStage({name: 'customGrayScale', // 阶段名称fragmentShader: `uniform sampler2D colorTexture;varying vec2 v_textureCoordinates;void main() {vec4 color = texture2D(colorTexture, v_textureCoordinates);float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); // 灰度公式gl_FragColor = vec4(vec3(gray), 1.0);}`,
});// 添加到场景
viewer.scene.postProcessStages.add(grayScaleStage);
代码解读
uniform sampler2D colorTexture
: 传入当前帧缓冲区的纹理。v_textureCoordinates
: 当前像素的纹理坐标。texture2D
: 从帧缓冲区中取出像素颜色。
4. 后处理阶段的管线组合
Cesium 提供了 PostProcessStageComposite
,用于将多个后处理阶段组合为一个管线。
示例:组合灰度和泛光
const grayScale = new Cesium.PostProcessStage({name: 'grayScale',fragmentShader: `uniform sampler2D colorTexture;varying vec2 v_textureCoordinates;void main() {vec4 color = texture2D(colorTexture, v_textureCoordinates);float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));gl_FragColor = vec4(vec3(gray), 1.0);}`,
});const bloom = Cesium.PostProcessStageLibrary.createBloomStage();const compositeStage = new Cesium.PostProcessStageComposite({stages: [grayScale, bloom],
});// 添加到场景
viewer.scene.postProcessStages.add(compositeStage);
5. GPU 与 CPU 数据交互
Uniforms
用于从 CPU 传递数据到 GLSL 着色器中,适合传递全局参数,例如时间、亮度。
示例
const customStage = new Cesium.PostProcessStage({name: 'timeBasedEffect',fragmentShader: `uniform sampler2D colorTexture;uniform float u_time;varying vec2 v_textureCoordinates;void main() {vec4 color = texture2D(colorTexture, v_textureCoordinates);float wave = abs(sin(u_time));gl_FragColor = vec4(color.rgb * wave, 1.0);}`,uniforms: {u_time: 0.0,},
});// 动态更新时间
viewer.scene.postProcessStages.add(customStage);
viewer.clock.onTick.addEventListener(() => {customStage.uniforms.u_time += viewer.clock.deltaTime;
});
Attributes
Cesium 的后处理阶段通常操作整个屏幕像素,因此主要通过 uniforms
传递全局数据。
6. 性能优化
- 避免过多的后处理阶段:
- 每个后处理阶段都会增加 GPU 的负载,尽量减少不必要的阶段。
- 降低分辨率:
- 可以通过降低后处理阶段的纹理分辨率来提高性能。
- 合并后处理阶段:
- 使用
PostProcessStageComposite
合并多个阶段,减少渲染开销。
- 使用
总结
Cesium 的后处理阶段是对场景渲染的补充和增强,通过 PostProcessStage
和 GLSL 着色器可以实现丰富的视觉效果。以下是关键点:
- 内置后处理效果:如泛光、景深、抗锯齿等。
- 自定义效果:通过 GLSL 自定义片段着色器实现独特的视觉效果。
- 性能优化:合理管理后处理阶段数量和复杂度。
熟练使用后处理技术,能极大提升 Cesium 应用的视觉表现力!
PostProcessStage
类是 Cesium 中用于实现后处理效果的核心类。后处理效果是指在渲染过程的最后阶段对场景进行的一些图像处理,例如泛光(bloom)、景深(depth of field)、色调映射(tonemapping)等。
PostProcessStage
类概述
PostProcessStage
允许开发者对渲染的帧进行后处理操作。它通过使用 GLSL 片段着色器(fragment shader)来改变场景的渲染结果。开发者可以通过 PostProcessStage
类来实现自定义的后处理效果,或者使用 Cesium 提供的内置后处理阶段。
1. PostProcessStage
类的结构和属性
主要属性
-
name (
String
):- 后处理阶段的名称,用于标识该阶段。
- 默认值为
""
。
-
fragmentShader (
String
):- 自定义的 GLSL 片段着色器代码,用于处理图像的像素。
- 如果没有指定
fragmentShader
,则需要设置 uniforms 和 textures。
-
uniforms (
Object
):- 一个对象,用于传递给着色器的参数。参数是从 CPU 到 GPU 的数据,通常是全局数据,如时间、颜色等。
- 例如:
uniforms: {u_time: 0.0, // 时间参数 }
-
enabled (
Boolean
):- 设置是否启用该后处理阶段。
- 默认为
true
,即启用。
-
clearColor (
Color
):- 如果该后处理阶段的渲染输出区域需要清除,可以使用该属性指定清除颜色。
- 默认为
undefined
,表示不清除。
-
inputTexture (
Texture
):- 输入纹理,通常为当前场景的帧缓冲区纹理。
- 默认情况下,
PostProcessStage
会使用 Cesium 的默认场景纹理。
2. 创建和应用后处理阶段
在 Cesium 中创建后处理阶段的步骤通常如下:
-
定义自定义着色器:
编写一个自定义的 GLSL 片段着色器,处理图像的颜色、模糊、变换等。 -
将后处理阶段添加到场景:
使用viewer.scene.postProcessStages.add()
方法将后处理阶段添加到场景中。
示例:自定义后处理效果(灰度化)
const grayScaleStage = new Cesium.PostProcessStage({name: 'customGrayScale',fragmentShader: `uniform sampler2D colorTexture;varying vec2 v_textureCoordinates;void main() {vec4 color = texture2D(colorTexture, v_textureCoordinates);float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); // 灰度公式gl_FragColor = vec4(vec3(gray), 1.0);}`,uniforms: {colorTexture: viewer.scene.frameState.context.getFramebufferTexture(),}
});// 将自定义灰度化后处理阶段添加到场景
viewer.scene.postProcessStages.add(grayScaleStage);
代码解读:
fragmentShader
:自定义 GLSL 代码,将颜色转换为灰度。uniforms
:将当前的帧缓冲纹理传递给着色器,colorTexture
是后处理阶段的输入纹理。PostProcessStage
创建后添加到场景中。
3. 内置的后处理阶段
Cesium 提供了一些常用的内置后处理效果,可以直接在场景中启用。这些内置阶段通过 PostProcessStageLibrary
提供。
常见的内置后处理效果:
-
Bloom(泛光):
用于突出显示高亮区域,模拟光晕效果。const bloom = viewer.scene.postProcessStages.bloom; bloom.enabled = true; bloom.threshold = 0.8; // 高亮阈值 bloom.intensity = 2.0; // 光晕强度
-
FXAA(快速近似抗锯齿):
用于减少图像的锯齿现象。const fxaa = Cesium.PostProcessStageLibrary.createFXAA(); viewer.scene.postProcessStages.add(fxaa); fxaa.enabled = true;
-
Depth of Field(景深):
模拟相机的景深效果,模糊远近对象。const depthOfField = Cesium.PostProcessStageLibrary.createDepthOfFieldStage(); viewer.scene.postProcessStages.add(depthOfField); depthOfField.enabled = true; depthOfField.uniforms.focalDistance = 200.0; // 对焦距离 depthOfField.uniforms.delta = 1.5; // 模糊强度 depthOfField.uniforms.sigma = 2.0;
-
Tonemapping(色调映射):
调整场景的亮度和对比度。const tonemapping = Cesium.PostProcessStageLibrary.createTonemappingStage(); viewer.scene.postProcessStages.add(tonemapping); tonemapping.enabled = true; tonemapping.uniforms.brightness = 1.2; // 亮度
4. 管理后处理阶段的顺序
多个后处理阶段可以通过 PostProcessStageComposite
类进行组合,按顺序处理图像。这样可以创建复杂的后处理效果。
示例:组合多个后处理阶段(灰度和泛光)
const grayScale = new Cesium.PostProcessStage({name: 'grayScale',fragmentShader: `uniform sampler2D colorTexture;varying vec2 v_textureCoordinates;void main() {vec4 color = texture2D(colorTexture, v_textureCoordinates);float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));gl_FragColor = vec4(vec3(gray), 1.0);}`,
});const bloom = Cesium.PostProcessStageLibrary.createBloomStage();const compositeStage = new Cesium.PostProcessStageComposite({stages: [grayScale, bloom], // 按顺序应用灰度和泛光效果
});// 将组合后的后处理阶段添加到场景
viewer.scene.postProcessStages.add(compositeStage);
代码解读:
PostProcessStageComposite
:将多个后处理阶段(如灰度和泛光)组合成一个处理管线。stages
:设置多个后处理阶段的顺序。
5. 性能优化
在使用后处理阶段时,尤其是自定义效果时,可能会面临性能问题。以下是一些优化建议:
- 减少后处理阶段的数量:每增加一个后处理阶段,GPU 渲染的负载就会增加,因此应尽量减少不必要的后处理阶段。
- 调整分辨率:可以通过将后处理阶段应用于较低分辨率的帧缓冲区,减少图像处理的开销。
- 批量处理:尽量将多个后处理阶段合并成一个处理管线,减少渲染状态切换。
6. 总结
PostProcessStage
是 Cesium 中一个非常重要的类,它允许开发者使用自定义的 GLSL 着色器和内置效果来处理渲染输出图像。通过 PostProcessStage,开发者可以实现各种后处理效果,如泛光、景深、色调映射等。使用 PostProcessStageComposite
,可以将多个后处理阶段组合起来,创建复杂的效果。
- 内置效果:如泛光、景深、抗锯齿等。
- 自定义效果:通过编写 GLSL 着色器来创建新的后处理效果。
- 性能考虑:合理控制后处理阶段的数量和复杂度。