Created
September 11, 2018 10:08
-
-
Save KeanW/1e001e51a4c7207c7f42fa4862905b7b to your computer and use it in GitHub Desktop.
Streamline implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as MeshLine from './THREE.MeshLine.js'; | |
export class Streamline extends THREE.Mesh { | |
public vertices: THREE.Vector3[]; | |
private _meshLine: any; | |
private _lineGeometry: THREE.Geometry; | |
private _vis: number; | |
constructor( | |
verts: THREE.Vector3[], | |
color: THREE.Color, | |
width: number, | |
opacity: number, | |
growTime: number, | |
displayTime: number, | |
resolution: THREE.Vector2, | |
remove?: (s: Streamline) => void | |
) { | |
super(); | |
this._meshLine = null; | |
this._vis = 0; | |
this.createMeshLine(verts, color, width, opacity, resolution); | |
// Fade the line's visibility to make it grow across the space | |
// and then shrink in the same direction | |
this.fadeIn( | |
growTime, | |
(s) => { | |
setTimeout(() => { | |
this.fadeOut(growTime, remove); | |
}, displayTime); | |
} | |
); | |
} | |
private createMeshLine( | |
verts: THREE.Vector3[], | |
color: THREE.Color, | |
width: number, | |
opacity: number, | |
resolution: THREE.Vector2 | |
) { | |
if (!this._lineGeometry) { | |
this._lineGeometry = new THREE.Geometry(); | |
} | |
this._meshLine = this.createMeshLineGeometry(this._meshLine, verts, this._lineGeometry, true); | |
this.material = this.createMeshLineMaterial(this._meshLine, width, opacity, color, resolution); | |
this.geometry = this._meshLine.geometry; | |
} | |
private createMeshLineGeometry( | |
ml: any, | |
verts: THREE.Vector3[], | |
geom: THREE.Geometry, | |
fit: boolean | |
): any { | |
if (fit) { | |
this.createCurve(verts, geom); | |
} else { | |
for (let vert of verts) { | |
geom.vertices.push(vert); | |
} | |
geom.verticesNeedUpdate = true; | |
} | |
if (!ml) { | |
ml = new MeshLine.MeshLine(); | |
} | |
// Set the width at each vertex based on its position - which gives a taper - | |
// and then subtract the current visibility setting. This means the taper will follow | |
// the start of the line, rather than it being truncated | |
// (this.vis only gets set for streamlines as they're shrinking) | |
ml.setGeometry(geom, (p: number) => p - this._vis); | |
return ml; | |
} | |
private createCurve(verts: THREE.Vector3[], geom: THREE.Geometry): void { | |
// Create a spline fitting the vertices | |
// and get 100 points along its length | |
let curve = new THREE.SplineCurve3(verts); | |
let points = curve.getPoints(100); | |
for (let pt of points) { | |
geom.vertices.push(pt); | |
} | |
geom.verticesNeedUpdate = true; | |
} | |
private createMeshLineMaterial( | |
ml: any, | |
width: number, | |
opacity: number, | |
color: THREE.Color, | |
resolution: THREE.Vector2 | |
): any { | |
let mat: any = new MeshLine.MeshLineMaterial({ | |
color: color, | |
lineWidth: width, | |
opacity: opacity, | |
transparent: true, | |
visibility: 0, // default is invisible, we will grow outwards | |
resolution: resolution, | |
attributes: { | |
previous: ml.previous, | |
next: ml.next, | |
side: ml.side, | |
width: ml.width, | |
counters: ml.counters | |
} | |
}); | |
// Disable depthTest for decent performance | |
mat.depthTest = false; | |
return mat; | |
} | |
private fadeIn(growTime: number, callback?: (s) => void): void { | |
// Not needed, as it's the default in the material definition | |
// (<any>this.material).uniforms.visibility.value = 0.0; | |
this.fadeVisibility(1, 0.1, growTime, undefined, callback); | |
} | |
private fadeOut(growTime: number, callback? : (s) => void): void { | |
(<any>this.material).uniforms.visibility.value = -1.0; | |
this.fadeVisibility(0, 0.1, growTime, (vis: any) => { | |
// Set the visibility level as we shrink, so that the per-vertex | |
// linewidth calculation function can maintain the taper at the | |
// start point. The visibility is negative and > -1, so add 1 | |
// to put it in the right range for when we pick it up later | |
this._vis = vis.value + 1; | |
// Call meshLine.process() to force a per-vertex linewidth recalc | |
this._meshLine.process(); | |
}, callback); | |
} | |
private fadeVisibility( | |
target: number, | |
increment: number, | |
growTime: number, | |
process?: (vis: any) => void, | |
callback?: (s: Streamline) => void | |
): void { | |
setTimeout(() => { | |
let vis = (<any>this.material).uniforms.visibility; | |
if (vis.value < target) { | |
vis.value += increment; | |
// Optional processing call that can be used (for instance) | |
// to store the visibility value and recalculate per-vertex linewidths | |
if (process) { | |
process(vis); | |
} | |
// Recurse | |
this.fadeVisibility(target, increment, growTime, process, callback); | |
} else { | |
if (callback) { | |
callback(this); | |
} | |
} | |
}, growTime); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment