怎么使用three.js 绘制三维带箭头线
发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,今天就跟大家聊聊有关怎么使用three.js 绘制三维带箭头线,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。需求:这个需求是个刚需啊!在一个地
千家信息网最后更新 2025年01月16日怎么使用three.js 绘制三维带箭头线
今天就跟大家聊聊有关怎么使用three.js 绘制三维带箭头线,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
需求:这个需求是个刚需啊!在一个地铁场景里展示逃生路线,这个路线肯定是要有指示箭头的,为了画这个箭头,我花了不少于十几个小时,总算做出来了,但始终有点问题。我对这个箭头的要求是,无论场景拉近还是拉远,这个箭头不能太大,也不能太小看不清,形状不能变化,否则就不像箭头了。
使用到了 three.js 的 Line2.js 和一个开源库MeshLine.js
部分代码:
DrawPath.js:
/** * 绘制路线 */import * as THREE from '../build/three.module.js';import { MeshLine, MeshLineMaterial, MeshLineRaycast } from '../js.my/MeshLine.js';import { Line2 } from '../js/lines/Line2.js';import { LineMaterial } from '../js/lines/LineMaterial.js';import { LineGeometry } from '../js/lines/LineGeometry.js';import { GeometryUtils } from '../js/utils/GeometryUtils.js';import { CanvasDraw } from '../js.my/CanvasDraw.js';import { Utils } from '../js.my/Utils.js';import { Msg } from '../js.my/Msg.js';let DrawPath = function () { let _self = this; let _canvasDraw = new CanvasDraw(); let utils = new Utils(); let msg = new Msg(); this._isDrawing = false; this._path = []; this._lines = []; this._arrows = []; let _depthTest = true; let _side = 0; let viewerContainerId = '#cc'; let viewerContainer = $(viewerContainerId)[0]; let objects; let camera; let turn; let scene; this.config = function (objects_, camera_, scene_, turn_) { objects = objects_; camera = camera_; turn = turn_; scene = scene_; this._oldDistance = 1; this._oldCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z } } this.start = function () { if (!this._isDrawing) { this._isDrawing = true; viewerContainer.addEventListener('click', ray); viewerContainer.addEventListener('mousedown', mousedown); viewerContainer.addEventListener('mouseup', mouseup); } msg.show("请点击地面画线"); } this.stop = function () { if (this._isDrawing) { this._isDrawing = false; viewerContainer.removeEventListener('click', ray); viewerContainer.addEventListener('mousedown', mousedown); viewerContainer.addEventListener('mouseup', mouseup); } msg.show("停止画线"); } function mousedown(params) { this._mousedownPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z } } function mouseup(params) { this._mouseupPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z } } function ray(e) { turn.unFocusButton(); let raycaster = createRaycaster(e.clientX, e.clientY); let intersects = raycaster.intersectObjects(objects.all); if (intersects.length > 0) { let point = intersects[0].point; let distance = utils.distance(this._mousedownPosition.x, this._mousedownPosition.y, this._mousedownPosition.z, this._mouseupPosition.x, this._mouseupPosition.y, this._mouseupPosition.z); if (distance < 5) { _self._path.push({ x: point.x, y: point.y + 50, z: point.z }); if (_self._path.length > 1) { let point1 = _self._path[_self._path.length - 2]; let point2 = _self._path[_self._path.length - 1]; drawLine(point1, point2); drawArrow(point1, point2); } } } } function createRaycaster(clientX, clientY) { let x = (clientX / $(viewerContainerId).width()) * 2 - 1; let y = -(clientY / $(viewerContainerId).height()) * 2 + 1; let standardVector = new THREE.Vector3(x, y, 0.5); let worldVector = standardVector.unproject(camera); let ray = worldVector.sub(camera.position).normalize(); let raycaster = new THREE.Raycaster(camera.position, ray); return raycaster; } this.refresh = function () { if (_self._path.length > 1) { let distance = utils.distance(this._oldCameraPos.x, this._oldCameraPos.y, this._oldCameraPos.z, camera.position.x, camera.position.y, camera.position.z); let ratio = 1; if (this._oldDistance != 0) { ratio = Math.abs((this._oldDistance - distance) / this._oldDistance) } if (distance > 5 && ratio > 0.1) { console.log("======== DrawPath 刷新 ====================================================") for (let i = 0; i < _self._path.length - 1; i++) { let arrow = _self._arrows[i]; let point1 = _self._path[i]; let point2 = _self._path[i + 1]; refreshArrow(point1, point2, arrow); } this._oldDistance = distance; this._oldCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z } } } } function drawLine(point1, point2) { const positions = []; positions.push(point1.x / 50, point1.y / 50, point1.z / 50); positions.push(point2.x / 50, point2.y / 50, point2.z / 50); let geometry = new LineGeometry(); geometry.setPositions(positions); let matLine = new LineMaterial({ color: 0x009900, linewidth: 0.003, // in world units with size attenuation, pixels otherwise dashed: true, depthTest: _depthTest, side: _side }); let line = new Line2(geometry, matLine); line.computeLineDistances(); line.scale.set(50, 50, 50); scene.add(line); _self._lines.push(line); } function drawArrow(point1, point2) { let arrowLine = _self.createArrowLine(point1, point2); var meshLine = arrowLine.meshLine; let canvasTexture = _canvasDraw.drawArrow(THREE, renderer, 300, 100); //箭头 var material = new MeshLineMaterial({ useMap: true, map: canvasTexture, color: new THREE.Color(0x00f300), opacity: 1, resolution: new THREE.Vector2($(viewerContainerId).width(), $(viewerContainerId).height()), lineWidth: arrowLine.lineWidth, depthTest: _depthTest, side: _side, repeat: new THREE.Vector2(1, 1), transparent: true, sizeAttenuation: 1 }); var mesh = new THREE.Mesh(meshLine.geometry, material); mesh.scale.set(50, 50, 50); scene.add(mesh); _self._arrows.push(mesh); } function refreshArrow(point1, point2, arrow) { let arrowLine = _self.createArrowLine(point1, point2); var meshLine = arrowLine.meshLine; let canvasTexture = _canvasDraw.drawArrow(THREE, renderer, 300, 100); //箭头 var material = new MeshLineMaterial({ useMap: true, map: canvasTexture, color: new THREE.Color(0x00f300), opacity: 1, resolution: new THREE.Vector2($(viewerContainerId).width(), $(viewerContainerId).height()), lineWidth: arrowLine.lineWidth, depthTest: _depthTest, side: _side, repeat: new THREE.Vector2(1, 1), transparent: true, sizeAttenuation: 1 }); arrow.geometry = meshLine.geometry; arrow.material = material; } this.createArrowLine = function (point1, point2) { let centerPoint = { x: (point1.x + point2.x) / 2, y: (point1.y + point2.y) / 2, z: (point1.z + point2.z) / 2 }; let distance = utils.distance(point1.x, point1.y, point1.z, point2.x, point2.y, point2.z); var startPos = { x: (point1.x + point2.x) / 2 / 50, y: (point1.y + point2.y) / 2 / 50, z: (point1.z + point2.z) / 2 / 50 } let d = utils.distance(centerPoint.x, centerPoint.y, centerPoint.z, camera.position.x, camera.position.y, camera.position.z); if (d < 2000) d = 2000; if (d > 10000) d = 10000; let lineWidth = 100 * d / 4000; //console.log("d=", d); let sc = 0.035; var endPos = { x: startPos.x + (point2.x - point1.x) * sc * d / distance / 50, y: startPos.y + (point2.y - point1.y) * sc * d / distance / 50, z: startPos.z + (point2.z - point1.z) * sc * d / distance / 50 } var arrowLinePoints = []; arrowLinePoints.push(startPos.x, startPos.y, startPos.z); arrowLinePoints.push(endPos.x, endPos.y, endPos.z); var meshLine = new MeshLine(); meshLine.setGeometry(arrowLinePoints); return { meshLine: meshLine, lineWidth: lineWidth }; } this.setDepthTest = function (bl) { if (bl) { _depthTest = true; this._lines.map(line => { line.material.depthTest = true; line.material.side = 0; }); this._arrows.map(arrow => { arrow.material.depthTest = true; arrow.material.side = 0; }); } else { _depthTest = false; this._lines.map(line => { line.material.depthTest = false; line.material.side = THREE.DoubleSide; }); this._arrows.map(arrow => { arrow.material.depthTest = false; arrow.material.side = THREE.DoubleSide; }); } } /** * 撤销 */ this.undo = function () { scene.remove(this._lines[this._lines.length - 1]); scene.remove(this._arrows[this._arrows.length - 1]); _self._path.splice(this._path.length - 1, 1); _self._lines.splice(this._lines.length - 1, 1); _self._arrows.splice(this._arrows.length - 1, 1); }}DrawPath.prototype.constructor = DrawPath;export { DrawPath }
show.js中的部分代码:
let drawPath; //绘制线路 drawPath = new DrawPath(); drawPath.config( objects, camera, scene, turn ); $("#rightContainer").show(); $("#line-start").on("click", function (event) { drawPath.start(); }); $("#line-stop").on("click", function (event) { drawPath.stop(); }); $("#line-undo").on("click", function (event) { drawPath.undo(); }); $("#line-show").on("click", function (event) { drawPath.refresh(); }); let depthTest = true; $("#line-depthTest").on("click", function (event) { if (depthTest) { drawPath.setDepthTest(false); depthTest = false; } else { drawPath.setDepthTest(true); depthTest = true; } });setInterval(() => { drawPath && drawPath.refresh();}, 100);
效果图:
还是有点问题:
虽然这个效果图中,场景拉近,箭头有点大,但是最大大小还是做了控制的,就是这个形状有点问题,可能是视角的问题。
我期望的效果应该是这样的,就是无论从什么角度看,箭头不要变形:
看完上述内容,你们对怎么使用three.js 绘制三维带箭头线有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。
箭头
问题
内容
场景
效果
路线
还是
三维
代码
就是
形状
效果图
部分
需求
最大
地铁
地面
大小
小时
指示
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
地平线4 连接不上服务器
贞丰众云科技互联网有限公司
上海制造网络技术方法
网络服务器配置与管理教材
向支付宝中国网络技术完成
数据库数据和前台数据检验
psdzdata数据库
sql数据库 命令
wid内部数据库
北京服务器硬盘价格
万方中外专利数据库官网
为什么飞卢小说连接服务器超时
连接数据库并更新数据
饥荒服务器怎么不显示
带你深度了解agc云数据库
国家安全局网络安全法
国产化数据库优化
vb显示数据库字段
网络安全的环境问题
如何用电脑登录数据库
手机无法服务器
免费手机流量软件开发
新西兰网络安全策略2019
盛开互联网科技有限公司
远程桌面访问服务器太慢
编辑数据库那个软件是
软件开发甲方联系函
mp4格式打开服务器运行失败
逍遥模拟酷我音乐的数据库
高考填报志愿服务器