WebGL three.js學習筆記 法向量網格材質MeshNormalMaterial的介紹和建立360度全景天空盒的方法

WebGL學習----Three.js學習筆記(5)

點擊查看demo演示

Demo地址:https://nsytsqdtn.github.io/demo/360/360

簡單網格材質 MeshNormalMaterial

MeshNormalMaterial是一種不受渲染時使用的顏色影響的材質,它只與本身每個面從內到外的法向量有關。法向量在webgl中用處十分普遍,光的反射,以及三維圖形的紋理映射都與這個有關。
javascript

MeshNormalMaterial
MeshNormalMaterial

從圖中能夠看到,網格的每一面渲染的顏色都是不同的,若是咱們想要在物體表面添加法向量,咱們可使用的THREE.ArrowHelper去表示每個法向量,它的參數爲

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"00.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度全景背景

360度全景背景可以讓人有身臨其境的感受,全部這裏的背景使用了全景背景web

在這裏插入圖片描述
在這裏插入圖片描述

若是想要使用全景的背景,就須要6張6個方向的圖片來合成一個完整的背景(也可使用1張6方向的圖片),而後把這些貼圖賦值給 scene.background

 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            width100%;
17            height850px;
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            antialiastrue
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(50window.innerWidth / window.innerHeight, 10100);
41        camera.position.set(04060);
42        camera.up.x = 0;//設置攝像機的上方向爲哪一個方向,這裏定義攝像的上方爲Y軸正方向
43        camera.up.y = 1;
44        camera.up.z = 0;
45        camera.lookAt(000);
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(000);
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(03030);
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"00.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(101010);
155        let sphereGeometry = new THREE.SphereGeometry(102020);
156        let planeGeometry = new THREE.PlaneGeometry(101011);
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>
複製代碼
相關文章
相關標籤/搜索