用 three.js 绘制三维带箭头线 (线内箭头)

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

成都创新互联公司是一家集网站建设,西畴企业网站建设,西畴品牌网站建设,网站定制,西畴网站建设报价,网络营销,网络优化,西畴网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

/**
 * @author WestLangley / http://github.com/WestLangley
 *
 * parameters = {
 *  color: ,
 *  linewidth: ,
 *  dashed: ,
 *  dashScale: ,
 *  dashSize: ,
 *  gapSize: ,
 *  resolution: , // to be set by renderer
 * }
*/

import {
    ShaderLib,
    ShaderMaterial,
    UniformsLib,
    UniformsUtils,
    Vector2
} from"../build/three.module.js";

UniformsLib.line= {

    linewidth: { 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
        #include
        #include
        #include
        #include

        uniformfloat linewidth;
        uniform vec2 resolution;

        attribute vec3 instanceStart;
        attribute vec3 instanceEnd;

        attribute vec3 instanceColorStart;
        attribute vec3 instanceColorEnd;

        varying vec2 vUv;

        varyingfloat lineLength;

        #ifdef USE_DASH

            uniformfloat dashScale;
            attributefloat instanceDistanceStart;
            attributefloat instanceDistanceEnd;
            varyingfloat 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
            #include
            #include

        }
        `,

    fragmentShader:
        `
        uniform vec3 diffuse;
        uniformfloat opacity;
        uniform sampler2D map;

        varyingfloat lineLength;

        #ifdef USE_DASH

            uniformfloat dashSize;
            uniformfloat gapSize;

        #endif

        varyingfloat vLineDistance;

        #include
        #include
        #include
        #include
        #include

        varying vec2 vUv;

void main() {

            #include

            #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
            #include

            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 
            //#include 
            //#include 
            //#include 

        }
        `
};

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;

            }

        },

        linewidth: {

            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 };

文章题目:用 three.js 绘制三维带箭头线 (线内箭头)
网站地址:http://ybzwz.com/article/dsopoio.html