君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景

君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。

以下为 html 源文件中引入 TrackballControls 库的关键代码,其中 camera 和 renderer 需要对 Threejs 有所了解方可理解:

		<script>
			var controls;
			controls = new THREE.TrackballControls( camera, renderer.domElement );

			function animate() {
				requestAnimationFrame( animate, renderer.domElement );
				controls.update();
				renderer.render( scene, camera );
			}
		</script>

以下代码归原作者所有,但在以下所署两网址未找到与此一致的最新代码,而有一些类似的可用代码,可以参考一下。

上面代码中引用的 js/controls/TrackballControls.js 代码原文,可拷贝可新建 TrackballControls.js 引入,并按上面方式使用即可:

/**
 * @author Eberhard Graether / http://egraether.com/
 * @author Mark Lundin 	/ http://mark-lundin.com
 */

THREE.TrackballControls = function ( object, domElement ) {

	var _this = this;
	var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };

	this.object = object;
	this.domElement = ( domElement !== undefined ) ? domElement : document;

	// API

	this.enabled = true;

	this.screen = { left: 0, top: 0, width: 0, height: 0 };

	this.rotateSpeed = 1.0;
	this.zoomSpeed = 1.2;
	this.panSpeed = 0.3;

	this.noRotate = false;
	this.noZoom = false;
	this.noPan = false;
	this.noRoll = false;

	this.staticMoving = false;
	this.dynamicDampingFactor = 0.2;

	this.minDistance = 0;
	this.maxDistance = Infinity;

	this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];

	// internals

	this.target = new THREE.Vector3();

	var EPS = 0.000001;

	var lastPosition = new THREE.Vector3();

	var _state = STATE.NONE,
	_prevState = STATE.NONE,

	_eye = new THREE.Vector3(),

	_rotateStart = new THREE.Vector3(),
	_rotateEnd = new THREE.Vector3(),

	_zoomStart = new THREE.Vector2(),
	_zoomEnd = new THREE.Vector2(),

	_touchZoomDistanceStart = 0,
	_touchZoomDistanceEnd = 0,

	_panStart = new THREE.Vector2(),
	_panEnd = new THREE.Vector2();

	// for reset

	this.target0 = this.target.clone();
	this.position0 = this.object.position.clone();
	this.up0 = this.object.up.clone();

	// events

	var changeEvent = { type: 'change' };
	var startEvent = { type: 'start'};
	var endEvent = { type: 'end'};

	// methods

	this.handleResize = function () {

		if ( this.domElement === document ) {

			this.screen.left = 0;
			this.screen.top = 0;
			this.screen.width = window.innerWidth;
			this.screen.height = window.innerHeight;

		} else {

			var box = this.domElement.getBoundingClientRect();
			// adjustments come from similar code in the jquery offset() function
			var d = this.domElement.ownerDocument.documentElement;
			this.screen.left = box.left + window.pageXOffset - d.clientLeft;
			this.screen.top = box.top + window.pageYOffset - d.clientTop;
			this.screen.width = box.width;
			this.screen.height = box.height;

		}

	};

	this.handleEvent = function ( event ) {

		if ( typeof this[ event.type ] == 'function' ) {

			this[ event.type ]( event );

		}

	};

	var getMouseOnScreen = ( function () {

		var vector = new THREE.Vector2();

		return function ( pageX, pageY ) {

			vector.set(
				( pageX - _this.screen.left ) / _this.screen.width,
				( pageY - _this.screen.top ) / _this.screen.height
			);

			return vector;

		};

	}() );

	var getMouseProjectionOnBall = ( function () {

		var vector = new THREE.Vector3();
		var objectUp = new THREE.Vector3();
		var mouseOnBall = new THREE.Vector3();

		return function ( pageX, pageY ) {

			mouseOnBall.set(
				( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
				( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5),
				0.0
			);

			var length = mouseOnBall.length();

			if ( _this.noRoll ) {

				if ( length < Math.SQRT1_2 ) {

					mouseOnBall.z = Math.sqrt( 1.0 - length*length );

				} else {

					mouseOnBall.z = .5 / length;

				}

			} else if ( length > 1.0 ) {

				mouseOnBall.normalize();

			} else {

				mouseOnBall.z = Math.sqrt( 1.0 - length * length );

			}

			_eye.copy( _this.object.position ).sub( _this.target );

			vector.copy( _this.object.up ).setLength( mouseOnBall.y )
			vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) );
			vector.add( _eye.setLength( mouseOnBall.z ) );

			return vector;

		};

	}() );

	this.rotateCamera = (function(){

		var axis = new THREE.Vector3(),
			quaternion = new THREE.Quaternion();

		return function () {

			var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );

			if ( angle ) {

				axis.crossVectors( _rotateStart, _rotateEnd ).normalize();

				angle *= _this.rotateSpeed;

				quaternion.setFromAxisAngle( axis, -angle );

				_eye.applyQuaternion( quaternion );
				_this.object.up.applyQuaternion( quaternion );

				_rotateEnd.applyQuaternion( quaternion );

				if ( _this.staticMoving ) {

					_rotateStart.copy( _rotateEnd );

				} else {

					quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
					_rotateStart.applyQuaternion( quaternion );

				}

			}
		}

	}());

	this.zoomCamera = function () {

		if ( _state === STATE.TOUCH_ZOOM_PAN ) {

			var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
			_touchZoomDistanceStart = _touchZoomDistanceEnd;
			_eye.multiplyScalar( factor );

		} else {

			var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;

			if ( factor !== 1.0 && factor > 0.0 ) {

				_eye.multiplyScalar( factor );

				if ( _this.staticMoving ) {

					_zoomStart.copy( _zoomEnd );

				} else {

					_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;

				}

			}

		}

	};

	this.panCamera = (function(){

		var mouseChange = new THREE.Vector2(),
			objectUp = new THREE.Vector3(),
			pan = new THREE.Vector3();

		return function () {

			mouseChange.copy( _panEnd ).sub( _panStart );

			if ( mouseChange.lengthSq() ) {

				mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );

				pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
				pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );

				_this.object.position.add( pan );
				_this.target.add( pan );

				if ( _this.staticMoving ) {

					_panStart.copy( _panEnd );

				} else {

					_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );

				}

			}
		}

	}());

	this.checkDistances = function () {

		if ( !_this.noZoom || !_this.noPan ) {

			if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {

				_this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );

			}

			if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {

				_this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );

			}

		}

	};

	this.update = function () {

		_eye.subVectors( _this.object.position, _this.target );

		if ( !_this.noRotate ) {

			_this.rotateCamera();

		}

		if ( !_this.noZoom ) {

			_this.zoomCamera();

		}

		if ( !_this.noPan ) {

			_this.panCamera();

		}

		_this.object.position.addVectors( _this.target, _eye );

		_this.checkDistances();

		_this.object.lookAt( _this.target );

		if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) {

			_this.dispatchEvent( changeEvent );

			lastPosition.copy( _this.object.position );

		}

	};

	this.reset = function () {

		_state = STATE.NONE;
		_prevState = STATE.NONE;

		_this.target.copy( _this.target0 );
		_this.object.position.copy( _this.position0 );
		_this.object.up.copy( _this.up0 );

		_eye.subVectors( _this.object.position, _this.target );

		_this.object.lookAt( _this.target );

		_this.dispatchEvent( changeEvent );

		lastPosition.copy( _this.object.position );

	};

	// listeners

	function keydown( event ) {

		if ( _this.enabled === false ) return;

		window.removeEventListener( 'keydown', keydown );

		_prevState = _state;

		if ( _state !== STATE.NONE ) {

			return;

		} else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {

			_state = STATE.ROTATE;

		} else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {

			_state = STATE.ZOOM;

		} else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {

			_state = STATE.PAN;

		}

	}

	function keyup( event ) {

		if ( _this.enabled === false ) return;

		_state = _prevState;

		window.addEventListener( 'keydown', keydown, false );

	}

	function mousedown( event ) {

		if ( _this.enabled === false ) return;

		event.preventDefault();
		event.stopPropagation();

		if ( _state === STATE.NONE ) {

			_state = event.button;

		}

		if ( _state === STATE.ROTATE && !_this.noRotate ) {

			_rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );
			_rotateEnd.copy( _rotateStart );

		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {

			_zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
			_zoomEnd.copy(_zoomStart);

		} else if ( _state === STATE.PAN && !_this.noPan ) {

			_panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
			_panEnd.copy(_panStart)

		}

		document.addEventListener( 'mousemove', mousemove, false );
		document.addEventListener( 'mouseup', mouseup, false );

		_this.dispatchEvent( startEvent );

	}

	function mousemove( event ) {

		if ( _this.enabled === false ) return;

		event.preventDefault();
		event.stopPropagation();

		if ( _state === STATE.ROTATE && !_this.noRotate ) {

			_rotateEnd.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );

		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {

			_zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );

		} else if ( _state === STATE.PAN && !_this.noPan ) {

			_panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );

		}

	}

	function mouseup( event ) {

		if ( _this.enabled === false ) return;

		event.preventDefault();
		event.stopPropagation();

		_state = STATE.NONE;

		document.removeEventListener( 'mousemove', mousemove );
		document.removeEventListener( 'mouseup', mouseup );
		_this.dispatchEvent( endEvent );

	}

	function mousewheel( event ) {

		if ( _this.enabled === false ) return;

		event.preventDefault();
		event.stopPropagation();

		var delta = 0;

		if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9

			delta = event.wheelDelta / 40;

		} else if ( event.detail ) { // Firefox

			delta = - event.detail / 3;

		}

		_zoomStart.y += delta * 0.01;
		_this.dispatchEvent( startEvent );
		_this.dispatchEvent( endEvent );

	}

	function touchstart( event ) {

		if ( _this.enabled === false ) return;

		switch ( event.touches.length ) {

			case 1:
				_state = STATE.TOUCH_ROTATE;
				_rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
				_rotateEnd.copy( _rotateStart );
				break;

			case 2:
				_state = STATE.TOUCH_ZOOM_PAN;
				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
				_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );

				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
				_panStart.copy( getMouseOnScreen( x, y ) );
				_panEnd.copy( _panStart );
				break;

			default:
				_state = STATE.NONE;

		}
		_this.dispatchEvent( startEvent );

	}

	function touchmove( event ) {

		if ( _this.enabled === false ) return;

		event.preventDefault();
		event.stopPropagation();

		switch ( event.touches.length ) {

			case 1:
				_rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
				break;

			case 2:
				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
				_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );

				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
				_panEnd.copy( getMouseOnScreen( x, y ) );
				break;

			default:
				_state = STATE.NONE;

		}

	}

	function touchend( event ) {

		if ( _this.enabled === false ) return;

		switch ( event.touches.length ) {

			case 1:
				_rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
				_rotateStart.copy( _rotateEnd );
				break;

			case 2:
				_touchZoomDistanceStart = _touchZoomDistanceEnd = 0;

				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
				_panEnd.copy( getMouseOnScreen( x, y ) );
				_panStart.copy( _panEnd );
				break;

		}

		_state = STATE.NONE;
		_this.dispatchEvent( endEvent );

	}

	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

	this.domElement.addEventListener( 'mousedown', mousedown, false );

	this.domElement.addEventListener( 'mousewheel', mousewheel, false );
	this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox

	this.domElement.addEventListener( 'touchstart', touchstart, false );
	this.domElement.addEventListener( 'touchend', touchend, false );
	this.domElement.addEventListener( 'touchmove', touchmove, false );

	window.addEventListener( 'keydown', keydown, false );
	window.addEventListener( 'keyup', keyup, false );

	this.handleResize();

	// force an update at start
	this.update();

};

THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
时间: 2024-11-10 11:31:27

君子性非异也,善假于物也 - Threejs 引入TrackballControls 查看场景的相关文章

优秀程序员无他-善假于物也

运用一门程序设计语言对大多数程序员来说是小菜一碟,但是更上一层楼成为一名专家级的软件开发者,恐怕目前还是大多数人的梦想.<程序员的思维修炼>一书中将程序员分为5个层级:新手,高级新手,胜任者,精通者,专家.根据作者的调查研究结果,在这5个层级中,大多数的程序员属于高级新手.而且居于这个层级的程序员从入行1.2年的到工作10来年都大有人在. 身为一个程序员,如何才能尽快的突破自身的瓶颈,得到快速的提升那?这可真不是三言两语可以说清楚.本人09年毕业投身软件行业,2012年初离开工作了三年的公司A

善假于物的让我们的网站推广更行之有效

我想各位站长都听过这句话:假舆马者,非利足也,而致千里,假舟楫者,非能水也,而绝江河,君子性非异也,善假于物也.成功的人与普通的人没有什么区别,只是善于利用有利的外部条件.上古如此,现在也是一样的,各位站长何不尝试一下这条古人留下的成功的途径,让自己的网站借助东风走的更远呢? 借助东风的方法很简单,也就是将自己的网站和已经成功的网站联系到一起,借助成功网站的名气,让自己的网站推广效果更上一层楼.俗话说:近朱者赤,近墨者黑,在网站推广中,将自己的网站放在什么位置,选择与谁共舞,是至关重要的一点.如

阿里云全球首批 MVP 傅奎专访 - 君子善假于物

个人基本介绍 很荣幸能成为阿里云全球第一批MVP(MVP计划).原本以为可以窃喜一番,没想到紧接着就是花肉同学的夺命催稿钉(钉).[花肉酱:人家也不想的啦] 作为信息安全领域摸爬滚打十年以上的从业人员,我练过渗透,干过产品,做过集成,卖过服务,吹过咨询,也曾在互联网电商企业"扫黄(牛)打黑(产)"一线与职业黑客.羊毛党直接对抗.目前正全面负责千寻位置公司(www.qxwz.com)未来时空基础设施的的信息安全工作. 我不擅长写自我介绍类的材料,一方面受限于我的文字表达能力,同时也因为我

海王星辰1/3营业额来自非药品类做假单应付检查

记者探访岛城五家知名药店,全都可以用医保卡买日用品 记者用医保卡在五家药店买到的生活日用品. "2005年4月,海王星辰在青岛开了第一家分店,截至2006年5月已经拥有直营门店18家,但其中却只有一家可以刷医保卡,记得那时我还在门店工作,因为不能刷卡我们被隔壁的两家药店抢走不少生意,直到 2006年10月底,海王在青岛的17家门店同时通过了GSP认证.取得了医保刷卡的资格,当拿到刷卡机的时候,我们的店员特别兴奋,甚至拿着扩音器向隔壁的药店喊话:'我们也能刷卡了!'很多店都放鞭炮来庆祝,那一刻我们

淘宝客推广应善假于物 短网址已成必备利剑

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 真正做过淘宝客的朋友应该都知道:淘宝客推广链接由于过长而且容易被屏蔽所以短网址一直是淘宝客必备工具.如果还不知道"短网址到底是什么东西"的朋友,请先自己问问度娘吧.今天笔者就和大家分享下短网址服务在淘宝客推广中的重要性以及应该注意的事项,使其真正成为淘宝客推广利剑.笔者和广大淘宝客一样,也是从菜鸟一步一步爬起来的,这期间走

假记忆植入老鼠获成功 盗梦空间场景可实现

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp; 在把科幻小说变成现实的实验中,麻省理工学院研究人员成功把假记忆植入老鼠大脑 把记忆植入某人大脑的概念是2010年影片<盗梦空间>的情节 北京时间7月29日消息,据国外媒体报道,把思想植入某人大脑是好莱坞恐怖片的情节.而研究人员在把科幻情节变成现实的实验中,已经成功地植入假记忆.美国麻省理工学院科学家已证实,可在现实生活中做到这一点,至少在老鼠身体上是这样

Tcl Tk Introduction

Tcl Tk Introduction eryar@163.com 摘要Abstract:Tcl/Tck脚本可以很容易实现用户自定义的命令,方便的创建图形化的用户界面GUI,所以Tcl和Tk的应用领域几乎覆盖了图形和工程应用的全部范围,包括计算机辅助设计.软件开发.测试.仪器控制.科学可视化及多媒体方面.即可以使用Tcl/Tk实现AVEVA中的PML类似的功能,允许用户自己编写简单程序实现程序的二次开发. 关键字Key Words:AVEVA, PDMS, PML, Tcl/Tk, Script

我不生产代码,我只是代码的搬运工

问题描述 我不生产代码,我只是代码的搬运工君子性非异也,善假于物也大家怎么看待过度依赖现成的代码,控件的开发行为作为技术大牛的你们,面试时讨厌这样的员工吗 解决方案 解决方案二:什么是"过渡依赖",这很难界定啊好比大文豪文章,一样是每个字都从字典里弄出来的这跟大段大段的重复抄袭完全是两回事就是如果用现成的代码改改就能实现不同的业务需要,这样的员工其实办事效率很高的但是如果只会复制粘贴,改一点就报错了,这样的员工根本还没入门好吗解决方案三:不讨厌,但是也不信任这样的人.这其实就是流水线上

Visualization of Curves and Surfaces in OpenSceneGraph

Visualization of Curves and Surfaces in OpenSceneGraph eryar@163.com 君子性非异也,善假于物也. 在学习计算机辅助几何造型(CAGD)等内容时,总是想把NURBS曲线.曲面显示出来,这样才能领会其中的奥妙.而现在大部分的教材都只是给出定理及其相关性质的证明,编程实现曲线及曲面显示的书籍很少. OpenSceneGraph是使用OpenGL技术开发的一套C++编程接口,借助这个工具可以让程序员能够更加快速.便捷的创建高性能.跨平台