• 用 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

     

  • 相关阅读:
    epoll精髓【epoll】
    linux下调试core的命令,察看堆栈状态命令 摘录(http://blog.csdn.net/yearn520/article/details/6663265)
    使用epoll 在 linux 上开发高性能应用服务器【epoll】
    linux下epoll如何实现高效处理百万句柄的[转]【epoll】
    log4cplus入门
    非阻塞式服务器和客户端程序(TCP)【简单的原理例子】
    Linux有用的命令记录
    在Linux上的使用开源C++日志库log4cplus
    静态库和动态库的区别
    localtime多线下不安全,localtime_r线程安全
  • 原文地址:https://www.cnblogs.com/s0611163/p/15549819.html
Copyright © 2020-2023  润新知