用 three.js 绘制三维带箭头线 (线内箭头)
在LineMaterial.js基础上修改的ArrowLineMaterial.js代码:
成都创新互联公司是一家集网站建设,西畴企业网站建设,西畴品牌网站建设,网站定制,西畴网站建设报价,网络营销,网络优化,西畴网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
/** * @author WestLangley / http://github.com/WestLangley * * parameters = { * color:, * linewidth: */ 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, * dashed: , * dashScale: , * dashSize: , * gapSize: , * resolution: , // to be set by renderer * } #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://azwzsj.com/article/dsopoio.html