基于Cesium实现逼真的水特效

Cesium 自带有水特效材质,实例代码如下:

 1 var primitives = scene.primitives.add(
 2     new Cesium.Primitive({
 3       geometryInstances: new Cesium.GeometryInstance({
 4         geometry: new Cesium.RectangleGeometry({
 5           rectangle: Cesium.Rectangle.fromDegrees(
 6             -180.0,
 7             -90.0,
 8             180.0,
 9             90.0
10           ),
11           vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
12         }),
13       }),
14       appearance: new Cesium.EllipsoidSurfaceAppearance({
15         aboveGround: false,
16       }),
17       show: true
18     })
19   );

 

 1 primitive.appearance.material = new Cesium.Material({
 2     fabric: {
 3       type: "Water",
 4       uniforms: {
 5         specularMap: "../images/earthspec1k.jpg",
 6         normalMap: Cesium.buildModuleUrl(
 7           "Assets/Textures/waterNormals.jpg"
 8         ),
 9         frequency: 10000.0,
10         animationSpeed: 0.01,
11         amplitude: 1.0,
12       },
13     },
14   });
说明:
specularMap: 着色器源码:float specularMapValue = texture2D(specularMap, materialInput.st).r;用于判断当前区域是否为水域。
normalMap:水波动的法线纹理贴图
frequency:波的数量
animationSpeed:水震动的速度
amplitude:振幅大小

使用发现自带的水特效效果不是特别好,于是简单改改,将水透明化,代码如下:
 1 fragmentShaderSource: 'varying vec3 v_positionMC;\n' +
 2                     'varying vec3 v_positionEC;\n' +
 3                     'varying vec2 v_st;\n' +
 4                     'void main()\n' +
 5                     '{\n' +
 6                     'czm_materialInput materialInput;\n' +
 7                     'vec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n' +
 8                     '#ifdef FACE_FORWARD\n' +
 9                     'normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n' +
10                     '#endif\n' +
11                     'materialInput.s = v_st.s;\n' +
12                     'materialInput.st = v_st;\n' +
13                     'materialInput.str = vec3(v_st, 0.0);\n' +
14                     'materialInput.normalEC = normalEC;\n' +
15                     'materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\n' +
16                     'vec3 positionToEyeEC = -v_positionEC;\n' +
17                     'materialInput.positionToEyeEC = positionToEyeEC;\n' +
18                     'czm_material material = czm_getMaterial(materialInput);\n' +
19                     '#ifdef FLAT\n' +
20                     'gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n' +
21                     '#else\n' +
22                     'gl_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n' +
23                     'gl_FragColor.a=0.85;\n' +
24                     '#endif\n' +
25                     '}\n'

 

 结合倾斜摄影数据,改改水的相关参数也还凑合,可以看。但是你想要的水面倒影,水折射肯定是没有的。

下面我们可以看看three.js的水,看着挺清澈透明的,现实生活中也就生活用水有这个效果。但几乎有水的折射和反射效果了。

 

 这里借鉴一下three.js的水特效代码:

  1 vertexShader: [
  2 
  3         '#include <common>',
  4         '#include <fog_pars_vertex>',
  5         '#include <logdepthbuf_pars_vertex>',
  6 
  7         'uniform mat4 textureMatrix;',
  8 
  9         'varying vec4 vCoord;',
 10         'varying vec2 vUv;',
 11         'varying vec3 vToEye;',
 12 
 13         'void main() {',
 14 
 15         '    vUv = uv;',
 16         '    vCoord = textureMatrix * vec4( position, 1.0 );',
 17 
 18         '    vec4 worldPosition = modelMatrix * vec4( position, 1.0 );',
 19         '    vToEye = cameraPosition - worldPosition.xyz;',
 20 
 21         '    vec4 mvPosition =  viewMatrix * worldPosition;', // used in fog_vertex
 22         '    gl_Position = projectionMatrix * mvPosition;',
 23 
 24         '    #include <logdepthbuf_vertex>',
 25         '    #include <fog_vertex>',
 26 
 27         '}'
 28 
 29     ].join( '\n' ),
 30 
 31     fragmentShader: [
 32 
 33         '#include <common>',
 34         '#include <fog_pars_fragment>',
 35         '#include <logdepthbuf_pars_fragment>',
 36 
 37         'uniform sampler2D tReflectionMap;',
 38         'uniform sampler2D tRefractionMap;',
 39         'uniform sampler2D tNormalMap0;',
 40         'uniform sampler2D tNormalMap1;',
 41 
 42         '#ifdef USE_FLOWMAP',
 43         '    uniform sampler2D tFlowMap;',
 44         '#else',
 45         '    uniform vec2 flowDirection;',
 46         '#endif',
 47 
 48         'uniform vec3 color;',
 49         'uniform float reflectivity;',
 50         'uniform vec4 config;',
 51 
 52         'varying vec4 vCoord;',
 53         'varying vec2 vUv;',
 54         'varying vec3 vToEye;',
 55 
 56         'void main() {',
 57 
 58         '    #include <logdepthbuf_fragment>',
 59 
 60         '    float flowMapOffset0 = config.x;',
 61         '    float flowMapOffset1 = config.y;',
 62         '    float halfCycle = config.z;',
 63         '    float scale = config.w;',
 64 
 65         '    vec3 toEye = normalize( vToEye );',
 66 
 67         // determine flow direction
 68         '    vec2 flow;',
 69         '    #ifdef USE_FLOWMAP',
 70         '        flow = texture2D( tFlowMap, vUv ).rg * 2.0 - 1.0;',
 71         '    #else',
 72         '        flow = flowDirection;',
 73         '    #endif',
 74         '    flow.x *= - 1.0;',
 75 
 76         // sample normal maps (distort uvs with flowdata)
 77         '    vec4 normalColor0 = texture2D( tNormalMap0, ( vUv * scale ) + flow * flowMapOffset0 );',
 78         '    vec4 normalColor1 = texture2D( tNormalMap1, ( vUv * scale ) + flow * flowMapOffset1 );',
 79 
 80         // linear interpolate to get the final normal color
 81         '    float flowLerp = abs( halfCycle - flowMapOffset0 ) / halfCycle;',
 82         '    vec4 normalColor = mix( normalColor0, normalColor1, flowLerp );',
 83 
 84         // calculate normal vector
 85         '    vec3 normal = normalize( vec3( normalColor.r * 2.0 - 1.0, normalColor.b,  normalColor.g * 2.0 - 1.0 ) );',
 86 
 87         // calculate the fresnel term to blend reflection and refraction maps
 88         '    float theta = max( dot( toEye, normal ), 0.0 );',
 89         '    float reflectance = reflectivity + ( 1.0 - reflectivity ) * pow( ( 1.0 - theta ), 5.0 );',
 90 
 91         // calculate final uv coords
 92         '    vec3 coord = vCoord.xyz / vCoord.w;',
 93         '    vec2 uv = coord.xy + coord.z * normal.xz * 0.05;',
 94 
 95         '    vec4 reflectColor = texture2D( tReflectionMap, vec2( 1.0 - uv.x, uv.y ) );',
 96         '    vec4 refractColor = texture2D( tRefractionMap, uv );',
 97 
 98         // multiply water color with the mix of both textures
 99         '    gl_FragColor = vec4( color, 1.0 ) * mix( refractColor, reflectColor, reflectance );',
100 
101         '    #include <tonemapping_fragment>',
102         '    #include <encodings_fragment>',
103         '    #include <fog_fragment>',
104 
105         '}'
106 
107     ].join( '\n' )

融入到Cesium当中效果勉强可以看了,效果图如下:

 

图1

 

 图2


图一和图二是同一份数据,,图一的水折射用的是影像图,图二的水折射是在水面几何数据下贴了石块纹理图,其实实际上的水是透明无色的。