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

  1. /**
  2. * @author WestLangley / http://github.com/WestLangley
  3. *
  4. * parameters = {
  5. * color: <hex>,
  6. * linewidth: <float>,
  7. * dashed: <boolean>,
  8. * dashScale: <float>,
  9. * dashSize: <float>,
  10. * gapSize: <float>,
  11. * resolution: <Vector2>, // to be set by renderer
  12. * }
  13. */
  14.  
  15. import {
  16. ShaderLib,
  17. ShaderMaterial,
  18. UniformsLib,
  19. UniformsUtils,
  20. Vector2
  21. } from "../build/three.module.js";
  22.  
  23. UniformsLib.line = {
  24.  
  25. linewidth: { value: 1 },
  26. resolution: { value: new Vector2(1, 1) },
  27. dashScale: { value: 1 },
  28. dashSize: { value: 1 },
  29. gapSize: { value: 1 } // todo FIX - maybe change to totalSize
  30.  
  31. };
  32.  
  33. ShaderLib['line'] = {
  34.  
  35. uniforms: UniformsUtils.merge([
  36. UniformsLib.common,
  37. UniformsLib.fog,
  38. UniformsLib.line
  39. ]),
  40.  
  41. vertexShader:
  42. `
  43. #include <common>
  44. #include <color_pars_vertex>
  45. #include <fog_pars_vertex>
  46. #include <logdepthbuf_pars_vertex>
  47. #include <clipping_planes_pars_vertex>
  48.  
  49. uniform float linewidth;
  50. uniform vec2 resolution;
  51.  
  52. attribute vec3 instanceStart;
  53. attribute vec3 instanceEnd;
  54.  
  55. attribute vec3 instanceColorStart;
  56. attribute vec3 instanceColorEnd;
  57.  
  58. varying vec2 vUv;
  59.  
  60. varying float lineLength;
  61.  
  62. #ifdef USE_DASH
  63.  
  64. uniform float dashScale;
  65. attribute float instanceDistanceStart;
  66. attribute float instanceDistanceEnd;
  67. varying float vLineDistance;
  68.  
  69. #endif
  70.  
  71. void trimSegment( const in vec4 start, inout vec4 end ) {
  72.  
  73. // trim end segment so it terminates between the camera plane and the near plane
  74.  
  75. // conservative estimate of the near plane
  76. float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
  77. float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
  78. float nearEstimate = - 0.5 * b / a;
  79.  
  80. float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
  81.  
  82. end.xyz = mix( start.xyz, end.xyz, alpha );
  83.  
  84. }
  85.  
  86. void main() {
  87.  
  88. #ifdef USE_COLOR
  89.  
  90. vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
  91.  
  92. #endif
  93.  
  94. #ifdef USE_DASH
  95.  
  96. vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
  97.  
  98. #endif
  99.  
  100. float aspect = resolution.x / resolution.y;
  101.  
  102. vUv = uv;
  103.  
  104. // camera space
  105. vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
  106. vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
  107.  
  108. // special case for perspective projection, and segments that terminate either in, or behind, the camera plane
  109. // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
  110. // but we need to perform ndc-space calculations in the shader, so we must address this issue directly
  111. // perhaps there is a more elegant solution -- WestLangley
  112.  
  113. bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
  114.  
  115. if ( perspective ) {
  116.  
  117. if ( start.z < 0.0 && end.z >= 0.0 ) {
  118.  
  119. trimSegment( start, end );
  120.  
  121. } else if ( end.z < 0.0 && start.z >= 0.0 ) {
  122.  
  123. trimSegment( end, start );
  124.  
  125. }
  126.  
  127. }
  128.  
  129. // clip space
  130. vec4 clipStart = projectionMatrix * start;
  131. vec4 clipEnd = projectionMatrix * end;
  132.  
  133. // ndc space
  134. vec2 ndcStart = clipStart.xy / clipStart.w;
  135. vec2 ndcEnd = clipEnd.xy / clipEnd.w;
  136.  
  137. // direction
  138. vec2 dir = ndcEnd - ndcStart;
  139.  
  140. // account for clip-space aspect ratio
  141. dir.x *= aspect;
  142. dir = normalize( dir );
  143.  
  144. // perpendicular to dir
  145. vec2 offset = vec2( dir.y, - dir.x );
  146.  
  147. // undo aspect ratio adjustment
  148. dir.x /= aspect;
  149. offset.x /= aspect;
  150.  
  151. // sign flip
  152. if ( position.x < 0.0 ) offset *= - 1.0;
  153.  
  154. // endcaps
  155. if ( position.y < 0.0 ) {
  156.  
  157. offset += - dir;
  158.  
  159. } else if ( position.y > 1.0 ) {
  160.  
  161. offset += dir;
  162.  
  163. }
  164.  
  165. // adjust for linewidth
  166. offset *= linewidth;
  167.  
  168. // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
  169. offset /= resolution.y;
  170.  
  171. // select end
  172. vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
  173.  
  174. // back to clip space
  175. offset *= clip.w;
  176.  
  177. clip.xy += offset;
  178.  
  179. gl_Position = clip;
  180.  
  181. vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation
  182.  
  183. //lineLength = distance(ndcStart, ndcEnd);
  184. lineLength = distance(ndcStart, ndcEnd) * (1.57 + abs(atan(dir.x / dir.y))) / 2.0;
  185. //lineLength = distance(clipStart.xyz, clipEnd.xyz);
  186. //lineLength = distance(start.xyz, end.xyz);
  187.  
  188. #include <logdepthbuf_vertex>
  189. #include <clipping_planes_vertex>
  190. #include <fog_vertex>
  191.  
  192. }
  193. `,
  194.  
  195. fragmentShader:
  196. `
  197. uniform vec3 diffuse;
  198. uniform float opacity;
  199. uniform sampler2D map;
  200.  
  201. varying float lineLength;
  202.  
  203. #ifdef USE_DASH
  204.  
  205. uniform float dashSize;
  206. uniform float gapSize;
  207.  
  208. #endif
  209.  
  210. varying float vLineDistance;
  211.  
  212. #include <common>
  213. #include <color_pars_fragment>
  214. #include <fog_pars_fragment>
  215. #include <logdepthbuf_pars_fragment>
  216. #include <clipping_planes_pars_fragment>
  217.  
  218. varying vec2 vUv;
  219.  
  220. void main() {
  221.  
  222. #include <clipping_planes_fragment>
  223.  
  224. #ifdef USE_DASH
  225.  
  226. if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
  227.  
  228. if ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX
  229.  
  230. #endif
  231.  
  232. if ( abs( vUv.y ) > 1.0 ) {
  233.  
  234. float a = vUv.x;
  235. float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
  236. float len2 = a * a + b * b;
  237.  
  238. if ( len2 > 1.0 ) discard;
  239. }
  240.  
  241. vec4 diffuseColor = vec4( diffuse, opacity );
  242.  
  243. #include <logdepthbuf_fragment>
  244. #include <color_fragment>
  245.  
  246. vec4 c;
  247.  
  248. if ( abs( vUv.y ) > 1.0 ) {
  249. c = vec4(diffuseColor.rgb, diffuseColor.a);
  250. } else {
  251. vec2 rpt = vec2(0.5, 1.0);
  252.  
  253. rpt.y *= lineLength * 5.0;
  254. //rpt.y *= lineLength / 500.0;
  255.  
  256. rpt.y = floor(rpt.y + 0.5);
  257. if(rpt.y < 1.0) { rpt.y = 1.0; }
  258. if(rpt.y > 5.0) { rpt.y = 5.0; }
  259. c = vec4(1.0, 1.0, 1.0, 1.0);
  260. c *= texture2D( map, vUv * rpt );
  261. }
  262.  
  263. gl_FragColor = c;
  264.  
  265. //#include <premultiplied_alpha_fragment>
  266. //#include <tonemapping_fragment>
  267. //#include <encodings_fragment>
  268. //#include <fog_fragment>
  269.  
  270. }
  271. `
  272. };
  273.  
  274. var ArrowLineMaterial = function (parameters) {
  275.  
  276. ShaderMaterial.call(this, {
  277.  
  278. type: 'ArrowLineMaterial',
  279.  
  280. uniforms: Object.assign({}, UniformsUtils.clone(ShaderLib['line'].uniforms), {
  281. map: { value: null },
  282. }),
  283.  
  284. vertexShader: ShaderLib['line'].vertexShader,
  285. fragmentShader: ShaderLib['line'].fragmentShader,
  286.  
  287. clipping: true // required for clipping support
  288.  
  289. });
  290.  
  291. this.dashed = false;
  292.  
  293. Object.defineProperties(this, {
  294.  
  295. map: {
  296.  
  297. enumerable: true,
  298.  
  299. get: function () {
  300.  
  301. return this.uniforms.map.value;
  302.  
  303. },
  304.  
  305. set: function (value) {
  306.  
  307. this.uniforms.map.value = value;
  308.  
  309. }
  310.  
  311. },
  312.  
  313. color: {
  314.  
  315. enumerable: true,
  316.  
  317. get: function () {
  318.  
  319. return this.uniforms.diffuse.value;
  320.  
  321. },
  322.  
  323. set: function (value) {
  324.  
  325. this.uniforms.diffuse.value = value;
  326.  
  327. }
  328.  
  329. },
  330.  
  331. linewidth: {
  332.  
  333. enumerable: true,
  334.  
  335. get: function () {
  336.  
  337. return this.uniforms.linewidth.value;
  338.  
  339. },
  340.  
  341. set: function (value) {
  342.  
  343. this.uniforms.linewidth.value = value;
  344.  
  345. }
  346.  
  347. },
  348.  
  349. dashScale: {
  350.  
  351. enumerable: true,
  352.  
  353. get: function () {
  354.  
  355. return this.uniforms.dashScale.value;
  356.  
  357. },
  358.  
  359. set: function (value) {
  360.  
  361. this.uniforms.dashScale.value = value;
  362.  
  363. }
  364.  
  365. },
  366.  
  367. dashSize: {
  368.  
  369. enumerable: true,
  370.  
  371. get: function () {
  372.  
  373. return this.uniforms.dashSize.value;
  374.  
  375. },
  376.  
  377. set: function (value) {
  378.  
  379. this.uniforms.dashSize.value = value;
  380.  
  381. }
  382.  
  383. },
  384.  
  385. gapSize: {
  386.  
  387. enumerable: true,
  388.  
  389. get: function () {
  390.  
  391. return this.uniforms.gapSize.value;
  392.  
  393. },
  394.  
  395. set: function (value) {
  396.  
  397. this.uniforms.gapSize.value = value;
  398.  
  399. }
  400.  
  401. },
  402.  
  403. resolution: {
  404.  
  405. enumerable: true,
  406.  
  407. get: function () {
  408.  
  409. return this.uniforms.resolution.value;
  410.  
  411. },
  412.  
  413. set: function (value) {
  414.  
  415. this.uniforms.resolution.value.copy(value);
  416.  
  417. }
  418.  
  419. }
  420.  
  421. });
  422.  
  423. this.setValues(parameters);
  424.  
  425. };
  426.  
  427. ArrowLineMaterial.prototype = Object.create(ShaderMaterial.prototype);
  428. ArrowLineMaterial.prototype.constructor = ArrowLineMaterial;
  429.  
  430. ArrowLineMaterial.prototype.isLineMaterial = true;
  431.  
  432. export { ArrowLineMaterial };

ArrowLineMaterial.js中主要修改部分:

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

  1. varying float lineLength;

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

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

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

  1. uniform sampler2D map;
  2. varying float lineLength;

在片元着色器中贴图:

  1. vec4 c;
  2.  
  3. if ( abs( vUv.y ) > 1.0 ) {
  4. c = vec4(diffuseColor.rgb, diffuseColor.a);
  5. } else {
  6. vec2 rpt = vec2(0.5, 1.0);
  7.  
  8. rpt.y *= lineLength * 5.0;
  9. //rpt.y *= lineLength / 500.0;
  10.  
  11. rpt.y = floor(rpt.y + 0.5);
  12. if(rpt.y < 1.0) { rpt.y = 1.0; }
  13. if(rpt.y > 5.0) { rpt.y = 5.0; }
  14. c = vec4(1.0, 1.0, 1.0, 1.0);
  15. c *= texture2D( map, vUv * rpt );
  16. }
  17.  
  18. gl_FragColor = c;

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

  1. //#include <premultiplied_alpha_fragment>
  2. //#include <tonemapping_fragment>
  3. //#include <encodings_fragment>
  4. //#include <fog_fragment>

CanvasDraw.js代码:

  1. /**
  2. * canvas绘图
  3. */
  4.  
  5. let CanvasDraw = function () {
  6.  
  7. /**
  8. * 画文本和气泡
  9. */
  10. this.drawText = function (THREE, renderer, text, width) {
  11. let canvas = document.createElement("canvas");
  12. let ctx = canvas.getContext('2d');
  13.  
  14. canvas.width = width * 2;
  15. canvas.height = width * 2;
  16.  
  17. this.drawBubble(ctx, width - 10, width - 65, width, 45, 6, "#00c864");
  18.  
  19. //设置文字
  20. ctx.fillStyle = "#ffffff";
  21. ctx.font = '32px 宋体';
  22. ctx.fillText(text, width - 10 + 12, width - 65 + 34);
  23.  
  24. let canvasTexture = new THREE.CanvasTexture(canvas);
  25. canvasTexture.magFilter = THREE.NearestFilter;
  26. canvasTexture.minFilter = THREE.NearestFilter;
  27.  
  28. let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
  29. canvasTexture.anisotropy = maxAnisotropy;
  30.  
  31. return canvasTexture;
  32. }
  33.  
  34. /**
  35. * 画箭头
  36. */
  37. this.drawArrow = function (THREE, renderer, width, height) {
  38. let canvas = document.createElement("canvas");
  39. let ctx = canvas.getContext('2d');
  40.  
  41. canvas.width = width;
  42. canvas.height = height;
  43.  
  44. ctx.save();
  45.  
  46. ctx.translate(0, 0);
  47.  
  48. //this.drawRoundRectPath(ctx, width, height, 0);
  49.  
  50. //ctx.fillStyle = "#ffff00";
  51. //ctx.fill();
  52.  
  53. this.drawArrowBorder(ctx, 2, 0, 0, 4, 100, 50, 0, 96, 2, 100, 300, 50);
  54. ctx.fillStyle = "#ffffff";
  55. ctx.fill();
  56.  
  57. ctx.restore();
  58.  
  59. let canvasTexture = new THREE.CanvasTexture(canvas);
  60. canvasTexture.magFilter = THREE.NearestFilter;
  61. canvasTexture.minFilter = THREE.NearestFilter;
  62.  
  63. let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
  64. canvasTexture.anisotropy = maxAnisotropy;
  65.  
  66. return canvasTexture;
  67. }
  68.  
  69. /**
  70. * 画线内箭头
  71. */
  72. this.drawArrow3 = function (THREE, renderer, width, height, color) {
  73. let canvas = document.createElement("canvas");
  74. let ctx = canvas.getContext('2d');
  75.  
  76. canvas.width = width;
  77. canvas.height = height;
  78.  
  79. ctx.save();
  80.  
  81. ctx.translate(0, 0);
  82.  
  83. this.drawRoundRectPath(ctx, width, height, 0);
  84.  
  85. ctx.fillStyle = color;
  86. ctx.fill();
  87.  
  88. this.drawArrowBorder(ctx, 0, 350, 0, 400, 50, 450, 100, 400, 100, 350, 50, 400);
  89. ctx.fillStyle = "#ffffff";
  90. ctx.fill();
  91.  
  92. ctx.restore();
  93.  
  94. let canvasTexture = new THREE.CanvasTexture(canvas);
  95. canvasTexture.magFilter = THREE.NearestFilter;
  96. canvasTexture.minFilter = THREE.NearestFilter;
  97. canvasTexture.wrapS = THREE.RepeatWrapping;
  98. canvasTexture.wrapT = THREE.RepeatWrapping;
  99.  
  100. let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
  101. canvasTexture.anisotropy = maxAnisotropy;
  102.  
  103. return canvasTexture;
  104. }
  105.  
  106. /**
  107. * 画气泡
  108. */
  109. this.drawBubble = function (ctx, x, y, width, height, radius, fillColor) {
  110. ctx.save();
  111.  
  112. ctx.translate(x, y);
  113.  
  114. this.drawRoundRectPath(ctx, width, height, radius);
  115.  
  116. ctx.fillStyle = fillColor || "#000";
  117. ctx.fill();
  118.  
  119. this.drawTriangle(ctx, 20, height, 40, height, 10, 65);
  120. ctx.fillStyle = fillColor || "#000";
  121. ctx.fill();
  122.  
  123. ctx.restore();
  124. }
  125.  
  126. /**
  127. * 画三角形
  128. */
  129. this.drawTriangle = function (ctx, x1, y1, x2, y2, x3, y3) {
  130. ctx.beginPath();
  131.  
  132. ctx.moveTo(x1, y1);
  133. ctx.lineTo(x2, y2);
  134. ctx.lineTo(x3, y3);
  135.  
  136. ctx.closePath();
  137. }
  138.  
  139. /**
  140. * 画箭头边框
  141. */
  142. this.drawArrowBorder = function (ctx, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6) {
  143. ctx.beginPath();
  144.  
  145. ctx.moveTo(x1, y1);
  146. ctx.lineTo(x2, y2);
  147. ctx.lineTo(x3, y3);
  148. ctx.lineTo(x4, y4);
  149. ctx.lineTo(x5, y5);
  150. ctx.lineTo(x6, y6);
  151.  
  152. ctx.closePath();
  153. }
  154.  
  155. /**
  156. * 画圆角矩形
  157. */
  158. this.drawRoundRectPath = function (ctx, width, height, radius) {
  159. ctx.beginPath(0);
  160.  
  161. //从右下角顺时针绘制,弧度从0到1/2PI
  162. ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
  163.  
  164. //矩形下边线
  165. ctx.lineTo(radius, height);
  166.  
  167. //左下角圆弧,弧度从1/2PI到PI
  168. ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
  169.  
  170. //矩形左边线
  171. ctx.lineTo(0, radius);
  172.  
  173. //左上角圆弧,弧度从PI到3/2PI
  174. ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
  175.  
  176. //上边线
  177. ctx.lineTo(width - radius, 0);
  178.  
  179. //右上角圆弧
  180. ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
  181.  
  182. //右边线
  183. ctx.lineTo(width, height - radius);
  184.  
  185. ctx.closePath();
  186. }
  187.  
  188. /**
  189. * 画圆
  190. */
  191. this.drawCircle = function (THREE, renderer, width, height, radius, fillColor) {
  192. let canvas = document.createElement("canvas");
  193. let ctx = canvas.getContext('2d');
  194.  
  195. canvas.width = width;
  196. canvas.height = height;
  197.  
  198. ctx.save();
  199.  
  200. ctx.beginPath(0);
  201.  
  202. ctx.arc(width / 2, height / 2, radius, 0, 2 * Math.PI);
  203.  
  204. ctx.closePath();
  205.  
  206. ctx.fillStyle = fillColor || "#000";
  207. ctx.fill();
  208.  
  209. ctx.restore();
  210.  
  211. let texture = new THREE.CanvasTexture(canvas);
  212. texture.needsUpdate = true;
  213.  
  214. texture.magFilter = THREE.NearestFilter;
  215. texture.minFilter = THREE.NearestFilter;
  216.  
  217. let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
  218. texture.anisotropy = maxAnisotropy;
  219.  
  220. return texture;
  221. }
  222.  
  223. }
  224.  
  225. CanvasDraw.prototype.constructor = CanvasDraw;
  226.  
  227. export { CanvasDraw }

DrawPath2.js代码:

  1. /**
  2. * 绘制路线
  3. */
  4.  
  5. import * as THREE from '../build/three.module.js';
  6.  
  7. import { Line2 } from '../js/lines/Line2.js';
  8. import { LineGeometry } from '../js/lines/LineGeometry.js';
  9.  
  10. import { CanvasDraw } from '../js.my/CanvasDraw.js';
  11. import { ArrowLineMaterial } from '../js.my/ArrowLineMaterial.js';
  12.  
  13. import { Utils } from '../js.my/Utils.js';
  14. import { Msg } from '../js.my/Msg.js';
  15.  
  16. let DrawPath2 = function () {
  17.  
  18. let _self = this;
  19.  
  20. let _canvasDraw = new CanvasDraw();
  21. let utils = new Utils();
  22. let msg = new Msg();
  23.  
  24. this._isDrawing = false;
  25. this._path = [];
  26. this._lines = [];
  27. this.color = '#00F300';
  28.  
  29. this._depthTest = true;
  30. this._hide = false;
  31.  
  32. let _side = 0;
  33.  
  34. let viewerContainerId = '#threeCanvas';
  35. let viewerContainer = $(viewerContainerId)[0];
  36.  
  37. let objects;
  38. let camera;
  39. let turn;
  40. let scene;
  41.  
  42. this.config = function (objects_, camera_, scene_, turn_) {
  43. objects = objects_;
  44. camera = camera_;
  45. turn = turn_;
  46. scene = scene_;
  47.  
  48. this._oldDistance = 1;
  49. this._oldCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z }
  50. }
  51.  
  52. this.start = function () {
  53. if (!this._isDrawing) {
  54. this._isDrawing = true;
  55. viewerContainer.addEventListener('click', ray);
  56. viewerContainer.addEventListener('mousedown', mousedown);
  57. viewerContainer.addEventListener('mouseup', mouseup);
  58. }
  59. }
  60.  
  61. this.stop = function () {
  62. if (this._isDrawing) {
  63. this._isDrawing = false;
  64. viewerContainer.removeEventListener('click', ray);
  65. viewerContainer.removeEventListener('mousedown', mousedown);
  66. viewerContainer.removeEventListener('mouseup', mouseup);
  67. }
  68. }
  69.  
  70. function mousedown(params) {
  71. this._mousedownPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z }
  72. }
  73.  
  74. function mouseup(params) {
  75. this._mouseupPosition = { x: camera.position.x, y: camera.position.y, z: camera.position.z }
  76. }
  77.  
  78. function ray(e) {
  79. turn.unFocusButton();
  80.  
  81. let raycaster = createRaycaster(e.clientX, e.clientY);
  82. let objs = [];
  83. objects.all.map(object => {
  84. if (object.material.visible) {
  85. objs.push(object);
  86. }
  87. });
  88. let intersects = raycaster.intersectObjects(objs);
  89. if (intersects.length > 0) {
  90. let point = intersects[0].point;
  91.  
  92. let distance = utils.distance(this._mousedownPosition.x, this._mousedownPosition.y, this._mousedownPosition.z, this._mouseupPosition.x, this._mouseupPosition.y, this._mouseupPosition.z);
  93.  
  94. if (distance < 5) {
  95. _self._path.push({ x: point.x, y: point.y + 50, z: point.z });
  96.  
  97. if (_self._path.length > 1) {
  98. let point1 = _self._path[_self._path.length - 2];
  99. let point2 = _self._path[_self._path.length - 1];
  100.  
  101. drawLine(point1, point2);
  102. }
  103. }
  104. }
  105. }
  106.  
  107. function createRaycaster(clientX, clientY) {
  108. let x = (clientX / $(viewerContainerId).width()) * 2 - 1;
  109. let y = -(clientY / $(viewerContainerId).height()) * 2 + 1;
  110.  
  111. let standardVector = new THREE.Vector3(x, y, 0.5);
  112.  
  113. let worldVector = standardVector.unproject(camera);
  114.  
  115. let ray = worldVector.sub(camera.position).normalize();
  116.  
  117. let raycaster = new THREE.Raycaster(camera.position, ray);
  118.  
  119. return raycaster;
  120. }
  121.  
  122. this.refresh = function () {
  123.  
  124. }
  125.  
  126. function drawLine(point1, point2) {
  127. let n = Math.round(utils.distance(point1.x, point1.y, point1.z, point2.x, point2.y, point2.z) / 500);
  128. if (n < 1) n = 1;
  129. for (let i = 0; i < n; i++) {
  130. let p1 = {};
  131. p1.x = point1.x + (point2.x - point1.x) / n * i;
  132. p1.y = point1.y + (point2.y - point1.y) / n * i;
  133. p1.z = point1.z + (point2.z - point1.z) / n * i;
  134.  
  135. let p2 = {};
  136. p2.x = point1.x + (point2.x - point1.x) / n * (i + 1);
  137. p2.y = point1.y + (point2.y - point1.y) / n * (i + 1);
  138. p2.z = point1.z + (point2.z - point1.z) / n * (i + 1);
  139.  
  140. drawLine2(p1, p2);
  141. }
  142. }
  143.  
  144. function drawLine2(point1, point2) {
  145. const positions = [];
  146.  
  147. positions.push(point1.x / 50, point1.y / 50, point1.z / 50);
  148. positions.push(point2.x / 50, point2.y / 50, point2.z / 50);
  149.  
  150. let geometry = new LineGeometry();
  151. geometry.setPositions(positions);
  152.  
  153. geometry.setColors([
  154. parseInt(_self.color.substr(1, 2), 16) / 256,
  155. parseInt(_self.color.substr(3, 2), 16) / 256,
  156. parseInt(_self.color.substr(5, 2), 16) / 256,
  157. parseInt(_self.color.substr(1, 2), 16) / 256,
  158. parseInt(_self.color.substr(3, 2), 16) / 256,
  159. parseInt(_self.color.substr(5, 2), 16) / 256
  160. ]);
  161.  
  162. let canvasTexture = _canvasDraw.drawArrow3(THREE, renderer, 100, 800, _self.color); //箭头
  163.  
  164. let matLine = new ArrowLineMaterial({
  165. map: canvasTexture,
  166. color: new THREE.Color(0xffffff),
  167. linewidth: 0.005, // in world units with size attenuation, pixels otherwise
  168. dashed: false,
  169. depthTest: _self._depthTest,
  170. side: _side,
  171. vertexColors: THREE.VertexColors,
  172. resolution: new THREE.Vector2(1, $(viewerContainerId).height() / $(viewerContainerId).width())
  173. });
  174.  
  175. let line = new Line2(geometry, matLine);
  176. line.computeLineDistances();
  177. line.scale.set(50, 50, 50);
  178.  
  179. scene.add(line);
  180. _self._lines.push(line);
  181. }
  182.  
  183. this.setDepthTest = function (bl) {
  184. if (bl) {
  185. _self._depthTest = true;
  186. this._lines.map(line => {
  187. line.material.depthTest = true;
  188. line.material.side = 0;
  189. });
  190. } else {
  191. _self._depthTest = false;
  192. this._lines.map(line => {
  193. line.material.depthTest = false;
  194. line.material.side = THREE.DoubleSide;
  195. });
  196. }
  197. }
  198.  
  199. this.getPath = function () {
  200. return this._path;
  201. }
  202.  
  203. this.hide = function () {
  204. this._lines.map(line => scene.remove(line));
  205. this._hide = true;
  206. }
  207.  
  208. this.show = function () {
  209. this._lines.map(line => scene.add(line));
  210. this._hide = false;
  211. }
  212.  
  213. this.isShow = function () {
  214. return !this._hide;
  215. }
  216.  
  217. this.create = function (path, color) {
  218. _self.color = color;
  219. _self._path = path;
  220.  
  221. if (_self._path.length > 1) {
  222. for (let i = 0; i < _self._path.length - 1; i++) {
  223. let point1 = _self._path[i];
  224. let point2 = _self._path[i + 1];
  225.  
  226. drawLine(point1, point2);
  227. }
  228. }
  229. }
  230.  
  231. this.getDepthTest = function () {
  232. return _self._depthTest;
  233. }
  234.  
  235. this.undo = function () {
  236. scene.remove(this._lines[this._lines.length - 1]);
  237. _self._path.splice(this._path.length - 1, 1);
  238. _self._lines.splice(this._lines.length - 1, 1);
  239. }
  240.  
  241. }
  242.  
  243. DrawPath2.prototype.constructor = DrawPath2;
  244.  
  245. export { DrawPath2 }

效果图:

缺陷:

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

用 three.js 绘制三维带箭头线 (线内箭头)的更多相关文章

  1. OpenLayer——绘制带箭头的线

    绘制带箭头的线,计算相对复杂,多少是有点影响性能了.更简单的做法:初始.目标点用不同的点进行强调即可. <!DOCTYPE html> <html lang="en&quo ...

  2. 如何利用百度地图JSAPI画带箭头的线?

    百度地图JSAPI提供两种绘制多折线的方式,一种是已知多折线经纬度坐标串通过AddOverlay接口进行添加:另一种是通过在地图上鼠标单击进行绘制(鼠标绘制工具条库).目前这两种方式只能绘制多折线,并 ...

  3. AE常用代码(标注要素、AE中画带箭头的线、如何获得投影坐标、参考坐标、投影方式、FeatureCount注意事项)

    手上的电脑已经用了将近三年了,想入手一台Surface Pro,所以计划着把电脑上的资料整理下,部分资料打算发到博客上来,资料有同事.也有自己的.也有来自网络的,来源途径太多,也没法详细注明,请见谅! ...

  4. 使用原生JavaScript的Canvas实现拖拽式图形绘制,支持画笔、线条、箭头、三角形、矩形、平行四边形、梯形以及多边形和圆形,不依赖任何库和插件,有演示demo

    前言 需要用到图形绘制,没有找到完整的图形绘制实现,所以自己实现了一个 - - 一.实现的功能 1.基于oop思想构建,支持坐标点.线条(由坐标点组成,包含方向).多边形(由多个坐标点组成).圆形(包 ...

  5. Matlab绘图基础——绘制三维表面

    %绘制三维表面 ------------------------------------- %1.绘制线框图:mesh:每一条曲线称为mesh line %首先利用meshgrid函数产生平面区域内的 ...

  6. Matlab绘图基础——绘制三维曲线

    %% 绘制三维曲线 %plot3函数,其中每一组x,y,z组成一组曲线的坐标参数,选项的定义和plot函数相同. %1.当x,y,z是同维向量时,则x,y,z 对应元素构成一条三维曲线. x0 = 0 ...

  7. three.js 3d三维网页代码加密的实现方法

    http://www.jiamisoft.com/blog/17827-three-js-3dsanweiwangyejiami.html https://www.html5tricks.com/ta ...

  8. js 绘制数学函数

    <!-- <!doctype html> --> <html lang="en"> <head> <meta charset= ...

  9. 使用Matlab绘制三维图的几种方法

    以下六个函数都可以实现绘制三维图像: surf(xx,yy,zz); surfc(xx,yy,zz); mesh(xx,yy,zz); meshc(xx,yy,zz); meshz(xx,yy,zz) ...

  10. 【转】JS大总结(带实例)

    JS大总结(带实例) JavaScript事务查询综合click() 对象.click() 使对象被点击.closed 对象.closed 对象窗口是否已封闭true/falseclearTimeou ...

随机推荐

  1. 【uniapp】学习笔记day02 | uniapp搭建

    起因:需要做一个小程序,家人们谁懂啊,老师我真的不会做,由于懒得看视频学习,于是只能看博客学习了. uniapp 好处: 1.不用关心适配问题 2.可以发布到各大平台的小程序 3.上手容易,使用vue ...

  2. lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O

    -- create a class Animal={name = "no_name" , age=0 } function Animal:bark(voice) print(sel ...

  3. vertx 的http服务表单提交与mysql验证

    1.依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:/ ...

  4. C++学习笔记二:变量与数据类型(整型)

    1.int(整型数据): 1.1 进制的表示:十进制,八进制,16进制,二进制 int number1 = 15; // Decimal int number2 = 017; // Octal int ...

  5. VUE路由基本操作

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. CH395实现主动ping对端功能(代码及说明)

    目录 1.PING原理 1.1简介 1.2协议 1.3通信流程 2.代码解释 3.工程链接 PING原理 1.简介 PING是基于ICMP(Internet Control Message Proto ...

  7. .NET周刊【12月第2期 2023-12-13】

    国内文章 用最清爽的方式开发dotNet https://www.cnblogs.com/ncellit/p/17881779.html 本文介绍了如何以清爽的方式开发dotNet应用,特别是简单的A ...

  8. MongoDB副本集的搭建和管理(高可用)

    使得mongodb具备自动故障转移.高可用.读写分离. 副本集默认情况下读写都只是通过主库,副节点只是备份数据而已,但是可以设置副节点允许读操作,这样就可以做成读写分离. 使用pymongo的时候也可 ...

  9. 使用kubeadm在Centos8上部署kubernetes1.18

    // 查看系统版本 cat /etc/centos-release CentOS Linux release 8.1.1911 (Core) // 如果系统环境为8.0(云服务器默认最大安装环境为8. ...

  10. JPA复杂查询时间查询分页排序

    JPA复杂查询时间查询分页排序 JPA复杂查询时间查询分页排序,工作上用到,因为项目是jpa,记录.代码囊括了:查询条件+时间范围+分页+排序 其实我也不太想用jpa,但是他也有优点,操作可以兼容多种 ...