4.法向材質
法向材質可以將材質的顏色設置為其法向量的方向,有時候對於調試很有幫助。
法向材質的設定很簡單,甚至不用設置任何參數:
new THREE.MeshNormalMaterial()
材質的顏色與照相機與該物體的角度相關,下面我們只改變照相機位置,觀察兩個角度的顏色變化:
camera.position.set(5, 25, 25);的效果:
camera.position.set(25, 25, 25);的效果:
我們觀察的是同樣的三個面,但是由於觀察的角度不同,物體的顏色就不同了。因此,在調試時,要知道物體的法向量,使用法向材質就很有效。
源碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>3.js測試8.1</title> </head> <body onload="init()"> <canvas id="mainCanvas" width="400px" height="300px" ></canvas> </body> <script type="text/javascript" src="js/three.min.js"></script> <script type="text/javascript"> function init() { var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('mainCanvas') }); renderer.setClearColor(0x000000); var scene = new THREE.Scene(); // camera var camera = new THREE.OrthographicCamera(-5, 5, 3.75, -3.75, 0.1, 100); camera.position.set(25, 25, 25); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); // light var light = new THREE.PointLight(0xffffff, 1, 100); light.position.set(10, 15, 5); scene.add(light); var material = new THREE.MeshNormalMaterial(); var cube = new THREE.Mesh(new THREE.CubeGeometry(5, 5, 5), material); scene.add(cube); renderer.render(scene, camera); } </script> </html>
5.材質的紋理貼圖
在此之前,我們使用的材質都是單一顏色的,有時候,我們卻希望使用圖像作為材質。這時候,就需要導入圖像作為紋理貼圖,並添加到相應的材質中。下面,我們介紹具體的做法。
5.1 單張圖像應用於長方體
首先,我們選擇一張長寬均為128像素的圖像:
將其導入紋理中:
var texture = THREE.ImageUtils.loadTexture('img/0.png');
然后,將材質的map屬性設置為texture:
var material = new THREE.MeshLambertMaterial({ map: texture });
這樣就完成了將圖片應用於材質的基本步驟。但是由於現在我們還沒使用動畫,畫面只被渲染了一次,而在導入紋理之前,已經完成了這次渲染,因此看到的只是一片黑。所以,如果沒有重繪函數(將在下一篇介紹),就需要在完成導入紋理的步驟后,重新繪制畫面,這是在回調函數中實現的:
var texture = THREE.ImageUtils.loadTexture('img/0.png', {}, function() { renderer.render(scene, camera); }); var material = new THREE.MeshLambertMaterial({ map: texture });
現在,就能看到這樣的效果了:
類似地,如果將其應用於球體,將會把整個球體應用該圖像:
源碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>3.js測試8.2</title> </head> <body onload="init()"> <canvas id="mainCanvas" width="400px" height="300px" ></canvas> </body> <script type="text/javascript" src="js/three.min.js"></script> <script type="text/javascript"> function init() { var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('mainCanvas') }); renderer.setClearColor(0x000000); var scene = new THREE.Scene(); // camera var camera = new THREE.OrthographicCamera(-10, 10, 7.5, -7.5, 0.1, 100); camera.position.set(25, 25, 25); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); // light var light = new THREE.PointLight(0xffffff, 1, 1000); light.position.set(10, 15, 20); scene.add(light); var texture = THREE.ImageUtils.loadTexture('img/0.png', {}, function() { renderer.render(scene, camera); }); var material = new THREE.MeshLambertMaterial({ map: texture }); // var cube = new THREE.Mesh(new THREE.CubeGeometry(5, 5, 5), material); // scene.add(cube); var sphere = new THREE.Mesh(new THREE.SphereGeometry(5, 25, 15), material); scene.add(sphere); renderer.render(scene, camera); } </script> </html>
5.2 六張圖像應用於長方體
有時候,我們希望長方體的六面各種的貼圖都不同。因此,我們首先准備了六張顏色各異的圖像,分別寫了數字0到5。然后,分別導入圖像到六個紋理,並設置到六個材質中:
var materials = []; for (var i = 0; i < 6; ++i) { materials.push(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture('img/' + i + '.png', {}, function() { renderer.render(scene, camera); }), overdraw: true })); } var cube = new THREE.Mesh(new THREE.CubeGeometry(5, 5, 5), new THREE.MeshFaceMaterial(materials)); scene.add(cube);
效果為:
源碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>3.js測試8.3</title> </head> <body onload="init()"> <canvas id="mainCanvas" width="400px" height="300px" ></canvas> </body> <script type="text/javascript" src="js/three.min.js"></script> <script type="text/javascript"> function init() { var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('mainCanvas') }); renderer.setClearColor(0x000000); var scene = new THREE.Scene(); // camera var camera = new THREE.OrthographicCamera(-10, 10, 7.5, -7.5, 0.1, 100); camera.position.set(25, 25, 25); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); // light var light = new THREE.PointLight(0xffffff, 1, 1000); light.position.set(10, 15, 20); scene.add(light); var materials = []; for (var i = 0; i < 6; ++i) { materials.push(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture('img/' + i + '.png', {}, function() { renderer.render(scene, camera); }), overdraw: true })); } var cube = new THREE.Mesh(new THREE.CubeGeometry(5, 5, 5), new THREE.MeshFaceMaterial(materials)); scene.add(cube); renderer.render(scene, camera); } </script> </html>
5.3 棋盤格
現在,我們有一個黑白相間的圖像:
我們希望用它填滿一個屏幕。按照之前的做法依法炮制:
var texture = THREE.ImageUtils.loadTexture('img/chess.png', {}, function() { renderer.render(scene, camera); });
效果是:
可是,棋盤格是8橫8縱64個小方格組成的,那應該怎么辦呢?
首先,我們需要指定重復方式為兩個方向(wrapS和wrapT)都重復:
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
然后,設置兩個方向上都重復4次,由於我們的圖像本來是有2行2列,所以重復4次即為8行8列:
texture.repeat.set(4, 4);
最終就得到了棋盤格:
源碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>3.js測試8.4</title> </head> <body onload="init()"> <canvas id="mainCanvas" width="400px" height="300px" ></canvas> </body> <script type="text/javascript" src="js/three.min.js"></script> <script type="text/javascript"> function init() { var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('mainCanvas') }); //renderer.setClearColor(0x666666); var scene = new THREE.Scene(); // camera var camera = new THREE.OrthographicCamera(-10, 10, 7.5, -7.5, 0.1, 100); camera.position.set(0, 0, 25); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); // light var light = new THREE.PointLight(0xffffff, 1, 1000); light.position.set(10, 15, 20); scene.add(light); var texture = THREE.ImageUtils.loadTexture('img/chess.png', {}, function() { renderer.render(scene, camera); }); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(4, 4); var material = new THREE.MeshLambertMaterial({ map: texture }); var plane = new THREE.Mesh(new THREE.PlaneGeometry(12, 12), material); scene.add(plane); renderer.render(scene, camera); } </script> </html>
整理自張雯莉《Three.js入門指南》