import * as THREE from 'three'
export const roadWidth = 12 // 道路宽度基础
export const roadLengthScale = 5 // 道路长度倍数
export const ImgLoader = new THREE.TextureLoader()
const repaintCbs = {}
let m_azimuthalAngle = null;
let m_polarAngle = null;
// 重写控制器实例的update方法,加入钩子
function decoratorCtrl(ctrl){
const fn = ctrl.update
ctrl.update = function() {
let azimuthalAngle = this.getAzimuthalAngle() // 水平旋转角度
let polarAngle = this.getPolarAngle() // 垂直旋转角度
if(m_azimuthalAngle !== azimuthalAngle || m_polarAngle !== polarAngle) {
m_azimuthalAngle = azimuthalAngle
m_polarAngle = polarAngle
for(let key in repaintCbs) {
repaintCbs[key](azimuthalAngle, polarAngle)
}
}
fn()
}
}
// 注册重绘函数
function registerRepaint(uuid, fn) {
repaintCbs[uuid] = fn
}
// 注销重绘函数
function cancelRepaint(uuid) {
if(repaintCbs[uuid]) delete repaintCbs[uuid]
}
export { decoratorCtrl, registerRepaint, cancelRepaint }
const flashCbs = {}
const timer = setInterval(() => {
for(let key in flashCbs) {
flashCbs[key]()
}
},250)
// 扩展 Mesh 的功能,加入到其原型中
let Mesh_Extension = {
bPicked: false, // 是否可交互(滑过有高亮)
bSelected: false, // 是否可选取(点击有高亮)
onSelected: null, // 被选中的回调函数
onCancelSelected: null, // 取消选中的回调函数
choosedTarget: null, // 被选中时,转嫁到其他网格体
// 对自身设置高亮
highlight: function (color = 0xff0000) {
this.originColor = this.material.color.clone();
this.originEmColor = this.material.emissive ? this.material.emissive.clone() : null;
if (color) {
this.material.color.set(color);
this.material.emissive && this.material.emissive.set(color);
}
},
// 对自身取消高亮
unHighlight: function () {
if(this.originColor) {
this.material.color.set(this.originColor);
this.originColor = null
}
if(this.originEmColor) {
this.material.emissive && this.material.emissive.set(this.originEmColor);
this.originEmColor = null
}
},
// 对自身设置闪烁
flashlight: function (color = 0xff0000) {
flashCbs[this.uuid] = () => {
this.flashing = !this.flashing
if(this.flashing) {
this.highlight(color)
}else{
this.unHighlight()
}
}
},
// 对自身取消闪烁
unFlashlight: function () {
if(flashCbs[this.uuid]) delete flashCbs[this.uuid]
},
// 基于物体的包围盒,增大可点击区域
addClickBox(scale = [1,1,1], choosedTarget) {
let mesh = this
mesh.geometry.computeBoundingBox()
let box = mesh.geometry.boundingBox
let x = Math.abs(box.max.x - box.min.x) * scale[0]
let y = Math.abs(box.max.y - box.min.y) * scale[1]
let z = Math.abs(box.max.z - box.min.z) * scale[2]
let boxGeom = new THREE.BoxGeometry(x, y, z);
let boxMater = new THREE.MeshBasicMaterial({
visible: false,
});
let clickBox = new THREE.Mesh(boxGeom, boxMater)
clickBox.name = 'clickArea'
clickBox.bPicked = true
clickBox.bSelected = true
mesh.add(clickBox)
clickBox.choosedTarget = choosedTarget || mesh
},
// 显示/隐藏网格体
targetMesh(target = false) {
this.visible = target
},
}
Object.assign(THREE.Mesh.prototype, Mesh_Extension)
import * as THREE from 'three'
import * as sceneConfig from './sceneConfig.js'
import createRoad from './model/road.js'
import createBuild from './model/building.js'
import {createLight, createPassage} from './model/light.js'
import createArrow from './model/arrow.js'
const roadWidth = sceneConfig.roadWidth // 道路宽度基础
const roadLengthScale = sceneConfig.roadLengthScale // 道路长度倍数
const ImgLoader = sceneConfig.ImgLoader
export default {
ARROW_SHAPE: {},
choosedMesh: null, //被选中的物体, 暂时仅支持单选
// 高亮
HighLight(mesh) {
if (this.tempObject) this.tempObject.unHighlight()
this.tempObject = mesh;
this.tempObject.highlight(0xff0000)
},
// 取消高亮
NoHighLight() {
if (this.tempObject) this.tempObject.unHighlight()
},
// 获取后代网格体
findAllChildrenMesh(root, meshs) {
root = root || window.SceneApp.scene
meshs = meshs || []
if (root.isMesh || root.isGroup) {
meshs.push(root)
}
root.children.forEach((v) => {
meshs.concat(this.findAllChildrenMesh(v, meshs))
})
return meshs
},
// 获取一个路口及其子网格体
getRoadMesh() {
return createRoad()
},
// 设置路口方位
setCrossroadPos(crossroad, dir, roadType) {
if (!crossroad || !dir) return;
let radius;
let shape = this.getCrossroadShape(roadType)
switch (shape) {
case 4:
radius = 0.5
break;
case 6:
radius = Math.sqrt(3) / 2
break;
case 8:
radius = 0.5 / Math.tan(Math.PI / 8)
break;
default:
break;
};
switch (dir) {
case 1:
crossroad.rotation.set(-0.5 * Math.PI, 0, 0.25 * Math.PI);
if (shape === 4) {
crossroad.position.set(-radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2), 0, radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2))
} else if (shape === 6) {
if (roadType.every((v) => { return [1, 3, 4, 6, 7, 9].indexOf(v) >= 0 })) {
crossroad.position.set(-(roadLengthScale / 4 + radius / 2) * roadWidth, 0, roadWidth * ((roadLengthScale / 2 + radius) * radius));
crossroad.rotation.set(-0.5 * Math.PI, 0, Math.PI / 3);
} else {
crossroad.position.set(-(roadLengthScale / 2 + 1) * radius * roadWidth + 1.5, 0, roadWidth * (roadLengthScale / 4 + radius / 2));
crossroad.rotation.set(-0.5 * Math.PI, 0, Math.PI / 6);
}
} else {
crossroad.position.set(-(radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth, 0, (radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth);
}
break;
case 2:
crossroad.rotation.set(-0.5 * Math.PI, 0, 0.5 * Math.PI);
if (shape === 6) {
crossroad.position.set(0, 0, roadWidth * (radius + 0.5 * roadLengthScale));
} else {
crossroad.position.set(0, 0, (radius + 0.5 * roadLengthScale) * roadWidth);
}
break;
case 3:
crossroad.rotation.set(-0.5 * Math.PI, 0, 0.75 * Math.PI);
if (shape === 4) {
crossroad.position.set(radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2), 0, radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2))
} else if (shape === 6) {
if (roadType.every((v) => [1, 3, 4, 6, 7, 9].indexOf(v) >= 0)) {
crossroad.position.set((roadLengthScale / 4 + radius / 2) * roadWidth, 0, roadWidth * ((roadLengthScale / 2 + radius) * radius));
crossroad.rotation.set(-0.5 * Math.PI, 0, Math.PI * 2 / 3);
} else {
crossroad.position.set((roadLengthScale / 2 + 1) * radius * roadWidth - 1.5, 0, roadWidth * (roadLengthScale / 4 + radius / 2));
crossroad.rotation.set(-0.5 * Math.PI, 0, Math.PI * 5 / 6);
}
} else {
crossroad.position.set((radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth, 0, (radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth);
}
break;
case 4:
crossroad.rotation.set(-0.5 * Math.PI, 0, 0);
if (shape === 6) {
crossroad.position.set(-roadWidth * (radius + 0.5 * roadLengthScale), 0, 0);
} else {
crossroad.position.set(-(radius + 0.5 * roadLengthScale) * roadWidth, 0, 0);
}
break;
case 6:
crossroad.rotation.set(-0.5 * Math.PI, 0, -Math.PI);
if (shape === 6) {
crossroad.position.set(roadWidth * (radius + 0.5 * roadLengthScale), 0, 0);
} else {
crossroad.position.set((radius + 0.5 * roadLengthScale) * roadWidth, 0, 0);
}
break;
case 7:
crossroad.rotation.set(-0.5 * Math.PI, 0, -0.25 * Math.PI);
if (shape === 4) {
crossroad.position.set(-radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2), 0, -radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2))
} else if (shape === 6) {
if (roadType.every((v) => [1, 3, 4, 6, 7, 9].indexOf(v) >= 0)) {
crossroad.position.set(-(roadLengthScale / 4 + radius / 2) * roadWidth, 0, -roadWidth * ((roadLengthScale / 2 + radius) * radius));
crossroad.rotation.set(-0.5 * Math.PI, 0, -Math.PI / 3);
} else {
crossroad.position.set(-(roadLengthScale / 2 + 1) * radius * roadWidth + 1.5, 0, -roadWidth * (roadLengthScale / 4 + radius / 2));
crossroad.rotation.set(-0.5 * Math.PI, 0, -Math.PI / 6);
}
} else {
crossroad.position.set(-(radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth, 0, -(radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth);
}
break;
case 8:
crossroad.rotation.set(-0.5 * Math.PI, 0, -0.5 * Math.PI);
if (shape === 6) {
crossroad.position.set(0, 0, -roadWidth * (radius + 0.5 * roadLengthScale));
} else {
crossroad.position.set(0, 0, -(radius + 0.5 * roadLengthScale) * roadWidth);
}
break;
case 9:
crossroad.rotation.set(-0.5 * Math.PI, 0, -0.75 * Math.PI);
if (shape === 4) {
crossroad.position.set(radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2), 0, -radius * roadWidth * (1 + roadLengthScale) / Math.sqrt(2))
} else if (shape === 6) {
if (roadType.every((v) => [1, 3, 4, 6, 7, 9].indexOf(v) >= 0)) {
crossroad.position.set((roadLengthScale / 4 + radius / 2) * roadWidth, 0, -roadWidth * ((roadLengthScale / 2 + radius) * radius));
crossroad.rotation.set(-0.5 * Math.PI, 0, -Math.PI * 2 / 3);
} else {
crossroad.position.set((roadLengthScale / 2 + 1) * radius * roadWidth - 1.5, 0, -roadWidth * (roadLengthScale / 4 + radius / 2));
crossroad.rotation.set(-0.5 * Math.PI, 0, -Math.PI * 5 / 6);
}
} else {
crossroad.position.set((radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth, 0, -(radius + 0.5 * roadLengthScale) / Math.sqrt(2) * roadWidth);
}
break;
default:
break;
}
if(shape === 4) crossroad.setLightPos({ x: (0.5 * roadLengthScale + 1 + 0.3) * roadWidth, y: -roadWidth / 2.3, z: 1.5 })
if(shape === 6) crossroad.setLightPos({ x: (0.5 * roadLengthScale + 1 + 1.1) * roadWidth, y: -roadWidth / 2.3, z: 1.5 })
if(shape === 8) crossroad.setLightPos({ x: (0.5 * roadLengthScale + 1 + 1.8) * roadWidth, y: -roadWidth / 2.3, z: 1.5 })
},
/** 获取路口形状,根据所选的路口,确定使用正四边形、正六边形 或 正八边形
* @param: roadType: 方向集合,例 [2,4,6,8]
* return 4|6|8
*/
getCrossroadShape(roadType) {
if (roadType.every((v) => { return [2, 4, 6, 8].indexOf(v) >= 0 }) || roadType.every((v) => { return [1, 3, 7, 9].indexOf(v) >= 0 })) {
return 4
} else if (roadType.every((v) => { return [1, 3, 4, 6, 7, 9].indexOf(v) >= 0 })
|| roadType.every((v) => { return [1, 2, 3, 7, 8, 9].indexOf(v) >= 0 })
/*|| roadType.every(function(v){return [2,3,4,6,7,8].indexOf(v) >= 0})
|| roadType.every(function(v){return [1,2,4,6,8,9].indexOf(v) >= 0})*/) {
return 6
} else {
return 8
}
},
// 根据路口形状,填补中间处的空白
getCenterRoad(shape, roadType) {
let texture = ImgLoader.load("/static/scene/roadBg.png"); //图片路径
texture.wrapT = THREE.RepeatWrapping;
texture.wrapS = THREE.RepeatWrapping;
let planeMaterial;
let planeGeometry;
let road;
switch (shape) {
case 4:
texture.repeat.set(10, 10)
planeMaterial = new THREE.MeshLambertMaterial({ map: texture })
planeGeometry = new THREE.PlaneGeometry(roadWidth, roadWidth);
road = new THREE.Mesh(planeGeometry, planeMaterial);
road.rotation.set(-0.5 * Math.PI, 0, 0);
if (roadType.every((v) => [1, 3, 7, 9].indexOf(v) >= 0)) {
road.rotation.set(-0.5 * Math.PI, 0, 0.25 * Math.PI);
}
break;
case 6: // 此处的底图形状绘制非最佳方案,应参考八边形,待修改
planeMaterial = new THREE.MeshLambertMaterial({ map: texture })
var roadArr = []
var offset;
if (roadType.every((v) => [1, 3, 4, 6, 7, 9].indexOf(v) >= 0)) {
roadArr = [
null,
{ dir: 1, x: -0.5 * roadWidth, y: -0.25 * Math.sqrt(3) * roadWidth },
{ dir: 3, x: 0, y: 0.5 * roadWidth / Math.sqrt(3) - 0.5 * roadWidth * Math.sqrt(3) },
{ dir: 6, x: 0.5 * roadWidth, y: -0.25 * Math.sqrt(3) * roadWidth },
{ dir: 9, x: 0.5 * roadWidth, y: 0.25 * Math.sqrt(3) * roadWidth },
{ dir: 7, x: 0, y: 0.5 * roadWidth * Math.sqrt(3) - 0.5 * roadWidth / Math.sqrt(3) },
{ dir: 4, x: -0.5 * roadWidth, y: 0.25 * Math.sqrt(3) * roadWidth },
]
offset = [1, 3, 6, 9, 7, 4].findIndex(v => roadType.indexOf(v) > -1)
} else {
roadArr = [
null,
{ dir: 1, x: -0.5 * roadWidth, y: -0.25 * Math.sqrt(3) * roadWidth },
{ dir: 2, x: 0, y: 0.5 * roadWidth / Math.sqrt(3) - 0.5 * roadWidth * Math.sqrt(3) },
{ dir: 3, x: 0.5 * roadWidth, y: -0.25 * Math.sqrt(3) * roadWidth },
{ dir: 9, x: 0.5 * roadWidth, y: 0.25 * Math.sqrt(3) * roadWidth },
{ dir: 8, x: 0, y: 0.5 * roadWidth * Math.sqrt(3) - 0.5 * roadWidth / Math.sqrt(3) },
{ dir: 7, x: -0.5 * roadWidth, y: 0.25 * Math.sqrt(3) * roadWidth },
]
offset = [1, 2, 3, 9, 7, 8].findIndex(v => roadType.indexOf(v) > -1)
}
var points = [ // 从方向1的左侧开始
{ x: -roadWidth, y: 0 },
{ x: -0.5 * roadWidth, y: -0.5 * Math.sqrt(3) * roadWidth },
{ x: 0.5 * roadWidth, y: -0.5 * Math.sqrt(3) * roadWidth },
{ x: roadWidth, y: 0 },
{ x: 0.5 * roadWidth, y: 0.5 * Math.sqrt(3) * roadWidth },
{ x: -0.5 * roadWidth, y: 0.5 * Math.sqrt(3) * roadWidth },
]
points = points.splice(offset).concat(points)
let _arr = roadArr.splice(offset + 1)
roadArr.splice(1, 0, ..._arr)
var roadShape = new THREE.Shape();
roadArr.forEach((v, i, arr) => {
if (i === 0) {
roadShape.moveTo(points[0].x, points[0].y);
} else {
let road = v;
let index = i % 6
let lastIndex = (i + 4) % 6 + 1 // 当前方向的上一方向
let secondIndex = (index + 1) % 7 // 当前方向的下一方向
let thirdIndex = secondIndex % 6 + 1 // 当前方向的下二方向
let fourthIndex = thirdIndex % 6 + 1 // 当前方向的下三方向
let target = points[index]
if (!roadType.find(v => v === road.dir)) { // 当前方向没有车道
if (!roadType.find(v => v === roadArr[secondIndex].dir)) { // 判断下一个方向是否有车道, 连续两个方向没有车道时
if (!roadType.find(v => v === roadArr[thirdIndex].dir)) {
if (!roadType.find(v => v === roadArr[fourthIndex].dir)) { // 连续四个方向没有车道
let second = roadArr[secondIndex]
let third = roadArr[thirdIndex]
roadShape.quadraticCurveTo((second.x + third.x) / 2, (second.y + third.y) / 2, points[fourthIndex % 6].x, points[fourthIndex % 6].y);
} else { // 连续三个方向没有车道
roadShape.quadraticCurveTo(roadArr[secondIndex].x, roadArr[secondIndex].y, points[thirdIndex % 6].x, points[thirdIndex % 6].y);
}
} else {
return;
}
} else if (!roadType.find(v => v === roadArr[lastIndex].dir)) {
roadShape.lineTo(target.x, target.y);
} else {
roadShape.quadraticCurveTo(road.x, road.y, target.x, target.y);
}
} else {
roadShape.lineTo(target.x, target.y);
}
}
})
planeGeometry = new THREE.ShapeGeometry(roadShape)
road = new THREE.Mesh(planeGeometry, planeMaterial)
road.rotation.set(-0.5 * Math.PI, 0, 0);
if (roadType.every((v) => [1, 3, 4, 6, 7, 9].indexOf(v) >= 0)) {
road.rotation.set(-0.5 * Math.PI, 0, Math.PI / 6);
}
break;
case 8:
planeMaterial = new THREE.MeshLambertMaterial({ map: texture })
var points = [ // 从方向1的左侧开始
{ x: -(0.5 + 1 / Math.sqrt(2)) * roadWidth, y: -0.5 * roadWidth },
{ x: -0.5 * roadWidth, y: -(0.5 + 1 / Math.sqrt(2)) * roadWidth },
{ x: 0.5 * roadWidth, y: -(0.5 + 1 / Math.sqrt(2)) * roadWidth },
{ x: (0.5 + 1 / Math.sqrt(2)) * roadWidth, y: -0.5 * roadWidth },
{ x: (0.5 + 1 / Math.sqrt(2)) * roadWidth, y: 0.5 * roadWidth },
{ x: 0.5 * roadWidth, y: (0.5 + 1 / Math.sqrt(2)) * roadWidth },
{ x: -0.5 * roadWidth, y: (0.5 + 1 / Math.sqrt(2)) * roadWidth },
{ x: -(0.5 + 1 / Math.sqrt(2)) * roadWidth, y: 0.5 * roadWidth },
]
var roadArr = [
null,
{ dir: 1, x: -0.5 * roadWidth, y: -0.5 * roadWidth },
{ dir: 2, x: 0, y: -1 / Math.sqrt(2) * roadWidth },
{ dir: 3, x: 0.5 * roadWidth, y: -0.5 * roadWidth },
{ dir: 6, x: 1 / Math.sqrt(2) * roadWidth, y: 0 },
{ dir: 9, x: 0.5 * roadWidth, y: 0.5 * roadWidth },
{ dir: 8, x: 0, y: 1 / Math.sqrt(2) * roadWidth },
{ dir: 7, x: -0.5 * roadWidth, y: 0.5 * roadWidth },
{ dir: 4, x: -1 / Math.sqrt(2) * roadWidth, y: 0 },
]
var offset = [1, 2, 3, 6, 9, 7, 8, 4].findIndex(v => roadType.indexOf(v) > -1)
points = points.splice(offset).concat(points)
var _arr = roadArr.splice(offset + 1)
roadArr.splice(1, 0, ..._arr)
var roadShape = new THREE.Shape()
let sites = []
roadArr.forEach((road, i, arr) => {
let index = i % 8
let target = points[index]
if (i === 0) {
sites.push({ x: points[0].x, y: points[0].y })
} else {
if (!roadType.find(v => v === road.dir)) { // 当前方向没有车道
let offsetX = road.x
let offsetY = road.y
if (sites[sites.length - 1].noLane) { // 连续的无车道方向
sites.pop()
let startIndex = points.findIndex(v => v.x === sites[sites.length - 1].x && v.y === sites[sites.length - 1].y)
let endIndex = points.findIndex(v => v.x === target.x && v.y === target.y) || 8
offsetX = (arr[startIndex + 1].x + arr[endIndex].x) / 2
offsetY = (arr[startIndex + 1].y + arr[endIndex].y) / 2
}
sites.push({ x: target.x, y: target.y, type: "curve", noLane: true, offsetX: offsetX, offsetY: offsetY })
} else {
sites.push({ x: target.x, y: target.y, type: "straight" })
}
}
})
sites.forEach((site, i) => {
if (i === 0) {
roadShape.moveTo(site.x, site.y)
} else if (site.type === 'curve') {
roadShape.quadraticCurveTo(site.offsetX, site.offsetY, site.x, site.y);
} else {
roadShape.lineTo(site.x, site.y);
}
})
planeGeometry = new THREE.ShapeGeometry(roadShape);
road = new THREE.Mesh(planeGeometry, planeMaterial)
road.rotation.set(-0.5 * Math.PI, 0, 0);
window.SceneApp.scene.add(road);
break;
default:
break;
};
road.receiveShadow = true;
road.name = 'centerRoad';
return road
},
// 根据路口形状,绘制装饰物
drawDecoration(scene, shape, roadType) {
if (roadType.every((v) => [2, 4, 6, 8].indexOf(v) >= 0)) {
let build = createBuild({ x: roadWidth * 3.5, y: roadWidth * 1.5, z: roadWidth * 3.5 }, { x: 0, y: -1 * Math.PI, z: 0 });
scene.add(build)
build = createBuild({ x: roadWidth * -3.5, y: roadWidth * 1.5, z: roadWidth * 3.5 }, { x: 0, y: 0.5 * Math.PI, z: 0 });
scene.add(build)
build = createBuild({ x: roadWidth * 3.5, y: roadWidth * 1.5, z: roadWidth * -3.5 }, { x: 0, y: -0.5 * Math.PI, z: 0 });
scene.add(build)
build = createBuild({ x: roadWidth * -3.5, y: roadWidth * 1.5, z: roadWidth * -3.5 }, { x: 0, y: -2 * Math.PI, z: 0 });
scene.add(build)
} else if (roadType.every((v) => [1, 3, 7, 9].indexOf(v) >= 0)) {
let build = createBuild({ x: roadWidth * -3.5 * Math.sqrt(2), y: roadWidth * 1.5, z: 0 }, { x: 0, y: 0.25 * Math.PI, z: 0 });
scene.add(build)
build = createBuild({ x: 0, y: roadWidth * 1.5, z: roadWidth * 3.5 * Math.sqrt(2) }, { x: 0, y: 0.75 * Math.PI, z: 0 });
scene.add(build)
build = createBuild({ x: roadWidth * 3.5 * Math.sqrt(2), y: roadWidth * 1.5, z: 0 }, { x: 0, y: -0.75 * Math.PI, z: 0 });
scene.add(build)
build = createBuild({ x: 0, y: roadWidth * 1.5, z: roadWidth * -3.5 * Math.sqrt(2) }, { x: 0, y: -0.25 * Math.PI, z: 0 });
scene.add(build)
} else {
let roadTexture = ImgLoader.load("/static/scene/road.jpg"); //图片路径
roadTexture.wrapT = THREE.RepeatWrapping;
roadTexture.wrapS = THREE.RepeatWrapping;
roadTexture.repeat.set(30, 30);
let roadMaterial = new THREE.MeshLambertMaterial({ map: roadTexture });
let roadGeometry = new THREE.PlaneGeometry(roadWidth * roadLengthScale * 2.5, roadWidth * roadLengthScale * 2.5);
let road = new THREE.Mesh(roadGeometry, roadMaterial);
road.rotation.set(-0.5 * Math.PI, 0, 0);
road.position.set(0, -0.1, 0)
road.receiveShadow = true;
road.name = "decorations"
scene.add(road)
}
},
// 创建方向标注
createDirTitle(scene) {
var spriteMaterial = new THREE.SpriteMaterial({ map: ImgLoader.load("/static/scene/dirN.png") });
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(2, 2, 2)
sprite.position.set(0, 2, -1.8 * roadWidth)
scene.add(sprite);
},
// 画车道线
drawLane(laneList, crossroad) {
// 人行道
const pavement = laneList.find((v) => {
return v.type === "pavement"
})
let zebra = this.findAllChildrenMesh(crossroad).find((v) => { return v.name === 'zebra' })
if (zebra) {
zebra.userData = pavement
zebra.targetMesh(!!pavement)
}
// 车道
const _laneList = laneList.filter((v) => {
return v.type !== "pavement"
})
const laneNum = _laneList.length
_laneList.forEach((lane, index) => {
let i = index + 1
if (i < laneNum) {
let lineWidth = roadWidth / 5
let lineGeometry = new THREE.PlaneGeometry(lineWidth, roadWidth / 150);
let lineMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
let line = new THREE.Mesh(lineGeometry, lineMaterial);
line.position.set(0.5 * roadWidth * roadLengthScale - lineWidth - 0.3, -i * roadWidth / 2 / laneNum, 0.05);
line.name = "laneLine";
crossroad.add(line);
}
// 加箭头
let arrow = createArrow(lane.type, laneNum);
arrow.position.set(0.5 * roadWidth * roadLengthScale - 2.75, (0.5 - i) * roadWidth / 2 / laneNum, 0.05);
arrow.userData = lane
crossroad.add(arrow);
})
},
// 画信号灯
drawLight(channels, crossroad) {
// 行人通道
let passageChannel = channels.find((v) => {
return v.type == 31
})
let passageMesh = this.findAllChildrenMesh(crossroad).find((v) => { return v.name === 'passageChannel' })
if(passageMesh) {
passageMesh.userData = passageChannel
passageMesh.targetMesh(!!passageChannel)
}
let _channels = channels.filter((v) => {
return v.type != 31
})
var light = createLight(_channels); // 返回灯杆主体
crossroad.add(light);
crossroad.setLightPos();
},
// 绘制路口名称
drawRoadName(parent, text = "", width = 4, height = 1) {
const base = 64
width = width * base
height = height * base
let bgColor = "#fff"
let font = {
size: 30,
color: '#000'
}
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, width, height);
ctx.font = font.size + 'px " bold';
ctx.fillStyle = font.color;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, width / 2, height / 2, width);
let texture = new THREE.CanvasTexture(canvas)
var spriteMaterial = new THREE.SpriteMaterial({ map: texture });
var sprite = new THREE.Sprite(spriteMaterial);
sprite.name = "roadName"
sprite.scale.set(width / base * 2, height / base * 2)
sprite.position.set((0.5 * roadLengthScale - 1) * roadWidth, 0, 1);
let _nameSprite = parent.children.find(v => v.name === "roadName") // 删除原来的道路名,更好的方式应该是更换材质,待修改
if (_nameSprite) parent.remove(_nameSprite)
if (!text) return;
parent.add(sprite)
},
}