maptalks 开发GIS地图(30)maptalks.three.23- custom-electricShield
1. 电子罩栏,这个效果很不错了。可是用在什么地方比较合适呢?
2. 定义扩展对象类
1 class ElectricShield extends maptalks.BaseObject { 2 constructor(coordinate, options, material, layer) { 3 options = maptalks.Util.extend({}, OPTIONS, options, { layer, coordinate }); 4 super(); 5 //Initialize internal configuration 6 // https://github.com/maptalks/maptalks.three/blob/1e45f5238f500225ada1deb09b8bab18c1b52cf2/src/BaseObject.js#L135 7 this._initOptions(options); 8 const { altitude, radius } = options; 9 //generate geometry 10 const r = layer.distanceToVector3(radius, radius).x; 11 const geometry = new THREE.SphereBufferGeometry(r, 50, 50, 0, Math.PI * 2); 12 13 //Initialize internal object3d 14 // https://github.com/maptalks/maptalks.three/blob/1e45f5238f500225ada1deb09b8bab18c1b52cf2/src/BaseObject.js#L140 15 // this._createMesh(geometry, material); 16 this._createGroup(); 17 const mesh = new THREE.Mesh(geometry, material); 18 this.getObject3d().add(mesh); 19 //set object3d position 20 const z = layer.distanceToVector3(altitude, altitude).x; 21 const position = layer.coordinateToVector3(coordinate, z); 22 this.getObject3d().position.copy(position); 23 this.getObject3d().rotation.x = Math.PI / 2; 24 } 25 26 _animation() { 27 const ball = this.getObject3d().children[0]; 28 const speed = this.getOptions().speed; 29 ball.material.uniforms.time.value += speed; 30 } 31 }
3. 电子罩栏的材质,其中使用了 ShaderMaterial
1 function getMaterial() { 2 var ElectricShield = { 3 uniforms: { 4 time: { 5 type: "f", 6 value: 0 7 }, 8 color: { 9 type: "c", 10 value: new THREE.Color("#9999FF") 11 }, 12 opacity: { 13 type: "f", 14 value: 1 15 } 16 }, 17 vertexShaderSource: "\n precision lowp float;\n precision lowp int;\n " 18 .concat( 19 THREE.ShaderChunk.fog_pars_vertex, 20 "\n varying vec2 vUv;\n void main() {\n vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n " 21 ) 22 .concat(THREE.ShaderChunk.fog_vertex, "\n }\n"), 23 fragmentShaderSource: ` 24 #if __VERSION__ == 100 25 #extension GL_OES_standard_derivatives : enable 26 #endif 27 uniform vec3 color; 28 uniform float opacity; 29 uniform float time; 30 varying vec2 vUv; 31 #define pi 3.1415926535 32 #define PI2RAD 0.01745329252 33 #define TWO_PI (2. * PI) 34 float rands(float p){ 35 return fract(sin(p) * 10000.0); 36 } 37 float noise(vec2 p){ 38 float t = time / 20000.0; 39 if(t > 1.0) t -= floor(t); 40 return rands(p.x * 14. + p.y * sin(t) * 0.5); 41 } 42 vec2 sw(vec2 p){ 43 return vec2(floor(p.x), floor(p.y)); 44 } 45 vec2 se(vec2 p){ 46 return vec2(ceil(p.x), floor(p.y)); 47 } 48 vec2 nw(vec2 p){ 49 return vec2(floor(p.x), ceil(p.y)); 50 } 51 vec2 ne(vec2 p){ 52 return vec2(ceil(p.x), ceil(p.y)); 53 } 54 float smoothNoise(vec2 p){ 55 vec2 inter = smoothstep(0.0, 1.0, fract(p)); 56 float s = mix(noise(sw(p)), noise(se(p)), inter.x); 57 float n = mix(noise(nw(p)), noise(ne(p)), inter.x); 58 return mix(s, n, inter.y); 59 } 60 float fbm(vec2 p){ 61 float z = 2.0; 62 float rz = 0.0; 63 vec2 bp = p; 64 for(float i = 1.0; i < 6.0; i++){ 65 rz += abs((smoothNoise(p) - 0.5)* 2.0) / z; 66 z *= 2.0; 67 p *= 2.0; 68 } 69 return rz; 70 } 71 void main() { 72 vec2 uv = vUv; 73 vec2 uv2 = vUv; 74 if (uv.y < 0.5) { 75 discard; 76 } 77 uv *= 4.; 78 float rz = fbm(uv); 79 uv /= exp(mod(time * 2.0, pi)); 80 rz *= pow(15., 0.9); 81 gl_FragColor = mix(vec4(color, opacity) / rz, vec4(color, 0.1), 0.2); 82 if (uv2.x < 0.05) { 83 gl_FragColor = mix(vec4(color, 0.1), gl_FragColor, uv2.x / 0.05); 84 } 85 if (uv2.x > 0.95){ 86 gl_FragColor = mix(gl_FragColor, vec4(color, 0.1), (uv2.x - 0.95) / 0.05); 87 } 88 }` 89 }; 90 let material = new THREE.ShaderMaterial({ 91 uniforms: ElectricShield.uniforms, 92 defaultAttributeValues: {}, 93 vertexShader: ElectricShield.vertexShaderSource, 94 fragmentShader: ElectricShield.fragmentShaderSource, 95 blending: THREE.AdditiveBlending, 96 depthWrite: !1, 97 depthTest: !0, 98 side: THREE.DoubleSide, 99 transparent: !0 100 }); 101 return material; 102 }
4. 添加电子罩栏
1 var ballElectric, material; 2 function addElectricShield() { 3 material = getMaterial(); 4 ballElectric = new ElectricShield(map.getCenter(), { radius: 500 }, material, threeLayer) 5 threeLayer.addMesh(ballElectric); 6 initGui(); 7 animation(); 8 }
5. 页面显示
6. 源码地址
https://github.com/WhatGIS/maptalkMap/tree/main/threelayer/demo