本文適合對(duì)vue,arcgis4.x,threejs,ES6較熟悉的人群食用。
效果圖:
(資料圖)
素材:
主要思路:
先用arcgisexternalRenderers封裝了一個(gè)ExternalRendererLayer,在里面把a(bǔ)rcgis和threejs的context關(guān)聯(lián),然后再寫(xiě)個(gè)子類繼承它,這部分類容在上一個(gè)帖子里面有講過(guò)。
子類AreaLayer繼承它,并在里面實(shí)現(xiàn)繪制流光邊界線的方法,我這里其實(shí)就是繪制城市區(qū)域的邊界線。嘗試過(guò)直線LineCurve3,三維二次貝塞爾曲線QuadraticBezierCurve3,三維三次貝塞爾曲線CubicBezierCurve3,結(jié)果感覺(jué)差不多=_=,所以最后還是用CatmullRomCurve3這個(gè)來(lái)構(gòu)建管道,這個(gè)類使用也比其他的方便。
1:創(chuàng)建一個(gè)基于圖片的材質(zhì)
1 const lineImg = require("../../../../public/static/img/line.png") 2 let lineTexture = new THREE.TextureLoader().load(lineImg) 3 lineTexture.wrapS = lineTexture.wrapT = THREE.RepeatWrapping; //每個(gè)都重復(fù) 4 lineTexture.repeat.set(1, 1) 5 lineTexture.needsUpdate = true 6 7 let lineMaterial = new THREE.MeshBasicMaterial({ 8 map: lineTexture, 9 side: THREE.DoubleSide,10 transparent: true11 })2:處理坐標(biāo)轉(zhuǎn)換數(shù)據(jù)
1 let linePoints = []2 for(let i = 0; i < pointList.length; i++) {3 var item = pointList[i];4 var renderLinePoints = this.lngLatToXY(this.view, [item[0], item[1], 10]);5 var vector3List = renderLinePoints.vector3List;6 7 linePoints.push(new THREE.Vector3(vector3List.x, vector3List.y, vector3List.z));8 }3:構(gòu)建TubeGeometry,創(chuàng)建Mesh
1 const curvePath = new THREE.CatmullRomCurve3(linePoints) // 曲線路徑2 3 let geometry = new THREE.TubeGeometry(curvePath, 64, 30, 8, true )4 let lineMesh = new THREE.Mesh(geometry, lineMaterial);
4:最后再updateModels里面更新貼圖的位置(其實(shí)就是render事件)。
1 updateModels(context) {2 super.updateModels(context);3 4 if (this.textures.length > 0) {5 this.textures.forEach(texture => {6 if (texture) texture.offset.x -= 0.01;7 })8 }9 }ExternalRendererLayer:
1 import * as THREE from "three" 2 import Stats from "three/examples/jsm/libs/stats.module.js" 3 import * as webMercatorUtils from "@arcgis/core/geometry/support/webMercatorUtils" 4 import * as externalRenderers from "@arcgis/core/views/3d/externalRenderers" 5 6 export default class ExternalRendererLayer { 7 constructor({ 8 view, 9 options 10 }) { 11 this.view = view 12 this.options = options 13 14 this.objects = [] 15 this.scene = null 16 this.camera = null 17 this.renderer = null 18 19 this.setup(); 20 } 21 22 setup() { 23 if (process.env.NODE_ENV !== "production") { 24 const sid = setTimeout(() => { 25 clearTimeout(sid) 26 //構(gòu)建幀率查看器 27 let stats = new Stats() 28 stats.setMode(0) 29 stats.domElement.style.position = "absolute" 30 stats.domElement.style.left = "0px" 31 stats.domElement.style.top = "0px" 32 document.body.appendChild(stats.domElement) 33 function render() { 34 stats.update() 35 requestAnimationFrame(render) 36 } 37 render() 38 }, 5000) 39 } 40 } 41 42 apply() { 43 let myExternalRenderer = { 44 setup: context => { 45 this.createSetup(context) 46 }, 47 render: context => { 48 this.createRender(context) 49 } 50 } 51 52 externalRenderers.add(this.view, myExternalRenderer); 53 } 54 55 createSetup(context) { 56 this.scene = new THREE.Scene(); // 場(chǎng)景 57 this.camera = new THREE.PerspectiveCamera(); // 相機(jī) 58 59 this.setLight(); 60 61 // 添加坐標(biāo)軸輔助工具 62 const axesHelper = new THREE.AxesHelper(10000000); 63 this.scene.Helpers = axesHelper; 64 this.scene.add(axesHelper); 65 66 this.renderer = new THREE.WebGLRenderer({ 67 context: context.gl, // 可用于將渲染器附加到已有的渲染環(huán)境(RenderingContext)中 68 premultipliedAlpha: false, // renderer是否假設(shè)顏色有 premultiplied alpha. 默認(rèn)為true 69 // antialias: true 70 // logarithmicDepthBuffer: false 71 // logarithmicDepthBuffer: true 72 }); 73 this.renderer.setPixelRatio(window.devicePixelRatio); // 設(shè)置設(shè)備像素比。通常用于避免HiDPI設(shè)備上繪圖模糊 74 this.renderer.setViewport(0, 0, this.view.width, this.view.height); // 視口大小設(shè)置 75 76 // 防止Three.js清除ArcGIS JS API提供的緩沖區(qū)。 77 this.renderer.autoClearDepth = false; // 定義renderer是否清除深度緩存 78 this.renderer.autoClearStencil = false; // 定義renderer是否清除模板緩存 79 this.renderer.autoClearColor = false; // 定義renderer是否清除顏色緩存 80 // this.renderer.autoClear = false; 81 82 // ArcGIS JS API渲染自定義離屏緩沖區(qū),而不是默認(rèn)的幀緩沖區(qū)。 83 // 我們必須將這段代碼注入到three.js運(yùn)行時(shí)中,以便綁定這些緩沖區(qū)而不是默認(rèn)的緩沖區(qū)。 84 const originalSetRenderTarget = this.renderer.setRenderTarget.bind( 85 this.renderer 86 ); 87 this.renderer.setRenderTarget = target => { 88 originalSetRenderTarget(target); 89 if (target == null) { 90 // 綁定外部渲染器應(yīng)該渲染到的顏色和深度緩沖區(qū) 91 context.bindRenderTarget(); 92 } 93 }; 94 95 this.addModels(context); 96 97 context.resetWebGLState(); 98 } 99 100 createRender(context) {101 const cam = context.camera;102 this.camera.position.set(cam.eye[0], cam.eye[1], cam.eye[2]);103 this.camera.up.set(cam.up[0], cam.up[1], cam.up[2]);104 this.camera.lookAt(105 new THREE.Vector3(cam.center[0], cam.center[1], cam.center[2])106 );107 // this.camera.near = 1;108 // this.camera.far = 100;109 110 // 投影矩陣可以直接復(fù)制111 this.camera.projectionMatrix.fromArray(cam.projectionMatrix);112 113 this.updateModels(context);114 115 this.renderer.state.reset();116 117 context.bindRenderTarget();118 119 this.renderer.render(this.scene, this.camera);120 121 // 請(qǐng)求重繪視圖。122 externalRenderers.requestRender(this.view);123 124 // cleanup125 context.resetWebGLState();126 }127 128 //經(jīng)緯度坐標(biāo)轉(zhuǎn)成三維空間坐標(biāo)129 lngLatToXY(view, points) {130 131 let vector3List; // 頂點(diǎn)數(shù)組132 133 let pointXYs;134 135 136 // 計(jì)算頂點(diǎn)137 let transform = new THREE.Matrix4(); // 變換矩陣138 let transformation = new Array(16);139 140 // 將經(jīng)緯度坐標(biāo)轉(zhuǎn)換為xy值\141 let pointXY = webMercatorUtils.lngLatToXY(points[0], points[1]);142 143 // 先轉(zhuǎn)換高度為0的點(diǎn)144 transform.fromArray(145 externalRenderers.renderCoordinateTransformAt(146 view,147 [pointXY[0], pointXY[1], points[148 2]], // 坐標(biāo)在地面上的點(diǎn)[x值, y值, 高度值]149 view.spatialReference,150 transformation151 )152 );153 154 pointXYs = pointXY;155 156 vector3List =157 new THREE.Vector3(158 transform.elements[12],159 transform.elements[13],160 transform.elements[14]161 )162 163 return {164 vector3List: vector3List,165 pointXYs: pointXYs166 };167 }168 169 setLight() {170 console.log("setLight")171 let ambient = new THREE.AmbientLight(0xffffff, 0.7);172 this.scene.add(ambient);173 let directionalLight = new THREE.DirectionalLight(0xffffff, 0.7);174 directionalLight.position.set(100, 300, 200);175 this.scene.add(directionalLight);176 }177 178 addModels(context) {179 console.log("addModels")180 }181 182 updateModels(context) {183 // console.log("updateModels")184 }185 186 }View CodeAreaLayer:源碼中mapx.queryTask是封裝了arcgis的query查詢,這個(gè)可以替換掉,我只是要接收返回的rings數(shù)組,自行構(gòu)建靜態(tài)數(shù)據(jù)也行
1 import * as THREE from "three" 2 import ExternalRendererLayer from "./ExternalRendererLayer.js" 3 import Graphic from "@arcgis/core/Graphic"; 4 import SpatialReference from "@arcgis/core/geometry/SpatialReference" 5 import * as externalRenderers from "@arcgis/core/views/3d/externalRenderers" 6 7 import mapx from "@/utils/mapUtils.js"; 8 9 export default class AreaLayer extends ExternalRendererLayer { 10 constructor({ 11 view, 12 options 13 }) { 14 super({ 15 view, 16 options 17 }) 18 } 19 20 setup() { 21 super.setup() 22 23 this.textures = [] 24 } 25 26 addModels(context) { 27 // super.addModels(context) 28 // =====================mesh加載=================================// 29 const url = config.mapservice[1].base_url + config.mapservice[1].jd_url; 30 // const url = "http://10.100.0.132:6080/arcgis/rest/services/wuchang_gim/gim_region/MapServer/2"; 31 mapx.queryTask(url, { 32 where: "1=1", 33 returnGeometry: true 34 }).then(featureSet => { 35 if (featureSet.length > 0) { 36 featureSet.forEach(feature => { 37 const polygon = feature.geometry; 38 const rings = polygon.rings; 39 rings.forEach(ring => { 40 this._addModel(ring); 41 }) 42 }) 43 } 44 }).catch(error => { 45 console.log(error) 46 }) 47 } 48 49 _addModel(pointList) { 50 const lineImg = require("../../../../public/static/img/line.png") 51 let lineTexture = new THREE.TextureLoader().load(lineImg) 52 lineTexture.wrapS = lineTexture.wrapT = THREE.RepeatWrapping; //每個(gè)都重復(fù) 53 lineTexture.repeat.set(1, 1) 54 lineTexture.needsUpdate = true 55 56 let lineMaterial = new THREE.MeshBasicMaterial({ 57 map: lineTexture, 58 side: THREE.DoubleSide, 59 transparent: true 60 }) 61 62 //確定幾何體位置 63 let linePoints = [] 64 // let curvePath = new THREE.CurvePath(); 65 for(let i = 0; i < pointList.length; i++) { 66 var item = pointList[i]; 67 var renderLinePoints = this.lngLatToXY(this.view, [item[0], item[1], 10]); 68 var vector3List = renderLinePoints.vector3List; 69 70 linePoints.push(new THREE.Vector3(vector3List.x, vector3List.y, vector3List.z)); 71 72 // if(i < pointList.length - 1) { 73 // var item1 = pointList[i + 1]; 74 // var renderLinePoints1 = this.lngLatToXY(this.view, [item1[0], item1[1], 10]); 75 // var vector3List1 = renderLinePoints1.vector3List; 76 77 // // var item2 = pointList[i + 1]; 78 // // var renderLinePoints2 = this.lngLatToXY(this.view, [item2[0], item2[1], 10]); 79 // // var vector3List2 = renderLinePoints2.vector3List; 80 81 // const line = new THREE.LineCurve3(vector3List, vector3List1); 82 // // const line = new THREE.QuadraticBezierCurve3(vector3List, vector3List1, vector3List2); 83 // curvePath.curves.push(line) 84 // } 85 } 86 87 // console.log(curvePath) 88 89 // CatmullRomCurve3創(chuàng)建一條平滑的三維樣條曲線 90 const curvePath = new THREE.CatmullRomCurve3(linePoints) // 曲線路徑 91 92 let geometry = new THREE.TubeGeometry(curvePath, 64, 30, 8, true ) 93 let lineMesh = new THREE.Mesh(geometry, lineMaterial); 94 95 this.scene.add(lineMesh); 96 97 this.textures.push(lineTexture); 98 this.objects.push(lineMesh); 99 }100 101 102 updateModels(context) {103 super.updateModels(context);104 105 if (this.textures.length > 0) {106 this.textures.forEach(texture => {107 if (texture) texture.offset.x -= 0.01;108 })109 }110 }111 112 }View Code 關(guān)鍵詞:
總導(dǎo)演劇透杭州亞運(yùn)會(huì)開(kāi)幕式創(chuàng)意 02:30從冬奧會(huì)到大運(yùn)會(huì)再到亞運(yùn)會(huì),“簡(jiǎn)約、安全、精彩”的六字方針如
百度AI大模型文心一言向全社會(huì)開(kāi)放 可體驗(yàn)生成式AI 百度近日宣布,其AI大模型“文心一言”已全面向全社會(huì)開(kāi)放,用戶可從蘋
天下之無(wú)道也久矣天將以夫子為木鐸是什么意思 0471房產(chǎn)來(lái)為大家解答以上的問(wèn)題。天下之無(wú)道也久矣天將以夫子為木鐸是
河北臨漳開(kāi)展2023年“招才引智”活動(dòng) 為引導(dǎo)暑期“返家鄉(xiāng)”大學(xué)生關(guān)注家鄉(xiāng)發(fā)展、了解家鄉(xiāng)政策,學(xué)成后能夠回
9月4日起??濱河?xùn)|、西路早晚高峰期限行調(diào)流措施恢復(fù) 9月4日起濱河?xùn)|、西路早晚高峰期限行調(diào)流措施恢復(fù),主流媒體,山西門戶。
歡送會(huì)上送崗位 原標(biāo)題:歡送會(huì)上送崗位8月29日,天津市和平區(qū)總工會(huì)勞模協(xié)會(huì)組織轄區(qū)