From cb15ed333d7efcbc9e79b929fb6e6bf629e86efb Mon Sep 17 00:00:00 2001 From: tsengyushiang Date: Tue, 3 Dec 2024 13:07:45 +0000 Subject: [PATCH] enhance: line use miter joints and arrow gaps. --- src/three/TraceMesh.ts | 154 +++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 90 deletions(-) diff --git a/src/three/TraceMesh.ts b/src/three/TraceMesh.ts index 5d85ae1..46e3bba 100644 --- a/src/three/TraceMesh.ts +++ b/src/three/TraceMesh.ts @@ -35,14 +35,21 @@ bool isUvBackground(vec2 uv) { void main() { vec2 uv = vec2(mod(vUv.x, 1.0), vUv.y); - if (isUvBackground(uv)) { - discard; + if (!isUvBackground(uv) && mod(vUv.x,2.0)<1.0) { + gl_FragColor = vec4(vColor, 1.0); + return; } - gl_FragColor = vec4(vColor, 1.0); + gl_FragColor = vec4(0.0,0.0,0.0, 0.2); } `; +interface Point { + x: number; + y: number; + z: number; +} + export default class TraceMesh extends THREE.Mesh { constructor() { const geometry = new THREE.BufferGeometry(); @@ -58,74 +65,57 @@ export default class TraceMesh extends THREE.Mesh { this.frustumCulled = false; } - updateTrace(points: Array<{ x: number; y: number; z: number }>) { - const { attributes } = points.reduce<{ - latestPoint: { x: number; y: number; z: number } | undefined; - attributes: { - indices: number[]; - vertices: number[]; - uvs: number[]; - colors: number[]; - }; - }>( - (prev, point, index) => { - const { attributes, latestPoint } = prev; - if (!latestPoint) - return { - ...prev, - latestPoint: point, - }; - - const prePoint = new THREE.Vector2(latestPoint.x, latestPoint.z); - const curPoint = new THREE.Vector2(point.x, point.z); - const direction = new THREE.Vector2() - .subVectors(curPoint, prePoint) - .normalize(); - - const thick = 5e-1; - const thickOffset = new THREE.Vector2( - -direction.y, - direction.x - ).multiplyScalar(thick / 2); - const uvLength = - new THREE.Vector2().subVectors(curPoint, prePoint).length() / thick; - - const point1 = new THREE.Vector2().addVectors(prePoint, thickOffset); - const uv1 = [0, 0]; - const point2 = new THREE.Vector2().subVectors(prePoint, thickOffset); - const uv2 = [0, 1]; - const point3 = new THREE.Vector2().addVectors(curPoint, thickOffset); - const endUvX = - index === points.length - 1 ? Math.floor(uvLength) : uvLength; - const uv3 = [endUvX, 0]; - const point4 = new THREE.Vector2().subVectors(curPoint, thickOffset); - const uv4 = [endUvX, 1]; - - attributes.vertices.push( - point1.x, - 1e-1, - point1.y, - point2.x, - 1e-1, - point2.y, - point3.x, - 1e-1, - point3.y, - point4.x, - 1e-1, - point4.y - ); + private computeJointDirection(p0: Point, p1: Point, p2: Point) { + if (!p0) { + const vec = new THREE.Vector2(p2.x - p1.x, p2.z - p1.z); + return new THREE.Vector2(-vec.y, vec.x).normalize(); + } + if (!p2) { + const vec = new THREE.Vector2(p1.x - p0.x, p1.z - p0.z); + return new THREE.Vector2(-vec.y, vec.x).normalize(); + } + + const vec1 = new THREE.Vector2(p1.x - p0.x, p1.z - p0.z).normalize(); + const vec2 = new THREE.Vector2(p2.x - p1.x, p2.z - p1.z).normalize(); + const vec = new THREE.Vector2().addVectors(vec1, vec2).normalize(); + return new THREE.Vector2(-vec.y, vec.x).normalize(); + } + + updateTrace(points: Array) { + const indices: number[] = []; + const vertices: number[] = []; + const uvs: number[] = []; + const colors: number[] = []; + let accLength = 0; + + for (let pointIndex = 0; pointIndex < points.length; pointIndex++) { + const thick = 5e-1; + const p0 = points[pointIndex - 1]; + const p1 = points[pointIndex]; + const p2 = points[pointIndex + 1]; + const thickOffset = this.computeJointDirection(p0, p1, p2).multiplyScalar( + thick / 2.0 + ); + + const point = new THREE.Vector2(p1.x, p1.z); + const point1 = new THREE.Vector2().addVectors(point, thickOffset); + const point2 = new THREE.Vector2().subVectors(point, thickOffset); + vertices.push(point1.x, 1e-1, point1.y, point2.x, 1e-1, point2.y); + + if (pointIndex > 0) { + accLength += + new THREE.Vector2(p1.x - p0.x, p1.z - p0.z).length() / thick; + } + uvs.push(accLength, 0, accLength, 1); - const color1 = new THREE.Color() - .setHSL(prePoint.length() / 1e1, 1, 0.5) - .toArray(); - const color2 = new THREE.Color() - .setHSL(curPoint.length() / 1e1, 1, 0.5) - .toArray(); - attributes.colors.push(...color1, ...color1, ...color2, ...color2); + const color = new THREE.Color() + .setHSL(point.length() / 1e1, 1, 0.5) + .toArray(); + colors.push(...color, ...color); - const startIndex = (index - 1) * 4; - attributes.indices.push( + if (pointIndex > 0) { + const startIndex = (pointIndex - 1) * 2; + indices.push( startIndex + 0, startIndex + 2, startIndex + 1, @@ -133,37 +123,21 @@ export default class TraceMesh extends THREE.Mesh { startIndex + 3, startIndex + 1 ); - - attributes.uvs.push(...uv1, ...uv2, ...uv3, ...uv4); - - return { - latestPoint: point, - attributes, - }; - }, - { - latestPoint: undefined, - attributes: { - indices: [], - vertices: [], - uvs: [], - colors: [], - }, } - ); + } - this.geometry.setIndex(attributes.indices); + this.geometry.setIndex(indices); this.geometry.setAttribute( "position", - new THREE.BufferAttribute(new Float32Array(attributes.vertices), 3) + new THREE.BufferAttribute(new Float32Array(vertices), 3) ); this.geometry.setAttribute( "uv", - new THREE.BufferAttribute(new Float32Array(attributes.uvs), 2) + new THREE.BufferAttribute(new Float32Array(uvs), 2) ); this.geometry.setAttribute( "color", - new THREE.BufferAttribute(new Float32Array(attributes.colors), 3) + new THREE.BufferAttribute(new Float32Array(colors), 3) ); } }