Fence
Example
Example Source Code
vue
<template>
<div style="height: 500px" class="vw-full vh-full">
<div style="height: 400px">
<mb-map
:zoom="13"
:center="mapCenter"
:bearing="0"
:pitch="45"
@created="createdHandler"
>
<mb-tianditu-layer />
</mb-map>
</div>
</div>
</template>
<script setup lang="ts">
import * as THREE from 'three'
import type { MapboxInstance } from '@mapbox-vue3/core'
const mapCenter = [116.390799, 39.915876]
let map: MapboxInstance
const createdHandler = (mapbox: MapboxInstance) => {
map = mapbox
loaderModels()
}
const loaderModels = () => {
const boundary1 = [
[116.385394, 39.92098],
[116.38591, 39.911632],
[116.389942, 39.911565],
[116.390457, 39.908734],
[116.392174, 39.908733],
[116.39226, 39.911959],
[116.396294, 39.911894],
[116.395691, 39.921438],
[116.385394, 39.92098],
]
addThreeLayer(boundary1)
}
const addThreeLayer = (boundary1: number[][]) => {
const threeLayer = new map.mapboxgl.supermap.ThreeLayer('threeLayer')
threeLayer.on('initialized', render)
let light: THREE.PointLight
function render(this: any) {
const renderer = threeLayer.getThreeRenderer(),
scene = threeLayer.getScene(),
camera = threeLayer.getCamera()
light = new THREE.PointLight(0xffffff, 0.8)
light.position.copy(camera.position)
scene.add(light)
scene.add(new THREE.AmbientLight(0xffffff))
const centerBoundary = this.getCoordinatesCenter(boundary1)
const centerPoint = this.lngLatToPosition(centerBoundary)
const outer = boundary1.map((coords) =>
this.lngLatToPosition({
lng: coords[0],
lat: coords[1],
}).sub(centerPoint)
)
const polygonMesh = addFencing(outer.map((p) => [p.x, 0, p.y]))
polygonMesh.rotation.x = Math.PI / 2
polygonMesh.rotation.y = Math.PI * 2.98
threeLayer.setPosition(polygonMesh, [116.390714, 39.916535])
scene.add(polygonMesh)
renderer.render(scene, camera)
}
threeLayer.on('render', () => {
light && light.position.copy(threeLayer.renderer.camera.position)
})
map.addLayer(threeLayer)
}
const addFencing = (points: number[][]) => {
const height = 1500 // 高度 height
// 围栏距离 fence distance
const pointDistance: number[] = []
const distance = points.reduce((totalDistance, point, index) => {
let segmentDistance = 0
if (index > 0) {
const lastPoint = new THREE.Vector3(...points[index - 1])
const currPoint = new THREE.Vector3(...point)
segmentDistance = lastPoint.distanceTo(currPoint)
}
totalDistance += segmentDistance
pointDistance.push(totalDistance)
return totalDistance
}, 0)
const geometry = new THREE.BufferGeometry()
const posArr: number[] = []
const uvArr: number[] = []
points.forEach((point, index) => {
if (index == 0) return
const lastPoint = points[index - 1]
// 三角面1 triangle1
posArr.push(...lastPoint)
uvArr.push(pointDistance[index - 1] / distance, 0)
posArr.push(...point)
uvArr.push(pointDistance[index] / distance, 0)
posArr.push(lastPoint[0], lastPoint[1] + height, lastPoint[2])
uvArr.push(pointDistance[index - 1] / distance, 1)
// 三角面2 triangle2
posArr.push(...point)
uvArr.push(pointDistance[index] / distance, 0)
posArr.push(point[0], point[1] + height, point[2])
uvArr.push(pointDistance[index] / distance, 1)
posArr.push(lastPoint[0], lastPoint[1] + height, lastPoint[2])
uvArr.push(pointDistance[index - 1] / distance, 1)
})
geometry.setAttribute(
'position',
new THREE.BufferAttribute(new Float32Array(posArr), 3)
)
geometry.setAttribute(
'uv',
new THREE.BufferAttribute(new Float32Array(uvArr), 2)
)
geometry.computeVertexNormals()
const texture = new THREE.TextureLoader().load(
`${__RESOURCE_URL__}images/wall.png`
)
texture.wrapS = THREE.RepeatWrapping
texture.wrapT = THREE.RepeatWrapping
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
map: texture,
transparent: true,
opacity: 0.9,
depthWrite: false,
side: THREE.DoubleSide,
})
const mesh = new THREE.Mesh(geometry, material)
return mesh
}
</script>