首頁 web前端 js教程 使用three.js做出的3D效果圖?

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

May 26, 2018 pm 02:45 PM
3dmax javascript

       以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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

See all articles