iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么使用three.js 绘制三维带箭头线
  • 668
分享到

怎么使用three.js 绘制三维带箭头线

2023-06-25 12:06:39 668人浏览 独家记忆
摘要

今天就跟大家聊聊有关怎么使用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 绘制三维带箭头线

还是有点问题:

怎么使用three.js 绘制三维带箭头线

虽然这个效果图中,场景拉近,箭头有点大,但是最大大小还是做了控制的,就是这个形状有点问题,可能是视角的问题。

我期望的效果应该是这样的,就是无论从什么角度看,箭头不要变形:

怎么使用three.js 绘制三维带箭头线

看完上述内容,你们对怎么使用three.js 绘制三维带箭头线有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网精选频道,感谢大家的支持。

--结束END--

本文标题: 怎么使用three.js 绘制三维带箭头线

本文链接: https://www.lsjlt.com/news/304459.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何在 Golang 中替换正则表达式匹配的文本?
    在 go 中,可使用 regexp.replaceall 函数替换符合正则表达式的文本,该函数需要三个参数:待替换字符串、匹配模式和替换文本。例如,将字符串中 "fox" 替换为 "do...
    99+
    2024-05-14
    golang 正则表达式
  • 如何在 Golang 中测试随机数生成器的准确性?
    在 go 中测试随机数生成器准确性的步骤包括:生成大量随机数并计算每个范围内的出现次数,以确保均匀分布。针对指定均值和标准差计算每个范围内的出现次数,以确保正态分布。 如何在 Gola...
    99+
    2024-05-14
    golang 随机数
  • 面向对象设计原则在C++中的体现
    c++++ 体现了 oop 原则,包括:封装:使用类将数据和方法封装在对象中。继承:允许派生类从基类继承数据和行为。多态:允许对象的行为根据其类型而改变,通过虚函数实现。 面向对象设计...
    99+
    2024-05-14
    c++ 面向对象
  • c语言怎么区分小数和整数
    c 语言区分小数和整数的方法有:数据类型不同:小数类型(float、double)包含小数点,整数类型(int)不包含。printf() 函数中使用不同格式化字符串:小数用 %f,整数用...
    99+
    2024-05-14
    c语言
  • 设计模式在C++ 中的可复用性和可扩展性
    在 c++++ 中,设计模式通过提供经过验证的解决方案来提高可复用性和可扩展性。可复用性允许重复使用代码,例如 factory method 模式,它支持创建不同的产品而不影响具体类。可...
    99+
    2024-05-14
    c++ 设计模式 高可扩展性
  • C++语法中函数模板的灵活运用
    C++ 语法中函数模板的灵活运用 函数模板是 C++ 中的一项强大功能,允许您创建可用于不同数据类型的一组代码。这可以提高代码的可重用性,并使您能够编写更通用、更可维护的代码。 语法 ...
    99+
    2024-05-14
    c++语法 函数模板 c++
  • c语言怎么计算字符串长度和宽度
    在 c 语言中,计算字符串长度和宽度的函数分别为:strlen() 函数用于计算字符串长度,不包括终止符 '\0'。strwidth() 函数用于计算字符串在终端中的宽度,返回显示像素数...
    99+
    2024-05-14
    c语言
  • 如何用 Golang 正则匹配多个单词或字符串?
    golang 正则表达式使用管道符 | 来匹配多个单词或字符串,将各个选项作为逻辑 or 表达式分隔开来。例如:匹配 "fox" 或 "dog":fox|dog匹配 "quick"、"b...
    99+
    2024-05-14
    golang 正则 python
  • c语言怎么跳出多层循环
    在 c 语言中,可以使用嵌套的 break 语句跳出多层循环。对于每个要跳出的循环层,都需要一个单独的 break 语句。例如:使用一个 break 语句跳出内层循环再使用一个 brea...
    99+
    2024-05-14
    c语言
  • c语言怎么注释成中文
    c语言中文注释提供两种方式:行内注释(以"//"开头)和块注释(以"/"开头并以"/"结尾)。最佳实践包括:使用简明扼要的语言,在函数和类开头处添加块注释,在关键部分添加行内注释,保持注...
    99+
    2024-05-14
    c语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作