赞
踩
如有不明白的可以加QQ:2354528292;wx: aichitudousien
更多教学视频请访问:https://space.bilibili.com/236087412
源码获取:https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.3c3a645ezznpcA&ft=t&id=714973095604
先看看视频效果
Three.js 建筑可视化监控
分别具备楼层展示,楼层热力度分析,扩散波特效,无人机飞行,飞行路径点规划,扩散波特效,多场景下钻,多文本渲染,路径动画
这里和以前文章的加载场景一样,没有变化
app = new ZThree('screen'); app.initThree(); // app.initHelper(); app.initOrbitControls(); light = app.initLight(); stats = app.initStatus(); selectObj = app.initRaycaster(); window.app = app; camera = app.camera; bloomComposer = app.bloomComposer(); camera.position.set(...this.cameraPosition); scene = app.scene; renderer = app.renderer; renderer.logarithmicDepthBuffer = true; renderer.autoClear = false; controls = app.controls; controls.target.set(...this.target); controls.maxDistance = 2000; controls.maxPolarAngle = Math.PI / 2.2; clock = new THREE.Clock();
import axios from "axios"; import * as THREE from 'three' import { getDistance, getRhumbLineBearing } from "geolib"; import { BufferGeometryUtils } from "three/examples/jsm/utils/BufferGeometryUtils.js"; // 中心点数组 const center = [114.0504053235054, 22.532816043569957]; // 初始化创建组 let iR = new THREE.Group(); iR.scale.set(20, 20, 20); iR.name = "建组"; let iR_Road = new THREE.Group(); iR_Road.name = "公路"; iR_Road.scale.set(20, 20, 20); let iR_Line = new THREE.Group(); iR_Line.name = "公路动画线"; iR_Line.scale.set(20, 20, 20); // 包围盒数组对象 let collider_building = []; // 线条数组对象 let linelist = []; // 建组数组对象 let geos_building = []; let MAT_BUILDING; // 线材质 let MAT_ROAD = new THREE.LineBasicMaterial({ color: 0x00ff00, linewidth: 10 }); let MAT_ROAD_HIGEWAY; /** * 获得地图数据 */ export function createBuildingRoad(app, buildingMaterials, lineMaterial) { return new Promise(resolve => { axios({ url: "/json/export.json" }).then(res => { MAT_BUILDING = buildingMaterials; MAT_ROAD_HIGEWAY = lineMaterial; LoadBuildings(res.data, app); app.scene.add(iR); app.scene.add(iR_Road); app.scene.add(iR_Line); resolve(true) }); }) } /** * 加载地图模型 */ function LoadBuildings(data, app) { let features = data.features; for (let i = 0; i < features.length; i++) { let fel = features[i]; if (!fel["properties"]) return; let info = fel.properties; // building 建筑 highway 公路 if (info["building"]) { addBuilding(fel.geometry.coordinates, info, info["height"]); } else if (info["highway"]) { if (fel.geometry.type == "LineString") { // if ( // info["highway"] === "trunk_link" || // info["highway"] === "motorway" // ) { // addRoadTrunk(fel.geometry.coordinates, info); // } else { // // addRoad(fel.geometry.coordinates, info); // } addRoadTrunk(fel.geometry.coordinates, info); } } } linelist.forEach((e, i) => { const line2 = app.createAnimateLine({ type: "pipe", pointList: e, material: MAT_ROAD_HIGEWAY, number: 100, radius: 0.01 }); line2.rotateZ(-Math.PI); iR_Road.add(line2); }); let mergeGeometry = BufferGeometryUtils.mergeBufferGeometries( geos_building ); let mesh = new THREE.Mesh(mergeGeometry, MAT_BUILDING); iR.add(mesh); } /** * 添加建筑 * @param {Array} data 坐标数组 * @param {Object} info 建筑信息 * @param {Number} height 建组高度 */ function addBuilding(data, info, height = 1) { height = height ? height : 1; let shape, geometry; // 建筑物的孔 let holes = []; for (let i = 0; i < data.length; i++) { let el = data[i]; if (i == 0) { // 建筑路劲 shape = genShape(el, center); } else { // 当前孔的路径 holes.push(genShape(el, center)); } } // 将孔添加到当前建组中 for (let i = 0; i < holes.length; i++) { shape.holes.push(holes[i]); } if (height > 10) { height = 0.1 * height } else { height = 8 * height } geometry = genGeometry(shape, { curveSegments: 1, // depth: height, depth: 0.1 * height, bevelEnabled: false }); geometry.rotateX(Math.PI / 2); geometry.rotateZ(Math.PI); geos_building.push(geometry); let helper = genHelper(geometry); if (helper) { helper.name = info["name"] ? info["name"] : "Building"; helper.info = info; collider_building.push(helper); } } /** * 添加公路 * @param {Array} d 坐标数组 * @param {Object} info 建筑信息 */ function addRoadTrunk(d, info) { // 点数组 let points = []; for (let i = 0; i < d.length; i++) { if (!d[0][1]) return; let el = d[i]; if (!el[0] || !el[1]) return; let elp = [el[0], el[1]]; // 位置转换 elp = GPSRelativePosition([elp[0], elp[1]], center); points.push([elp[0], 0, elp[1]]); } linelist.push(points); } /** * 添加公路 * @param {Array} d 坐标数组 * @param {Object} info 建筑信息 */ function addRoad(d, info) { // 点数组 let points = []; for (let i = 0; i < d.length; i++) { if (!d[0][1]) return; let el = d[i]; if (!el[0] || !el[1]) return; let elp = [el[0], el[1]]; // 位置转换 elp = GPSRelativePosition([elp[0], elp[1]], center); points.push(new THREE.Vector3(elp[0], 0.5, elp[1])); } // 通过点队列设置该 BufferGeometry 的 attribute let geometry = new THREE.BufferGeometry().setFromPoints(points); geometry.rotateZ(Math.PI); let line = new THREE.Line(geometry, MAT_ROAD); line.info = info; // 计算LineDashedMaterial所需的距离的值的数组 line.computeLineDistances(); iR_Road.add(line); line.position.set(line.position.x, 0, line.position.z); } /** * 添加建筑 * @param {Array} points 坐标数组 * @param {Array} center 地理位置中心点 * @return {Object} */ function genShape(points, center) { let shape = new THREE.Shape(); for (let i = 0; i < points.length; i++) { let elp = points[i]; elp = GPSRelativePosition(elp, center); if (i == 0) { shape.moveTo(elp[0], elp[1]); } else { shape.lineTo(elp[0], elp[1]); } } return shape; } /** * 生成Geometry * @param {Object} shape shape对象 * @param {Object} settings 建筑配置项 * @return {Object} 建组对象 */ function genGeometry(shape, settings) { // 挤压缓冲几何体 let geometry = new THREE.ExtrudeBufferGeometry(shape, settings); geometry.computeBoundingBox(); return geometry; } /** * 建组包围盒子 * @param {Object} geometry */ function genHelper(geometry) { if (!geometry.boundingBox) { geometry.computeBoundingBox(); } let box3 = geometry.boundingBox; // 检测包围盒是不是无穷大 if (!isFinite(box3.max.x)) { return false; } let helper = new THREE.Box3Helper(box3, 0xffff00); helper.updateMatrixWorld(); return helper; } /** * GPS经纬度转化 * @param {Array} objPosi 坐标数组 * @param {Array} centerPosi 中心点 * @return {Array} 转化后的数组 */ function GPSRelativePosition(objPosi, centerPosi) { let dis = getDistance(objPosi, centerPosi); // Get bearing angle let bearing = getRhumbLineBearing(objPosi, centerPosi); // Calculate X by centerPosi.x + distance * cos(rad) let x = centerPosi[0] + dis * Math.cos((bearing * Math.PI) / 180); // Calculate Y by centerPosi.y + distance * sin(rad) let y = centerPosi[1] + dis * Math.sin((bearing * Math.PI) / 180); // Reverse X (it work) return [-x / 100, y / 100]; }
道路和建筑数据在开源地图OpenStreetMap上获取即可,可获取道路,建筑,水系等多种数据,虽然数据比较简陋,不过拿来做demo数据还是可以的
cylinder = loaderCylinder(app);
export function loaderCylinder(app) { let texture = new THREE.TextureLoader().load("images/zhu.png") texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复 texture.repeat.set(1, 1) texture.needsUpdate = true let geometry = new THREE.CylinderGeometry(8, 8, 4, 64); let materials = [ new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, transparent: true }), new THREE.MeshBasicMaterial({ transparent: true, opacity: 0, side: THREE.DoubleSide }), new THREE.MeshBasicMaterial({ transparent: true, opacity: 0, side: THREE.DoubleSide }) ] let mesh = new THREE.Mesh(geometry, materials) app.scene.add(mesh) return mesh; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。