基于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
图一和图二是同一份数据,,图一的水折射用的是影像图,图二的水折射是在水面几何数据下贴了石块纹理图,其实实际上的水是透明无色的。