Source: modules/model/ModelSwapAnimator.js

import * as Cesium from "cesium";

export class ModelSwapAnimator {

    /**
     * Constructor for the ModelSwapAnimator class.
     * @constructor
     * @param viewer Cesium Viewer instance.
     * @param options
     */
    constructor(viewer, options) {
        this.viewer = viewer;
        this.options = options || {};
        this.center = options.center || Cesium.Cartesian3.fromDegrees(127.3839550536586, 36.46552371257934);
        this.currentModel = null;
    }

    async loadModel(url, maxValue = 1.0) {
        const viewer = this.viewer;

        const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(this.center);
        const model = await Cesium.Model.fromGltfAsync({
            url: url,
            modelMatrix: modelMatrix,
            upAxis: Cesium.Cartesian3.UNIT_Z,
            forwardAxis: Cesium.Cartesian3.UNIT_X,
        });

        const customShader = new Cesium.CustomShader({
            lightingModel: Cesium.LightingModel.UNLIT,
            uniforms: {
                u_maxValue: {
                    type: Cesium.UniformType.FLOAT,
                    value: maxValue,
                },
            },
            fragmentShaderText: `
              //uniform float u_maxValue;
            
              float linearOpacity(float value) {
                float minValue = 0.0;
                float maxValue = u_maxValue;
                float opacity = (value - minValue) / (maxValue - minValue);
                return clamp(opacity, 0.0, 1.0);
              }
            
              vec3 colorRamp(vec3 color1, vec3 color2, vec3 color3, float value) {
                float minValue = 0.0;
                float maxValue = u_maxValue;
                vec3 finalColor;
                if (value <= minValue) {
                    finalColor = color1;
                } else if (value >= maxValue) {
                    finalColor = color3;
                } else {
                    float mid = (minValue + maxValue) * 0.5;
            
                    if (value < mid) {
                        float t = (value - minValue) / (mid - minValue);
                        finalColor = mix(color1, color2, t);
                    } else {
                        float t = (value - mid) / (maxValue - mid);
                        finalColor = mix(color2, color3, t);
                    }
                }
                return finalColor;
              }
            
              float unpackDepth(const in vec4 rgba_depth) {
                return dot(rgba_depth, vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));
              }
            
              float decode2(vec4 color) {
                return color.r * 256.0 * 256.0 * 256.0 +
                       color.g * 256.0 * 256.0 +
                       color.b * 256.0 +
                       color.a;
              }
              
              float decode(vec4 color) {
                return color.a * 256.0 * 256.0 * 256.0 +
                       color.b * 256.0 * 256.0 +
                       color.g * 256.0 +
                       color.r;
              }
              
              void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
                vec4 color = vec4(material.diffuse, material.alpha);
                
                float value = unpackDepth(color);

                vec3 color1 = vec3(1.0, 0.0, 0.0);
                vec3 color2 = vec3(0.0, 1.0, 0.0);
                vec3 color3 = vec3(0.0, 0.0, 1.0);
                
                material.diffuse = colorRamp(color3, color2, color1, value);
                material.alpha = linearOpacity(value);
              }
            `,
        });
        model.customShader = customShader;

        viewer.scene.primitives.add(model);

        model.readyEvent.addEventListener(() => {

            const currentModel = this.currentModel;
            if (currentModel) {
                viewer.scene.primitives.remove(currentModel);
            }
            this.currentModel = model;
        });
    }
}