MeshNormalMaterial是一種不受渲染時使用的顏色影響的材質,它只與本身每個面從內到外的法向量有關。法向量在webgl中用處十分普遍,光的反射,以及三維圖形的紋理映射都與這個有關。
javascript
THREE.ArrowHelper(dir, origin, length, color, headLength, headWidth)php
其中參數的意義爲: dir:方向,默認是法向量 origin:開始的座標位置 length:輔助線的長度 color:輔助線的顏色 headLength:頭部的長度 headWidth:頭部的寬度css
對於一個球體,要描述它每個面的法向量,首先須要對它的每個面進行遍歷,取出這個面上的三個頂點(由於webgl的面都是三角形,因此是三個頂點),經過divideScalar(3)這個函數計算它的中心位置,咱們就能夠在這個中心位置點上,從內向外引出一個ArrowHelper,來模擬法向量。html
1 for(let i=0;i<sphereGeometry.faces.length;i++){//在每個面上面循環
2 let face = sphereGeometry.faces[i];//獲得每一個面的對象
3 let centroid = new THREE.Vector3();
4 //先建立一個vector3對象,要使用這個對象找到每一個面的中心
5 centroid.add(sphereGeometry.vertices[face.a]);
6 // 將這該面的三個頂點的索引傳給sphereGeometry.vertices找到其頂點的座標
7 //再添加進centroid
8 centroid.add(sphereGeometry.vertices[face.b]);
9 centroid.add(sphereGeometry.vertices[face.c]);
10 centroid.divideScalar(3);//三角形的中心點座標
11 let arrow = new THREE.ArrowHelper(
12 face.normal,//face這個面的法向量
13 centroid,
14 2,
15 0xffcc55,
16 0.5,
17 0.5);//箭頭輔助線,至關於把法向量用箭頭表示出來
18 sphere.add(arrow);
19 }
複製代碼
其中,centroid.add(sphereGeometry.vertices[face.a])這段代碼中的sphereGeometry.vertices存有幾何體的全部頂點信息,經過[ ]索引能夠取得其中的某一個頂點。face.a還有下面的face.b和c都是該面的頂點索引號,表示這個面是由頂點編號爲face.a,face.b,face.c的三個頂點所構成的一個三角形(webgl的面都是三角形),而後咱們再計算這三個頂點的中心點。java
在菜單面板中設置一些MeshNormalmaterial的一些屬性,便於去測試這種材質的一些特質
其中:
this.visible = meshMaterial.visible;//是否可見 this.wireframe = meshMaterial.wireframe;//是否以線框的方式渲染物體 this.wireframeWidth = meshMaterial.wireframeLinewidth;//線框的寬度 this.transparent = meshMaterial.transparent;//是否透明 this.opacity = meshMaterial.opacity;//透明度,須要transparent爲true纔有效果 this.side = "front";//邊的渲染方式,有三種,前面,後面,還有雙面 this.selectMesh = "sphere";//當前選擇的幾何體 this.shading = "smooth";//着色方式,有平面着色和平滑着色,對一個面很平的幾何體幾乎看不出區別,如正方體git
1function initDatGUI() {
2 //設置菜單中須要的參數
3 controls = new function () {
4 this.rotationSpeed = 0.02;
5 this.visible = meshMaterial.visible;//是否可見
6 this.wireframe = meshMaterial.wireframe;//是否以線框的方式渲染物體
7 this.wireframeWidth = meshMaterial.wireframeLinewidth;//線框的寬度
8 this.transparent = meshMaterial.transparent;//是否透明
9 this.opacity = meshMaterial.opacity;//透明度,須要transparent爲true纔有效果
10 this.side = "front";//邊的渲染方式,有三種,前面,後面,還有雙面
11 this.selectMesh = "sphere";//當前選擇的幾何體
12 this.shading = "smooth";//着色方式,有平面着色和平滑着色,對一個面很平的幾何體幾乎看不出區別,如正方體
13 };
14 let gui = new dat.GUI();
15 //將剛剛設置的參數添加到菜單中
16 let F1 = gui.addFolder("Mesh");
17 F1.add(controls, "rotationSpeed", 0, 0.1);
18 F1.add(controls, "visible").onChange(function (e) {
19 meshMaterial.visible = e;
20 });
21 F1.add(controls, "wireframe").onChange(function (e) {
22 meshMaterial.wireframe = e;
23 });
24 F1.add(controls, "wireframeWidth",0,10).onChange(function (e) {
25 meshMaterial.wireframeWidth = e;
26 });
27 F1.add(controls, "transparent").onChange(function (e) {
28 meshMaterial.transparent = e;
29 });
30 F1.add(controls, "opacity",0,1).onChange(function (e) {
31 meshMaterial.opacity = e;
32 });
33 F1.add(controls, "side",["front","back","double"]).onChange(function (e) {
34 switch (e) {
35 case "front":
36 meshMaterial.side = THREE.FrontSide;
37 break;
38 case "back":
39 meshMaterial.side = THREE.BackSide;
40 break;
41 case "double":
42 meshMaterial.side = THREE.DoubleSide;
43 break;
44 }
45 meshMaterial.needsUpdate = true;//要在程序中讓材質更新須要添加這一句話
46 });
47 F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) {
48 //先把場景的物體清除,再來添加
49 scene.remove(cube);
50 scene.remove(sphere);
51 scene.remove(plane);
52 switch (e) {
53 case "sphere":
54 scene.add(sphere);
55 break;
56 case "cube":
57 scene.add(cube);
58 break;
59 case "plane":
60 scene.add(plane);
61 break;
62 }
63 });
64 F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) {
65 switch (e) {
66 case "flat":
67 meshMaterial.shading = THREE.FlatShading;
68 break;
69 case "smooth":
70 meshMaterial.shading = THREE.SmoothShading;
71 break;
72 }
73 meshMaterial.needsUpdate = true;//要在程序中讓材質更新須要添加這一句話
74 });
75 }
複製代碼
注意在程序運行過程當中想要改變材質的屬性,須要在改完之後,添加一句 meshMaterial.needsUpdate = true,這樣才能更新成功。github
360度全景背景可以讓人有身臨其境的感受,全部這裏的背景使用了全景背景web
1 let urls =[
2 'image/posx.jpg',
3 'image/negx.jpg',
4 'image/posy.jpg',
5 'image/negy.jpg',
6 'image/posz.jpg',
7 'image/negz.jpg'
8 ];//引入6個方向的貼圖
9 let cubeMap = THREE.ImageUtils.loadTextureCube( urls );
10 scene = new THREE.Scene();
11 scene.background = cubeMap;
複製代碼
這些圖片的須要按照順序擺放,右左上下後前,不然背景會錯亂。
這裏給一個全景圖片的網站,裏面有不少的360度風景圖,都是6張類型的,下載下來解壓後就能夠直接引入
http://www.humus.name/index.php?page=Texturesapp
本例子的完整代碼以下:dom
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Depth Material Test</title>
6 <script src="../../import/three.js"></script>
7 <script src="../../import/stats.js"></script>
8 <script src="../../import/Setting.js"></script>
9 <script src="../../import/OrbitControls.js"></script>
10 <script src="../../import/dat.gui.min.js"></script>
11 <script src="../../import/SceneUtils.js"></script>
12 <style type="text/css">
13 div#WebGL-output {
14 border: none;
15 cursor: pointer;
16 width: 100%;
17 height: 850px;
18 background-color: #333333;
19 }
20 </style>
21</head>
22<body onload="Start()">
23<div id="WebGL-output"></div>
24<script>
25 let camera, renderer, scene, light;
26 let controller;
27 let controls;
28 let cube, sphere, plane, meshMaterial;
29
30 function initThree() {
31 //渲染器初始化
32 renderer = new THREE.WebGLRenderer({
33 antialias: true
34 });
35 renderer.setSize(window.innerWidth, window.innerHeight);
36 renderer.setClearColor(0x333333);
37 document.getElementById("WebGL-output").appendChild(renderer.domElement);//將渲染添加到div中
38
39 //初始化攝像機,這裏使用透視投影攝像機
40 camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 10, 100);
41 camera.position.set(0, 40, 60);
42 camera.up.x = 0;//設置攝像機的上方向爲哪一個方向,這裏定義攝像的上方爲Y軸正方向
43 camera.up.y = 1;
44 camera.up.z = 0;
45 camera.lookAt(0, 0, 0);
46
47 //初始化場景
48 let urls =[
49 'image/posx.jpg',
50 'image/negx.jpg',
51 'image/posy.jpg',
52 'image/negy.jpg',
53 'image/posz.jpg',
54 'image/negz.jpg'
55 ];//引入6個方向的貼圖
56 let cubeMap = THREE.ImageUtils.loadTextureCube( urls );
57 scene = new THREE.Scene();
58 scene.background = cubeMap;
59
60 //相機的移動
61 controller = new THREE.OrbitControls(camera, renderer.domElement);
62 controller.target = new THREE.Vector3(0, 0, 0);
63
64
65 light = new THREE.AmbientLight(0x0c0c0c);
66 scene.add(light);
67
68 // add spotlight for the shadows
69 light = new THREE.SpotLight(0xffffff);
70 light.position.set(0, 30, 30);
71 scene.add(light);
72
73 }
74
75 //初始化菜單面板
76 function initDatGUI() {
77 //設置菜單中須要的參數
78 controls = new function () {
79 this.rotationSpeed = 0.02;
80 this.visible = meshMaterial.visible;//是否可見
81 this.wireframe = meshMaterial.wireframe;//是否以線框的方式渲染物體
82 this.wireframeWidth = meshMaterial.wireframeLinewidth;//線框的寬度
83 this.transparent = meshMaterial.transparent;//是否透明
84 this.opacity = meshMaterial.opacity;//透明度,須要transparent爲true纔有效果
85 this.side = "front";//邊的渲染方式,有三種,前面,後面,還有雙面
86 this.selectMesh = "sphere";//當前選擇的幾何體
87 this.shading = "smooth";//着色方式,有平面着色和平滑着色,對一個面很平的幾何體幾乎看不出區別,如正方體
88 };
89 let gui = new dat.GUI();
90 //將剛剛設置的參數添加到菜單中
91 let F1 = gui.addFolder("Mesh");
92 F1.add(controls, "rotationSpeed", 0, 0.1);
93 F1.add(controls, "visible").onChange(function (e) {
94 meshMaterial.visible = e;
95 });
96 F1.add(controls, "wireframe").onChange(function (e) {
97 meshMaterial.wireframe = e;
98 });
99 F1.add(controls, "wireframeWidth",0,10).onChange(function (e) {
100 meshMaterial.wireframeWidth = e;
101 });
102 F1.add(controls, "transparent").onChange(function (e) {
103 meshMaterial.transparent = e;
104 });
105 F1.add(controls, "opacity",0,1).onChange(function (e) {
106 meshMaterial.opacity = e;
107 });
108 F1.add(controls, "side",["front","back","double"]).onChange(function (e) {
109 switch (e) {
110 case "front":
111 meshMaterial.side = THREE.FrontSide;
112 break;
113 case "back":
114 meshMaterial.side = THREE.BackSide;
115 break;
116 case "double":
117 meshMaterial.side = THREE.DoubleSide;
118 break;
119 }
120 meshMaterial.needsUpdate = true;//要在程序中讓材質更新須要添加這一句話
121 });
122 F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) {
123 //先把場景的物體清除,再來添加
124 scene.remove(cube);
125 scene.remove(sphere);
126 scene.remove(plane);
127 switch (e) {
128 case "sphere":
129 scene.add(sphere);
130 break;
131 case "cube":
132 scene.add(cube);
133 break;
134 case "plane":
135 scene.add(plane);
136 break;
137 }
138 });
139 F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) {
140 switch (e) {
141 case "flat":
142 meshMaterial.shading = THREE.FlatShading;
143 break;
144 case "smooth":
145 meshMaterial.shading = THREE.SmoothShading;
146 break;
147 }
148 meshMaterial.needsUpdate = true;//要在程序中讓材質更新須要添加這一句話
149 });
150 }
151
152 function initObject() {
153 //建立正方體,球和地面的幾何體
154 let cubeGeometry = new THREE.BoxGeometry(10, 10, 10);
155 let sphereGeometry = new THREE.SphereGeometry(10, 20, 20);
156 let planeGeometry = new THREE.PlaneGeometry(10, 10, 1, 1);
157 //建立一個法向量材質
158 meshMaterial = new THREE.MeshNormalMaterial();
159
160 cube = new THREE.Mesh(cubeGeometry, meshMaterial);
161 sphere = new THREE.Mesh(sphereGeometry, meshMaterial);
162 plane = new THREE.Mesh(planeGeometry, meshMaterial);
163 //把三者的位置統一
164 cube.position.set(0,0,0);
165 sphere.position = cube.position;
166 plane.position = cube.position;
167
168 //在球的每個面上顯示一個法向量,方便觀測這種法向量材質的渲染方式
169 for(let i=0;i<sphereGeometry.faces.length;i++){//在每個面上面循環
170 let face = sphereGeometry.faces[i];//獲得每一個面的對象
171 let centroid = new THREE.Vector3();//先建立一個vector3對象,要使用這個對象找到每一個面的中心,
172 centroid.add(sphereGeometry.vertices[face.a]);
173 // 將這該面的三個頂點的索引傳給sphereGeom.vertices找到其頂點的座標,再添加進centroid
174 centroid.add(sphereGeometry.vertices[face.b]);
175 centroid.add(sphereGeometry.vertices[face.c]);
176 centroid.divideScalar(3);//三角形的中心點座標
177 let arrow = new THREE.ArrowHelper(
178 face.normal,
179 centroid,
180 2,
181 0xffcc55,
182 0.5,
183 0.5);//箭頭輔助線,至關於把法向量用箭頭表示出來
184 sphere.add(arrow);
185 }
186 scene.add(sphere);
187 }
188
189 function rotation() {
190 scene.traverse(function (e) {
191 if (e instanceof THREE.Mesh) {
192 e.rotation.y += controls.rotationSpeed;
193 }
194 })
195 }
196
197 //渲染函數
198 function render() {
199 rotation();
200 stats.update();
201 renderer.clear();
202 requestAnimationFrame(render);
203 renderer.render(scene, camera);
204 }
205
206 //功能函數
207 function setting() {
208 loadFullScreen();
209 loadAutoScreen(camera, renderer);
210 loadStats();
211 }
212
213 //運行主函數,敲代碼的時候總是敲錯,因此改了一個名字,叫Start更方便
214 function Start() {
215 initThree();
216 initObject();
217 initDatGUI();
218 setting();
219 render();
220 }
221</script>
222</body>
223</html>
複製代碼