Cesium 着色器代码 CustomShader 动态更新参数

1,233 阅读1分钟

在 cesium 中,CustomShader 是一个相对底层的Api,基本深入开发 cesium 的同学多多少少会和这个 Api 有所接触。

具体使用文档请参考

CustomShader文档

本篇文章的主题是动态更新参数,在CustomShader中动态更新参数,需要了解 uniforms 对象。下表是 uniforms 对象支持的格式。

UniformTypeGLSL typeJS type
FLOATfloatNumber
VEC2vec2Cartesian2
VEC3vec3Cartesian3
VEC4vec4Cartesian4
INTintNumber
INT_VEC2ivec2Cartesian2
INT_VEC3ivec3Cartesian3
INT_VEC4ivec4Cartesian4
BOOLboolBoolean
BOOL_VEC2bvec2Cartesian2
BOOL_VEC3bvec3Cartesian3
BOOL_VEC4bvec4Cartesian4
MAT2mat2Matrix2
MAT3mat3Matrix3
MAT4mat4Matrix4
SAMPLER_2Dsampler2DTextureUniform

CustomShader 可以被用在 Cesium3DTileset、Model、等对象中,这里的 Model 也可以是从 layer 中获取的,例如 const modal = layer.getModel()

const customShader = new Cesium.CustomShader(/* ... */);

// Applying to all tiles in a tileset.
const tileset = await Cesium.Cesium3DTileset.fromUrl(
  "http://example.com/tileset.json", {
    customShader: customShader
});
viewer.scene.primitives.add(tileset);

// Applying to a model directly
const model = await Cesium.Model.fromGltfAsync({,
  url: "http://example.com/model.gltf",
  customShader: customShader
});

现在我们假设使用的是从 const modal = layer.getModel() 这里获取的 modal 对象,然后修改 modal 对象中的 customShader。

    const textureUniformShader = new Cesium.CustomShader({
        uniforms: {
            u_texture: {
                type: Cesium.UniformType.SAMPLER_2D,
                value: new Cesium.TextureUniform({
                    url: urlBack,
                    repeat: false,
                }),
            },
            u_time: {
                type: Cesium.UniformType.FLOAT,
                value: 0,
            },
        },
        vertexShaderText: `
        void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
            // v_normalMC = vsInput.attributes.positionMC;
            // vsOutput.positionMC.y = 12.8 * vsInput.attributes.positionMC.y;
            // vsOutput.positionMC.x = 12.8 * vsInput.attributes.positionMC.x;

            // This model's x and y coordinates are in the range [0, 1], which
            // conveniently doubles as UV coordinates.
            vec2 uv = vsInput.attributes.positionMC.xy;
            // Make the point cloud undulate in a complex wave that varies in
            // both space and time. The amplitude is based on the original shape
            // of the point cloud (which already is a wavy surface). The wave
            // is computed relative to the center of the model, hence the
            // transformations from [0, 1] -> [-1, 1] -> [0, 1]
            float amplitude = 2.0 * vsInput.attributes.positionMC.z - 1.0;
            float wave = amplitude * sin(2.0 * czm_pi * uv.x - 2.0 * u_time) * sin(u_time);
            vsOutput.positionMC.z = 0.5 + 0.5 * wave;
            // Make the points pulse in and out by changing their size
            vsOutput.pointSize = 10.0 + 5.0 * sin(u_time);
        }`,
        fragmentShaderText: `
            void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material)
            {
            // Make the points circular instead of square
                // float
            // Make a sinusoid color palette that moves in the general direction
            // of the wave, but at a different speed.
            // Coefficients were chosen arbitrarily
            vec2 uv = fsInput.attributes.positionMC.xy;
            material.diffuse = 0.2 * fsInput.attributes.color_0.rgb;
            material.diffuse += vec3(0.2, 0.3, 0.4) + vec3(0.2, 0.3, 0.4) * sin(2.0 * czm_pi * vec3(3.0, 2.0, 1.0) * uv.x - 3.0 * u_time);
        }
        `,
    });

    const startTime = performance.now();
    viewer.scene.postUpdate.addEventListener(function () {
        const elapsedTimeSeconds = (performance.now() - startTime) / 1000;
        textureUniformShader.setUniform("u_time", elapsedTimeSeconds);
        modal.customShader = textureUniformShader
    });

通过使用 setUniform textureUniformShader.setUniform("u_time", elapsedTimeSeconds); 来修改和更新参数值。