Browse Source

JSM: Added module and TS files for fat lines.

Mugen87 6 years ago
parent
commit
b8a14f73b1

+ 11 - 0
docs/manual/en/introduction/Import-via-modules.html

@@ -133,6 +133,17 @@
 						<li>TeapotBufferGeometry</li>
 					</ul>
 				</li>
+				<li>lines
+					<ul>
+						<li>Line2</li>
+						<li>LineGeometry</li>
+						<li>LineMaterial</li>
+						<li>LineSegments2</li>
+						<li>LineSegmentsGeometry</li>
+						<li>Wireframe</li>
+						<li>WireframeGeometry2</li>
+					</ul>
+				</li>
 				<li>loaders
 					<ul>
 						<li>3MFLoader</li>

+ 1 - 1
examples/js/lines/Line2.js

@@ -20,7 +20,7 @@ THREE.Line2.prototype = Object.assign( Object.create( THREE.LineSegments2.protot
 
 	isLine2: true,
 
-	copy: function ( source ) {
+	copy: function ( /* source */ ) {
 
 		// todo
 

+ 1 - 1
examples/js/lines/LineGeometry.js

@@ -87,7 +87,7 @@ THREE.LineGeometry.prototype = Object.assign( Object.create( THREE.LineSegmentsG
 
 	},
 
-	copy: function ( source ) {
+	copy: function ( /* source */ ) {
 
 		// todo
 

+ 1 - 1
examples/js/lines/LineSegments2.js

@@ -54,7 +54,7 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 
 	}() ),
 
-	copy: function ( source ) {
+	copy: function ( /* source */ ) {
 
 		// todo
 

+ 1 - 3
examples/js/lines/LineSegmentsGeometry.js

@@ -9,8 +9,6 @@ THREE.LineSegmentsGeometry = function () {
 
 	this.type = 'LineSegmentsGeometry';
 
-	var plane = new THREE.BufferGeometry();
-
 	var positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
 	var uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ];
 	var index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
@@ -249,7 +247,7 @@ THREE.LineSegmentsGeometry.prototype = Object.assign( Object.create( THREE.Insta
 
 	},
 
-	copy: function ( source ) {
+	copy: function ( /* source */ ) {
 
 		// todo
 

+ 1 - 1
examples/js/lines/Wireframe.js

@@ -54,7 +54,7 @@ THREE.Wireframe.prototype = Object.assign( Object.create( THREE.Mesh.prototype )
 
 	}() ),
 
-	copy: function ( source ) {
+	copy: function ( /* source */ ) {
 
 		// todo
 

+ 1 - 1
examples/js/lines/WireframeGeometry2.js

@@ -21,7 +21,7 @@ THREE.WireframeGeometry2.prototype = Object.assign( Object.create( THREE.LineSeg
 
 	isWireframeGeometry2: true,
 
-	copy: function ( source ) {
+	copy: function ( /* source */ ) {
 
 		// todo
 

+ 8 - 0
examples/jsm/lines/Line2.d.ts

@@ -0,0 +1,8 @@
+import { LineGeometry } from './LineGeometry';
+import { LineSegments2 } from './LineSegments2';
+import { LineMaterial } from './LineMaterial';
+
+export class Line2 extends LineSegments2 {
+  constructor(geometry?: LineGeometry, material?: LineMaterial);
+  isLine2: boolean;
+}

+ 38 - 0
examples/jsm/lines/Line2.js

@@ -0,0 +1,38 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ */
+
+
+import { LineSegments2 } from "../lines/LineSegments2.js";
+import { LineGeometry } from "../lines/LineGeometry.js";
+import { LineMaterial } from "../lines/LineMaterial.js";
+
+var Line2 = function ( geometry, material ) {
+
+	LineSegments2.call( this );
+
+	this.type = 'Line2';
+
+	this.geometry = geometry !== undefined ? geometry : new LineGeometry();
+	this.material = material !== undefined ? material : new LineMaterial( { color: Math.random() * 0xffffff } );
+
+};
+
+Line2.prototype = Object.assign( Object.create( LineSegments2.prototype ), {
+
+	constructor: Line2,
+
+	isLine2: true,
+
+	copy: function ( /* source */ ) {
+
+		// todo
+
+		return this;
+
+	}
+
+} );
+
+export { Line2 };

+ 12 - 0
examples/jsm/lines/LineGeometry.d.ts

@@ -0,0 +1,12 @@
+import {
+  Line
+} from '../../../src/Three';
+
+import { LineSegmentsGeometry } from './LineSegmentsGeometry';
+
+export class LineGeometry extends LineSegmentsGeometry {
+  constructor();
+  isLineGeometry: boolean;
+
+  fromLine(line: Line): this;
+}

+ 103 - 0
examples/jsm/lines/LineGeometry.js

@@ -0,0 +1,103 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ */
+
+
+import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
+
+var LineGeometry = function () {
+
+	LineSegmentsGeometry.call( this );
+
+	this.type = 'LineGeometry';
+
+};
+
+LineGeometry.prototype = Object.assign( Object.create( LineSegmentsGeometry.prototype ), {
+
+	constructor: LineGeometry,
+
+	isLineGeometry: true,
+
+	setPositions: function ( array ) {
+
+		// converts [ x1, y1, z1,  x2, y2, z2, ... ] to pairs format
+
+		var length = array.length - 3;
+		var points = new Float32Array( 2 * length );
+
+		for ( var i = 0; i < length; i += 3 ) {
+
+			points[ 2 * i ] = array[ i ];
+			points[ 2 * i + 1 ] = array[ i + 1 ];
+			points[ 2 * i + 2 ] = array[ i + 2 ];
+
+			points[ 2 * i + 3 ] = array[ i + 3 ];
+			points[ 2 * i + 4 ] = array[ i + 4 ];
+			points[ 2 * i + 5 ] = array[ i + 5 ];
+
+		}
+
+		LineSegmentsGeometry.prototype.setPositions.call( this, points );
+
+		return this;
+
+	},
+
+	setColors: function ( array ) {
+
+		// converts [ r1, g1, b1,  r2, g2, b2, ... ] to pairs format
+
+		var length = array.length - 3;
+		var colors = new Float32Array( 2 * length );
+
+		for ( var i = 0; i < length; i += 3 ) {
+
+			colors[ 2 * i ] = array[ i ];
+			colors[ 2 * i + 1 ] = array[ i + 1 ];
+			colors[ 2 * i + 2 ] = array[ i + 2 ];
+
+			colors[ 2 * i + 3 ] = array[ i + 3 ];
+			colors[ 2 * i + 4 ] = array[ i + 4 ];
+			colors[ 2 * i + 5 ] = array[ i + 5 ];
+
+		}
+
+		LineSegmentsGeometry.prototype.setColors.call( this, colors );
+
+		return this;
+
+	},
+
+	fromLine: function ( line ) {
+
+		var geometry = line.geometry;
+
+		if ( geometry.isGeometry ) {
+
+			this.setPositions( geometry.vertices );
+
+		} else if ( geometry.isBufferGeometry ) {
+
+			this.setPositions( geometry.position.array ); // assumes non-indexed
+
+		}
+
+		// set colors, maybe
+
+		return this;
+
+	},
+
+	copy: function ( /* source */ ) {
+
+		// todo
+
+		return this;
+
+	}
+
+} );
+
+export { LineGeometry };

+ 28 - 0
examples/jsm/lines/LineMaterial.d.ts

@@ -0,0 +1,28 @@
+import {
+  Color,
+  MaterialParameters,
+  ShaderMaterial,
+  Vector2
+} from '../../../src/Three';
+
+export interface LineMaterialParameters extends MaterialParameters {
+  color?: number;
+  dashed?: boolean;
+  dashScale?: number;
+  dashSize?: number;
+  gapSize?: number;
+  linewidth?: number;
+  resolution?: Vector2;
+}
+
+export class LineMaterial extends ShaderMaterial {
+  constructor(parameters?: LineMaterialParameters);
+  color: Color;
+  dashed: boolean;
+  dashScale: number;
+  dashSize: number;
+  gapSize: number;
+  isLineMaterial: boolean;
+  linewidth: number;
+  resolution: Vector2;
+}

+ 401 - 0
examples/jsm/lines/LineMaterial.js

@@ -0,0 +1,401 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  linewidth: <float>,
+ *  dashed: <boolean>,
+ *  dashScale: <float>,
+ *  dashSize: <float>,
+ *  gapSize: <float>,
+ *  resolution: <Vector2>, // 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 <common>
+		#include <color_pars_vertex>
+		#include <fog_pars_vertex>
+		#include <logdepthbuf_pars_vertex>
+		#include <clipping_planes_pars_vertex>
+
+		uniform float linewidth;
+		uniform vec2 resolution;
+
+		attribute vec3 instanceStart;
+		attribute vec3 instanceEnd;
+
+		attribute vec3 instanceColorStart;
+		attribute vec3 instanceColorEnd;
+
+		varying vec2 vUv;
+
+		#ifdef USE_DASH
+
+			uniform float dashScale;
+			attribute float instanceDistanceStart;
+			attribute float instanceDistanceEnd;
+			varying float 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
+
+			#include <logdepthbuf_vertex>
+			#include <clipping_planes_vertex>
+			#include <fog_vertex>
+
+		}
+		`,
+
+	fragmentShader:
+		`
+		uniform vec3 diffuse;
+		uniform float opacity;
+
+		#ifdef USE_DASH
+
+			uniform float dashSize;
+			uniform float gapSize;
+
+		#endif
+
+		varying float vLineDistance;
+
+		#include <common>
+		#include <color_pars_fragment>
+		#include <fog_pars_fragment>
+		#include <logdepthbuf_pars_fragment>
+		#include <clipping_planes_pars_fragment>
+
+		varying vec2 vUv;
+
+		void main() {
+
+			#include <clipping_planes_fragment>
+
+			#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 <logdepthbuf_fragment>
+			#include <color_fragment>
+
+			gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );
+
+			#include <premultiplied_alpha_fragment>
+			#include <tonemapping_fragment>
+			#include <encodings_fragment>
+			#include <fog_fragment>
+
+		}
+		`
+};
+
+var LineMaterial = function ( parameters ) {
+
+	ShaderMaterial.call( this, {
+
+		type: 'LineMaterial',
+
+		uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
+
+		vertexShader: ShaderLib[ 'line' ].vertexShader,
+		fragmentShader: ShaderLib[ 'line' ].fragmentShader
+
+	} );
+
+	this.dashed = false;
+
+	Object.defineProperties( this, {
+
+		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 );
+
+};
+
+LineMaterial.prototype = Object.create( ShaderMaterial.prototype );
+LineMaterial.prototype.constructor = LineMaterial;
+
+LineMaterial.prototype.isLineMaterial = true;
+
+LineMaterial.prototype.copy = function ( source ) {
+
+	ShaderMaterial.prototype.copy.call( this, source );
+
+	this.color.copy( source.color );
+
+	this.linewidth = source.linewidth;
+
+	this.resolution = source.resolution;
+
+	// todo
+
+	return this;
+
+};
+
+
+export { LineMaterial };

+ 13 - 0
examples/jsm/lines/LineSegments2.d.ts

@@ -0,0 +1,13 @@
+import {
+  Mesh,
+} from '../../../src/Three';
+
+import { LineMaterial } from './LineMaterial';
+import { LineSegmentsGeometry } from './LineSegmentsGeometry';
+
+export class LineSegments2 extends Mesh {
+  constructor(geometry?: LineSegmentsGeometry, material?: LineMaterial);
+  isLineSegments2: boolean;
+
+  computeLineDistances(): this;
+}

+ 76 - 0
examples/jsm/lines/LineSegments2.js

@@ -0,0 +1,76 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ */
+
+import {
+	InstancedInterleavedBuffer,
+	InterleavedBufferAttribute,
+	Mesh,
+	Vector3
+} from "../../../build/three.module.js";
+import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
+import { LineMaterial } from "../lines/LineMaterial.js";
+
+var LineSegments2 = function ( geometry, material ) {
+
+	Mesh.call( this );
+
+	this.type = 'LineSegments2';
+
+	this.geometry = geometry !== undefined ? geometry : new LineSegmentsGeometry();
+	this.material = material !== undefined ? material : new LineMaterial( { color: Math.random() * 0xffffff } );
+
+};
+
+LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {
+
+	constructor: LineSegments2,
+
+	isLineSegments2: true,
+
+	computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry...
+
+		var start = new Vector3();
+		var end = new Vector3();
+
+		return function computeLineDistances() {
+
+			var geometry = this.geometry;
+
+			var instanceStart = geometry.attributes.instanceStart;
+			var instanceEnd = geometry.attributes.instanceEnd;
+			var lineDistances = new Float32Array( 2 * instanceStart.data.count );
+
+			for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {
+
+				start.fromBufferAttribute( instanceStart, i );
+				end.fromBufferAttribute( instanceEnd, i );
+
+				lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
+				lineDistances[ j + 1 ] = lineDistances[ j ] + start.distanceTo( end );
+
+			}
+
+			var instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1
+
+			geometry.addAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
+			geometry.addAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1
+
+			return this;
+
+		};
+
+	}() ),
+
+	copy: function ( /* source */ ) {
+
+		// todo
+
+		return this;
+
+	}
+
+} );
+
+export { LineSegments2 };

+ 23 - 0
examples/jsm/lines/LineSegmentsGeometry.d.ts

@@ -0,0 +1,23 @@
+import {
+  EdgesGeometry,
+  InstancedBufferGeometry,
+  LineSegments,
+  Matrix4,
+  Mesh,
+  WireframeGeometry
+} from '../../../src/Three';
+
+export class LineSegmentsGeometry extends InstancedBufferGeometry {
+  constructor();
+  isLineSegmentsGeometry: boolean;
+
+  applyMatrix(matrix: Matrix4): this;
+  computeBoundingBox(): void;
+  computeBoundingSphere(): void;
+  fromEdgesGeometry(geometry: WireframeGeometry): this;
+  fromLineSegements(lineSegments: LineSegments): this;
+  fromMesh(mesh: Mesh): this;
+  fromWireframeGeometry(geometry: EdgesGeometry): this;
+  setColors(array: number[] | Float32Array): this;
+  setPositions(array: number[] | Float32Array): this;
+}

+ 271 - 0
examples/jsm/lines/LineSegmentsGeometry.js

@@ -0,0 +1,271 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ */
+
+import {
+	Box3,
+	Float32BufferAttribute,
+	InstancedBufferGeometry,
+	InstancedInterleavedBuffer,
+	InterleavedBufferAttribute,
+	Sphere,
+	Vector3,
+	WireframeGeometry
+} from "../../../build/three.module.js";
+
+var LineSegmentsGeometry = function () {
+
+	InstancedBufferGeometry.call( this );
+
+	this.type = 'LineSegmentsGeometry';
+
+	var positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
+	var uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ];
+	var index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
+
+	this.setIndex( index );
+	this.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+	this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+
+};
+
+LineSegmentsGeometry.prototype = Object.assign( Object.create( InstancedBufferGeometry.prototype ), {
+
+	constructor: LineSegmentsGeometry,
+
+	isLineSegmentsGeometry: true,
+
+	applyMatrix: function ( matrix ) {
+
+		var start = this.attributes.instanceStart;
+		var end = this.attributes.instanceEnd;
+
+		if ( start !== undefined ) {
+
+			matrix.applyToBufferAttribute( start );
+
+			matrix.applyToBufferAttribute( end );
+
+			start.data.needsUpdate = true;
+
+		}
+
+		if ( this.boundingBox !== null ) {
+
+			this.computeBoundingBox();
+
+		}
+
+		if ( this.boundingSphere !== null ) {
+
+			this.computeBoundingSphere();
+
+		}
+
+		return this;
+
+	},
+
+	setPositions: function ( array ) {
+
+		var lineSegments;
+
+		if ( array instanceof Float32Array ) {
+
+			lineSegments = array;
+
+		} else if ( Array.isArray( array ) ) {
+
+			lineSegments = new Float32Array( array );
+
+		}
+
+		var instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz
+
+		this.addAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
+		this.addAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
+
+		//
+
+		this.computeBoundingBox();
+		this.computeBoundingSphere();
+
+		return this;
+
+	},
+
+	setColors: function ( array ) {
+
+		var colors;
+
+		if ( array instanceof Float32Array ) {
+
+			colors = array;
+
+		} else if ( Array.isArray( array ) ) {
+
+			colors = new Float32Array( array );
+
+		}
+
+		var instanceColorBuffer = new InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb
+
+		this.addAttribute( 'instanceColorStart', new InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb
+		this.addAttribute( 'instanceColorEnd', new InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb
+
+		return this;
+
+	},
+
+	fromWireframeGeometry: function ( geometry ) {
+
+		this.setPositions( geometry.attributes.position.array );
+
+		return this;
+
+	},
+
+	fromEdgesGeometry: function ( geometry ) {
+
+		this.setPositions( geometry.attributes.position.array );
+
+		return this;
+
+	},
+
+	fromMesh: function ( mesh ) {
+
+		this.fromWireframeGeometry( new WireframeGeometry( mesh.geometry ) );
+
+		// set colors, maybe
+
+		return this;
+
+	},
+
+	fromLineSegements: function ( lineSegments ) {
+
+		var geometry = lineSegments.geometry;
+
+		if ( geometry.isGeometry ) {
+
+			this.setPositions( geometry.vertices );
+
+		} else if ( geometry.isBufferGeometry ) {
+
+			this.setPositions( geometry.position.array ); // assumes non-indexed
+
+		}
+
+		// set colors, maybe
+
+		return this;
+
+	},
+
+	computeBoundingBox: function () {
+
+		var box = new Box3();
+
+		return function computeBoundingBox() {
+
+			if ( this.boundingBox === null ) {
+
+				this.boundingBox = new Box3();
+
+			}
+
+			var start = this.attributes.instanceStart;
+			var end = this.attributes.instanceEnd;
+
+			if ( start !== undefined && end !== undefined ) {
+
+				this.boundingBox.setFromBufferAttribute( start );
+
+				box.setFromBufferAttribute( end );
+
+				this.boundingBox.union( box );
+
+			}
+
+		};
+
+	}(),
+
+	computeBoundingSphere: function () {
+
+		var vector = new Vector3();
+
+		return function computeBoundingSphere() {
+
+			if ( this.boundingSphere === null ) {
+
+				this.boundingSphere = new Sphere();
+
+			}
+
+			if ( this.boundingBox === null ) {
+
+				this.computeBoundingBox();
+
+			}
+
+			var start = this.attributes.instanceStart;
+			var end = this.attributes.instanceEnd;
+
+			if ( start !== undefined && end !== undefined ) {
+
+				var center = this.boundingSphere.center;
+
+				this.boundingBox.getCenter( center );
+
+				var maxRadiusSq = 0;
+
+				for ( var i = 0, il = start.count; i < il; i ++ ) {
+
+					vector.fromBufferAttribute( start, i );
+					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
+
+					vector.fromBufferAttribute( end, i );
+					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
+
+				}
+
+				this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
+
+				if ( isNaN( this.boundingSphere.radius ) ) {
+
+					console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this );
+
+				}
+
+			}
+
+		};
+
+	}(),
+
+	toJSON: function () {
+
+		// todo
+
+	},
+
+	clone: function () {
+
+		// todo
+
+	},
+
+	copy: function ( /* source */ ) {
+
+		// todo
+
+		return this;
+
+	}
+
+} );
+
+export { LineSegmentsGeometry };

+ 13 - 0
examples/jsm/lines/Wireframe.d.ts

@@ -0,0 +1,13 @@
+import {
+  Mesh,
+} from '../../../src/Three';
+
+import { LineMaterial } from './LineMaterial';
+import { LineSegmentsGeometry } from './LineSegmentsGeometry';
+
+export class Wireframe extends Mesh {
+  constructor(geometry?: LineSegmentsGeometry, material?: LineMaterial);
+  isWireframe: boolean;
+
+  computeLineDistances(): this;
+}

+ 76 - 0
examples/jsm/lines/Wireframe.js

@@ -0,0 +1,76 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ */
+
+import {
+	InstancedInterleavedBuffer,
+	InterleavedBufferAttribute,
+	Mesh,
+	Vector3
+} from "../../../build/three.module.js";
+import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
+import { LineMaterial } from "../lines/LineMaterial.js";
+
+var Wireframe = function ( geometry, material ) {
+
+	Mesh.call( this );
+
+	this.type = 'Wireframe';
+
+	this.geometry = geometry !== undefined ? geometry : new LineSegmentsGeometry();
+	this.material = material !== undefined ? material : new LineMaterial( { color: Math.random() * 0xffffff } );
+
+};
+
+Wireframe.prototype = Object.assign( Object.create( Mesh.prototype ), {
+
+	constructor: Wireframe,
+
+	isWireframe: true,
+
+	computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry...
+
+		var start = new Vector3();
+		var end = new Vector3();
+
+		return function computeLineDistances() {
+
+			var geometry = this.geometry;
+
+			var instanceStart = geometry.attributes.instanceStart;
+			var instanceEnd = geometry.attributes.instanceEnd;
+			var lineDistances = new Float32Array( 2 * instanceStart.data.count );
+
+			for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {
+
+				start.fromBufferAttribute( instanceStart, i );
+				end.fromBufferAttribute( instanceEnd, i );
+
+				lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
+				lineDistances[ j + 1 ] = lineDistances[ j ] + start.distanceTo( end );
+
+			}
+
+			var instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1
+
+			geometry.addAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
+			geometry.addAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1
+
+			return this;
+
+		};
+
+	}() ),
+
+	copy: function ( /* source */ ) {
+
+		// todo
+
+		return this;
+
+	}
+
+} );
+
+export { Wireframe };

+ 11 - 0
examples/jsm/lines/WireframeGeometry2.d.ts

@@ -0,0 +1,11 @@
+import {
+  BufferGeometry,
+  Geometry
+} from '../../../src/Three';
+
+import { LineSegmentsGeometry } from './LineSegmentsGeometry';
+
+export class WireframeGeometry2 extends LineSegmentsGeometry {
+  constructor(geometry: Geometry | BufferGeometry);
+  isWireframeGeometry2: boolean;
+}

+ 39 - 0
examples/jsm/lines/WireframeGeometry2.js

@@ -0,0 +1,39 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ *
+ */
+
+import {
+	WireframeGeometry
+} from "../../../build/three.module.js";
+import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
+
+var WireframeGeometry2 = function ( geometry ) {
+
+	LineSegmentsGeometry.call( this );
+
+	this.type = 'WireframeGeometry2';
+
+	this.fromWireframeGeometry( new WireframeGeometry( geometry ) );
+
+	// set colors, maybe
+
+};
+
+WireframeGeometry2.prototype = Object.assign( Object.create( LineSegmentsGeometry.prototype ), {
+
+	constructor: WireframeGeometry2,
+
+	isWireframeGeometry2: true,
+
+	copy: function ( /* source */ ) {
+
+		// todo
+
+		return this;
+
+	}
+
+} );
+
+export { WireframeGeometry2 };

+ 8 - 0
utils/modularize.js

@@ -48,6 +48,14 @@ var files = [
 	{ path: 'geometries/ParametricGeometries.js', dependencies: [], ignoreList: [] },
 	{ path: 'geometries/TeapotBufferGeometry.js', dependencies: [], ignoreList: [] },
 
+	{ path: 'lines/Line2.js', dependencies: [ { name: 'LineSegments2', path: 'lines/LineSegments2.js' }, { name: 'LineGeometry', path: 'lines/LineGeometry.js' }, { name: 'LineMaterial', path: 'lines/LineMaterial.js' } ], ignoreList: [] },
+	{ path: 'lines/LineGeometry.js', dependencies: [ { name: 'LineSegmentsGeometry', path: 'lines/LineSegmentsGeometry.js' } ], ignoreList: [] },
+	{ path: 'lines/LineMaterial.js', dependencies: [], ignoreList: [] },
+	{ path: 'lines/LineSegments2.js', dependencies: [ { name: 'LineSegmentsGeometry', path: 'lines/LineSegmentsGeometry.js' }, { name: 'LineMaterial', path: 'lines/LineMaterial.js' } ], ignoreList: [] },
+	{ path: 'lines/LineSegmentsGeometry.js', dependencies: [], ignoreList: [] },
+	{ path: 'lines/Wireframe.js', dependencies: [ { name: 'LineSegmentsGeometry', path: 'lines/LineSegmentsGeometry.js' }, { name: 'LineMaterial', path: 'lines/LineMaterial.js' } ], ignoreList: [] },
+	{ path: 'lines/WireframeGeometry2.js', dependencies: [ { name: 'LineSegmentsGeometry', path: 'lines/LineSegmentsGeometry.js' } ], ignoreList: [] },
+
 	{ path: 'loaders/3MFLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/AMFLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/AssimpJSONLoader.js', dependencies: [], ignoreList: [] },