mcpField
C
cesiumjs-materials-shaders

cesiumjs-materials-shaders

github.com/cesiumgs开发193217 次安装6 周前更新
代码仓库

关于 cesiumjs-materials-shaders

面向 CesiumJS 开发者的材质、着色器与后期处理指南,介绍 Fabric 材质、自定义着色器、图像照明和屏幕空间处理阶段。

主要功能

  1. 01为 Primitive 创建 Fabric 材质
  2. 02使用 CustomShader 注入 GLSL
  3. 03配置基于图像的照明
  4. 04添加内置或自定义后期处理阶段

适用场景

  1. 01为 Primitive 表面应用图案或纹理
  2. 02用 GLSL 自定义模型或瓦片集渲染
  3. 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 },
});

性能提示

  1. 内置类型优先使用 Material.fromType()——缓存的着色器程序可避免重新编译。
  2. 纹理材质使用 Material.fromTypeAsync(),以避免默认纹理闪烁。
  3. 将 PostProcessStage.textureScale 设为小于 1.0 的值(例如 0.5),以减少高开销阶段处理的像素数。
  4. 禁用未使用的内置阶段(bloom.enabled = false)——启用的阶段会占用 GPU 资源。
  5. 将效果合并到 PostProcessStageComposite 中,以减少中间纹理分配。
  6. 尽量减少 PostProcessStage 数量——每个阶段都需要一次全屏绘制调用和一个帧缓冲区。

另请参阅

  • cesiumjs-custom-shader —— 为 Model.customShader、Cesium3DTileset.customShader、VoxelPrimitive.customShader 编写 GLSL(结构体参考、元数据、要素 ID)
  • cesiumjs-primitives —— Primitive API 对象的几何体、外观和材质应用
  • cesiumjs-3d-tiles —— Cesium3DTileset 加载与样式设置
  • cesiumjs-models-particles —— 模型加载与 glTF

评论

支持 Markdown