Cesium 实现 FlowMap

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 引入 Cesium 核心库 -->
<link href="path/to/cesium/Widgets/widgets.css" rel="stylesheet">
<script src="path/to/cesium/Cesium.js"></script>
<div id="cesiumContainer"></div>
 
<script>
// 初始化 Cesium Viewer
const viewer = new Cesium.Viewer('cesiumContainer', {
  terrainProvider: Cesium.createWorldTerrain(),
  baseLayerPicker: false
});
</script>

  

1. 创建 FlowMap 材质(基于 Fabric 材质系统)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const flowMapMaterial = new Cesium.Material({
  fabric: {
    type: 'FlowMapMaterial',
    uniforms: {
      flowMapTexture: 'path/to/flowmap.png'// FlowMap 纹理(RG通道存储流向)
      normalMap: 'path/to/waterNormals.jpg'// 法线贴图
      speed: 0.5,                             // 流动速度
      time: 0,                                // 时间变量
      amplitude: 1.0                          // 波纹振幅
    },
    source: `
      // GLSL 着色器代码
      uniform sampler2D flowMapTexture;
      uniform sampler2D normalMap;
      uniform float speed;
      uniform float time;
      uniform float amplitude;
       
      varying vec2 v_st;
      varying vec3 v_positionEC;
 
      void main() {
        // 采样 FlowMap 获取流向
        vec2 flowVector = texture2D(flowMapTexture, v_st).rg * 2.0 - 1.0;
        flowVector *= speed;
 
        // 计算双相位偏移
        float phase0 = fract(time * 0.1);
        float phase1 = fract(time * 0.1 + 0.5);
        vec2 uvOffset0 = flowVector * phase0;
        vec2 uvOffset1 = flowVector * phase1;
 
        // 混合法线贴图
        vec4 normalColor0 = texture2D(normalMap, v_st * 10.0 + uvOffset0);
        vec4 normalColor1 = texture2D(normalMap, v_st * 10.0 + uvOffset1);
        float lerpFactor = abs(0.5 - phase0) * 2.0;
        vec3 normal = mix(normalColor0.rgb, normalColor1.rgb, lerpFactor);
 
        // 计算光照与颜色
        vec3 positionToEye = normalize(-v_positionEC);
        vec3 reflected = reflect(positionToEye, normal);
        vec4 baseColor = vec4(0.1, 0.3, 0.8, 0.8); // 基础水色
        gl_FragColor = vec4(baseColor.rgb * (0.5 + dot(normal, positionToEye)), baseColor.a);
      }
    `
  }
});

  

(FlowMap + 噪声函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// 定义波浪材质(参考搜索结果)
const waterMaterial = new Cesium.Material({
  fabric: {
    type: "DynamicWater",
    uniforms: {
      normalMap: './waterNormals.jpg', // 法线贴图(需禁用压缩)
      flowMap: './flowmap.png',        // FlowMap 流向纹理(RG通道)
      noiseTexture: './noise.png',     // 噪声纹理
      speed: 0.3,                     // 流动速度
      amplitude: 5.0,                 // 波浪振幅
      time: 0                         // 时间变量
    },
    source: `
      uniform sampler2D normalMap;
      uniform sampler2D flowMap;
      uniform sampler2D noiseTexture;
      uniform float speed;
      uniform float amplitude;
      uniform float time;
       
      varying vec2 v_st;
      varying vec3 v_positionEC;
 
      // 噪声函数(参考)
      float noise(vec2 p) {
        return texture2D(noiseTexture, p * 0.01).r;
      }
 
      void main() {
        // 采样 FlowMap 获取流向
        vec2 flowDir = texture2D(flowMap, v_st).rg * 2.0 - 1.0;
        flowDir *= speed;
 
        // 双相位混合(参考)
        float phase0 = fract(time * 0.1);
        float phase1 = fract(time * 0.1 + 0.5);
        vec2 uvOffset0 = flowDir * phase0;
        vec2 uvOffset1 = flowDir * phase1;
 
        // 动态波浪计算(参考)
        vec3 normal0 = texture2D(normalMap, v_st * 10.0 + uvOffset0).rgb;
        vec3 normal1 = texture2D(normalMap, v_st * 10.0 + uvOffset1).rgb;
        vec3 finalNormal = mix(normal0, normal1, abs(0.5 - phase0) * 2.0);
         
        // 噪声增强细节(参考)
        float waveNoise = noise(v_st * 5.0 + time) * amplitude;
        finalNormal.xy += vec2(waveNoise * 0.1);
 
        // 光照与颜色
        vec3 viewDir = normalize(-v_positionEC);
        float specular = pow(max(dot(viewDir, finalNormal), 0.0), 32.0);
        gl_FragColor = vec4(mix(vec3(0.1, 0.3, 0.8), vec3(1.0), specular), 0.8);
      }
    `
  }
});
 
// 创建水面几何体(参考)
const waterPrimitive = viewer.scene.primitives.add(
  new Cesium.GroundPrimitive({
    geometryInstances: new Cesium.GeometryInstance({
      geometry: new Cesium.RectangleGeometry({
        rectangle: Cesium.Rectangle.fromDegrees(-75.0, 40.0, -74.0, 41.0),
        vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
      })
    }),
    appearance: new Cesium.EllipsoidSurfaceAppearance({
      material: waterMaterial,
      aboveGround: true
    })
  })
);
 
// 更新时间变量(参考)
viewer.scene.preUpdate.addEventListener(() => {
  waterMaterial.uniforms.time = Cesium.JulianDate.now().secondsOfDay;
});

  

 

2. 应用材质到几何体

 

复制代码
// 创建平面几何体
const rectangle = Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0);
const primitive = viewer.scene.primitives.add(
  new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
      geometry: new Cesium.RectangleGeometry({
        rectangle: rectangle,
        vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
      })
    }),
    appearance: new Cesium.EllipsoidSurfaceAppearance({
      aboveGround: false
    })
  })
);

// 应用 FlowMap 材质
primitive.appearance.material = flowMapMaterial;

// 更新时间变量
viewer.scene.preUpdate.addEventListener(() => {
  flowMapMaterial.uniforms.time = Cesium.JulianDate.now().secondsOfDay;
});
复制代码

 


关键参数说明

  1. FlowMap 纹理制作:

    • 使用工具(如 Houdini Labs 或 Flowmap Painter)生成 RG 通道编码的向量场纹理 
    • 确保纹理导入时禁用压缩(如设置 disableCompression: true) 
  2. 动态效果优化:

    • 双相位插值:通过 phase0 和 phase1 实现无缝循环流动,避免跳跃感
    • 法线混合:叠加多层法线贴图增强波纹细节 
  3. 性能调优:

    • 降低 frequency(波纹密度)和 amplitude(振幅)以减轻 GPU 负载 
    • 使用 Cesium.RequestScheduler 控制纹理加载优先级 
posted @   zhh  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
历史上的今天:
2021-02-26 大疆 osgb 转 3dtile 报错
点击右上角即可分享
微信分享提示