Cesium实现动态水面效果

目录

1.使用Primitive实现动态水面效果

2.版本问题 


1.使用Primitive实现动态水面效果

     let points = [
        [87.07131373100303, 29.40857655725876],
        [87.33503858397042, 29.41843499494008],
        [87.33072496578943, 29.193059292424955],
        [87.05098771260403, 29.20286249623694],
      ];
      let polygonArr = [];
      points.map((ele) => {
        polygonArr.push(...ele, 0);
      });
      viewer.scene.primitives.add(
        new Cesium.Primitive({
          geometryInstances: new Cesium.GeometryInstance({
            geometry: new Cesium.PolygonGeometry({
              polygonHierarchy: new Cesium.PolygonHierarchy(
                Cesium.Cartesian3.fromDegreesArrayHeights(polygonArr)
              ),
              height: 4400,
            }),
          }),
          appearance: new Cesium.EllipsoidSurfaceAppearance({
            aboveGround: true,
            material: new Cesium.Material({
              fabric: {
                type: "Water",
                uniforms: {
                  normalMap: require("@/assets/img/waterdudv.jpg"),
                  frequency: 1000.0,
                  animationSpeed: 0.05,
                  amplitude: 10.0,
                },
              },
            }),
          }),
          show: true,
        })
      );
      viewer.scene.globe.depthTestAgainstTerrain = true;
      viewer.camera.setView({
        //定位到范围中心点
        destination: Cesium.Cartesian3.fromDegrees(
          87.07131373100303,
          29.40857655725876,
          12000
        ),
        orientation: {
          heading: Cesium.Math.toRadians(130.304929908965146), //1
          pitch: Cesium.Math.toRadians(-17.364771143804237),
          roll: 0.09931507517437696,
        },
      });

水面动态效果

示例代码1 

 DrawwaterFun3() {
      let points = [
        [87.07131373100303, 29.40857655725876],
        [87.33503858397042, 29.41843499494008],
        [87.33072496578943, 29.193059292424955],
        [87.05098771260403, 29.20286249623694],
      ];
      let polygonArr = [];
      points.map((ele) => {
        polygonArr.push(...ele, 0);
      });
      viewer.scene.primitives.add(
        new Cesium.Primitive({
          geometryInstances: new Cesium.GeometryInstance({
            geometry: new Cesium.PolygonGeometry({
              polygonHierarchy: new Cesium.PolygonHierarchy(
                Cesium.Cartesian3.fromDegreesArrayHeights(polygonArr)
              ),
              height: 4400,
            }),
          }),
          appearance: new Cesium.EllipsoidSurfaceAppearance({
            aboveGround: true,
            material: new Cesium.Material({
              fabric: {
                type: "Water",
                uniforms: {
                  normalMap: require("@/assets/img/waterdudv.jpg"),
                  frequency: 1000.0,
                  animationSpeed: 0.05,
                  amplitude: 10.0,
                },
              },
            }),
          }),
          show: true,
        })
      );
      viewer.scene.globe.depthTestAgainstTerrain = true;
      viewer.camera.setView({
        //定位到范围中心点
        destination: Cesium.Cartesian3.fromDegrees(
          87.07131373100303,
          29.40857655725876,
          12000
        ),
        orientation: {
          heading: Cesium.Math.toRadians(130.304929908965146), //1
          pitch: Cesium.Math.toRadians(-17.364771143804237),
          roll: 0.09931507517437696,
        },
      });
    }

水面动态效果

示例代码2

 DrawwaterFun2() {
      const riverPolygon = new Cesium.PolygonGeometry({
        polygonHierarchy: new Cesium.PolygonHierarchy(
          Cesium.Cartesian3.fromDegreesArray([
            140.0, 30.0, 0, 150.0, 30.0, 0, 150.0, 20.0, 0, 140.0, 20.0, 0,
          ])
        ),
        height: 20,
        extrudedHeight: 0,
        ellipsoid: Cesium.Ellipsoid.WGS84,
      });
      // 自定义材质
      const riverMaterial = new Cesium.Material({
        fabric: {
          type: "Water",
          uniforms: {
            // baseWaterColor: new Cesium.Color(64 / 255.0, 157 / 255.0, 253 / 255.0, 0.5),
            normalMap: require("@/assets/img/waterdudv.jpg"),
            frequency: 1000.0,
            animationSpeed: 0.1,
            amplitude: 10,
            specularIntensity: 10,
          },
        },
      });
      // 河道的riverPrimitive
      const riverPrimitive = new Cesium.Primitive({
        geometryInstances: new Cesium.GeometryInstance({
          id: "river",
          geometry: riverPolygon,
        }),
        appearance: new Cesium.EllipsoidSurfaceAppearance({
          material: riverMaterial,
        }),
        show: true,
        allowPicking: false,
        asynchronous: false,
      });
      viewer.scene.primitives.add(riverPrimitive);
      viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(150.0, 30.0, 10000000),
      });
    },

2024-01-24-16-57-53

示例代码3 

    DrawwaterFun() {
      this.viewer.scene.globe.depthTestAgainstTerrain = false;
      var waterPrimitive = new Cesium.Primitive({
        show: true, // 默认隐藏
        allowPicking: false,
        geometryInstances: new Cesium.GeometryInstance({
          geometry: new Cesium.PolygonGeometry({
            polygonHierarchy: new Cesium.PolygonHierarchy(
              Cesium.Cartesian3.fromDegreesArrayHeights([
                130.0, 30.0, 0, 150.0, 30.0, 0, 150.0, 10.0, 0, 130.0, 10.0, 0,
              ])
            ),
            vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
            //extrudedHeight: 0,//注释掉此属性可以只显示水面
            //perPositionHeight : true//注释掉此属性水面就贴地了
          }),
        }),
        // 可以设置内置的水面shader
        appearance: new Cesium.EllipsoidSurfaceAppearance({
          material: new Cesium.Material({
            fabric: {
              type: "Water",
              uniforms: {
                //baseWaterColor:new Cesium.Color(0.0, 0.0, 1.0, 0.5),
                //blendColor: new Cesium.Color(0.0, 0.0, 1.0, 0.5),
                //specularMap: 'gray.jpg',
                normalMap: require("@/assets/img/waterdudv.jpg"),
                //normalMap: "本地贴图地址 或 base64",
                frequency: 100000.0,
                animationSpeed: 0.5,
                amplitude: 10.0,
              },
            },
          }),
        }),
      });
      this.viewer.scene.primitives.add(waterPrimitive);

      this.viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(140, 20, 6000000.0),
        orientation: {
          heading: Cesium.Math.toRadians(0.0), //默认朝北0度,顺时针方向,东是90度
          pitch: Cesium.Math.toRadians(-90), //默认朝下看-90,0为水平看,
          roll: Cesium.Math.toRadians(0), //默认0
        },
      });
      return;
      // //1 创建 geometry
      // const polygon = new Cesium.PolygonGeometry({
      //   polygonHierarchy: new Cesium.PolygonHierarchy(
      //     Cesium.Cartesian3.fromDegreesArray([90, 40, 120, 40, 120, 30, 90, 30])
      //   ),
      // });
      // const geometry = Cesium.PolygonGeometry.createGeometry(polygon);
      // //2,创建geometryInstance
      // const instance = new Cesium.GeometryInstance({
      //   geometry: geometry,
      // });
      // //3,创建 material
      // var material = new Cesium.Material({
      //   fabric: {
      //     type: "Water",
      //     uniforms: {
      //       baseWaterColor: new Cesium.Color.fromCssColorString("#001165"),
      //       normalMap: require("@/assets/img/waterdudv.jpg"),
      //       specularMap: require("@/assets/img/water.jpg"),
      //       // blendColor: new Cesium.Color.fromCssColorString("#333"),
      //       frequency: 20000,
      //       animationSpeed: 0.1,
      //       amplitude: 50,
      //       specularIntensity: 0.5,
      //     },
      //   },
      // });
      // // 4 创建Appearance
      // var appearance = new Cesium.EllipsoidSurfaceAppearance({
      //   material: material,
      // });
      // let primitive = viewer.scene.primitives.add(
      //   new Cesium.Primitive({
      //     geometryInstances: instance,
      //     appearance: appearance,
      //     asynchronous: false,
      //   })
      // );
    },

2024-01-24-16-59-10

示例代码4

 DrawwaterFun5() {
      var box = new Cesium.BoxGeometry({
        vertexFormat: Cesium.VertexFormat.POSITION_NORMAL_AND_ST,
        maximum: new Cesium.Cartesian3(250000.0, 250000.0, 250000.0),
        minimum: new Cesium.Cartesian3(-250000.0, -250000.0, -250000.0),
      });
      var geometry = Cesium.BoxGeometry.createGeometry(box);

      let inst = new Cesium.GeometryInstance({
        geometry: geometry,
      });

      // 自定义材质
      let aper = new Cesium.MaterialAppearance({
        material: new Cesium.Material({
          fabric: {
            uniforms: {
              iTime: 0,
            },
            source: `
        const int NUM_STEPS = 8;
      const float PI     = 3.141592;
      const float EPSILON  = 1e-3;
      //#define EPSILON_NRM (0.1 / iResolution.x)
      #define EPSILON_NRM (0.1 / 200.0)
      // sea
      const int ITER_GEOMETRY = 3;
      const int ITER_FRAGMENT = 5;
      const float SEA_HEIGHT = 0.6;
      const float SEA_CHOPPY = 4.0;
      const float SEA_SPEED = 1.8;
      const float SEA_FREQ = 0.16;
      const vec3 SEA_BASE = vec3(0.1,0.19,0.22);
      const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
      //#define SEA_TIME (1.0 + iTime * SEA_SPEED)
      const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
      // math
      mat3 fromEuler(vec3 ang) {
        vec2 a1 = vec2(sin(ang.x),cos(ang.x));
        vec2 a2 = vec2(sin(ang.y),cos(ang.y));
        vec2 a3 = vec2(sin(ang.z),cos(ang.z));
        mat3 m;
        m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
        m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
        m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
        return m;
      }
      float hash( vec2 p ) {
        float h = dot(p,vec2(127.1,311.7));
        return fract(sin(h)*43758.5453123);
      }
      float noise( in vec2 p ) {
        vec2 i = floor( p );
        vec2 f = fract( p );
        vec2 u = f*f*(3.0-2.0*f);
        return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),
                 hash( i + vec2(1.0,0.0) ), u.x),
              mix( hash( i + vec2(0.0,1.0) ),
                 hash( i + vec2(1.0,1.0) ), u.x), u.y);
      }
      // lighting
      float diffuse(vec3 n,vec3 l,float p) {
        return pow(dot(n,l) * 0.4 + 0.6,p);
      }
      float specular(vec3 n,vec3 l,vec3 e,float s) {
        float nrm = (s + 8.0) / (PI * 8.0);
        return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
      }
      // sky
      vec3 getSkyColor(vec3 e) {
        e.y = max(e.y,0.0);
        return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4);
      }
      // sea
      float sea_octave(vec2 uv, float choppy) {
        uv += noise(uv);
        vec2 wv = 1.0-abs(sin(uv));
        vec2 swv = abs(cos(uv));
        wv = mix(wv,swv,wv);
        return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
      }
      float map(vec3 p) {
        float freq = SEA_FREQ;
        float amp = SEA_HEIGHT;
        float choppy = SEA_CHOPPY;
        vec2 uv = p.xz; uv.x *= 0.75;
        float d, h = 0.0;
        float SEA_TIME = 1.0 + iTime * SEA_SPEED;
        for(int i = 0; i < ITER_GEOMETRY; i++) {
          d = sea_octave((uv+SEA_TIME)*freq,choppy);
          d += sea_octave((uv-SEA_TIME)*freq,choppy);
          h += d * amp;
          uv *= octave_m; freq *= 1.9; amp *= 0.22;
          choppy = mix(choppy,1.0,0.2);
        }
        return p.y - h;
      }
      float map_detailed(vec3 p) {
        float freq = SEA_FREQ;
        float amp = SEA_HEIGHT;
        float choppy = SEA_CHOPPY;
        vec2 uv = p.xz; uv.x *= 0.75;
        float SEA_TIME = 1.0 + iTime * SEA_SPEED;
        float d, h = 0.0;
        for(int i = 0; i < ITER_FRAGMENT; i++) {
          d = sea_octave((uv+SEA_TIME)*freq,choppy);
          d += sea_octave((uv-SEA_TIME)*freq,choppy);
          h += d * amp;
          uv *= octave_m; freq *= 1.9; amp *= 0.22;
          choppy = mix(choppy,1.0,0.2);
        }
        return p.y - h;
      }
      vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
        float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0);
        fresnel = pow(fresnel,3.0) * 0.65;
        vec3 reflected = getSkyColor(reflect(eye,n));
        vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
        vec3 color = mix(refracted,reflected,fresnel);
        float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
        color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
        color += vec3(specular(n,l,eye,60.0));
        return color;
      }
      // tracing
      vec3 getNormal(vec3 p, float eps) {
        vec3 n;
        n.y = map_detailed(p);
        n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
        n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
        n.y = eps;
        return normalize(n);
      }
      float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
        float tm = 0.0;
        float tx = 1000.0;
        float hx = map(ori + dir * tx);
        if(hx > 0.0) return tx;
        float hm = map(ori + dir * tm);
        float tmid = 0.0;
        for(int i = 0; i < NUM_STEPS; i++) {
          tmid = mix(tm,tx, hm/(hm-hx));
          p = ori + dir * tmid;
          float hmid = map(p);
          if(hmid < 0.0) {
            tx = tmid;
            hx = hmid;
          } else {
            tm = tmid;
            hm = hmid;
          }
        }
        return tmid;
      }
           vec4 czm_getMaterial(vec2 vUv)
           {
            vec2 uv = vUv;
            uv = vUv * 2.0 - 1.0;
            float time = iTime * 0.3 + 0.0*0.01;
            // ray
            vec3 ang = vec3(0, 1.2, 0.0);
              vec3 ori = vec3(0.0,3.5,0);
            vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;
            dir = normalize(dir) * fromEuler(ang);
            // tracing
            vec3 p;
            heightMapTracing(ori,dir,p);
            vec3 dist = p - ori;
            vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
            vec3 light = normalize(vec3(0.0,1.0,0.8));
            // color
            vec3 color = mix(
              getSkyColor(dir),
              getSeaColor(p,n,light,dir,dist),
              pow(smoothstep(0.0,-0.05,dir.y),0.3));
               return vec4( pow(color,vec3(0.75)), 1.0 );
           }
        `,
          },
        }),
        translucent: true,
        vertexShaderSource: `
        in vec3 position3DHigh;
        in vec3 position3DLow;
        in float batchId;
        in vec2 st;
        in vec3 normal;
        out vec2 v_st;
        out vec3 v_positionEC;
        out vec3 v_normalEC;
        void main() {
            v_st = st;
            vec4 p = czm_computePosition();
            v_positionEC = (czm_modelViewRelativeToEye * p).xyz;      // position in eye coordinates
            v_normalEC = czm_normal * normal;                         // normal in eye coordinates
            gl_Position = czm_modelViewProjectionRelativeToEye * p;
        }
                    `,
        fragmentShaderSource: `
      in vec2 v_st;
      in vec3 v_positionEC;
      in vec3 v_normalEC;
      void main()  {
        vec3 positionToEyeEC = -v_positionEC;
        vec3 normalEC = normalize(v_normalEC);
        czm_materialInput materialInput;
        materialInput.normalEC = normalEC;
        materialInput.positionToEyeEC = positionToEyeEC;
        materialInput.st = v_st;
        vec4 color = czm_getMaterial(v_st);
        out_FragColor = color;
      }
                `,
      });

      let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
        Cesium.Cartesian3.fromDegrees(110, 40, 10)
      );

      viewer.scene.primitives.add(
        new Cesium.Primitive({
          geometryInstances: inst,
          appearance: aper,
          asynchronous: false,
          modelMatrix: modelMatrix,
        })
      );
      viewer.camera.flyToBoundingSphere(
        new Cesium.BoundingSphere(
          Cesium.Cartesian3.fromDegrees(110, 40, 10),
          950000
        ),
        {
          duration: 0.1,
        }
      );
      function renderLoop(timestamp) {
        aper.material.uniforms.iTime = timestamp / 1000;
        requestAnimationFrame(renderLoop);
      }
      renderLoop();
    },

2024-01-24-17-14-30

2.版本问题 

CesiumV1.113 出现的问题

 CesiumV1.111 出现的问题CesiumV1.112出现的问题

Cesium实现动态水面效果_第1张图片

CesiumV1.110 出现的问题Cesium实现动态水面效果_第2张图片

CesiumV1.109 出现的问题 

Cesium实现动态水面效果_第3张图片

在github上面找解决办法:
1.第一位说是多边形图元设置材质不起效果,后面cesium工作人员给了建议,试了效果也不好

2.第二位呢直接做了版本回退,测试了1.108、1.109、1.110,1.111,1.112,1.113几个版本,发现1.108版本效果正常

这个时候,我才知道版本问题,我刚开始用的是最新版本1.113,最新版本有这个bug,所以我也回退到1.108

Cesium实现动态水面效果_第4张图片

Cesium实现动态水面效果_第5张图片

 版本开始回退之后,我运行,地图加载不出来,报如下错,

 

Cesium实现动态水面效果_第6张图片

 在网上又找了办法,说是会请求cesium icon的资源,由于服务器在国外就会报错,得加自己的地图,我又改了下: 

    initCesium() {
      new Promise(async (resolve, reject) => {
        const imageryLayer = await new Cesium.ImageryLayer(
          new Cesium.UrlTemplateImageryProvider({
            url: "http://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
            minimumLevel: 1,
            maximumLevel: 18,
            crs: "WGS84", // 使用84坐标系,默认为:GCJ02
          })
        );
        this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
          selectionIndicator: false,
          infoBox: false,
          contextOptions: {
            msaaLevel: 8, // 硬件反走样,默认值为 1
            requestWebgl2: true,
            //requestWebgl1: true,
          },
          baseLayer: imageryLayer,
          animation: false,
          timeline: false, // 底部时间线
          fullscreenButton: false, // 全屏
          vrButton: false, // VR
          sceneModePicker: false, // 选择视角的模式(球体、平铺、斜视平铺)
          baseLayerPicker: false, // 图层选择器(地形影像服务)
          navigationHelpButton: false, // 导航帮助(手势,鼠标)
          geocoder: false, // 位置查找工具
          homeButton: false, // 视角返回初始位置
          shouldAnimate: true,
          shadows: true,
        });
        this.viewer.scene.globe.baseColor = Cesium.Color.BLACK; // 设置地球颜色
        this.viewer.scene.debugShowFramesPerSecond = true;
        this.viewer.cesiumWidget.creditContainer.style.display = "none"; // 去除logo
        window.viewer = this.viewer;
        this.DrawOnLineGaoDeMapFun();
        //this.DrawOnlineTdtMapFun()
        //this.DrawUnOnlineTdtMapFun()
        this.DrawTerrainProviderFun();
        /
        //this.SetViewFun()
        resolve(viewer);
      }).then(() => {
        this.LeftClickFun();
        this.AllDrawFun();
      });
    },

 

参考:

1.Cesium动态水面(任意多边形PolygonGeometry)保姆级教程-CSDN博客

2.Cesium自定义shader材质实现逼真水面,支持uniforms属性实时修改-CSDN博客 

你可能感兴趣的:(前端,javascript,开发语言)