zoukankan      html  css  js  c++  java
  • 用 three.js 绘制三维带箭头线 (线内箭头)

    在LineMaterial.js基础上修改的ArrowLineMaterial.js代码:

    /**
     * @author WestLangley / http://github.com/WestLangley
     *
     * parameters = {
     *  color: <hex>,
     *  line <float>,
     *  dashed: <boolean>,
     *  dashScale: <float>,
     *  dashSize: <float>,
     *  gapSize: <float>,
     *  resolution: <Vector2>, // to be set by renderer
     * }
     */
    
    import {
        ShaderLib,
        ShaderMaterial,
        UniformsLib,
        UniformsUtils,
        Vector2
    } from "../build/three.module.js";
    
    UniformsLib.line = {
    
        line { value: 1 },
        resolution: { value: new Vector2(1, 1) },
        dashScale: { value: 1 },
        dashSize: { value: 1 },
        gapSize: { value: 1 } // todo FIX - maybe change to totalSize
    
    };
    
    ShaderLib['line'] = {
    
        uniforms: UniformsUtils.merge([
            UniformsLib.common,
            UniformsLib.fog,
            UniformsLib.line
        ]),
    
        vertexShader:
            `
            #include <common>
            #include <color_pars_vertex>
            #include <fog_pars_vertex>
            #include <logdepthbuf_pars_vertex>
            #include <clipping_planes_pars_vertex>
    
            uniform float linewidth;
            uniform vec2 resolution;
    
            attribute vec3 instanceStart;
            attribute vec3 instanceEnd;
    
            attribute vec3 instanceColorStart;
            attribute vec3 instanceColorEnd;
    
            varying vec2 vUv;
    
            varying float lineLength;
    
            #ifdef USE_DASH
    
                uniform float dashScale;
                attribute float instanceDistanceStart;
                attribute float instanceDistanceEnd;
                varying float vLineDistance;
    
            #endif
    
            void trimSegment( const in vec4 start, inout vec4 end ) {
    
                // trim end segment so it terminates between the camera plane and the near plane
    
                // conservative estimate of the near plane
                float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
                float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
                float nearEstimate = - 0.5 * b / a;
    
                float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
    
                end.xyz = mix( start.xyz, end.xyz, alpha );
    
            }
    
            void main() {
    
                #ifdef USE_COLOR
    
                    vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
    
                #endif
    
                #ifdef USE_DASH
    
                    vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
    
                #endif
    
                float aspect = resolution.x / resolution.y;
    
                vUv = uv;
    
                // camera space
                vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
                vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
    
                // special case for perspective projection, and segments that terminate either in, or behind, the camera plane
                // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
                // but we need to perform ndc-space calculations in the shader, so we must address this issue directly
                // perhaps there is a more elegant solution -- WestLangley
    
                bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
    
                if ( perspective ) {
    
                    if ( start.z < 0.0 && end.z >= 0.0 ) {
    
                        trimSegment( start, end );
    
                    } else if ( end.z < 0.0 && start.z >= 0.0 ) {
    
                        trimSegment( end, start );
    
                    }
    
                }
    
                // clip space
                vec4 clipStart = projectionMatrix * start;
                vec4 clipEnd = projectionMatrix * end;
    
                // ndc space
                vec2 ndcStart = clipStart.xy / clipStart.w;
                vec2 ndcEnd = clipEnd.xy / clipEnd.w;
    
                // direction
                vec2 dir = ndcEnd - ndcStart;
    
                // account for clip-space aspect ratio
                dir.x *= aspect;
                dir = normalize( dir );
    
                // perpendicular to dir
                vec2 offset = vec2( dir.y, - dir.x );
    
                // undo aspect ratio adjustment
                dir.x /= aspect;
                offset.x /= aspect;
    
                // sign flip
                if ( position.x < 0.0 ) offset *= - 1.0;
    
                // endcaps
                if ( position.y < 0.0 ) {
    
                    offset += - dir;
    
                } else if ( position.y > 1.0 ) {
    
                    offset += dir;
    
                }
    
                // adjust for linewidth
                offset *= linewidth;
    
                // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
                offset /= resolution.y;
    
                // select end
                vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
    
                // back to clip space
                offset *= clip.w;
    
                clip.xy += offset;
    
                gl_Position = clip;
    
                vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation
    
                //lineLength = distance(ndcStart, ndcEnd);
                lineLength = distance(ndcStart, ndcEnd) * (1.57 + abs(atan(dir.x / dir.y))) / 2.0;
                //lineLength = distance(clipStart.xyz, clipEnd.xyz);
                //lineLength = distance(start.xyz, end.xyz);
    
                #include <logdepthbuf_vertex>
                #include <clipping_planes_vertex>
                #include <fog_vertex>
    
            }
            `,
    
        fragmentShader:
            `
            uniform vec3 diffuse;
            uniform float opacity;
            uniform sampler2D map;
    
            varying float lineLength;
    
            #ifdef USE_DASH
    
                uniform float dashSize;
                uniform float gapSize;
    
            #endif
    
            varying float vLineDistance;
    
            #include <common>
            #include <color_pars_fragment>
            #include <fog_pars_fragment>
            #include <logdepthbuf_pars_fragment>
            #include <clipping_planes_pars_fragment>
    
            varying vec2 vUv;
    
            void main() {
    
                #include <clipping_planes_fragment>
    
                #ifdef USE_DASH
    
                    if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
    
                    if ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX
    
                #endif
    
                if ( abs( vUv.y ) > 1.0 ) {
    
                    float a = vUv.x;
                    float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
                    float len2 = a * a + b * b;
    
                    if ( len2 > 1.0 ) discard;
                }
    
                vec4 diffuseColor = vec4( diffuse, opacity );
    
                #include <logdepthbuf_fragment>
                #include <color_fragment>
    
                vec4 c;
    
                if ( abs( vUv.y ) > 1.0 ) {
                    c = vec4(diffuseColor.rgb, diffuseColor.a); 
                } else {
                    vec2 rpt = vec2(0.5, 1.0);
                    
                    rpt.y *= lineLength * 5.0;
                    //rpt.y *= lineLength / 500.0;
    
                    rpt.y = floor(rpt.y + 0.5);
                    if(rpt.y < 1.0) { rpt.y = 1.0; }
                    if(rpt.y > 5.0) { rpt.y = 5.0; }
                    c = vec4(1.0, 1.0, 1.0, 1.0); 
                    c *= texture2D( map, vUv * rpt );
                }
                
                gl_FragColor = c;
    
                //#include <premultiplied_alpha_fragment>
                //#include <tonemapping_fragment>
                //#include <encodings_fragment>
                //#include <fog_fragment>
    
            }
            `
    };
    
    var ArrowLineMaterial = function (parameters) {
    
        ShaderMaterial.call(this, {
    
            type: 'ArrowLineMaterial',
    
            uniforms: Object.assign({}, UniformsUtils.clone(ShaderLib['line'].uniforms), {
                map: { value: null },
            }),
    
            vertexShader: ShaderLib['line'].vertexShader,
            fragmentShader: ShaderLib['line'].fragmentShader,
    
            clipping: true // required for clipping support
    
        });
    
        this.dashed = false;
    
        Object.defineProperties(this, {
    
            map: {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.map.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.map.value = value;
    
                }
    
            },
    
            color: {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.diffuse.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.diffuse.value = value;
    
                }
    
            },
    
            line {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.linewidth.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.linewidth.value = value;
    
                }
    
            },
    
            dashScale: {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.dashScale.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.dashScale.value = value;
    
                }
    
            },
    
            dashSize: {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.dashSize.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.dashSize.value = value;
    
                }
    
            },
    
            gapSize: {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.gapSize.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.gapSize.value = value;
    
                }
    
            },
    
            resolution: {
    
                enumerable: true,
    
                get: function () {
    
                    return this.uniforms.resolution.value;
    
                },
    
                set: function (value) {
    
                    this.uniforms.resolution.value.copy(value);
    
                }
    
            }
    
        });
    
        this.setValues(parameters);
    
    };
    
    ArrowLineMaterial.prototype = Object.create(ShaderMaterial.prototype);
    ArrowLineMaterial.prototype.constructor = ArrowLineMaterial;
    
    ArrowLineMaterial.prototype.isLineMaterial = true;
    
    
    export { ArrowLineMaterial };
    View Code

    ArrowLineMaterial.js中主要修改部分:

    在顶点着色器中定义变量:

    varying float lineLength;
    View Code

    在顶点着色器中计算一下线的长度:

    lineLength = distance(ndcStart, ndcEnd) * (1.57 + abs(atan(dir.x / dir.y))) / 2.0;
    View Code

    在片元着色器中定义变量:

    uniform sampler2D map;
    varying float lineLength;
    View Code

    在片元着色器中贴图:

    vec4 c;
    
    if ( abs( vUv.y ) > 1.0 ) {
        c = vec4(diffuseColor.rgb, diffuseColor.a); 
    } else {
        vec2 rpt = vec2(0.5, 1.0);
        
        rpt.y *= lineLength * 5.0;
        //rpt.y *= lineLength / 500.0;
    
        rpt.y = floor(rpt.y + 0.5);
        if(rpt.y < 1.0) { rpt.y = 1.0; }
        if(rpt.y > 5.0) { rpt.y = 5.0; }
        c = vec4(1.0, 1.0, 1.0, 1.0); 
        c *= texture2D( map, vUv * rpt );
    }
    
    gl_FragColor = c;
    View Code

    在片元着色器中注释掉下面几行,使线的颜色和canvas中设置的颜色一致:

    //#include <premultiplied_alpha_fragment>
    //#include <tonemapping_fragment>
    //#include <encodings_fragment>
    //#include <fog_fragment>
    View Code

    CanvasDraw.js代码:

    /**
     * canvas绘图
     */
    
    let CanvasDraw = function () {
    
        /**
         * 画文本和气泡
         */
        this.drawText = function (THREE, renderer, text, width) {
            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext('2d');
    
            canvas.width = width * 2;
            canvas.height = width * 2;
    
            this.drawBubble(ctx, width - 10, width - 65, width, 45, 6, "#00c864");
    
            //设置文字
            ctx.fillStyle = "#ffffff";
            ctx.font = '32px 宋体';
            ctx.fillText(text, width - 10 + 12, width - 65 + 34);
    
            let canvasTexture = new THREE.CanvasTexture(canvas);
            canvasTexture.magFilter = THREE.NearestFilter;
            canvasTexture.minFilter = THREE.NearestFilter;
    
            let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
            canvasTexture.anisotropy = maxAnisotropy;
    
            return canvasTexture;
        }
    
        /**
         * 画箭头
         */
        this.drawArrow = function (THREE, renderer, width, height) {
            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext('2d');
    
            canvas.width = width;
            canvas.height = height;
    
            ctx.save();
    
            ctx.translate(0, 0);
    
            //this.drawRoundRectPath(ctx, width, height, 0);
    
            //ctx.fillStyle = "#ffff00";
            //ctx.fill();
    
            this.drawArrowBorder(ctx, 2, 0, 0, 4, 100, 50, 0, 96, 2, 100, 300, 50);
            ctx.fillStyle = "#ffffff";
            ctx.fill();
    
            ctx.restore();
    
            let canvasTexture = new THREE.CanvasTexture(canvas);
            canvasTexture.magFilter = THREE.NearestFilter;
            canvasTexture.minFilter = THREE.NearestFilter;
    
            let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
            canvasTexture.anisotropy = maxAnisotropy;
    
            return canvasTexture;
        }
    
        /**
         * 画线内箭头
         */
        this.drawArrow3 = function (THREE, renderer, width, height, color) {
            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext('2d');
    
            canvas.width = width;
            canvas.height = height;
    
            ctx.save();
    
            ctx.translate(0, 0);
    
            this.drawRoundRectPath(ctx, width, height, 0);
    
            ctx.fillStyle = color;
            ctx.fill();
    
            this.drawArrowBorder(ctx, 0, 350, 0, 400, 50, 450, 100, 400, 100, 350, 50, 400);
            ctx.fillStyle = "#ffffff";
            ctx.fill();
    
            ctx.restore();
    
            let canvasTexture = new THREE.CanvasTexture(canvas);
            canvasTexture.magFilter = THREE.NearestFilter;
            canvasTexture.minFilter = THREE.NearestFilter;
            canvasTexture.wrapS = THREE.RepeatWrapping;
            canvasTexture.wrapT = THREE.RepeatWrapping;
    
            let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
            canvasTexture.anisotropy = maxAnisotropy;
    
            return canvasTexture;
        }
    
        /**
         * 画气泡
         */
        this.drawBubble = function (ctx, x, y, width, height, radius, fillColor) {
            ctx.save();
    
            ctx.translate(x, y);
    
            this.drawRoundRectPath(ctx, width, height, radius);
    
            ctx.fillStyle = fillColor || "#000";
            ctx.fill();
    
            this.drawTriangle(ctx, 20, height, 40, height, 10, 65);
            ctx.fillStyle = fillColor || "#000";
            ctx.fill();
    
            ctx.restore();
        }
    
        /**
         * 画三角形
         */
        this.drawTriangle = function (ctx, x1, y1, x2, y2, x3, y3) {
            ctx.beginPath();
    
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.lineTo(x3, y3);
    
            ctx.closePath();
        }
    
        /**
         * 画箭头边框
         */
        this.drawArrowBorder = function (ctx, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6) {
            ctx.beginPath();
    
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.lineTo(x3, y3);
            ctx.lineTo(x4, y4);
            ctx.lineTo(x5, y5);
            ctx.lineTo(x6, y6);
    
            ctx.closePath();
        }
    
        /**
         * 画圆角矩形
         */
        this.drawRoundRectPath = function (ctx, width, height, radius) {
            ctx.beginPath(0);
    
            //从右下角顺时针绘制,弧度从0到1/2PI  
            ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
    
            //矩形下边线  
            ctx.lineTo(radius, height);
    
            //左下角圆弧,弧度从1/2PI到PI  
            ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
    
            //矩形左边线  
            ctx.lineTo(0, radius);
    
            //左上角圆弧,弧度从PI到3/2PI  
            ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
    
            //上边线  
            ctx.lineTo(width - radius, 0);
    
            //右上角圆弧  
            ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
    
            //右边线  
            ctx.lineTo(width, height - radius);
    
            ctx.closePath();
        }
    
        /**
         * 画圆
         */
        this.drawCircle = function (THREE, renderer, width, height, radius, fillColor) {
            let canvas = document.createElement("canvas");
            let ctx = canvas.getContext('2d');
    
            canvas.width = width;
            canvas.height = height;
    
            ctx.save();
    
            ctx.beginPath(0);
    
            ctx.arc(width / 2, height / 2, radius, 0, 2 * Math.PI);
    
            ctx.closePath();
    
            ctx.fillStyle = fillColor || "#000";
            ctx.fill();
    
            ctx.restore();
    
            let texture = new THREE.CanvasTexture(canvas);
            texture.needsUpdate = true;
    
            texture.magFilter = THREE.NearestFilter;
            texture.minFilter = THREE.NearestFilter;
    
            let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
            texture.anisotropy = maxAnisotropy;
    
            return texture;
        }
    
    }
    
    CanvasDraw.prototype.constructor = CanvasDraw;
    
    export { CanvasDraw }
    View Code

    DrawPath2.js代码:

    /**
     * 绘制路线
     */
    
    import * as THREE from '../build/three.module.js';
    
    import { Line2 } from '../js/lines/Line2.js';
    import { LineGeometry } from '../js/lines/LineGeometry.js';
    
    import { CanvasDraw } from '../js.my/CanvasDraw.js';
    import { ArrowLineMaterial } from '../js.my/ArrowLineMaterial.js';
    
    import { Utils } from '../js.my/Utils.js';
    import { Msg } from '../js.my/Msg.js';
    
    let DrawPath2 = function () {
    
        let _self = this;
    
        let _canvasDraw = new CanvasDraw();
        let utils = new Utils();
        let msg = new Msg();
    
        this._isDrawing = false;
        this._path = [];
        this._lines = [];
        this.color = '#00F300';
    
        this._depthTest = true;
        this._hide = false;
    
        let _side = 0;
    
        let viewerContainerId = '#threeCanvas';
        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);
            }
        }
    
        this.stop = function () {
            if (this._isDrawing) {
                this._isDrawing = false;
                viewerContainer.removeEventListener('click', ray);
                viewerContainer.removeEventListener('mousedown', mousedown);
                viewerContainer.removeEventListener('mouseup', mouseup);
            }
        }
    
        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 objs = [];
            objects.all.map(object => {
                if (object.material.visible) {
                    objs.push(object);
                }
            });
            let intersects = raycaster.intersectObjects(objs);
            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);
                    }
                }
            }
        }
    
        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 () {
    
        }
    
        function drawLine(point1, point2) {
            let n = Math.round(utils.distance(point1.x, point1.y, point1.z, point2.x, point2.y, point2.z) / 500);
            if (n < 1) n = 1;
            for (let i = 0; i < n; i++) {
                let p1 = {};
                p1.x = point1.x + (point2.x - point1.x) / n * i;
                p1.y = point1.y + (point2.y - point1.y) / n * i;
                p1.z = point1.z + (point2.z - point1.z) / n * i;
    
                let p2 = {};
                p2.x = point1.x + (point2.x - point1.x) / n * (i + 1);
                p2.y = point1.y + (point2.y - point1.y) / n * (i + 1);
                p2.z = point1.z + (point2.z - point1.z) / n * (i + 1);
    
                drawLine2(p1, p2);
            }
        }
    
        function drawLine2(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);
    
            geometry.setColors([
                parseInt(_self.color.substr(1, 2), 16) / 256,
                parseInt(_self.color.substr(3, 2), 16) / 256,
                parseInt(_self.color.substr(5, 2), 16) / 256,
                parseInt(_self.color.substr(1, 2), 16) / 256,
                parseInt(_self.color.substr(3, 2), 16) / 256,
                parseInt(_self.color.substr(5, 2), 16) / 256
            ]);
    
            let canvasTexture = _canvasDraw.drawArrow3(THREE, renderer, 100, 800, _self.color); //箭头
    
            let matLine = new ArrowLineMaterial({
                map: canvasTexture,
                color: new THREE.Color(0xffffff),
                line 0.005, // in world units with size attenuation, pixels otherwise
                dashed: false,
                depthTest: _self._depthTest,
                side: _side,
                vertexColors: THREE.VertexColors,
                resolution: new THREE.Vector2(1, $(viewerContainerId).height() / $(viewerContainerId).width())
            });
    
            let line = new Line2(geometry, matLine);
            line.computeLineDistances();
            line.scale.set(50, 50, 50);
    
            scene.add(line);
            _self._lines.push(line);
        }
    
        this.setDepthTest = function (bl) {
            if (bl) {
                _self._depthTest = true;
                this._lines.map(line => {
                    line.material.depthTest = true;
                    line.material.side = 0;
                });
            } else {
                _self._depthTest = false;
                this._lines.map(line => {
                    line.material.depthTest = false;
                    line.material.side = THREE.DoubleSide;
                });
            }
        }
    
        this.getPath = function () {
            return this._path;
        }
    
        this.hide = function () {
            this._lines.map(line => scene.remove(line));
            this._hide = true;
        }
    
        this.show = function () {
            this._lines.map(line => scene.add(line));
            this._hide = false;
        }
    
        this.isShow = function () {
            return !this._hide;
        }
    
        this.create = function (path, color) {
            _self.color = color;
            _self._path = path;
    
            if (_self._path.length > 1) {
                for (let i = 0; i < _self._path.length - 1; i++) {
                    let point1 = _self._path[i];
                    let point2 = _self._path[i + 1];
    
                    drawLine(point1, point2);
                }
            }
        }
    
        this.getDepthTest = function () {
            return _self._depthTest;
        }
    
        this.undo = function () {
            scene.remove(this._lines[this._lines.length - 1]);
            _self._path.splice(this._path.length - 1, 1);
            _self._lines.splice(this._lines.length - 1, 1);
        }
    
    }
    
    DrawPath2.prototype.constructor = DrawPath2;
    
    export { DrawPath2 }
    View Code

    效果图:

     

    缺陷:

    2.5D视角观察,看着还行,但是把相机拉近观察,箭头就会变形。凑合着用。

    箭头贴图变形或者箭头显示不全,原因我猜可能是因为在场景中,线的远离相机的一端,在标准设备坐标系中比较细,线的靠近相机的一端,在标准设备坐标系中比较粗,但为了使线的粗细一样,靠近相机的一端被裁剪了,所以箭头可能会显示不全。

    不管是MeshLine还是three.js的Line2,这个带宽度的线,和三维场景中的三维模型是有区别的,无论场景拉近还是拉远,线的宽度不变,而三维模型场景拉远变小,拉近变大。

    Drawing arrow lines is hard!

    参考文章:

    https://www.cnblogs.com/dojo-lzz/p/9219290.html

    https://blog.csdn.net/Amesteur/article/details/95964526

     

  • 相关阅读:
    泛微云桥e-Bridge 目录遍历,任意文件读取
    (CVE-2020-8209)XenMobile-控制台存在任意文件读取漏洞
    selenium 使用初
    将HTML文件转换为MD文件
    Python对word文档进行操作
    使用java安装jar包出错,提示不是有效的JDK java主目录
    Windows server 2012安装VM tools异常解决办法
    ifconfig 命令,改变主机名,改DNS hosts、关闭selinux firewalld netfilter 、防火墙iptables规则
    iostat iotop 查看硬盘的读写、 free 查看内存的命令 、netstat 命令查看网络、tcpdump 命令
    使用w uptime vmstat top sar nload 等命令查看系统负载
  • 原文地址:https://www.cnblogs.com/s0611163/p/15549819.html
Copyright © 2011-2022 走看看