Quellcode durchsuchen

Examples: remove TypedArrayUtils and webgl_nearestneighbour demo.

Mugen87 vor 4 Jahren
Ursprung
Commit
b48604fac6

+ 0 - 1
docs/api/en/materials/ShaderMaterial.html

@@ -117,7 +117,6 @@
 			[example:webgl_materials_skin webgl / materials / skin]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
-			[example:webgl_nearestneighbour webgl / nearestneighbour]<br />
 			[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />
 			[example:webgl_postprocessing_godrays webgl / postprocessing / godrays]
 		</p>

+ 0 - 1
docs/api/zh/materials/ShaderMaterial.html

@@ -107,7 +107,6 @@
 			[example:webgl_materials_texture_hdr webgl / materials / texture / hdr]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
-			[example:webgl_nearestneighbour webgl / nearestneighbour]<br />
 			[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />
 			[example:webgl_postprocessing_godrays webgl / postprocessing / godrays]
 		</p>

+ 0 - 1
examples/files.json

@@ -200,7 +200,6 @@
 		"webgl_multiple_renderers",
 		"webgl_multiple_scenes_comparison",
 		"webgl_multiple_views",
-		"webgl_nearestneighbour",
 		"webgl_panorama_cube",
 		"webgl_panorama_equirectangular",
 		"webgl_performance",

+ 0 - 594
examples/js/utils/TypedArrayUtils.js

@@ -1,594 +0,0 @@
-THREE.TypedArrayUtils = {};
-
-/**
- * In-place quicksort for typed arrays (e.g. for Float32Array)
- * provides fast sorting
- * useful e.g. for a custom shader and/or BufferGeometry
- *
- * Complexity: http://bigocheatsheet.com/ see Quicksort
- *
- * Example:
- * points: [x, y, z, x, y, z, x, y, z, ...]
- * eleSize: 3 //because of (x, y, z)
- * orderElement: 0 //order according to x
- */
-
-THREE.TypedArrayUtils.quicksortIP = function ( arr, eleSize, orderElement ) {
-
-	var stack = [];
-	var sp = - 1;
-	var left = 0;
-	var right = arr.length / eleSize - 1;
-	var tmp = 0.0, x = 0, y = 0;
-
-	var swapF = function ( a, b ) {
-
-		a *= eleSize; b *= eleSize;
-
-		for ( y = 0; y < eleSize; y ++ ) {
-
-			tmp = arr[ a + y ];
-			arr[ a + y ] = arr[ b + y ];
-			arr[ b + y ] = tmp;
-
-		}
-
-	};
-
-	var i, j, swap = new Float32Array( eleSize ), temp = new Float32Array( eleSize );
-
-	while ( true ) {
-
-		if ( right - left <= 25 ) {
-
-			for ( j = left + 1; j <= right; j ++ ) {
-
-				for ( x = 0; x < eleSize; x ++ ) {
-
-					swap[ x ] = arr[ j * eleSize + x ];
-
-				}
-
-				i = j - 1;
-
-				while ( i >= left && arr[ i * eleSize + orderElement ] > swap[ orderElement ] ) {
-
-					for ( x = 0; x < eleSize; x ++ ) {
-
-						arr[ ( i + 1 ) * eleSize + x ] = arr[ i * eleSize + x ];
-
-					}
-
-					i --;
-
-				}
-
-				for ( x = 0; x < eleSize; x ++ ) {
-
-					arr[ ( i + 1 ) * eleSize + x ] = swap[ x ];
-
-				}
-
-			}
-
-			if ( sp == - 1 ) break;
-
-			right = stack[ sp -- ]; //?
-			left = stack[ sp -- ];
-
-		} else {
-
-			var median = ( left + right ) >> 1;
-
-			i = left + 1;
-			j = right;
-
-			swapF( median, i );
-
-			if ( arr[ left * eleSize + orderElement ] > arr[ right * eleSize + orderElement ] ) {
-
-				swapF( left, right );
-
-			}
-
-			if ( arr[ i * eleSize + orderElement ] > arr[ right * eleSize + orderElement ] ) {
-
-				swapF( i, right );
-
-			}
-
-			if ( arr[ left * eleSize + orderElement ] > arr[ i * eleSize + orderElement ] ) {
-
-				swapF( left, i );
-
-			}
-
-			for ( x = 0; x < eleSize; x ++ ) {
-
-				temp[ x ] = arr[ i * eleSize + x ];
-
-			}
-
-			while ( true ) {
-
-				do i ++; while ( arr[ i * eleSize + orderElement ] < temp[ orderElement ] );
-				do j --; while ( arr[ j * eleSize + orderElement ] > temp[ orderElement ] );
-
-				if ( j < i ) break;
-
-				swapF( i, j );
-
-			}
-
-			for ( x = 0; x < eleSize; x ++ ) {
-
-				arr[ ( left + 1 ) * eleSize + x ] = arr[ j * eleSize + x ];
-				arr[ j * eleSize + x ] = temp[ x ];
-
-			}
-
-			if ( right - i + 1 >= j - left ) {
-
-				stack[ ++ sp ] = i;
-				stack[ ++ sp ] = right;
-				right = j - 1;
-
-			} else {
-
-				stack[ ++ sp ] = left;
-				stack[ ++ sp ] = j - 1;
-				left = i;
-
-			}
-
-		}
-
-	}
-
-	return arr;
-
-};
-
-
-
-/**
- * k-d Tree for typed arrays (e.g. for Float32Array), in-place
- * provides fast nearest neighbour search
- * useful e.g. for a custom shader and/or BufferGeometry, saves tons of memory
- * has no insert and remove, only buildup and neares neighbour search
- *
- * Based on https://github.com/ubilabs/kd-tree-javascript by Ubilabs
- *
- * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
- *
- * Requires typed array quicksort
- *
- * Example:
- * points: [x, y, z, x, y, z, x, y, z, ...]
- * metric: function(a, b){	return Math.pow(a[0] - b[0], 2) +  Math.pow(a[1] - b[1], 2) +  Math.pow(a[2] - b[2], 2); }  //Manhatten distance
- * eleSize: 3 //because of (x, y, z)
- *
- * Further information (including mathematical properties)
- * http://en.wikipedia.org/wiki/Binary_tree
- * http://en.wikipedia.org/wiki/K-d_tree
- *
- * If you want to further minimize memory usage, remove Node.depth and replace in search algorithm with a traversal to root node (see comments at THREE.TypedArrayUtils.Kdtree.prototype.Node)
- */
-
-THREE.TypedArrayUtils.Kdtree = function ( points, metric, eleSize ) {
-
-	var scope = this;
-
-	var maxDepth = 0;
-
-	var getPointSet = function ( points, pos ) {
-
-		return points.subarray( pos * eleSize, pos * eleSize + eleSize );
-
-	};
-
-	function buildTree( points, depth, parent, pos ) {
-
-		var dim = depth % eleSize,
-			median,
-			node,
-			plength = points.length / eleSize;
-
-		if ( depth > maxDepth ) maxDepth = depth;
-
-		if ( plength === 0 ) return null;
-		if ( plength === 1 ) {
-
-			return new scope.Node( getPointSet( points, 0 ), depth, parent, pos );
-
-		}
-
-		THREE.TypedArrayUtils.quicksortIP( points, eleSize, dim );
-
-		median = Math.floor( plength / 2 );
-
-		node = new scope.Node( getPointSet( points, median ), depth, parent, median + pos );
-		node.left = buildTree( points.subarray( 0, median * eleSize ), depth + 1, node, pos );
-		node.right = buildTree( points.subarray( ( median + 1 ) * eleSize, points.length ), depth + 1, node, pos + median + 1 );
-
-		return node;
-
-	}
-
-	this.root = buildTree( points, 0, null, 0 );
-
-	this.getMaxDepth = function () {
-
-		return maxDepth;
-
-	};
-
-	this.nearest = function ( point, maxNodes, maxDistance ) {
-
-		 /* point: array of size eleSize
-			maxNodes: max amount of nodes to return
-			maxDistance: maximum distance to point result nodes should have
-			condition (not implemented): function to test node before it's added to the result list, e.g. test for view frustum
-		*/
-
-		var i,
-			result,
-			bestNodes;
-
-		bestNodes = new THREE.TypedArrayUtils.Kdtree.BinaryHeap(
-
-			function ( e ) {
-
-				return - e[ 1 ];
-
-			}
-
-		);
-
-		function nearestSearch( node ) {
-
-			var bestChild,
-				dimension = node.depth % eleSize,
-				ownDistance = metric( point, node.obj ),
-				linearDistance = 0,
-				otherChild,
-				i,
-				linearPoint = [];
-
-			function saveNode( node, distance ) {
-
-				bestNodes.push( [ node, distance ] );
-
-				if ( bestNodes.size() > maxNodes ) {
-
-					bestNodes.pop();
-
-				}
-
-			}
-
-			for ( i = 0; i < eleSize; i += 1 ) {
-
-				if ( i === node.depth % eleSize ) {
-
-					linearPoint[ i ] = point[ i ];
-
-				} else {
-
-					linearPoint[ i ] = node.obj[ i ];
-
-				}
-
-			}
-
-			linearDistance = metric( linearPoint, node.obj );
-
-			// if it's a leaf
-
-			if ( node.right === null && node.left === null ) {
-
-				if ( bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[ 1 ] ) {
-
-					saveNode( node, ownDistance );
-
-				}
-
-				return;
-
-			}
-
-			if ( node.right === null ) {
-
-				bestChild = node.left;
-
-			} else if ( node.left === null ) {
-
-				bestChild = node.right;
-
-			} else {
-
-				if ( point[ dimension ] < node.obj[ dimension ] ) {
-
-					bestChild = node.left;
-
-				} else {
-
-					bestChild = node.right;
-
-				}
-
-			}
-
-			// recursive search
-
-			nearestSearch( bestChild );
-
-			if ( bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[ 1 ] ) {
-
-				saveNode( node, ownDistance );
-
-			}
-
-			// if there's still room or the current distance is nearer than the best distance
-
-			if ( bestNodes.size() < maxNodes || Math.abs( linearDistance ) < bestNodes.peek()[ 1 ] ) {
-
-				if ( bestChild === node.left ) {
-
-					otherChild = node.right;
-
-				} else {
-
-					otherChild = node.left;
-
-				}
-
-				if ( otherChild !== null ) {
-
-					nearestSearch( otherChild );
-
-				}
-
-			}
-
-		}
-
-		if ( maxDistance ) {
-
-			for ( i = 0; i < maxNodes; i += 1 ) {
-
-				bestNodes.push( [ null, maxDistance ] );
-
-			}
-
-		}
-
-		nearestSearch( scope.root );
-
-		result = [];
-
-		for ( i = 0; i < maxNodes; i += 1 ) {
-
-			if ( bestNodes.content[ i ][ 0 ] ) {
-
-				result.push( [ bestNodes.content[ i ][ 0 ], bestNodes.content[ i ][ 1 ] ] );
-
-			}
-
-		}
-
-		return result;
-
-	};
-
-};
-
-/**
- * If you need to free up additional memory and agree with an additional O( log n ) traversal time you can get rid of "depth" and "pos" in Node:
- * Depth can be easily done by adding 1 for every parent (care: root node has depth 0, not 1)
- * Pos is a bit tricky: Assuming the tree is balanced (which is the case when after we built it up), perform the following steps:
- *   By traversing to the root store the path e.g. in a bit pattern (01001011, 0 is left, 1 is right)
- *   From buildTree we know that "median = Math.floor( plength / 2 );", therefore for each bit...
- *     0: amountOfNodesRelevantForUs = Math.floor( (pamountOfNodesRelevantForUs - 1) / 2 );
- *     1: amountOfNodesRelevantForUs = Math.ceil( (pamountOfNodesRelevantForUs - 1) / 2 );
- *        pos += Math.floor( (pamountOfNodesRelevantForUs - 1) / 2 );
- *     when recursion done, we still need to add all left children of target node:
- *        pos += Math.floor( (pamountOfNodesRelevantForUs - 1) / 2 );
- *        and I think you need to +1 for the current position, not sure.. depends, try it out ^^
- *
- * I experienced that for 200'000 nodes you can get rid of 4 MB memory each, leading to 8 MB memory saved.
- */
-THREE.TypedArrayUtils.Kdtree.prototype.Node = function ( obj, depth, parent, pos ) {
-
-	this.obj = obj;
-	this.left = null;
-	this.right = null;
-	this.parent = parent;
-	this.depth = depth;
-	this.pos = pos;
-
-};
-
-/**
- * Binary heap implementation
- */
-
-THREE.TypedArrayUtils.Kdtree.BinaryHeap = function ( scoreFunction ) {
-
-	this.content = [];
-	this.scoreFunction = scoreFunction;
-
-};
-
-THREE.TypedArrayUtils.Kdtree.BinaryHeap.prototype = {
-
-	push: function ( element ) {
-
-		// Add the new element to the end of the array.
-		this.content.push( element );
-
-		// Allow it to bubble up.
-		this.bubbleUp( this.content.length - 1 );
-
-	},
-
-	pop: function () {
-
-		// Store the first element so we can return it later.
-		var result = this.content[ 0 ];
-
-		// Get the element at the end of the array.
-		var end = this.content.pop();
-
-		// If there are any elements left, put the end element at the
-		// start, and let it sink down.
-		if ( this.content.length > 0 ) {
-
-			this.content[ 0 ] = end;
-			this.sinkDown( 0 );
-
-		}
-
-		return result;
-
-	},
-
-	peek: function () {
-
-		return this.content[ 0 ];
-
-	},
-
-	remove: function ( node ) {
-
-		var len = this.content.length;
-
-		// To remove a value, we must search through the array to find it.
-		for ( var i = 0; i < len; i ++ ) {
-
-			if ( this.content[ i ] == node ) {
-
-				// When it is found, the process seen in 'pop' is repeated
-				// to fill up the hole.
-				var end = this.content.pop();
-
-				if ( i != len - 1 ) {
-
-					this.content[ i ] = end;
-
-					if ( this.scoreFunction( end ) < this.scoreFunction( node ) ) {
-
-						this.bubbleUp( i );
-
-					} else {
-
-						this.sinkDown( i );
-
-					}
-
-				}
-
-				return;
-
-			}
-
-		}
-
-		throw new Error( 'Node not found.' );
-
-	},
-
-	size: function () {
-
-		return this.content.length;
-
-	},
-
-	bubbleUp: function ( n ) {
-
-		// Fetch the element that has to be moved.
-		var element = this.content[ n ];
-
-		// When at 0, an element can not go up any further.
-		while ( n > 0 ) {
-
-			// Compute the parent element's index, and fetch it.
-			var parentN = Math.floor( ( n + 1 ) / 2 ) - 1,
-				parent = this.content[ parentN ];
-
-			// Swap the elements if the parent is greater.
-			if ( this.scoreFunction( element ) < this.scoreFunction( parent ) ) {
-
-				this.content[ parentN ] = element;
-				this.content[ n ] = parent;
-
-				// Update 'n' to continue at the new position.
-				n = parentN;
-
-			} else {
-
-				// Found a parent that is less, no need to move it further.
-				break;
-
-			}
-
-		}
-
-	},
-
-	sinkDown: function ( n ) {
-
-		// Look up the target element and its score.
-		var length = this.content.length,
-			element = this.content[ n ],
-			elemScore = this.scoreFunction( element );
-
-		while ( true ) {
-
-			// Compute the indices of the child elements.
-			var child2N = ( n + 1 ) * 2, child1N = child2N - 1;
-
-			// This is used to store the new position of the element, if any.
-			var swap = null;
-
-			// If the first child exists (is inside the array)...
-			if ( child1N < length ) {
-
-				// Look it up and compute its score.
-				var child1 = this.content[ child1N ],
-					child1Score = this.scoreFunction( child1 );
-
-				// If the score is less than our element's, we need to swap.
-				if ( child1Score < elemScore ) swap = child1N;
-
-			}
-
-			// Do the same checks for the other child.
-			if ( child2N < length ) {
-
-				var child2 = this.content[ child2N ],
-					child2Score = this.scoreFunction( child2 );
-
-				if ( child2Score < ( swap === null ? elemScore : child1Score ) ) swap = child2N;
-
-			}
-
-			// If the element needs to be moved, swap it, and continue.
-			if ( swap !== null ) {
-
-				this.content[ n ] = this.content[ swap ];
-				this.content[ swap ] = element;
-				n = swap;
-
-			} else {
-
-				// Otherwise, we are done.
-				break;
-
-			}
-
-		}
-
-	}
-
-};

+ 0 - 64
examples/jsm/utils/TypedArrayUtils.d.ts

@@ -1,64 +0,0 @@
-export namespace TypedArrayUtils {
-	export function quicksortIP( arr: any[], eleSize: number, orderElement: number ): any[];
-
-	type Points = Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Float32Array | Float64Array | Uint8ClampedArray;
-
-	export class Kdtree {
-
-		self: this;
-		root: Node;
-		private maxDepth: number;
-
-		constructor( points: Points, metric: ( a: any, b: any ) => number, eleSize: number );
-
-		getPointSet( points: Points, pos: number ): Points;
-
-		buildTree(): Node;
-
-		getMaxDepth(): number;
-
-		nearest( point: [], maxNodes: number, maxDistance: number ): any[];
-
-	}
-
-	export namespace Kdtree {
-		export class Node {
-
-			obj: any;
-			left: Node | null;
-			right: Node | null;
-			parent: Node;
-			depth: number;
-			pos: any;
-
-			constructor( obj: any, depth: number, parent: Node, pos: any )
-
-		}
-
-
-		export class BinaryHeap {
-
-			content: any[];
-			scoreFunction: () => any;
-
-			constructor( scoreFunction?: () => any );
-
-		}
-
-		export namespace BinaryHeap {
-			export function push( element: any ): void;
-
-			export function pop(): any;
-
-			export function peek(): any;
-
-			export function remove( node: any ): any;
-
-			export function size(): number;
-
-			export function bubbleUp( n: number ): void;
-
-			export function sinkDown( n: number ): void;
-		}
-	}
-}

+ 0 - 596
examples/jsm/utils/TypedArrayUtils.js

@@ -1,596 +0,0 @@
-var TypedArrayUtils = {};
-
-/**
- * In-place quicksort for typed arrays (e.g. for Float32Array)
- * provides fast sorting
- * useful e.g. for a custom shader and/or BufferGeometry
- *
- * Complexity: http://bigocheatsheet.com/ see Quicksort
- *
- * Example:
- * points: [x, y, z, x, y, z, x, y, z, ...]
- * eleSize: 3 //because of (x, y, z)
- * orderElement: 0 //order according to x
- */
-
-TypedArrayUtils.quicksortIP = function ( arr, eleSize, orderElement ) {
-
-	var stack = [];
-	var sp = - 1;
-	var left = 0;
-	var right = arr.length / eleSize - 1;
-	var tmp = 0.0, x = 0, y = 0;
-
-	var swapF = function ( a, b ) {
-
-		a *= eleSize; b *= eleSize;
-
-		for ( y = 0; y < eleSize; y ++ ) {
-
-			tmp = arr[ a + y ];
-			arr[ a + y ] = arr[ b + y ];
-			arr[ b + y ] = tmp;
-
-		}
-
-	};
-
-	var i, j, swap = new Float32Array( eleSize ), temp = new Float32Array( eleSize );
-
-	while ( true ) {
-
-		if ( right - left <= 25 ) {
-
-			for ( j = left + 1; j <= right; j ++ ) {
-
-				for ( x = 0; x < eleSize; x ++ ) {
-
-					swap[ x ] = arr[ j * eleSize + x ];
-
-				}
-
-				i = j - 1;
-
-				while ( i >= left && arr[ i * eleSize + orderElement ] > swap[ orderElement ] ) {
-
-					for ( x = 0; x < eleSize; x ++ ) {
-
-						arr[ ( i + 1 ) * eleSize + x ] = arr[ i * eleSize + x ];
-
-					}
-
-					i --;
-
-				}
-
-				for ( x = 0; x < eleSize; x ++ ) {
-
-					arr[ ( i + 1 ) * eleSize + x ] = swap[ x ];
-
-				}
-
-			}
-
-			if ( sp == - 1 ) break;
-
-			right = stack[ sp -- ]; //?
-			left = stack[ sp -- ];
-
-		} else {
-
-			var median = ( left + right ) >> 1;
-
-			i = left + 1;
-			j = right;
-
-			swapF( median, i );
-
-			if ( arr[ left * eleSize + orderElement ] > arr[ right * eleSize + orderElement ] ) {
-
-				swapF( left, right );
-
-			}
-
-			if ( arr[ i * eleSize + orderElement ] > arr[ right * eleSize + orderElement ] ) {
-
-				swapF( i, right );
-
-			}
-
-			if ( arr[ left * eleSize + orderElement ] > arr[ i * eleSize + orderElement ] ) {
-
-				swapF( left, i );
-
-			}
-
-			for ( x = 0; x < eleSize; x ++ ) {
-
-				temp[ x ] = arr[ i * eleSize + x ];
-
-			}
-
-			while ( true ) {
-
-				do i ++; while ( arr[ i * eleSize + orderElement ] < temp[ orderElement ] );
-				do j --; while ( arr[ j * eleSize + orderElement ] > temp[ orderElement ] );
-
-				if ( j < i ) break;
-
-				swapF( i, j );
-
-			}
-
-			for ( x = 0; x < eleSize; x ++ ) {
-
-				arr[ ( left + 1 ) * eleSize + x ] = arr[ j * eleSize + x ];
-				arr[ j * eleSize + x ] = temp[ x ];
-
-			}
-
-			if ( right - i + 1 >= j - left ) {
-
-				stack[ ++ sp ] = i;
-				stack[ ++ sp ] = right;
-				right = j - 1;
-
-			} else {
-
-				stack[ ++ sp ] = left;
-				stack[ ++ sp ] = j - 1;
-				left = i;
-
-			}
-
-		}
-
-	}
-
-	return arr;
-
-};
-
-
-
-/**
- * k-d Tree for typed arrays (e.g. for Float32Array), in-place
- * provides fast nearest neighbour search
- * useful e.g. for a custom shader and/or BufferGeometry, saves tons of memory
- * has no insert and remove, only buildup and neares neighbour search
- *
- * Based on https://github.com/ubilabs/kd-tree-javascript by Ubilabs
- *
- * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
- *
- * Requires typed array quicksort
- *
- * Example:
- * points: [x, y, z, x, y, z, x, y, z, ...]
- * metric: function(a, b){	return Math.pow(a[0] - b[0], 2) +  Math.pow(a[1] - b[1], 2) +  Math.pow(a[2] - b[2], 2); }  //Manhatten distance
- * eleSize: 3 //because of (x, y, z)
- *
- * Further information (including mathematical properties)
- * http://en.wikipedia.org/wiki/Binary_tree
- * http://en.wikipedia.org/wiki/K-d_tree
- *
- * If you want to further minimize memory usage, remove Node.depth and replace in search algorithm with a traversal to root node (see comments at TypedArrayUtils.Kdtree.prototype.Node)
- */
-
-TypedArrayUtils.Kdtree = function ( points, metric, eleSize ) {
-
-	var scope = this;
-
-	var maxDepth = 0;
-
-	var getPointSet = function ( points, pos ) {
-
-		return points.subarray( pos * eleSize, pos * eleSize + eleSize );
-
-	};
-
-	function buildTree( points, depth, parent, pos ) {
-
-		var dim = depth % eleSize,
-			median,
-			node,
-			plength = points.length / eleSize;
-
-		if ( depth > maxDepth ) maxDepth = depth;
-
-		if ( plength === 0 ) return null;
-		if ( plength === 1 ) {
-
-			return new scope.Node( getPointSet( points, 0 ), depth, parent, pos );
-
-		}
-
-		TypedArrayUtils.quicksortIP( points, eleSize, dim );
-
-		median = Math.floor( plength / 2 );
-
-		node = new scope.Node( getPointSet( points, median ), depth, parent, median + pos );
-		node.left = buildTree( points.subarray( 0, median * eleSize ), depth + 1, node, pos );
-		node.right = buildTree( points.subarray( ( median + 1 ) * eleSize, points.length ), depth + 1, node, pos + median + 1 );
-
-		return node;
-
-	}
-
-	this.root = buildTree( points, 0, null, 0 );
-
-	this.getMaxDepth = function () {
-
-		return maxDepth;
-
-	};
-
-	this.nearest = function ( point, maxNodes, maxDistance ) {
-
-		 /* point: array of size eleSize
-			maxNodes: max amount of nodes to return
-			maxDistance: maximum distance to point result nodes should have
-			condition (not implemented): function to test node before it's added to the result list, e.g. test for view frustum
-		*/
-
-		var i,
-			result,
-			bestNodes;
-
-		bestNodes = new TypedArrayUtils.Kdtree.BinaryHeap(
-
-			function ( e ) {
-
-				return - e[ 1 ];
-
-			}
-
-		);
-
-		function nearestSearch( node ) {
-
-			var bestChild,
-				dimension = node.depth % eleSize,
-				ownDistance = metric( point, node.obj ),
-				linearDistance = 0,
-				otherChild,
-				i,
-				linearPoint = [];
-
-			function saveNode( node, distance ) {
-
-				bestNodes.push( [ node, distance ] );
-
-				if ( bestNodes.size() > maxNodes ) {
-
-					bestNodes.pop();
-
-				}
-
-			}
-
-			for ( i = 0; i < eleSize; i += 1 ) {
-
-				if ( i === node.depth % eleSize ) {
-
-					linearPoint[ i ] = point[ i ];
-
-				} else {
-
-					linearPoint[ i ] = node.obj[ i ];
-
-				}
-
-			}
-
-			linearDistance = metric( linearPoint, node.obj );
-
-			// if it's a leaf
-
-			if ( node.right === null && node.left === null ) {
-
-				if ( bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[ 1 ] ) {
-
-					saveNode( node, ownDistance );
-
-				}
-
-				return;
-
-			}
-
-			if ( node.right === null ) {
-
-				bestChild = node.left;
-
-			} else if ( node.left === null ) {
-
-				bestChild = node.right;
-
-			} else {
-
-				if ( point[ dimension ] < node.obj[ dimension ] ) {
-
-					bestChild = node.left;
-
-				} else {
-
-					bestChild = node.right;
-
-				}
-
-			}
-
-			// recursive search
-
-			nearestSearch( bestChild );
-
-			if ( bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[ 1 ] ) {
-
-				saveNode( node, ownDistance );
-
-			}
-
-			// if there's still room or the current distance is nearer than the best distance
-
-			if ( bestNodes.size() < maxNodes || Math.abs( linearDistance ) < bestNodes.peek()[ 1 ] ) {
-
-				if ( bestChild === node.left ) {
-
-					otherChild = node.right;
-
-				} else {
-
-					otherChild = node.left;
-
-				}
-
-				if ( otherChild !== null ) {
-
-					nearestSearch( otherChild );
-
-				}
-
-			}
-
-		}
-
-		if ( maxDistance ) {
-
-			for ( i = 0; i < maxNodes; i += 1 ) {
-
-				bestNodes.push( [ null, maxDistance ] );
-
-			}
-
-		}
-
-		nearestSearch( scope.root );
-
-		result = [];
-
-		for ( i = 0; i < maxNodes; i += 1 ) {
-
-			if ( bestNodes.content[ i ][ 0 ] ) {
-
-				result.push( [ bestNodes.content[ i ][ 0 ], bestNodes.content[ i ][ 1 ] ] );
-
-			}
-
-		}
-
-		return result;
-
-	};
-
-};
-
-/**
- * If you need to free up additional memory and agree with an additional O( log n ) traversal time you can get rid of "depth" and "pos" in Node:
- * Depth can be easily done by adding 1 for every parent (care: root node has depth 0, not 1)
- * Pos is a bit tricky: Assuming the tree is balanced (which is the case when after we built it up), perform the following steps:
- *   By traversing to the root store the path e.g. in a bit pattern (01001011, 0 is left, 1 is right)
- *   From buildTree we know that "median = Math.floor( plength / 2 );", therefore for each bit...
- *     0: amountOfNodesRelevantForUs = Math.floor( (pamountOfNodesRelevantForUs - 1) / 2 );
- *     1: amountOfNodesRelevantForUs = Math.ceil( (pamountOfNodesRelevantForUs - 1) / 2 );
- *        pos += Math.floor( (pamountOfNodesRelevantForUs - 1) / 2 );
- *     when recursion done, we still need to add all left children of target node:
- *        pos += Math.floor( (pamountOfNodesRelevantForUs - 1) / 2 );
- *        and I think you need to +1 for the current position, not sure.. depends, try it out ^^
- *
- * I experienced that for 200'000 nodes you can get rid of 4 MB memory each, leading to 8 MB memory saved.
- */
-TypedArrayUtils.Kdtree.prototype.Node = function ( obj, depth, parent, pos ) {
-
-	this.obj = obj;
-	this.left = null;
-	this.right = null;
-	this.parent = parent;
-	this.depth = depth;
-	this.pos = pos;
-
-};
-
-/**
- * Binary heap implementation
- */
-
-TypedArrayUtils.Kdtree.BinaryHeap = function ( scoreFunction ) {
-
-	this.content = [];
-	this.scoreFunction = scoreFunction;
-
-};
-
-TypedArrayUtils.Kdtree.BinaryHeap.prototype = {
-
-	push: function ( element ) {
-
-		// Add the new element to the end of the array.
-		this.content.push( element );
-
-		// Allow it to bubble up.
-		this.bubbleUp( this.content.length - 1 );
-
-	},
-
-	pop: function () {
-
-		// Store the first element so we can return it later.
-		var result = this.content[ 0 ];
-
-		// Get the element at the end of the array.
-		var end = this.content.pop();
-
-		// If there are any elements left, put the end element at the
-		// start, and let it sink down.
-		if ( this.content.length > 0 ) {
-
-			this.content[ 0 ] = end;
-			this.sinkDown( 0 );
-
-		}
-
-		return result;
-
-	},
-
-	peek: function () {
-
-		return this.content[ 0 ];
-
-	},
-
-	remove: function ( node ) {
-
-		var len = this.content.length;
-
-		// To remove a value, we must search through the array to find it.
-		for ( var i = 0; i < len; i ++ ) {
-
-			if ( this.content[ i ] == node ) {
-
-				// When it is found, the process seen in 'pop' is repeated
-				// to fill up the hole.
-				var end = this.content.pop();
-
-				if ( i != len - 1 ) {
-
-					this.content[ i ] = end;
-
-					if ( this.scoreFunction( end ) < this.scoreFunction( node ) ) {
-
-						this.bubbleUp( i );
-
-					} else {
-
-						this.sinkDown( i );
-
-					}
-
-				}
-
-				return;
-
-			}
-
-		}
-
-		throw new Error( 'Node not found.' );
-
-	},
-
-	size: function () {
-
-		return this.content.length;
-
-	},
-
-	bubbleUp: function ( n ) {
-
-		// Fetch the element that has to be moved.
-		var element = this.content[ n ];
-
-		// When at 0, an element can not go up any further.
-		while ( n > 0 ) {
-
-			// Compute the parent element's index, and fetch it.
-			var parentN = Math.floor( ( n + 1 ) / 2 ) - 1,
-				parent = this.content[ parentN ];
-
-			// Swap the elements if the parent is greater.
-			if ( this.scoreFunction( element ) < this.scoreFunction( parent ) ) {
-
-				this.content[ parentN ] = element;
-				this.content[ n ] = parent;
-
-				// Update 'n' to continue at the new position.
-				n = parentN;
-
-			} else {
-
-				// Found a parent that is less, no need to move it further.
-				break;
-
-			}
-
-		}
-
-	},
-
-	sinkDown: function ( n ) {
-
-		// Look up the target element and its score.
-		var length = this.content.length,
-			element = this.content[ n ],
-			elemScore = this.scoreFunction( element );
-
-		while ( true ) {
-
-			// Compute the indices of the child elements.
-			var child2N = ( n + 1 ) * 2, child1N = child2N - 1;
-
-			// This is used to store the new position of the element, if any.
-			var swap = null;
-
-			// If the first child exists (is inside the array)...
-			if ( child1N < length ) {
-
-				// Look it up and compute its score.
-				var child1 = this.content[ child1N ],
-					child1Score = this.scoreFunction( child1 );
-
-				// If the score is less than our element's, we need to swap.
-				if ( child1Score < elemScore ) swap = child1N;
-
-			}
-
-			// Do the same checks for the other child.
-			if ( child2N < length ) {
-
-				var child2 = this.content[ child2N ],
-					child2Score = this.scoreFunction( child2 );
-
-				if ( child2Score < ( swap === null ? elemScore : child1Score ) ) swap = child2N;
-
-			}
-
-			// If the element needs to be moved, swap it, and continue.
-			if ( swap !== null ) {
-
-				this.content[ n ] = this.content[ swap ];
-				this.content[ swap ] = element;
-				n = swap;
-
-			} else {
-
-				// Otherwise, we are done.
-				break;
-
-			}
-
-		}
-
-	}
-
-};
-
-export { TypedArrayUtils };

+ 0 - 1
examples/tags.json

@@ -53,7 +53,6 @@
 	"webgl_morphtargets_horse": [ "animation" ],
 	"webgl_multiple_elements": [ "differential equations", "physics" ],
 	"webgl_multiple_elements_text": [ "font" ],
-	"webgl_nearestneighbour": [ "kdtree" ],
 	"webgl_panorama_cube": [ "envmap" ],
 	"webgl_panorama_equirectangular": [ "envmap" ],
 	"webgl_points_billboards": [ "particles" ],

+ 0 - 224
examples/webgl_nearestneighbour.html

@@ -1,224 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - nearest neighbour</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<link type="text/css" rel="stylesheet" href="main.css">
-	</head>
-	<body>
-
-		<div id="info">
-			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - typed arrays<br/>
-			nearest neighbour for 500,000 sprites
-		</div>
-
-		<script type="x-shader/x-vertex" id="vertexshader">
-
-			//uniform float zoom;
-
-			attribute float alpha;
-
-			varying float vAlpha;
-
-			void main() {
-
-				vAlpha = 1.0 - alpha;
-
-				vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
-
-				gl_PointSize = 4.0 * ( 300.0 / -mvPosition.z );
-
-				gl_Position = projectionMatrix * mvPosition;
-
-			}
-
-		</script>
-
-		<script type="x-shader/x-fragment" id="fragmentshader">
-
-			uniform sampler2D tex1;
-
-			varying float vAlpha;
-
-			void main() {
-
-				gl_FragColor = texture2D( tex1, gl_PointCoord );
-				gl_FragColor.r = ( 1.0 - gl_FragColor.r ) * vAlpha + gl_FragColor.r;
-
-			}
-
-		</script>
-
-		<script type="module">
-
-			import * as THREE from '../build/three.module.js';
-
-			import { FirstPersonControls } from './jsm/controls/FirstPersonControls.js';
-			import { TypedArrayUtils } from './jsm/utils/TypedArrayUtils.js';
-
-			let camera, scene, renderer;
-			let controls;
-
-			const amountOfParticles = 500000, maxDistance = Math.pow( 120, 2 );
-			let positions, alphas, particles, _particleGeom;
-			let kdtree;
-
-			const clock = new THREE.Clock();
-
-			init();
-			animate();
-
-			function init() {
-
-				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000000 );
-
-				scene = new THREE.Scene();
-
-				// add a skybox background
-				const cubeTextureLoader = new THREE.CubeTextureLoader();
-
-				cubeTextureLoader.setPath( 'textures/cube/skyboxsun25deg/' );
-
-				const cubeTexture = cubeTextureLoader.load( [
-					'px.jpg', 'nx.jpg',
-					'py.jpg', 'ny.jpg',
-					'pz.jpg', 'nz.jpg',
-				] );
-
-				scene.background = cubeTexture;
-
-				//
-
-				renderer = new THREE.WebGLRenderer();
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				document.body.appendChild( renderer.domElement );
-
-				controls = new FirstPersonControls( camera, renderer.domElement );
-				controls.movementSpeed = 100;
-				controls.lookSpeed = 0.1;
-
-				controls.lookAt( 500, 500, 500 );
-
-				// create the custom shader
-
-				const textureLoader = new THREE.TextureLoader();
-
-				const imagePreviewTexture = textureLoader.load( 'textures/crate.gif' );
-
-				imagePreviewTexture.minFilter = THREE.LinearMipmapLinearFilter;
-				imagePreviewTexture.magFilter = THREE.LinearFilter;
-
-				const pointShaderMaterial = new THREE.ShaderMaterial( {
-					uniforms: {
-						tex1: { value: imagePreviewTexture },
-						zoom: { value: 9.0 }
-					},
-					vertexShader: document.getElementById( 'vertexshader' ).textContent,
-					fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
-					transparent: true
-				} );
-
-
-				//create particles with buffer geometry
-
-				positions = new Float32Array( amountOfParticles * 3 );
-				alphas = new Float32Array( amountOfParticles );
-
-				_particleGeom = new THREE.BufferGeometry();
-				_particleGeom.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
-				_particleGeom.setAttribute( 'alpha', new THREE.BufferAttribute( alphas, 1 ) );
-
-				particles = new THREE.Points( _particleGeom, pointShaderMaterial );
-
-				for ( let x = 0; x < amountOfParticles; x ++ ) {
-
-					positions[ x * 3 + 0 ] = Math.random() * 1000;
-					positions[ x * 3 + 1 ] = Math.random() * 1000;
-					positions[ x * 3 + 2 ] = Math.random() * 1000;
-
-					alphas[ x ] = 1.0;
-
-				}
-
-				const measureStart = new Date().getTime();
-
-				// creating the kdtree takes a lot of time to execute, in turn the nearest neighbour search will be much faster
-				kdtree = new TypedArrayUtils.Kdtree( positions, distanceFunction, 3 );
-
-				console.log( 'TIME building kdtree', new Date().getTime() - measureStart );
-
-				// display particles after the kd-tree was generated and the sorting of the positions-array is done
-				scene.add( particles );
-
-				window.addEventListener( 'resize', onWindowResize, false );
-
-			}
-
-			function onWindowResize() {
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				controls.handleResize();
-
-			}
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				//
-				displayNearest( camera.position );
-
-				controls.update( clock.getDelta() );
-
-				renderer.render( scene, camera );
-
-			}
-
-			function displayNearest( position ) {
-
-				// take the nearest 200 around him. distance^2 'cause we use the manhattan distance and no square is applied in the distance function
-				const imagePositionsInRange = kdtree.nearest( [ position.x, position.y, position.z ], 100, maxDistance );
-
-				// We combine the nearest neighbour with a view frustum. Doesn't make sense if we change the sprites not in our view... well maybe it does. Whatever you want.
-				const _frustum = new THREE.Frustum();
-				const _projScreenMatrix = new THREE.Matrix4();
-
-				_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
-				_frustum.setFromProjectionMatrix( _projScreenMatrix );
-
-				for ( let i = 0, il = imagePositionsInRange.length; i < il; i ++ ) {
-
-					const object = imagePositionsInRange[ i ];
-					const objectPoint = new THREE.Vector3().fromArray( object[ 0 ].obj );
-
-					if ( _frustum.containsPoint( objectPoint ) ) {
-
-						const objectIndex = object[ 0 ].pos;
-
-						// set the alpha according to distance
-						alphas[ objectIndex ] = 1.0 / maxDistance * object[ 1 ];
-
-						// update the attribute
-						_particleGeom.attributes.alpha.needsUpdate = true;
-
-					}
-
-				}
-
-			}
-
-			function distanceFunction( a, b ) {
-
-				return Math.pow( a[ 0 ] - b[ 0 ], 2 ) + Math.pow( a[ 1 ] - b[ 1 ], 2 ) + Math.pow( a[ 2 ] - b[ 2 ], 2 );
-
-			}
-
-		</script>
-	</body>
-</html>