Three.js Example 注解 —— canvas_geometry_panorama.html

本文搬自我的Github,https://github.com/555chy/three.js-example-comment,有兴趣的可以一起来完善,这个为Three.js的Example进行注解,方便初学者阅读

three.js 官网 Example 地址:https://threejs.org/examples/

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js canvas - panorama demo</title>
		<meta charset="utf-8">
		<!--
		如果没有设置viewport的width的话,网页很可能会超出手机屏幕宽度,具体多宽,要看浏览器定义的默认宽度是多少
		user-scalable=no,规定了用户不能缩放网页,但有些浏览器对该项支持不是很好,故需要设置minimum-scale和maximum-scale相同来限制用户缩放
		-->
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {
				background-color: rgb(200,200,200);
				margin: 0px;
				overflow: hidden;
			}
			#info {
				position: absolute;
				top: 0px; width: 100%;
				color: #ffffff;
				padding: 5px;
				font-family:Monospace;
				font-size:13px;
				font-weight: bold;
				text-align:center;
			}
			a {
				color: #ffffff;
			}
		</style>
	</head>
	<body>
		<div id="container"></div>
		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - panorama demo. cubemap by <a href="http://www.zfight.com/" target="_blank">Jochum Skoglund</a>.</div>

		<script src="../build/three.js"></script>

		<!--
		想要使用CanvasRenderer,必须添加如下两个js文件 
		Projector.js顾名思义上将3d图像投影到Canvas("2d")上,如果没有该文件会报如下错误
		THREE.Projector has been moved to /examples/js/renderers/Projector.js. three.js:42883:3
		TypeError: THREE.RenderableVertex is not a constructor 
		-->
		<script src="js/renderers/Projector.js"></script>
		<script src="js/renderers/CanvasRenderer.js"></script>

		<script>
			var camera, scene, renderer;

			//这里根本不需要canvas
			//var texture_placeholder,
			//标记是否存在用户交互
			isUserInteracting = false,
			//鼠标按下时的x,y坐标
			onMouseDownMouseX = 0, onMouseDownMouseY = 0,
			//longtitude 经度
			lon = 90, onMouseDownLon = 0,
			//latitude 维度
			lat = 0, onMouseDownLat = 0,
			phi = 0, theta = 0,
			//相机注视方向
			target = new THREE.Vector3();

			init();
			animate();

			function init() {
				var container, mesh;
				container = document.getElementById( 'container' );

				/*
				透视相机
				PerspectiveCamera(fov, aspect, near, far)
					fov(视场):从相机位置能够看到的部分场景。推荐默认值45
					aspect(长宽比):渲染结果输出区域的横向长度和纵向长度的比值。推荐默认值window.innerWidth/window.innerHeight
					near(近面):定义从距离相机多近的地方开始渲染场景。推荐默认值0.1
					far(远面):定义相机可以从它所处的位置看多远。默认值1000
				*/
				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
				
				scene = new THREE.Scene();

				/*
				texture_placeholder = document.createElement( 'canvas' );
				texture_placeholder.width = 128;
				texture_placeholder.height = 128;
				var context = texture_placeholder.getContext( '2d' );
				context.fillStyle = 'rgb( 200, 200, 200 )';
				context.fillRect( 0, 0, texture_placeholder.width, texture_placeholder.height );
				*/

				/*
				也可以从地图集中一次性批量提取图片,顺序分别是右左上下后前
				var textures = getTexturesFromAtlasFile( "textures/cube/sun_temple_stripe.jpg", 6 );
				
				如果下面的MultiMaterial中某个material缺失的话,会显示黑色
				*/
				var materials = [
/*
					loadTexture( 'textures/cube/skybox/px.jpg' ), // right
					loadTexture( 'textures/cube/skybox/nx.jpg' ), // left
					loadTexture( 'textures/cube/skybox/py.jpg' ), // top
					loadTexture( 'textures/cube/skybox/ny.jpg' ), // bottom
					loadTexture( 'textures/cube/skybox/pz.jpg' ), // back
					loadTexture( 'textures/cube/skybox/nz.jpg' )  // front
*/
					loadTexture( 'textures/cube/test/px.jpg' ), // right
					loadTexture( 'textures/cube/test/nx.jpg' ), // left
					loadTexture( 'textures/cube/test/py.jpg' ), // top
					loadTexture( 'textures/cube/test/ny.jpg' ), // bottom
					loadTexture( 'textures/cube/test/pz.jpg' ), // back
					loadTexture( 'textures/cube/test/nz.jpg' )  // front

				];

				//这里将立方体的每条边分成了7份,换成1份也是可以的,没影响
				mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MultiMaterial( materials ) );
				//由于默认情况只渲染物体外部,将某一坐标置反,可以达到渲染内部的效果
				//mesh.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, -1 ) );
				mesh.scale.x = - 1;
				
				//如果不设置的话,网格位置默认为Vector3{x:0,y:0,z:0}
				scene.add( mesh );

				renderer = new THREE.CanvasRenderer();
				//window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例
				renderer.setPixelRatio( window.devicePixelRatio );
				//设置渲染场景的大小
				renderer.setSize( window.innerWidth, window.innerHeight );
				//将渲染器的DOM元素(即Canvas)添加到HTML中
				container.appendChild( renderer.domElement );
				/*
				cullFace 剔除模式
					CullFaceNone = 0;
					CullFaceBack = 1;
					CullFaceFront = 2;
					CullFaceFrontBack = 3;
				
				frontFaceDirection 剔除方向
					FrontFaceDirectionCCCW 表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面。
					FrontFaceDirectionCW 表示顶点顺序为顺时针方向的表面为正面。
				*/
				renderer.setFaceCulling(THREE.CullFaceBack, THREE.FrontFaceDirectionCW);

				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
				document.addEventListener( 'wheel', onDocumentMouseWheel, false );

				//注意:触摸事件比鼠标事件少了一个touchend,因为暂不存在不放开手指的情况
				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
				document.addEventListener( 'touchmove', onDocumentTouchMove, false );

				window.addEventListener( 'resize', onWindowResize, false );

			}

			function onWindowResize() {
				//更新透视相机的宽高比。如果宽高比不对,那么正方形可能就不是正方形了
				camera.aspect = window.innerWidth / window.innerHeight;
				//更新相机的投影矩阵
				camera.updateProjectionMatrix();
				//重新设置渲染场景的大小
				renderer.setSize( window.innerWidth, window.innerHeight );
			}

			function loadTexture( path ) {
				//由于不是从canvas中获取图片,用canvas来初始化就显得很没道理
				//var texture = new THREE.Texture( texture_placeholder );
				var texture = new THREE.Texture();
				/*
				MeshBasicMaterial:与光照无关,仅根据材质的颜色或贴图来渲染物体
					color:材质的颜色
					map:材质的贴图
					wireframe: 显示三角形线框还是显示面
					side:可选的值有THREE.FrontSide(仅渲染正面)、THREE.BackSide(仅渲染背面)、THREE.DoubleSide(双面渲染)
					overdraw:过渡描绘。如果用THREE.CanvasRenderer对象,有缝隙时需设置该值。例如当前如果使用0.5以下的值,三角形的分界线就很明显。但是使用WebGLRenderer则不会有分割线
				*/	
				var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
				var image = new Image();
				image.onload = function () {
					texture.image = this;
					//由于图片是异步加载的,一旦检测到needsUpdate=true,three.js就会使用_gl.texImage2D将空的纹理数据传输到显存中,然后就将这个标志位设成false, 之后再使用该图片的时候就不需要重新加载显存数据了
					texture.needsUpdate = true;
				};
				image.src = path;
				return material;
			}

			function onDocumentMouseDown( event ) {
				//通知 Web 浏览器不要执行与事件关联的默认动作
				event.preventDefault();
				isUserInteracting = true;
				
				//clientX和clientY 表示事件触发时,相对于当前窗口的坐标
				onPointerDownPointerX = event.clientX;
				onPointerDownPointerY = event.clientY;

				onPointerDownLon = lon;
				onPointerDownLat = lat;
			}

			function onDocumentMouseMove( event ) {
				if ( isUserInteracting === true ) {
					//鼠标拖动的方向与相机注视的方向相反,与TrackballControls插件效果相近
					lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
					lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
				}
			}

			function onDocumentMouseUp( event ) {
				isUserInteracting = false;
			}

			function onDocumentMouseWheel( event ) {
				//delta可以获取鼠标滚轮的方向和速度。如果delta的值是负的,那么滚轮就是向下滚动,正的就是向上。deltaX, deltaY分别是滚轮滚动的坐标值
				camera.fov += event.deltaY * 0.05;
				
				//这里要设置一个视场范围,过大或过小的视场都会导致显示异常
				camera.fov = Math.max(10, camera.fov);
				camera.fov = Math.min(120, camera.fov);
				
				//更新相机的投影矩阵
				camera.updateProjectionMatrix();
			}

			function onDocumentTouchStart( event ) {
				/*
				event.touches存放的是多指触碰时的位置数组
				三个等号是恒等,比较数值的同时也比较类型。
                这里限制只有单指触摸的时候才执行相应的方法
				*/
				if ( event.touches.length === 1 ) {
					event.preventDefault();
					onPointerDownPointerX = event.touches[ 0 ].pageX;
					onPointerDownPointerY = event.touches[ 0 ].pageY;
					onPointerDownLon = lon;
					onPointerDownLat = lat;
				}
			}

			function onDocumentTouchMove( event ) {
				if ( event.touches.length == 1 ) {
					event.preventDefault();

					lon = ( onPointerDownPointerX - event.touches[0].pageX ) * 0.1 + onPointerDownLon;
					lat = ( event.touches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
				}
			}

			function animate() {
				requestAnimationFrame( animate );
				update();
			}

			function update() {
				//没有交互的情况下对改变观察方向
				if ( isUserInteracting === false ) {
					lon += 0.1;
				}
				//设置仰俯角范围[-85,85]
				lat = Math.max( - 85, Math.min( 85, lat ) );
				//THREE.Math.degToRad将角度转换成弧度
				phi = THREE.Math.degToRad( 90 - lat );
				theta = THREE.Math.degToRad( lon );

				//相机注视的点是一个半径为r的球上的一点,这是一个方向向量
				var r = 10;
				target.x = r * Math.sin( phi ) * Math.cos( theta );
				target.y = r * Math.cos( phi );
				target.z = r * Math.sin( phi ) * Math.sin( theta );
				
				//照相机看着球体上的某个点
				camera.lookAt( target );

				renderer.render( scene, camera );
			}
		</script>
	</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值