关于 cesiumjs-materials-shaders
面向 CesiumJS 开发者的材质、着色器与后期处理指南,介绍 Fabric 材质、自定义着色器、图像照明和屏幕空间处理阶段。
主要功能
- 01为 Primitive 创建 Fabric 材质
- 02使用 CustomShader 注入 GLSL
- 03配置基于图像的照明
- 04添加内置或自定义后期处理阶段
适用场景
- 01为 Primitive 表面应用图案或纹理
- 02用 GLSL 自定义模型或瓦片集渲染
- 03添加泛光、模糊或轮廓效果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cesiumgs/ cesiumjs-skills --skill cesiumjs-materials-shaders安装后在 Claude Code 中输入/cesiumjs-materials-shaders确认已加载。
详细介绍
CesiumJS 材质、着色器与后期处理
版本基线:CesiumJS 1.144(2026 年 8 月)。所有导入均使用 ES 模块风格。
材质系统(Fabric JSON)
Material 通过名为 Fabric 的 JSON 模式定义 图元 的表面外观。材质会编译为 GLSL,并由 MaterialAppearance 或 PolylineMaterialAppearance 使用。
材质的图像加载期间,CesiumJS 会渲染占位纹理,默认颜色为白色。从 1.144 版开始,静态属性 Texture.defaultColor 可以更改该占位颜色,避免材质构建期间出现白色闪烁。请注意,Texture 类在运行时公开,但未包含在已发布的 TypeScript 定义中,因此 TypeScript 调用方需要进行类型转换。
内置材质类型
表面: Color(颜色)、Image(图像、重复)、DiffuseMap、AlphaMap、SpecularMap、EmissionMap(图像、通道、重复)、BumpMap、NormalMap(图像、通道、强度、重复)。
图案: Grid(颜色、单元格透明度、线数、线宽)、Stripe(偶数颜色、奇数颜色、重复)、Checkerboard(浅色、深色、重复)、Dot(浅色、深色、重复)。
效果: Water(基础水色、混合颜色、法线贴图、频率、动画速度、振幅)、RimLighting(颜色、边缘光颜色、宽度)、Fade(淡入颜色、淡出颜色、最大距离)。
地形: ElevationContour(颜色、间距、宽度)、ElevationRamp(图像、最小高度、最大高度)。
折线: PolylineArrow(颜色)、PolylineDash(颜色、间隙颜色、虚线长度、虚线图案)、PolylineGlow(颜色、发光强度、渐隐强度)、PolylineOutline(颜色、轮廓颜色、轮廓宽度)。
创建材质
import { Material, Color, Cartesian2 } from "cesium";
// Shorthand with fromType (preferred for built-in types)
const colorMat = Material.fromType("Color", { color: new Color(1.0, 0.0, 0.0, 0.5) });
// Full Fabric notation
const gridMat = new Material({
fabric: {
type: "Grid",
uniforms: { color: Color.GREEN, cellAlpha: 0.1, lineCount: new Cartesian2(8, 8) },
},
});
// Async loading -- awaits textures before first frame, no flicker
const imageMat = await Material.fromTypeAsync("Image", { image: "./textures/facade.png" });
Fabric 材质用于图元外观。不要使用不存在的实体构造函数,例如 WaterMaterialProperty;要使用内置水材质,请创建 Material.fromType("Water", ...),并通过 Primitive 上的 MaterialAppearance 应用。
使用 GLSL 源代码自定义 Fabric
使用 source 编写内联 GLSL。着色器中可按名称访问在 uniforms 中声明的 uniform。
import { Material, Color } from "cesium";
const pulseMaterial = new Material({
fabric: {
uniforms: { color: Color.CYAN, speed: 2.0 },
source: `czm_material czm_getMaterial(czm_materialInput materialInput) {
czm_material material = czm_getDefaultMaterial(materialInput);
float pulse = sin(czm_frameNumber * speed * 0.01) * 0.5 + 0.5;
material.diffuse = color.rgb;
material.alpha = color.a * pulse;
return material;
}`,
},
translucent: true,
});
将材质应用于图元
import { Primitive, GeometryInstance, RectangleGeometry, Rectangle,
MaterialAppearance, Material, Color, Cartesian2 } from "cesium";
viewer.scene.primitives.add(new Primitive({
geometryInstances: new GeometryInstance({
geometry: new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-100, 30, -90, 40) }),
}),
appearance: new MaterialAppearance({
material: Material.fromType("Checkerboard", {
lightColor: Color.WHITE, darkColor: Color.BLACK, repeat: new Cartesian2(4, 4),
}),
}),
}));
合成子材质(Fabric materials + components)
import { Material, Color } from "cesium";
const compositeMat = new Material({ fabric: {
materials: {
gridMaterial: { type: "Grid" },
colorMaterial: { type: "Color", uniforms: { color: Color.BLUE } },
},
components: {
diffuse: "gridMaterial.diffuse + 0.2 * colorMaterial.diffuse",
alpha: "min(gridMaterial.alpha, colorMaterial.alpha)",
},
}});
CustomShader
CustomShader 会将用户 GLSL 注入 Model、Cesium3DTileset 和 VoxelPrimitive 渲染中,并可访问顶点属性、要素 ID 和 EXT_structural_metadata。
着色器编写相关内容——结构体参考、元数据访问、要素 ID、体素子集、1.139 版破坏性变更以及七个示例,请参阅 cesiumjs-custom-shader skill。 该 skill 负责 CustomShader 集成接口;着色器编写的详细内容则位于其中。
最简示例:
import { CustomShader, Model } from "cesium";
const shader = new CustomShader({
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
material.diffuse = vec3(1.0, 0.5, 0.0);
}
`,
});
const model = await Model.fromGltfAsync({ url: "./building.glb", customShader: shader });
viewer.scene.primitives.add(model);
ImageBasedLighting
控制 Model 和 Cesium3DTileset 的 PBR 基于图像的照明。imageBasedLightingFactor(Cartesian2)将漫反射(x)和镜面反射(y)缩放至 0 到 1。漫反射来自 sphericalHarmonicCoefficients(包含 9 个 Cartesian3、对应 L0-L2 的数组)。镜面反射来自 specularEnvironmentMaps(指向 KTX2 立方体贴图的 URL)。
import { ImageBasedLighting, Model, Cartesian2, Cartesian3 } from "cesium";
const coefficients = [ // 9 Cartesian3 values for L0..L2 bands
new Cartesian3(0.35, 0.35, 0.38), new Cartesian3(0.11, 0.11, 0.11),
new Cartesian3(0.04, 0.04, 0.04), new Cartesian3(-0.08, -0.08, -0.08),
new Cartesian3(-0.02, -0.02, -0.02), new Cartesian3(0.04, 0.04, 0.04),
new Cartesian3(-0.06, -0.06, -0.06), new Cartesian3(0.01, 0.01, 0.01),
new Cartesian3(-0.03, -0.03, -0.03),
];
const ibl = new ImageBasedLighting({
imageBasedLightingFactor: new Cartesian2(1.0, 1.0),
sphericalHarmonicCoefficients: coefficients,
specularEnvironmentMaps: "./environment/specular.ktx2",
});
const model = await Model.fromGltfAsync({ url: "./helmet.glb", imageBasedLighting: ibl });
viewer.scene.primitives.add(model);
// Disable: model.imageBasedLighting.imageBasedLightingFactor = new Cartesian2(0.0, 0.0);
后期处理
通过 viewer.scene.postProcessStages(PostProcessStageCollection)进行屏幕空间处理。各阶段按顺序执行;每个阶段都会读取 colorTexture 和 depthTexture。
内置效果(PostProcessStageLibrary)
所有工厂函数都会返回阶段复合对象,必须通过 viewer.scene.postProcessStages.add() 添加。
createBloomStage()(contrast、brightness、glowOnly、delta、sigma、stepSize)、createBlurStage()(delta、sigma、stepSize)、createDepthOfFieldStage()(focalDistance、delta、sigma、stepSize)、createEdgeDetectionStage()(color、length)、createSilhouetteStage([edgeStage])(将边缘检测阶段封装为轮廓复合对象)、createBlackAndWhiteStage()(gradations)、createBrightnessStage()(brightness)、createNightVisionStage()、createLensFlareStage()(intensity、distortion、ghostDispersal、haloWidth)。
通过工厂创建 Bloom(使用此方法,通过 postProcessStages.add 添加独立的 Bloom 实例):
import { PostProcessStageLibrary } from "cesium";
const bloom = viewer.scene.postProcessStages.add(
PostProcessStageLibrary.createBloomStage()
);
bloom.enabled = true;
bloom.uniforms.contrast = 128.0;
bloom.uniforms.brightness = -0.3;
bloom.uniforms.glowOnly = false;
bloom.uniforms.delta = 1.0;
bloom.uniforms.sigma = 3.78;
bloom.uniforms.stepSize = 5.0;
通过工厂创建 Silhouette(将边缘检测阶段传入轮廓复合对象):
import { PostProcessStageLibrary, Color } from "cesium";
const edgeStage = PostProcessStageLibrary.createEdgeDetectionStage();
edgeStage.uniforms.color = Color.YELLOW;
edgeStage.uniforms.length = 0.25;
const silhouette = PostProcessStageLibrary.createSilhouetteStage([edgeStage]);
viewer.scene.postProcessStages.add(silhouette);
集合阶段(Bloom、AO、FXAA、色调映射)
该集合提供始终存在的内置复合对象,包括 Bloom、环境光遮蔽和 FXAA——这些对象无需调用 add()。色调映射默认为 PBR_NEUTRAL。
import { Tonemapper, PostProcessStageLibrary } from "cesium";
// Bloom (collection shortcut — always present, no add() needed)
viewer.scene.postProcessStages.bloom.enabled = true;
viewer.scene.postProcessStages.bloom.uniforms.contrast = 128.0;
viewer.scene.postProcessStages.bloom.uniforms.brightness = -0.3;
// Ambient Occlusion (HBAO)
viewer.scene.postProcessStages.ambientOcclusion.enabled = true;
viewer.scene.postProcessStages.ambientOcclusion.uniforms.intensity = 3.0;
// FXAA
viewer.scene.postProcessStages.fxaa.enabled = true;
// Tonemapping: REINHARD, MODIFIED_REINHARD, FILMIC, ACES, PBR_NEUTRAL (default)
viewer.scene.postProcessStages.tonemapper = Tonemapper.ACES;
viewer.scene.postProcessStages.exposure = 1.2; // <1 darker, >1 brighter
// Depth of field (added via library)
const dof = viewer.scene.postProcessStages.add(
PostProcessStageLibrary.createDepthOfFieldStage()
);
dof.uniforms.focalDistance = 500.0; // meters from camera
dof.uniforms.sigma = 3.8;
**夜景/Bloom 视觉评估:**Bloom 应让明亮的城市灯光发出光晕,同时保留 周围区域的暗部。如果夜景图像下方存在 OSM 底图,请降低底图的
alpha/brightness,并谨慎使用 Bloom(将brightness设得更负、降低曝光), 以免标签和陆地泛白。浅色日间地图叠加黄色雾霾效果,不算成功的夜景灯光渲染。
自定义 PostProcessStage
自定义阶段会接收 colorTexture、depthTexture(sampler2D)和 v_textureCoordinates(vec2)。通过 out_FragColor 输出。Uniforms 可以是常量或函数(每帧重新求值)。
import { PostProcessStage } from "cesium";
const sepia = viewer.scene.postProcessStages.add(new PostProcessStage({
fragmentShader: `
uniform sampler2D colorTexture; in vec2 v_textureCoordinates; uniform float intensity;
void main() {
vec4 c = texture(colorTexture, v_textureCoordinates);
float gray = dot(c.rgb, vec3(0.299, 0.587, 0.114));
out_FragColor = vec4(mix(c.rgb, gray * vec3(1.2, 1.0, 0.8), intensity), c.a);
}`,
uniforms: { intensity: () => 0.8 }, // function uniform, re-evaluated each frame
}));
高亮选中要素
在片元着色器中使用 czm_selected(),并将要素赋给 stage.selected。
import { PostProcessStage, Color } from "cesium";
const highlight = viewer.scene.postProcessStages.add(new PostProcessStage({
fragmentShader: `
uniform sampler2D colorTexture; in vec2 v_textureCoordinates; uniform vec4 highlight;
void main() {
vec4 color = texture(colorTexture, v_textureCoordinates);
if (czm_selected()) {
out_FragColor = vec4(mix(color.rgb, highlight.rgb, highlight.a), 1.0);
} else { out_FragColor = color; }
}`,
uniforms: { highlight: () => new Color(1.0, 1.0, 0.0, 0.5) },
}));
highlight.selected = [pickedFeature];
PostProcessStageComposite
import { PostProcessStage, PostProcessStageComposite, PostProcessStageLibrary } from "cesium";
const blur = PostProcessStageLibrary.createBlurStage();
const combine = new PostProcessStage({
fragmentShader: `
uniform sampler2D colorTexture; uniform sampler2D blurTexture;
in vec2 v_textureCoordinates;
void main() {
vec4 orig = texture(colorTexture, v_textureCoordinates);
vec4 blurred = texture(blurTexture, v_textureCoordinates);
out_FragColor = mix(orig, blurred, 0.5);
}`,
uniforms: { blurTexture: blur.name }, // reference another stage's output by name
});
viewer.scene.postProcessStages.add(new PostProcessStageComposite({
stages: [blur, combine],
inputPreviousStageTexture: false, // both read the original scene texture
}));
管理阶段
viewer.scene.postProcessStages.remove(sepia); // remove specific stage
dof.enabled = false; // disable without removing
viewer.scene.postProcessStages.removeAll(); // remove all custom stages
BlendingState
为 Primitive 的 Appearance.renderState 预定义的混合预设。
| 预设 | 效果 |
|---|---|
BlendingState.DISABLED | 不混合 |
BlendingState.ALPHA_BLEND | 标准 Alpha:src*srcA + dst*(1-srcA) |
BlendingState.PRE_MULTIPLIED_ALPHA_BLEND | 预乘:src + dst*(1-srcA) |
BlendingState.ADDITIVE_BLEND | 加法:src*srcA + dst |
import { MaterialAppearance, BlendingState, Material, Color } from "cesium";
const appearance = new MaterialAppearance({
material: Material.fromType("Color", { color: Color.RED.withAlpha(0.5) }),
renderState: { depthTest: { enabled: true }, blending: BlendingState.ALPHA_BLEND },
});
性能提示
- 内置类型优先使用
Material.fromType()——缓存的着色器程序可避免重新编译。 - 纹理材质使用
Material.fromTypeAsync(),以避免默认纹理闪烁。 - 将
PostProcessStage.textureScale设为小于 1.0 的值(例如 0.5),以减少高开销阶段处理的像素数。 - 禁用未使用的内置阶段(
bloom.enabled = false)——启用的阶段会占用 GPU 资源。 - 将效果合并到
PostProcessStageComposite中,以减少中间纹理分配。 - 尽量减少
PostProcessStage数量——每个阶段都需要一次全屏绘制调用和一个帧缓冲区。
另请参阅
- cesiumjs-custom-shader —— 为
Model.customShader、Cesium3DTileset.customShader、VoxelPrimitive.customShader编写 GLSL(结构体参考、元数据、要素 ID) - cesiumjs-primitives —— Primitive API 对象的几何体、外观和材质应用
- cesiumjs-3d-tiles —— Cesium3DTileset 加载与样式设置
- cesiumjs-models-particles —— 模型加载与 glTF