1. 程式人生 > >three.js 02-04 之網格物件函式及屬性

three.js 02-04 之網格物件函式及屬性

    上一篇中,我們對自定義幾何體的相關知識做了一個簡單介紹,並講解了如何克隆(複製)一個幾何體。本篇我們要介紹的是關於 Mesh 網格物件常用的一些相關函式和屬性。照例,我們先上一個完整的示例,程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <title>示例 02.04 - 網格物件屬性</title>
	<script src="../build/three.js"></script>
	<script src="../build/js/ParametricGeometries.js"></script>
	<script src="../build/js/QuickHull.js"></script>
	<script src="../build/js/geometries/ConvexGeometry.js"></script>
	<script src="../build/js/controls/OrbitControls.js"></script>
	<script src="../build/js/libs/stats.min.js"></script>
	<script src="../build/js/libs/dat.gui.min.js"></script>
	<script src="../jquery/jquery-3.2.1.min.js"></script>
    <style>
        body {
            /* 設定 margin 為 0,並且 overflow 為 hidden,來完成頁面樣式 */
            margin: 0;
            overflow: hidden;
        }
		/* 統計物件樣式 */
		#Stats-output {
			position: absolute;
			left: 0px;
			top: 0px;
		}
    </style>
</head>
<body>

<!-- 用於 WebGL 輸出的 Div -->
<div id="WebGL-output"></div>
<!-- 用於統計 FPS 輸出的 Div -->
<div id="Stats-output"></div>

<!-- 執行 Three.js 示例的 Javascript 程式碼 -->
<script type="text/javascript">

	var scene;
	var camera;
	var render;
	var controls;
	var stats;
	
	var guiParams;
	var gui;
	
	var plane;
	var mesh;

    // 當所有元素載入完畢後,就執行我們 Three.js 相關的東西
    $(function() {
		stats = initStats();
		
		scene = new THREE.Scene();
		camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // 2147483647
		camera.position.set(-20, 25, 20);
		render = new THREE.WebGLRenderer( {antialias: true} ); // antialias 抗鋸齒
		render.setSize(window.innerWidth, window.innerHeight);
		render.setClearColor(0xEEEEEE);
		render.shadowMap.enabled = true; // 允許陰影投射
		$('#WebGL-output')[0].appendChild(render.domElement);
		window.addEventListener('resize', onWindowResize, false);
		var target = new THREE.Vector3(5, 0, 0);
		controls = new THREE.OrbitControls(camera, render.domElement);
		controls.target = target; // 解決 camera.lookAt(x, y, z) 失效問題
		camera.lookAt(target);
		
		scene.add(new THREE.AxisHelper(20));// 加入座標軸
		
		// 加入一個平面
		var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
		var planeMaterial = new THREE.MeshLambertMaterial( {color: 0xFFFFFF} );
		plane = new THREE.Mesh(planeGeometry, planeMaterial);
		plane.rotation.x = -0.5 * Math.PI; // 沿著 X軸旋轉-90°
		plane.position.x = 0;
		plane.position.y = 0;
		plane.position.z = 0;
		plane.receiveShadow = true; // 幾何平面接收陰影
		scene.add(plane);
		
		// 加入一個環境光源
		var ambientLight = new THREE.AmbientLight(0x090909);
		scene.add(ambientLight);
		
		// 加入一個聚光燈光源
		// 注:基礎材質 MeshBasicMaterial 不會對光源產生反應,因此要改用 MeshLambertMaterial 或 MeshPhongMaterial 材質才有效果
		var spotLight = new THREE.SpotLight( 0xFFFFFF);
		spotLight.position.set(-40, 40, 50);
		spotLight.castShadow = true; // 光源產生陰影
		spotLight.shadow.mapSize.width = 1024; // 必須是 2的冪,預設值為 512
		spotLight.shadow.mapSize.height = 1024; // 必須是 2的冪,預設值為 512
		scene.add(spotLight);
		
		// 定義 gui 控制引數
		guiParams = new function() {
			function addControlPoint(x, y, z) {
				var controlPoint = new function() {
					this.x = x;
					this.y = y;
					this.z = z;
				};
				return controlPoint;
			}
			
			this.scale = addControlPoint(1, 1, 1);
			this.position = addControlPoint(0, 4, 0);
			this.rotation = addControlPoint(1, 1, 1);
			this.translation = addControlPoint(0, 0, 0);
			this.visible = true;
		}
		
		// 定義 gui 並繫結引數
		gui = new dat.GUI();
		var folder = gui.addFolder('scale');
		folder.add(guiParams.scale, 'x', 0, 5);
		folder.add(guiParams.scale, 'y', 0, 5);
		folder.add(guiParams.scale, 'z', 0, 5);
		folder = gui.addFolder('position');
		folder.add(guiParams.position, 'x', -10, 10);
		folder.add(guiParams.position, 'y', -4, 20);
		folder.add(guiParams.position, 'z', -10, 10);
		folder = gui.addFolder('rotation');
		folder.add(guiParams.rotation, 'x', -4, 4);
		folder.add(guiParams.rotation, 'y', -4, 4);
		folder.add(guiParams.rotation, 'z', -4, 4);
		folder = gui.addFolder('translate');
		folder.add(guiParams.translation, 'x', -10, 10);
		folder.add(guiParams.translation, 'y', -10, 10);
		folder.add(guiParams.translation, 'z', -10, 10);
		
		gui.add(guiParams, 'visible');
		
		var material = new THREE.MeshLambertMaterial({color: 0x44ff44});
        var geom = new THREE.BoxGeometry(5, 8, 3);
        mesh = new THREE.Mesh(geom, material);
        mesh.position.y = 4;
        mesh.castShadow = true;
        scene.add(mesh);
		
		renderScene();
    });
	
	/** 初始化 stats 統計物件 */
	function initStats() {
		stats = new Stats();
		stats.setMode(0); // 0 為監測 FPS;1 為監測渲染時間
		$('#Stats-output').append(stats.domElement);
		return stats;
	}
	
	/** 渲染場景 */
	function renderScene() {
		stats.update();
		updateMesh(); // 更新物體
		requestAnimationFrame(renderScene);
		render.render(scene, camera);
	}
	
	/** 當瀏覽器視窗大小變化時觸發 */
	function onWindowResize() {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		render.setSize(window.innerWidth, window.innerHeight);
	}
	
	/** 更新物體 */
	function updateMesh() {
		mesh.visible = guiParams.visible;
		mesh.scale.set(guiParams.scale.x, guiParams.scale.y, guiParams.scale.z);
		mesh.position.set(guiParams.position.x, guiParams.position.y, guiParams.position.z);
		mesh.rotation.set(guiParams.rotation.x, guiParams.rotation.y, guiParams.rotation.z);
		mesh.translateX(guiParams.translation.x);
		mesh.translateY(guiParams.translation.y);
		mesh.translateZ(guiParams.translation.z);
	}

</script>
</body>
</html>
在這個示例中,你會看到一些下拉選單,通過這個選單你可以修改如 scale 比例、position 位置、rotation 旋轉、translation 轉移及 visible 可見等屬性,而且立即就可以看到修改結果。現在讓我們來逐一瞭解這些屬性或者相關函式:
  • position - 通過這個屬性我們可以改變物件在場景中的 x, y, z 座標上的位置。需要注意的是,一個物件的位置是相對於其父物件來講的,而父物件通常是你向其新增物件的那個場景。一般有以下幾種方式來改變物件的位置:第一種是 mesh.position.x = 5, mesh.position.y = 6, mesh.position.z = 7;第二種是示例中用到的那種方式;第三種是 mesh.position.setX(1), mesh.position.setY(1), mesh.position.setZ(1);
  • rotation - 通過這個屬性我們可以改變物件繞軸 x, y, z 旋轉的弧度。旋轉一週的弧度是 2 * Math.PI。方向的確定是用右手來測定的,方法是用右手握住要繞轉的軸,拇指方向與軸的箭頭方向保持一致,那麼四指所指的方向就是正方向;
  • scale - 通過這個屬性我們可以改變物件在 x, y, z 軸方向的比例。即沿指定軸縮放物件。當設的值小於 1 時,就是縮小;反之,就是放大;
  • translate - 通過這個屬性我們一樣可以達到類似 position 的效果。但是 translate 函式不是定義物件想要放在哪裡的絕對位置,而是定義相對於當前位置物件移動的量。舉個例子,假定場景中的一個立方體的位置是 (1, 2, 3),接下來我們把物件沿著 x 軸平移 4 個單位,即 translateX(4),那麼它現在的位置就變為了(5, 2, 3)。如果想要恢復它原來的位置,則可以呼叫 translateX(-4) 即可完成。當然直接呼叫 position.setX(1) 亦可達到相同效果;
  • visible - 通過它來設定物件在場景中的可見性。true 為可見;false 為不可見;
未完待續···