Procházet zdrojové kódy

Initial Spline Editor Example with Drag Controls

Joshua Koo před 10 roky
rodič
revize
95fac0f8a2

+ 229 - 0
examples/js/controls/DragControls.js

@@ -0,0 +1,229 @@
+/*
+ * @author zz85 / https://github.com/zz85
+ * Running this will allow you to drag three.js objects around the screen.
+ */
+THREE.DragControls = function( _camera, _objects, _domElement ) {
+
+	var _projector = new THREE.Projector();
+	var _raycaster = new THREE.Raycaster();
+
+	var _mouse = new THREE.Vector3(),
+		_offset = new THREE.Vector3();
+	var _selected, _hovered;
+
+	var p3subp1 = new THREE.Vector3();
+	var targetposition = new THREE.Vector3();
+	var zerovector = new THREE.Vector3();
+
+	this.enabled = false;
+
+	 /* Custom Event Handling */
+	var _listeners = {
+
+	};
+
+	var me = this;
+	this.on = function( event, handler ) {
+		
+		if ( !_listeners[ event ] ) _listeners[ event ] = [];
+
+		_listeners[ event ].push( handler );
+		return me;
+	
+	};
+
+	this.off = function( event, handler ) {
+		
+		var l = _listeners[ event ];
+		if ( !l ) return me;
+
+		if ( l.indexOf( handler ) > -1 ) {
+			
+			l.splice( handler, 1 );
+		
+		}
+
+		return me;
+
+	};
+
+	var notify = function( event, data, member ) {
+			
+		var l = _listeners[ event ];
+		if ( !l ) return;
+
+		if ( !member ) {
+					
+			for ( var i = 0; i < l.length; i ++ ) {
+						
+				l[ i ]( data );
+					
+			}
+				
+		}
+		
+	};
+
+	this.setObjects = function( objects ) {
+		
+		if ( objects instanceof THREE.Scene ) {
+			
+			_objects = objects.children;
+		
+		} else {
+			
+			_objects = objects;
+		
+		}
+	
+	};
+
+	this.setObjects( _objects );
+
+	this.activate = function() {
+		
+		_domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
+		_domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
+		_domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
+	
+	};
+
+	this.deactivate = function() {
+		
+		_domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+		_domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false );
+		_domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+	
+	};
+
+	this.activate();
+
+	function onDocumentMouseMove( event ) {
+
+		event.preventDefault();
+
+		_mouse.x = ( event.clientX / _domElement.width ) * 2 - 1;
+		_mouse.y = -( event.clientY / _domElement.height ) * 2 + 1;
+
+		_raycaster.setFromCamera( _mouse, _camera );
+		var ray = _raycaster.ray;
+
+
+		if ( _selected && me.enabled ) {
+			
+			var normal = _selected.normal;
+
+			// I found this article useful about plane-line intersections
+			// http://paulbourke.net/geometry/planeline/
+
+			var denom = normal.dot( ray.direction );
+			if ( denom == 0 ) {
+				// bail
+				console.log( 'no or infinite solutions' );
+				return;
+			
+			}
+
+			var num = normal.dot( p3subp1.copy( _selected.point ).sub( ray.origin ) );
+			var u = num / denom;
+
+			targetposition.copy( ray.direction ).multiplyScalar( u ).add( ray.origin ).sub( _offset );
+			// _selected.object.position.copy(targetposition);
+
+			var xLock, yLock, zLock = false;
+
+			var moveX, moveY, moveZ;
+			
+
+			if ( xLock ) {
+				
+				moveX = true;
+				moveY = false;
+				moveZ = false;
+			
+			} else if ( yLock ) {
+							
+				moveX = false;
+				moveY = true;
+				moveZ = false;
+						
+			} else {
+							
+				moveX = moveY = moveZ = true;
+						
+			}
+
+			// Reverse Matrix?
+			if ( moveX ) _selected.object.position.x = targetposition.x;
+			if ( moveY ) _selected.object.position.y = targetposition.y;
+			if ( moveZ ) _selected.object.position.z = targetposition.z;
+
+			notify( 'drag', _selected );
+
+			return;
+
+		}
+
+		_raycaster.setFromCamera( _mouse, _camera );
+		var intersects = _raycaster.intersectObjects( _objects );
+
+		if ( intersects.length > 0 ) {
+
+			_domElement.style.cursor = 'pointer';
+			_hovered = intersects[ 0 ];
+			notify( 'hoveron', _hovered );
+
+		} else {
+			
+			notify( 'hoveroff', _hovered );
+			_hovered = null;
+			_domElement.style.cursor = 'auto';
+
+		}
+
+	}
+
+	function onDocumentMouseDown( event ) {
+
+		event.preventDefault();
+
+		_mouse.x = ( event.clientX / _domElement.width ) * 2 - 1;
+		_mouse.y = -( event.clientY / _domElement.height ) * 2 + 1;
+
+		_raycaster.setFromCamera( _mouse, _camera );
+		var intersects = _raycaster.intersectObjects( _objects );
+		var ray = _raycaster.ray;
+
+		var normal = ray.direction; // normal ray to the camera position
+		if ( intersects.length > 0 ) {
+			
+			_selected = intersects[ 0 ];
+			_selected.ray = ray;
+			_selected.normal = normal ;
+			_offset.copy( _selected.point ).sub( _selected.object.position );
+
+			_domElement.style.cursor = 'move';
+
+			notify( 'dragstart', _selected );
+
+		}
+
+
+	}
+
+	function onDocumentMouseUp( event ) {
+
+		event.preventDefault();
+
+		if ( _selected ) {
+
+			notify( 'dragend', _selected );
+			_selected = null;
+		
+		}
+
+		_domElement.style.cursor = 'auto';
+
+	}
+
+}

+ 433 - 0
examples/webgl_geometry_spline_editor.html

@@ -0,0 +1,433 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - geometry - catmull spline editor</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.min.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/controls/TransformControls.js"></script>
+		<script src="js/renderers/Projector.js"></script>
+		<script src="js/controls/DragControls.js"></script>
+
+		<script src="js/libs/stats.min.js"></script>
+
+		<script>
+
+			String.prototype.format = function () {
+
+				var str = this;
+				for ( var i = 0; i < arguments.length; i ++ ) {
+
+					str = str.replace( '{' + i + '}', arguments[ i ] );
+
+				}
+				return str;
+
+			}
+
+			var container, stats;
+			var camera, scene, renderer;
+			var splineHelperObjects = [],
+				splineOutline;
+			var splinePointsLength = 4;
+			var positions = [];
+			var options;
+
+			var geometry = new THREE.BoxGeometry( 20, 20, 20 );
+
+			var ARC_SEGMENTS = 200;
+			var splineMesh;
+
+			var splines = {
+
+			};
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+				scene = new THREE.Scene();
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 1000;
+				scene.add( camera );
+
+				scene.add( new THREE.AmbientLight( 0xf0f0f0 ) );
+				var light = new THREE.SpotLight( 0xffffff, 1.5 );
+				light.position.set( 0, 1500, 200 );
+				light.castShadow = true;
+				light.shadowCameraNear = 200;
+				light.shadowCameraFar = camera.far;
+				light.shadowCameraFov = 70;
+				light.shadowBias = -0.000222;
+				light.shadowDarkness = 0.25;
+				light.shadowMapWidth = 1024;
+				light.shadowMapHeight = 1024;
+				scene.add( light );
+				spotlight = light;
+
+				var planeGeometry = new THREE.PlaneGeometry( 2000, 2000, 20, 20 );
+				planeGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
+				var planeMaterials = [ new THREE.MeshBasicMaterial( {
+					color: 0xeeeeee,
+					opacity: 0.5
+					} ), new THREE.MeshBasicMaterial( {
+						color: 0x405040,
+						wireframe: true,
+						opacity: 0.2,
+						transparent: true
+					} ) ];
+
+				var plane = THREE.SceneUtils.createMultiMaterialObject( planeGeometry, planeMaterials );
+				plane.position.y = -200;
+				plane.children[ 0 ].castShadow = false;
+				plane.children[ 0 ].receiveShadow = true;
+				scene.add( plane );
+				var axis = new THREE.AxisHelper();
+				axis.position.set( -500, -500, -500 );
+				scene.add( axis );
+
+				renderer = new THREE.WebGLRenderer( {
+					antialias: true
+				} );
+				renderer.setClearColor( 0xf0f0f0 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.shadowMapEnabled = true;
+				renderer.shadowMapSoft = true;
+				container.appendChild( renderer.domElement );
+				var info = document.createElement( 'div' );
+				info.style.position = 'absolute';
+				info.style.top = '10px';
+				info.style.width = '100%';
+				info.style.textAlign = 'center';
+				info.innerHTML = 'catmull-rom rom spline comparisions';
+				options = document.createElement( 'div' );
+				options.style.position = 'absolute';
+				options.style.top = '30px';
+				options.style.width = '100%';
+				options.style.textAlign = 'center';
+
+				options.innerHTML = 'Points: <input type="button" onclick="addPoint();" value="+" />\
+					<input type="button" onclick="removePoint();" value="-" />\
+					<input type="button" onclick="exportSpline();" value="Export" /><br />\
+					<input type="checkbox" id="uniform" checked /> <label for="uniform">Uniform Catmull-rom</label>  <input type="range" id="tension" onchange="splines.uniform.tension = tension.value;updateSplineOutline();" min=0 max=1 step=0.01 value=0.5 /> <span id="tension_value" /></span> <br />\
+					<input type="checkbox" id="centripetal" checked /> Centripetal Catmull-rom<br />\
+					<input type="checkbox" id="chordal" checked /> Chordal Catmull-rom<br />';
+
+				container.appendChild( info );
+				container.appendChild( options );
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				// Controls
+				controls = new THREE.OrbitControls( camera, renderer.domElement );
+				controls.damping = 0.2;
+				controls.addEventListener( 'change', render );
+
+				transformControl = new THREE.TransformControls( camera, renderer.domElement );
+				transformControl.addEventListener( 'change', render );
+
+				scene.add( transformControl );
+
+				// Hiding transform situation is a little in a mess :()
+				transformControl.addEventListener( 'change', function( e ) {
+
+					cancelHideTransorm();
+
+				} );
+
+				transformControl.addEventListener( 'mouseDown', function( e ) {
+
+					cancelHideTransorm();
+
+				} );
+
+				transformControl.addEventListener( 'mouseUp', function( e ) {
+
+					delayHideTransform();
+
+				} );
+
+				transformControl.addEventListener( 'objectChange', function( e ) {
+
+					updateSplineOutline();
+
+				} );
+
+				var dragcontrols = new THREE.DragControls( camera, splineHelperObjects, renderer.domElement ); // 
+
+				dragcontrols.on( 'hoveron', function( e ) {
+
+					transformControl.attach( e.object );
+					cancelHideTransorm(); // *
+
+				} )
+
+				dragcontrols.on( 'hoveroff', function( e ) {
+
+					if ( e ) delayHideTransform();
+
+				} )
+
+
+				controls.addEventListener( 'start', function() {
+
+					cancelHideTransorm();
+
+				} );
+
+				controls.addEventListener( 'end', function() {
+
+					delayHideTransform();
+
+				} );
+
+				var hiding;
+
+				function delayHideTransform() {
+
+					cancelHideTransorm();
+					hideTransform();
+
+				}
+
+				function hideTransform() {
+
+					hiding = setTimeout( function() {
+
+						transformControl.detach( transformControl.object );
+
+					}, 2500 )
+
+				}
+
+				function cancelHideTransorm() {
+
+					if ( hiding ) clearTimeout( hiding );
+
+				}
+
+
+				/*******
+				 * Curves
+				 *********/
+
+				var i;
+				for ( i = 0; i < splinePointsLength; i ++ ) {
+
+					addSplineObject( positions[ i ] );
+
+				}
+				positions = [];
+				for ( i = 0; i < splinePointsLength; i ++ ) {
+
+					positions.push( splineHelperObjects[ i ].position );
+
+				}
+
+				var geometry = new THREE.Geometry();
+
+				for ( var i = 0; i < ARC_SEGMENTS; i ++ ) {
+
+					geometry.vertices.push( new THREE.Vector3() );
+
+				}
+
+				var curve;
+
+
+				curve = new THREE.CatmullRomCurve3( positions );
+				curve.type = 'catmullrom';
+				curve.mesh = new THREE.Line( geometry.clone(), new THREE.LineBasicMaterial( {
+					color: 0xff0000,
+					opacity: 0.35,
+					linewidth: 2
+					} ) );
+				splines.uniform = curve;
+
+				curve = new THREE.CatmullRomCurve3( positions );
+				curve.type = 'centripetal';
+				curve.mesh = new THREE.Line( geometry.clone(), new THREE.LineBasicMaterial( {
+					color: 0x00ff00,
+					opacity: 0.35,
+					linewidth: 2
+					} ) );
+				splines.centripetal = curve;
+
+				curve = new THREE.CatmullRomCurve3( positions );
+				curve.type = 'chordal';
+				curve.mesh = new THREE.Line( geometry.clone(), new THREE.LineBasicMaterial( {
+					color: 0x0000ff,
+					opacity: 0.35,
+					linewidth: 2
+					} ) );
+				splines.chordal = curve;
+
+				for ( var k in splines ) {
+
+					var spline = splines[ k ];
+					scene.add( spline.mesh );
+
+				}
+
+				load( [ new THREE.Vector3( 289.76843686945404, 452.51481137238443, 56.10018915737797 ),
+						new THREE.Vector3( -53.56300074753207, 171.49711742836848, -14.495472686253045 ),
+						new THREE.Vector3( -91.40118730204415, 176.4306956436485, -6.958271935582161 ),
+						new THREE.Vector3( -383.785318791128, 491.1365363371675, 47.869296953772746 ) ] );
+
+			}
+
+			function addSplineObject( position ) {
+
+				var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( {
+					color: Math.random() * 0xffffff
+					} ) );
+				object.material.ambient = object.material.color;
+				if ( position ) {
+
+					object.position.copy( position );
+
+				} else {
+
+					object.position.x = Math.random() * 1000 - 500;
+					object.position.y = Math.random() * 600
+					object.position.z = Math.random() * 800 - 400;
+
+				}
+
+				object.castShadow = true;
+				object.receiveShadow = true;
+				scene.add( object );
+				splineHelperObjects.push( object );
+				return object;
+
+			}
+
+			function addPoint() {
+
+				splinePointsLength ++;
+				positions.push( addSplineObject()
+								.position );
+
+				updateSplineOutline();
+
+			}
+
+			function removePoint() {
+
+				if ( splinePointsLength <= 4 ) {
+
+					return;
+
+				}
+				splinePointsLength --;
+				positions.pop();
+				scene.remove( splineHelperObjects.pop() );
+
+				updateSplineOutline();
+
+			}
+
+			function updateSplineOutline() {
+
+				var p;
+
+				for ( var k in splines ) {
+
+					var spline = splines[ k ];
+
+					splineMesh = spline.mesh;
+
+					for ( var i = 0; i < ARC_SEGMENTS; i ++ ) {
+
+						p = splineMesh.geometry.vertices[ i ];
+						p.copy( spline.getPoint( i /  ( ARC_SEGMENTS - 1 ) ) );
+
+					}
+
+					splineMesh.geometry.verticesNeedUpdate = true;
+
+				}
+
+
+			}
+
+			function exportSpline() {
+
+				var p;
+				var strplace = [];
+				for ( i = 0; i < splinePointsLength; i ++ ) {
+
+					p = splineHelperObjects[ i ].position;
+					strplace.push( 'new THREE.Vector3({0}, {1}, {2})'.format( p.x, p.y, p.z ) )
+
+				}
+				console.log( strplace.join( ',\n' ) );
+				var code = '[' + ( strplace.join( ',\n\t' ) ) + ']';
+				prompt( 'copy and paste code', code );
+
+				}
+
+				function load( new_positions ) {
+
+				while ( new_positions.length > positions.length ) {
+
+					addPoint();
+
+				}
+
+				while ( new_positions.length < positions.length ) {
+
+					removePoint();
+
+				}
+
+				for ( i = 0; i < positions.length; i ++ ) {
+
+					positions[ i ].copy( new_positions[ i ] );
+
+				}
+
+				updateSplineOutline();
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+				render();
+				stats.update();
+				controls.update();
+				transformControl.update();
+
+			}
+
+			function render() {
+
+				splines.uniform.mesh.visible = uniform.checked;
+				splines.centripetal.mesh.visible = centripetal.checked;
+				splines.chordal.mesh.visible = chordal.checked;
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>