首页
/ CesiumGS中自定义材质与外观的实践指南

CesiumGS中自定义材质与外观的实践指南

2025-05-17 06:55:32作者:薛曦旖Francesca

概述

在三维地理可视化领域,CesiumGS作为一款强大的开源JavaScript库,为开发者提供了丰富的功能来创建高性能的地理空间应用。其中,Material(材质)和MaterialAppearance(材质外观)系统是Cesium中实现自定义渲染效果的核心机制。本文将深入探讨如何通过这两个类实现GLSL着色器注入,为Primitive(图元)添加自定义视觉效果。

核心概念解析

1. Material系统

Material是Cesium中定义物体表面视觉特性的核心类,它通过Fabric规范来配置材质属性。Fabric规范允许开发者:

  • 定义材质类型(type)
  • 设置统一变量(uniforms)
  • 编写GLSL着色代码(source)
  • 配置其他材质参数(如translucent等)

2. MaterialAppearance类

MaterialAppearance继承自Appearance,专门用于处理材质化的外观表现。它提供了:

  • 顶点着色器和片段着色器的自定义能力
  • 材质与几何体的绑定机制
  • 光照和渲染状态的控制

实践案例:动态变色立方体

下面我们通过一个完整的示例,展示如何创建一个随时间动态变色的立方体。

1. 几何体创建

首先创建基础的立方体几何体:

const boxGeometry = Cesium.BoxGeometry.fromDimensions({
    dimensions: new Cesium.Cartesian3(25000.0, 25000.0, 25000.0)
});

const boxInstance = new Cesium.GeometryInstance({
    geometry: boxGeometry,
    modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(
        Cesium.Cartesian3.fromDegrees(113, 33, 1250)
    ),
    attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
            Cesium.Color.WHITE
        )
    }
});

2. 自定义材质实现

创建自定义材质,定义随时间变化的颜色效果:

const customMaterial = new Cesium.Material({
    translucent: false,
    fabric: {
        type: 'CustomBoxShader',
        uniforms: {
            time: 0.0,
        },
        source: `
            uniform float time;
            czm_material czm_getMaterial(czm_materialInput materialInput) {
                czm_material material = czm_getDefaultMaterial(materialInput);
                material.diffuse = vec3(1.0, 1.0, 0.0); 
                material.alpha = 1.0;
                return material;
            }`
    }
});

3. 材质外观配置

通过MaterialAppearance实现更复杂的着色器控制:

const appearance = new Cesium.MaterialAppearance({
    material: customMaterial,
    flat: false,
    faceForward: true,
    translucent: true,
    closed: true,
    vertexShaderSource: `
        in vec3 position3DHigh;
        in vec3 position3DLow;
        in vec3 normal;
        in vec2 st;
        in float batchId;
        out vec3 v_positionEC;
        out vec3 v_normalEC;
        out vec2 v_st;
        uniform float testAppUniform;
        void main() {
            vec4 p = czm_computePosition();
            v_positionEC = (czm_modelViewRelativeToEye * p).xyz * testAppUniform; 
            v_normalEC = czm_normal * normal; 
            v_st = st;
            gl_Position = czm_modelViewProjectionRelativeToEye * p;
        }`,
    fragmentShaderSource: `
        in vec3 v_positionEC;
        in vec3 v_normalEC;
        in vec2 v_st;
        uniform vec4 testAppColorUniform;
        void main() {
            vec3 positionToEyeEC = -v_positionEC;
            vec3 normalEC = normalize(v_normalEC);
            #ifdef FACE_FORWARD
                normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);
            #endif
            czm_materialInput materialInput;
            materialInput.normalEC = normalEC;
            materialInput.positionToEyeEC = positionToEyeEC;
            materialInput.st = v_st;
            czm_material material = czm_getMaterial(materialInput);
            #ifdef FLAT
                out_FragColor = vec4(material.diffuse + material.emission, material.alpha);
            #else
                out_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);
            #endif
            out_FragColor.rgb = out_FragColor.rgb * testAppColorUniform.rgb; 
            out_FragColor.a = testAppColorUniform.a; 
        }`,
    materialCacheKey: "my-box-material-appearance"
});

4. 动画效果实现

通过requestAnimationFrame实现动态效果:

function animate() {
    customMaterial.uniforms.time++;
    const t = customMaterial.un
登录后查看全文
热门项目推荐
相关项目推荐