首頁  >  文章  >  web前端  >  使用three.js做出的3D效果圖?

使用three.js做出的3D效果圖?

零下一度
零下一度原創
2018-05-26 14:45:463771瀏覽

       以three.js方便的讓我們在網頁上做出各種不同的3D效果。如果希望2D繪圖內容,建議使用canvas來進行。但許多小夥伴不清楚到底如何為我們繪製和導入的圖形添加陰影效果,更是不清楚到底如何導入我們已經製作好的3dmax資源。所以這篇教學將簡要介紹如何將我們用3dmax製作好的資源導入進來,以及如何為我們導入的資源,包括所有自己繪製的圖形添加陰影。也有很多小夥伴表示根本記不住這些八股文一般的代碼。其實,每次需要寫程式碼的時候參考官方案例即可,不必背誦程式碼。如果編的多,那自然就記住了。如果編的少,我們也沒有必要付出大把時間背誦這些我們很少使用的程式碼。

       首先,先介紹如何導入3dmax的資源。這裡注意,經過我自己的測試,如果直接從本地打開文件的方式打開編寫的網頁,谷歌、IE等瀏覽器將無法顯示我們自己加載的資源,原因是由於本地打開文件後是file協議,所以瀏覽器會因為安全性問題而阻止我們載入本機資源。而火狐瀏覽器卻可以正常打開。所以建議大家在調試時使用火狐瀏覽器,或是使用tomcat、apache等先建立一個本地伺服器,透過網域來存取自己寫的網頁。不建議修改瀏覽器的安全性設定。

       我們先用3dmax製作圖形,這裡選擇自備的茶壺。用3dmax製作茶壺的教學網路上實在太多,所以這裡不再贅述,請不會的小夥伴搜尋教學即可,幾步即可搞定。        當然,並在製作好了之後不要忘記匯出。我們需要將其匯出成為一個mtl檔案和一個obj檔案。這一步操作大多製作茶壺的教學也都有,同樣是點點滑鼠就行。至於材質等,我們這裡不多考慮,畢竟學習要從簡單開始。

       以上圖的兩個檔案匯出之後,我們就可以參考官方的程式碼匯入我們自己的素材了。

       首先,我們除了three.js檔案之外,還需要引入個三個檔案。一個是OBJLoader.js,一個是MTLLoader.js,一個是DDSLoader.js。這些是官方提供的加載我們本地資源的庫文件,可以從官網下載。    這個網址既是官方案例。我們需要的文件也可以在這裡下載到。

       以下程式碼便是將素材導入的程式碼,除了像官方一樣導入檔案之外,還加入了陰影效果。


 1 var onError = function ( xhr ) { }; 
 2                 THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() ); 
 3                 var mtlLoader = new THREE.MTLLoader(); 
 4                 mtlLoader.setPath( './' );       //设置我们需要加载的mtl文件路径 
 5                 mtlLoader.load( 'lyn.mtl', function( material ) {      //这里加载我们需要的文件名   
 6                     material.preload(); 
 7                     var objLoader = new THREE.OBJLoader(); 
 8                     objLoader.setMaterials( material );      //材质,也可自定义 
 9                     objLoader.setPath( './' );               //设置要加载的obj文件的路径
 10                     objLoader.load( 'lyn.obj', function ( object ) {           //加载obj文件
 11                         object.position.z = 1;         //这里设置我们的素材相对于原来的大小以及旋转缩放等
 12                         object.position.y = -0.5;
 13                         object.scale.x = 0.2;
 14                         object.scale.y = 0.2;
 15                         object.scale.z = 0.2;
 16                         object1 = object;               //这里是对素材设置阴影的操作
 17                         for(var k in object.children){  //由于我们的素材并不是看上去的一个整体,所以需要进行迭代
 18                                                         //对其中的所有孩子都设置接收阴影以及投射阴影
 19                                                         //才能看到阴影效果
 20                             object.children[k].castShadow = true;   //设置该对象可以产生阴影
 21                             object.children[k].receiveShadow = true;  //设置该对象可以接收阴影
 22                         }
 23                         scene.add( object1 );
 24                         
 25                     }, onProgress, onError );
 26                 });

       上述的程式碼除了設定陰影以及調整大小之外,都是八股文,需要的時候複製貼上即可,如果經常從事這方面開發,才建議檢查原始碼的實作。有時我們會發現,即使導入後,我們也無法看到素材。我們需要考慮以下幾方面問題。第一方面,我們是否將我們的3dmax素材做的太大或太小。太大的話,我們只能看到素材的一部分,造成一種看不見的假象。太小,又會看不清楚或無法顯示。這種問題就需要各位根據我們攝影機的視距等來調整了。還有一種問題,就是由於我們沒有為我們的素材設定材質,而且我們的程式碼中沒有添加光源,導致只顯示黑漆漆的一片。所以,如果要看到這個素材,我們還需要加入光線。

      以下是新增聚光燈光源的程式碼,因為聚光燈光源可以聚焦,我們示範會方便一點。小朋友也可以自己動手嘗試其他光源。記住,我們需要的是點光源或平行光等光源。環境光是無法產生陰影的。但如果希望周圍顯示的更加清楚,我們也可以同時添加點光源和環境光,只是環境光的光強需要弱一些,避免環境光過強影響陰影的正常顯示。

function SpotLight(){
                light = new THREE.SpotLight( '#ffffff' ,1);
                light.castShadow = true;
                light.distance = 50; 
                light.angle = 0.6; 
                light.decay = 2;
                light.penumbra = 0.2;          
                light.position.set( 3, 2, 1 );
                light.shadow.camera.near = 1;
                light.shadow.camera.far = 3;
                light.shadow.camera.visible = true;            
                light.shadow.mapSize.width = 1024;
                light.shadow.mapSize.height = 1024;                                    
                light.target = sp;
                scene.add(light);
            }

     我們還需要一個地板,將陰影投射到我們的地板上,這樣才能看到陰影。而之前我們曾講到過receiveShadow這個屬性。假設我們創建了一個添加了材質的圖形sp。我們需要使用sp.receiveShadow=true來讓其可以接收陰影。如果設定為false,會出現什麼情況呢?

並沒有產生陰影。那如果我們設定為true,會是什麼樣子呢?

       可以看到,已经生成了阴影。所以,如果我们要让一个物体可以产生阴影,需要设置castShadow这个属性为true,而生成了阴影,总需要投射到某个物体上,才能被观察到。所以,接收投影需要将receiveShadow这个属性设置为true。

       完整的效果如下

       以下是完整代码。其中库文件以及3dmax的素材文件这里不提供,需要自己生成或者自己下载。也可以只学习阴影的生成方法。代码编写略仓促,不过除了各种事件的控制等,其他方面应该还是比较清晰的。欢迎批评之争。

1 <!DOCTYPE html>  
2 <html>  
3     <head>  
4         <style>  
5             html,  
6             body {  
7                 width: 100%;  
8                 height: 100%;  
9             } 
10              
11             body { 
12                 margin: 0; 
13             } 
14              
15             canvas { 
16                 width: 100%; 
17                 height: 100% 
18             } 
19         </style> 
20     </head> 
21     <body> 
22  
23         <script src="js/three.min.js?1.1.11"></script>        
24         <script src="js/jquery-1.12.4.js?1.1.11"></script> 
25         <script src="js/OBJLoader.js?1.1.11"></script> 
26         <script src="js/MTLLoader.js?1.1.11"></script> 
27         <script src="js/DDSLoader.js?1.1.11"></script>       
28         <script> 
29             var scene = new THREE.Scene(); 
30             var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000); 
31             camera.position.z = 6; 
32             camera.position.y = 1; 
33             camera.position.x = 2; 
34             camera.lookAt(new THREE.Vector3(0, 0, 0)); 
35  
36             var other = new THREE.Object3D(); 
37             other.add(camera);           
38             scene.add(other); 
39  
40             var renderer = new THREE.WebGLRenderer(); 
41             renderer.setSize(window.innerWidth, window.innerHeight); 
42             document.body.appendChild(renderer.domElement); 
43  
44             var geometry = new THREE.BoxGeometry(1,1,1); 
45             var material = new THREE.MeshPhongMaterial({ 
46                 color : &#39;#2194ce&#39;, 
47                 specular : &#39;#111111&#39;, 
48                 specular : 
10                                               
49             }); 
50             var sp = new THREE.Mesh(geometry,material); 
51             sp.position.z = -0.5; 
52  
53             var geometry = new THREE.ConeGeometry( 0.5, 1, 6 ); 
54             var material2 = new THREE.MeshPhongMaterial({ 
55                 color : &#39;#2194ce&#39;, 
56                 specular : &#39;#ffffff&#39;, 
57                 shininess : 100               
58             }); 
59             var sp2 = new THREE.Mesh(geometry,material2); 
60             sp2.position.x = -2.5; 
61             sp2.position.z = -1;   
62  
63             var ball = new THREE.SphereGeometry( 0.5, 32, 32 ); 
64             var material3 = new THREE.MeshPhongMaterial({ 
65                 color : &#39;#2194ce&#39;, 
66                 specular : &#39;#111111&#39;, 
67                 shininess : 100               
68             });      
69             var myBall = new THREE.Mesh(ball,material3); 
70             myBall.position.z = 1; 
71             myBall.position.x = -1; 
72             myBall.position.y = -1; 
73             myBall.castShadow = true; 
74             myBall.receiveShadow = true;   
75  
76             var light2 = new THREE.SpotLight( &#39;#ffffff&#39; ,1); 
77             light2.castShadow = true; 
78             light2.distance = 50; 
79             light2.angle = 0.3; 
80             light2.decay = 2; 
81             light2.penumbra = 0.2;          
82             light2.position.set( -2, 5, -2 ); 
83             light2.shadow.camera.near = 1; 
84             light2.shadow.camera.far = 3; 
85             light2.shadow.camera.visible = true;            
86             light2.shadow.mapSize.width = 1024; 
87             light2.shadow.mapSize.height = 1024;                                    
88             light2.target = sp; 
89             scene.add(light2); 
90             lightHelper2 = new THREE.SpotLightHelper(light2); 
91             scene.add(lightHelper2); 
92  
93             renderer.shadowMap.enabled = true; 
94              
95             var matFloor = new THREE.MeshPhongMaterial( { color:0x808080 } );            
96             var geoFloor = new THREE.BoxGeometry( 200, 0.1, 200 ); 
97             var mshFloor = new THREE.Mesh( geoFloor, matFloor ); 
98             var ambient = new THREE.AmbientLight( 0x111111); 
99             var lightHelper;        
100 
101             var light;
102             SpotLight();
103             lightHelper = new THREE.SpotLightHelper( light );
104 
105             sp.castShadow = true;
106             sp.receiveShadow = true;
107             sp2.castShadow = true;
108             sp2.receiveShadow = true;
109             mshFloor.castShadow = true;
110             mshFloor.receiveShadow = true;
111             mshFloor.position.set( 0, -2, 0 );
112            
113 
114             scene.add( mshFloor );
115             scene.add(sp);
116             scene.add(sp2);
117             scene.add(myBall);
118             scene.add( light );
119             scene.add(ambient);
120             scene.add(lightHelper);            
121            // 0.9854        
122             
123             //聚光灯光源
124            function SpotLight(){
125                 light = new THREE.SpotLight( &#39;#ffffff&#39; ,1);
126                 light.castShadow = true;
127                 light.distance = 50; 
128                 light.angle = 0.6; 
129                 light.decay = 2;
130                 light.penumbra = 0.2;          
131                 light.position.set( 3, 2, 1 );
132                 light.shadow.camera.near = 1;
133                 light.shadow.camera.far = 3;
134                 light.shadow.camera.visible = true;            
135                 light.shadow.mapSize.width = 1024;
136                 light.shadow.mapSize.height = 1024;                                    
137                 light.target = sp;
138                 scene.add(light);
139             }
140 
141             //点光源
142             function PointLight(){
143                 light = new THREE.PointLight(&#39;#ffffff&#39;,1,50,2);
144                     light.castShadow = true;
145                     light.position.set( 3, 2, 1 );           
146                     light.shadow.mapSize.width = 1024;
147                     light.shadow.mapSize.height = 1024;  
148                     scene.add(light);                    
149             }
150 
151             //平行光
152             function DirectLight(){
153                 light = new THREE.DirectionalLight(&#39;#ffffff&#39;,1);
154                     light.castShadow = true;
155                     light.position.set( 3, 2, 1 ); 
156                     light.decay = 2;
157                     light.penumbra = 0.2;          
158                     light.shadow.mapSize.width = 1024;
159                     light.shadow.mapSize.height = 1024;  
160                     scene.add(light); 
161             }
162 
163             var onProgress = function ( xhr ) {
164                     if ( xhr.lengthComputable ) {
165                         var percentComplete = xhr.loaded / xhr.total * 100;
166                         console.log( Math.round(percentComplete, 2) + &#39;% downloaded&#39; );
167                     }
168                 };
169 
170                 var onError = function ( xhr ) { };
171                 THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
172                 var mtlLoader = new THREE.MTLLoader();
173                 mtlLoader.setPath( &#39;./&#39; );       //设置我们需要加载的mtl文件路径
174                 mtlLoader.load( &#39;lyn.mtl&#39;, function( material ) {      //这里加载我们需要的文件名  
175                     material.preload();176                     var objLoader = new THREE.OBJLoader();
177                     objLoader.setMaterials( material );      //材质,也可自定义
178                     objLoader.setPath( &#39;./&#39; );               //设置要加载的obj文件的路径
179                     objLoader.load( &#39;lyn.obj&#39;, function ( object ) {           //加载obj文件
180                         object.position.z = 1;         //这里设置我们的素材相对于原来的大小以及旋转缩放等
181                         object.position.y = -0.5;
182                         object.scale.x = 0.2;
183                         object.scale.y = 0.2;
184                         object.scale.z = 0.2;
185                         object1 = object;               //这里是对素材设置阴影的操作
186                         for(var k in object.children){  //由于我们的素材并不是看上去的一个整体,所以需要进行迭代
187                                                         //对其中的所有孩子都设置接收阴影以及投射阴影
188                                                         //才能看到阴影效果
189                             object.children[k].castShadow = true;   //设置该对象可以产生阴影
190                             object.children[k].receiveShadow = true;  //设置该对象可以接收阴影
191                         }
192                         scene.add( object1 );
193                         
194                     }, onProgress, onError );
195                 });
196 
197 
198             var render = function() {
199                 requestAnimationFrame(render);
200                 lightHelper.update();
201                                       
202                 other.rotation.y += 0.01;
203                 sp2.rotation.x += 0.01;
204 
205                 renderer.render(scene, camera);
206             }
207             
208             render();
209             
210             //设置场景不停旋转
211             var tmp = 0;
212             var timer = setInterval(function(){
213                 if(tmp == 0){
214                     var route = (5 - light.position.y) / 50;
215                     light.position.y += route;
216                     if(route <= 0.001){
217                         tmp = 1;
218                     }
219                 }else{
220                     var route = (light.position.y - 1) / 50;
221                     light.position.y -= route;
222                     if(route <= 0.001){
223                         tmp = 0;
224                     }
225                 }
226             },15);
227 
228            //设置图中的立方体可以旋转
229             var left = false;
230             var right = false;
231             var boxLeft = false;
232             var boxRight = false;
233             var boxUp = false;
234             var boxDown = false;
235             var object1 = &#39;&#39;;                        
236             setInterval(function(){                
237                 if(left){                                                            
238                     object1.rotation.y -= 0.02;                  
239                 }else if(right){                                        
240                     object1.rotation.y += 0.02;            
241                 }else if(boxLeft){
242                     sp.rotation.y -= 0.02;
243                 }else if(boxRight){
244                     sp.rotation.y += 0.02;
245                 }else if(boxUp){246                     sp.rotation.x -= 0.02;
247                 }else if(boxDown){248                     sp.rotation.x += 0.02;
249                 }
250             },25);
251 
252             document.onkeydown = function(ev){
253                 var ev = ev || event;
254                 if(ev.keyCode == 65)
255                     left = true;
256                 else if(ev.keyCode == 68)
257                     right = true;   
258                 else if(ev.keyCode == 37)
259                     boxLeft = true;
260                 else if(ev.keyCode == 38)
261                     boxUp = true;
262                 else if(ev.keyCode == 39)
263                     boxRight = true;
264                 else if(ev.keyCode == 40)
265                     boxDown = true; 
266                 else if(ev.keyCode == 80){
267                     scene.remove(light);
268                     PointLight();
269                 }else if(ev.keyCode == 83){
270                     scene.remove(light);
271                     SpotLight();
272                 }else if(ev.keyCode == 17){
273                     scene.remove(light);
274                     DirectLight();
275                 }else if(ev.keyCode == 90){
276                     if(light.intensity < 10)
277                         light.intensity += 1;
278                 }else if(ev.keyCode == 88){
279                     if(light.intensity > 0)
280                         light.intensity -= 1;
281                 }else if(ev.keyCode == 67){
282                     scene.remove(sp);
283                     geometry = new THREE.BoxGeometry(1,1,1);
284                     material = new THREE.MeshPhongMaterial({
285                         color : &#39;#A44A32&#39;,
286                         specular : &#39;#ffffff&#39;,
287                         specular : 100                                               
288                     });
289                     var sp = new THREE.Mesh(geometry,material);
290                     sp.position.z = -0.5;
291                     scene.add(sp);
292                 }else if(ev.keyCode == 86){
293                     scene.remove(sp);
294                     geometry = new THREE.BoxGeometry(1,1,1);
295                     material = new THREE.MeshPhongMaterial({
296                         color : &#39;#2194ce&#39;,
297                         specular : &#39;#111111&#39;,
298                         specular : 100                                               
299                     });
300                     var sp = new THREE.Mesh(geometry,material);
301                     sp.position.z = -0.5;
302                     scene.add(sp);
303                 }     
304             }
305 
306             document.onkeyup = function(ev){
307                 var ev = ev || event;
308                 if(ev.keyCode == 65)
309                     left = false;
310                 else if(ev.keyCode == 68)
311                     right = false;
312                 else if(ev.keyCode == 37)
313                     boxLeft = false;
314                 else if(ev.keyCode == 38)
315                     boxUp = false;
316                 else if(ev.keyCode == 39)
317                     boxRight = false;
318                 else if(ev.keyCode == 40)
319                     boxDown = false; 
320             }
321 
322 
323         </script>
324     </body>
325 </html>


以上是使用three.js做出的3D效果圖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn