控制台
登录
注册
退出
我的消息
云图市场
应用管理
GeoHUB
产品介绍
产品介绍
高德开放平台产品介绍
查看全部文档
搜索定位
搜索
HOT
位置、周边、行政区、ID等查询接口
API
JS
Android
iOS
定位
HOT
基于LBS的定位服务
API
Android
iOS
地理/逆地理编码
位置名称与经纬度之间转换服务
API
JS
Android
iOS
地理围栏
虚拟空间围栏服务
API
Android
iOS
天气查询
查询目标区域当前/未来天气
路线导航
导航
HOT
轻松地在APP中加入导航能力
Android
iOS
路线规划
HOT
提供步行、驾车等规划能力
API
JS
Android
iOS
猎鹰服务
提供专业轨迹管理服务
API
Android
iOS
智能调度引擎
智能外勤调度,提升效益
物流服务
提供智慧物流API服务接口
地图产品
动态地图
HOT
动态地图展示、配置
API
JS
Android
iOS
HarmonyOS
3D地图
HOT
3D动态地图展示、配置
地铁图
简单易用的移动端地铁线路图开发接口
JS
Android
iOS
静态地图
灵活地将高德地图迁入应用网页
3D地形图
卫星地形图还原真实地形地貌
高级地图工具
高德地图小程序
NEW
自定义地图
地图数据可视化 (LOCA)
地图数据中心 (GeoHUB)
坐标拾取器
高德地图URI Web
高德地图URI APP
三维模型转换
微信小程序插件
地图Flutter插件
地图名片
解决方案
解决方案
提供各行业LBS解决方案
查看解决方案
手机银行
NEW
提供手机银行APP地图应用
智能派单
一站式精准智能派单解决方案
上门服务调度
提供上门业务调度解决方案
零售铺货
零售快消行业,渠道铺货解决方案
网格化营销
NEW
提供银行网格化营销场景应用
智慧交通
优化交通资源配置,赋能智慧交通系统
出行
提供网约车等出行场景解决方案
O2O
到店、到家等多种O2O业务解决方案
三农场景可视化
NEW
提供乡村振兴三农场景应用
社交
社交应用位置服务解决方案
运动
运动类应用解决方案
智能硬件
智能硬件LBS解决方案
智慧物流
针对物流行业提供解决方案
电商
电商物流行业解决方案
地址服务
综合地址服务,满足客户全景化需求
企业智图
一张图轻松管理企业数据
文档与支持
文档与支持
高德开放平台开发文档与服务支持
查看全部文档
API
Web服务 API
猎鹰服务 API
JS API
JS API
数据可视化JS API
地图组件
URI API
地铁图 JS API
Android 平台
Android 地图SDK
Android 轻量版地图SDK
Android 定位SDK
Android 导航SDK
Android 猎鹰SDK
iOS 平台
iOS 地图SDK
iOS 轻量版地图SDK
iOS 定位SDK
iOS 导航SDK
iOS 猎鹰SDK
服务与支持
常见问题
创建工单
示例中心
合规中心
服务升级
服务升级
高德开放平台服务升级计划
服务升级计划
服务提升
提升配额
商用服务
GeoHUB自定义地图
GeoHUB数据中心
产品升级
高级能力
企业智图SaaS
云图市场
为什么选择高德
历史记录
热门推荐
Android定位
Android定位问题相关
浏览器定位
JS API提供Geolocation定位插件
逆地理编码
经纬度转换为详细结构化的地址
自定义地图
7大类44种地图元素可定制
认证开发商
商业授权相关问题
开发者示例
ThreeJS使用
利用 ThreeJS 实现动态围栏效果
使用 ThreeJS 加载模型和路径动画
扩展图层
使用 Canvas 在地图上播放视频
示例代码报错,请检查
message:
stack:
‹
›
利用 ThreeJS 实现动态围栏效果
源代码编辑器
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"> <title>利用 ThreeJS 实现动态边界墙</title> <link rel="stylesheet" href="http://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" /> <style> html, body, #container { width: 100%; height: 100%; } </style> </head> <body> <div id="container"></div> <script> console.warn = console.log; </script> <script src="http://webapi.amap.com/maps?v=2.0&key=您申请的key值"></script> <script src="https://cdn.jsdelivr.net/npm/three@0.142/build/three.js"></script> <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@master/examples/js/loaders/GLTFLoader.js"> </script> <script>javascript: (function () { var script = document.createElement('script'); script.onload = function () { var stats = new Stats(); document.body.appendChild(stats.dom); requestAnimationFrame(function loop() { stats.update(); requestAnimationFrame(loop) }); }; script.src = 'https://mrdoob.github.io/stats.js/build/stats.min.js'; document.head.appendChild(script); })() </script> <script> const container = document.getElementById('container') const map = new AMap.Map('container', { center: [116.52668, 39.794678], zooms: [2, 20], zoom: 17.5, viewMode: '3D', mapStyle: 'amap://styles/grey', pitch: 52, }) map.on('click', (event) => { const {lng, lat} = event.lnglat console.log([lng, lat]) }) // 墙体路径原始数据 const data = [ [ [116.523344, 39.795124], [116.526568, 39.796617], [116.528888, 39.793540], [116.525796, 39.792064], [116.523344, 39.795124], ] ] // 地理坐标转为three坐标系,不管用不用arr,都需要转换一个非空数组 // 否则customCoords没实例化api会报错 const paths = map.customCoords.lngLatsToCoords(data) // 墙体高度 const height = 50 // 墙体颜色 const color = '#FFD500' // 动效纹理 let texture = null // 动效纹理偏移 let texture_offset = 0 // THREE相关变量 let camera, scene, renderer // 初始化图层 function initLayer () { const layer = new AMap.GLCustomLayer({ zIndex: 9999, visible: true, init: (gl) => { initThree(gl) createWall() animate() }, render: () => { const { near, far, fov, up, lookAt, position } = map.customCoords.getCameraParams() camera.near = near// 近平面 camera.far = far // 远平面 camera.fov = fov // 视野范围 camera.position.set(...position) camera.up.set(...up) camera.lookAt(...lookAt) // 更新相机坐标系 camera.updateProjectionMatrix() renderer.render(scene, camera) // 这里必须执行!重新设置 three 的 gl 上下文状态 renderer.resetState() } }) map.add(layer) } function initThree (gl) { camera = new THREE.PerspectiveCamera(60, container.clientWidth / container.clientHeight, 100, 1 << 30) renderer = new THREE.WebGLRenderer({ context: gl, // canvas: document.querySelector('.amap-layer'), //也可以直接用canvas初始化 antialias: true // 抗锯齿,默认false 耗性能 }) // 自动清空画布这里必须设置为 false,否则地图底图将无法显示 renderer.autoClear = false renderer.outputEncoding = THREE.sRGBEncoding scene = new THREE.Scene() // 增加环境光 const aLight = new THREE.AmbientLight(0xffffff, 0.3) scene.add(aLight) } function createCube () { const geometry = new THREE.BoxGeometry(200, 200, 200) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide, transparent: true, depthWrite: false }) const cube = new THREE.Mesh(geometry, material) cube.position.set(0, 0, 0) scene.add(cube) } function createWall () { let faceList = [] let faceVertexUvs = [] // 合并多个闭合范围 for (let i = 0; i < paths.length; i++) { const { face, uvs } = generateVecData(paths[i]) faceList = [...faceList, ...face] faceVertexUvs = [...faceVertexUvs, ...uvs] } // 背景层 const geometry = new THREE.BufferGeometry() geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(faceList), 3)) geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(faceVertexUvs), 2)) const material1 = new THREE.MeshBasicMaterial({ color: color, side: THREE.DoubleSide, transparent: true, depthWrite: false, alphaMap: new THREE.TextureLoader().load('./images/texture_1.png'), // 不透明图片 // wireframe: true }) const mesh1 = new THREE.Mesh(geometry, material1) scene.add(mesh1) // 动画层 const geometry2 = geometry.clone() texture = this.generateTexture(128, color) texture.wrapS = THREE.RepeatWrapping // 水平重复平铺 texture.wrapT = THREE.RepeatWrapping // 垂直重复平铺 const material2 = new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, transparent: true, depthWrite: false, map: texture }) const mesh2 = new THREE.Mesh(geometry2, material2) scene.add(mesh2) } /** * 创建一个闭合范围的模型数据 * @param res {Object} 包含面的顶点数据face,UV面的顶点数据uvs */ function generateVecData (arr) { const vec3List = [] // 顶点数组 let faceList = [] // 三角面数组 let faceVertexUvs = [] // 面的UV层队列,用于纹理和几何信息映射 // t3---t2 // | \ | // t0---t1 // UV面 // 下三角[t0, t1, t3] // 上三角[t3, t1, t2] const t0 = [0, 0] const t1 = [1, 0] const t2 = [1, 1] const t3 = [0, 1] for (let i = 0; i < arr.length; i++) { const [x1, y1] = arr[i] vec3List.push([x1, y1, 0]) vec3List.push([x1, y1, height]) } // 1---3 // | \ | // 0---2 // 三角面顶点,没有顺序要求,但要跟UV面顺序一致 // 下三角 [0,1,2] // 上三角 [1,2,3] for (let i = 0; i < vec3List.length - 2; i++) { if (i % 2 === 0) { // 下三角 faceList = [...faceList, ...vec3List[i], ...vec3List[i + 2], ...vec3List[i + 1]] // UV faceVertexUvs = [...faceVertexUvs, ...t0, ...t1, ...t3] } else { // 上三角 faceList = [...faceList, ...vec3List[i], ...vec3List[i + 1], ...vec3List[i + 2]] // UV faceVertexUvs = [...faceVertexUvs, ...t3, ...t1, ...t2] } } return { face: faceList, uvs: faceVertexUvs } } /** * 创建材质图 * @param size 尺寸为2的n次方 * @param color 颜色 * @returns {*} */ function generateTexture(size = 64, color ="#ff0000"){ let canvas = document.createElement('canvas') canvas.width = size canvas.height = size let ctx = canvas.getContext('2d') let linearGradient = ctx.createLinearGradient(0,0,0,size) linearGradient.addColorStop(0.2, hexToRgba(color, 0.0)) linearGradient.addColorStop(0.8, hexToRgba(color, 0.5)) linearGradient.addColorStop(1.0, hexToRgba(color, 1.0)) ctx.fillStyle = linearGradient ctx.fillRect(0,0, size, size) let texture = new THREE.Texture(canvas) texture.needsUpdate = true //必须 return texture } /** * 将十六进制的颜色值转成rgba * @param {String} hex * @param {number} opacity * @returns {string} */ function hexToRgba (hex, opacity = 1) { return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ',' + parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')' } // 动画 function animate () { // 纹理偏移 texture_offset -= 0.03 // 向上移动 texture.offset.set(0, texture_offset) if (map) { map.render() } requestAnimationFrame(() => { animate() }) } initLayer() </script> </body> </html>
控制台
清空
返回顶部
示例中心
常见问题
智能客服