maptalks+three实战项目 智慧城市项目
Posted aichitudousien
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了maptalks+three实战项目 智慧城市项目相关的知识,希望对你有一定的参考价值。
@
概述
如有不明白的可以加QQ:2354528292;wx: aichitudousien
更多教学视频请访问:https://space.bilibili.com/236087412
源码获取: https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.3c3a645eIMTaft&ft=t&id=714967503431
经过上一次使用three.js做了个demo,这次使用maptalks+three+vue来继续开发一个demo玩玩
先看视频效果:
[video(video-bvzzjqdd-1615007935063)(type-csdn)(url-https://live.csdn.net/v/embed/156451)(image-https://vedu.csdnimg.cn/92e455d21899461ba223cc19b3530db5/snapshots/47b9fea390504faa91d59a2836f73dde-00002.jpg)(title-maptalks+three 智慧城市)]
搭建开发环境
使用的开发框架是vue-cli3.0, webgl使用three.js,地图使用maptalks,开发工具为vscode
搭建完成后的目录为
搭建maptalks+three场景
和上一个项目初始化场景一样,先创建一个ZThree的类,然后写入一个初始化方法initMapTalks
initMapTalks(option)
let config =
center: [113.31915199756622, 23.109087176037534],
zoom: 17,
pitch: 70,
bearing: 180,
centerCross: true,
doubleClickZoom: false,
baseLayer: new maptalks.TileLayer(\'tile\',
urlTemplate: \'https://s.basemaps.cartocdn.com/dark_all/z/x/y.png\',
subdomains: [\'a\', \'b\', \'c\', \'d\']
)
;
option = Object.assign(config, option);
let map = new maptalks.Map(this.id, option);
let threeLayer = new ThreeLayer(\'t\',
forceRenderOnMoving: true,
forceRenderOnRotating: true
);
threeLayer.addTo(map);
ThreeLayer.prototype.coordinateToXYZ = function (coordinate, height = 0)
let z = this.distanceToVector3(height, height).x;
let v = this.coordinateToVector3(coordinate, z)
return [v.x, v.y, v.z];
return threeLayer;
- 实例化类
app = new ZThree("screen");
创建灯光
灯光代码和上次项目的代码一样,在博客中的智慧城市第一篇文章中查找
app.initLight();
此时我们看到的是已经成功创建好了地图
加载建筑模型
- 创建加载模型方法 loadBuilding
export function loadBuilding(threeLayer)
let features = buildingGeoJosn.features;
let polygons = features.map(f =>
let height = Number(f.properties.height);
let polygon = maptalks.GeoJSON.toGeometry(f);
polygon.setProperties(
height,
);
return polygon;
);
let material = new THREE.ShaderMaterial(
uniforms: bulidingShader.uniforms,
vertexShader: bulidingShader.vs,
fragmentShader: bulidingShader.fs,
side: THREE.DoubleSide,
transparent: true,
)
let mesh = threeLayer.toExtrudePolygons(polygons,
interactive: false
, material);
let meshs = [];
let bufferGeometry = mesh.getObject3d().geometry;
let geometry = new THREE.Geometry().fromBufferGeometry(bufferGeometry);
let
vertices,
faces,
faceVertexUvs
= geometry;
for (let i = 0, len = faces.length; i < len; i++)
let
a,
b,
c
= faces[i];
let p1 = vertices[a],
p2 = vertices[b],
p3 = vertices[c];
//top face
if (p1.z > 0 && p2.z > 0 && p3.z > 0)
let uvs = faceVertexUvs[0][i];
for (let j = 0, len1 = uvs.length; j < len1; j++)
uvs[j].x = 0;
uvs[j].y = 0;
mesh.getObject3d().geometry = new THREE.BufferGeometry().fromGeometry(geometry);
bufferGeometry.dispose();
geometry.dispose();
meshs.push(mesh);
threeLayer.addMesh(meshs);
- 在场景中调用此方法数据
loadBuilding(threeLayer);
数据可从此地址获得 https://www.openstreetmap.org/
此时我们可以看到的效果是,用的数据量小的做开发,后期数据自己替换即可
建筑贴图:
加载流光道路
流光道路使用MeshLineMaterial来实现,因为three.js的线条材质是没有宽度的,所以此处我们需要导入一个新的库THREE.MeshLine,当然可以使用管道tube来实现也是可以的,使用管道来实现请查看博客中的流光特效文章
export function loaderRoad(threeLayer, SpriteLine)
let texture = new THREE.TextureLoader().load(\'texture/road.png\');
texture.anisotropy = 16;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
let camera = threeLayer.getCamera();
let material = new MeshLineMaterial(
map: texture,
useMap: true,
lineWidth: 13,
sizeAttenuation: false,
transparent: true,
near: camera.near,
far: camera.far
);
let features = roadGeoJosn.features;
let meshs = []
features.forEach(item =>
if (item.geometry.type === \'LineString\' && item.properties?.highway === \'primary\')
let line = maptalks.GeoJSON.toGeometry(item);
let mesh = new SpriteLine(line,
altitude: 0
, material, threeLayer);
meshs.push(mesh);
)
threeLayer.addMesh(meshs);
数据来源和建筑的是一个地址,添加好后在场景中引入即可,流光动画只要偏移贴图的uv就好了
此时的效果
道路流光的贴图
加载水系
水系使用Ocean来制作,具体的可以在github上搜索Ocean来看案例
export function loaderWater(threeLayer)
let polygons = maptalks.GeoJSON.toGeometry(waterGeoJosn);
let oceans = polygons.map(p =>
let ocean = new Ocean(p,
waterNormals: \'texture/waternormals.jpg\'
, threeLayer)
return ocean;
);
threeLayer.addMesh(oceans);
水系的贴图
此时我们看到的效果是
加载大厦模型
模型在网上随便找了一个,勉强能用
加载模型代码
export async function loaderModel(app, threeLayer, position)
let model = await app.loaderModel(
"model/",
\'building\'
);
let material = new THREE.ShaderMaterial(
uniforms: modelShader.uniforms,
vertexShader: modelShader.vs,
fragmentShader: modelShader.fs,
side: THREE.DoubleSide,
transparent: true,
)
model.traverse(obj =>
obj.material = material;
obj.scale.set(1.5, 1.5, 1.5);
)
model.position.set(...position);
model.rotateX(Math.PI / 2)
threeLayer.addMesh(model);
return model;
模型下载地址:https://download.csdn.net/download/qq_39503511/15611779
加载成功后看到的效果:
加载飞行线条
飞行线条也和上期代码中的开发方式一样的,通过三个点生成贝塞尔曲线,在添加贴图偏移就好了
export function loaderCurve(app, threeLayer, geojson = curve)
let points = geojson.features.map(item =>
let coordinates = item.geometry.coordinates;
return [new THREE.Vector3(...threeLayer.coordinateToXYZ(coordinates)), new THREE.Vector3(...threeLayer.coordinateToXYZ([-73.98565649986267, 40.74843959459197], 258))]
)
let meshs = []
points.forEach((point, index) =>
let c = point[0].clone().add(point[1].clone()).divideScalar(2);
c.z += 4
let curve = new THREE.QuadraticBezierCurve3(point[0], c, point[1])
let points = curve.getPoints(80)
let line = new THREE.CatmullRomCurve3(points)
let tube = app.loaderTube(
line,
index % 2 === 0 ? tubeRedMaterial : tubeGreenMaterial
);
meshs.push(tube);
)
threeLayer.addMesh(meshs);
此时我们看到的效果是
创建圆锥体
export function loaderCone(threeLayer, geojson = cone)
let points = geojson.features.map(item =>
let coordinates = item.geometry.coordinates;
return threeLayer.coordinateToXYZ(coordinates, 100)
)
let geometry = new THREE.ConeGeometry(0.2, 0.4, 4);
let meshs = []
points.forEach(item =>
let material = new THREE.MeshBasicMaterial(
color: `rgb$rgb()`,
transparent: true,
opacity: 8,
side: THREE.DoubleSide,
depthWrite: false
);
let cone = new THREE.Mesh(geometry, material);
cone.rotateX(-Math.PI / 2);
cone.position.set(...item);
meshs.push(cone);
);
threeLayer.addMesh(meshs);
return meshs;
rgb函数是一个获取随机rbg颜色函数
export function rgb() //rgb颜色随机
let r = Math.floor(Math.random() * 256);
let g = Math.floor(Math.random() * 256);
let b = Math.floor(Math.random() * 256);
let rgb = \'(\' + r + \',\' + g + \',\' + b + \')\';
return rgb;
此时我们看到场景中的效果是
创建文本
最后再来创建一些基础的文本,使用精灵来创建
export function loaderText(app, threeLayer, geojson = text)
geojson.features.forEach(item =>
let coordinates = item.geometry.coordinates;
let position = threeLayer.coordinateToXYZ(coordinates, 200);
let name = item.properties.name;
let element = `
<div class="sprite-canvas">
<span class="sprite-layer">$name</span>
</div>`;
app.addHtmlCanvas(
parent: app.scene,
position,
element
)
)
addHtmlCanvas方法在上期已经贴出代码,通过html来生成canvas,然后在map使用就好
此时的效果:
最后我们给整个场景添加一个高光的后期处理就ok了
export function loaderBloom(threeLayer)
const params =
exposure: 1,
bloomStrength: 1.5,
bloomThreshold: 0,
bloomRadius: 0,
debug: false
;
const renderer = threeLayer.getThreeRenderer();
const size = threeLayer.getMap().getSize();
threeLayer.composer = new EffectComposer(renderer);
threeLayer.composer.setSize(size.width, size.height);
const scene = threeLayer.getScene(),
camera = threeLayer.getCamera();
threeLayer.renderPass = new RenderPass(scene, camera);
threeLayer.composer.addPass(threeLayer.renderPass);
const bloomPass = threeLayer.bloomPass = new UnrealBloomPass(new THREE.Vector2(size.width, size.height));
bloomPass.renderToScreen = true;
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
threeLayer.composer.addPass(bloomPass);
threeLayer.bloomEnable = true;
threeLayer.getRenderer().renderScene = function ()
const layer = this.layer;
layer._callbackBaseObjectAnimation();
this._syncCamera();
const renderer = this.context,
camera = this.camera,
scene = this.scene;
if (
layer.bloomEnable &&
layer.composer &&
layer.composer.passes.length > 1
)
layer.composer.render(0);
renderer.clearDepth();
camera.layers.set(0);
renderer.render(scene, camera);
this.completeRender();
;
ok, 此时我们的整个场景就比之前亮了,我们在替换一下数据就成视频中的效果了
关于Three.js实现智慧城市我实现的一些特效
关于所有特效的集成效果可见知乎上我发的视频https://www.zhihu.com/zvideo/1277995319629037568
1、OD线(着色器实现)
2、透明墙
3、地面扩散粒子
4、地震波
5、发光扩散半球
6、发光旋转四棱锥
7、流动线
8、上升粒子
9、建筑线框
10、圆扩散
11、建筑物纹理流动
12、建筑流动着色器版本
13、粒子地面
14、雷达扫描(着色器实现)
15、flyto
16、mesh动画
17、仿真道路
18、格网地面
19、科技风线框
20、数字柱
21、流动箭头(gif显示有问题)
22、能量罩
23、扫描光带
24、无人机巡航特效
25、线框渲染
26、Xray透视特效
27、类似守望先锋能量护盾
28、光束模拟
以上是关于maptalks+three实战项目 智慧城市项目的主要内容,如果未能解决你的问题,请参考以下文章