>  기사  >  웹 프론트엔드  >  three.js를 사용하여 만든 3D 렌더링?

three.js를 사용하여 만든 3D 렌더링?

零下一度
零下一度원래의
2018-05-26 14:45:463695검색

three.js를 사용하면 웹 페이지에 다양한 3D 효과를 쉽게 만들 수 있습니다. 2D로 컨텐츠를 그리려면 캔버스를 사용하는 것이 좋습니다. 하지만 많은 친구들은 우리가 그리고 가져오는 그래픽에 그림자 효과를 추가하는 방법을 모르고, 우리가 이미 제작한 3dmax 리소스를 가져오는 방법조차 모릅니다. 그래서 이번 튜토리얼에서는 3dmax로 만든 리소스를 가져오는 방법과 직접 그린 모든 그래픽을 포함하여 가져온 리소스에 그림자를 추가하는 방법을 간략하게 소개하겠습니다. 이런 8부작 에세이 같은 코드가 전혀 기억나지 않는다고 말하는 친구들도 많습니다. 실제로 코드를 작성해야 할 때마다 코드를 외우는 대신 공식 사례를 참고하면 됩니다. 화장을 많이 하다 보면 자연스럽게 기억하게 될 거예요. 컴파일 횟수를 줄이면 거의 사용하지 않는 코드를 외우느라 많은 시간을 소비할 필요가 없습니다.

먼저 3dmax 리소스를 가져오는 방법을 소개하겠습니다. 여기서 참고할 점은 제가 직접 테스트한 결과 작성된 웹페이지를 로컬 파일에서 직접 열면 Google, IE 등의 브라우저에서 로드한 리소스를 표시할 수 없다는 점입니다. 그 이유는 파일 프로토콜을 연 후 사용하기 때문입니다. 파일을 로컬로 저장하므로 서버를 탐색하면 보안 문제로 인해 로컬 리소스를 로드할 수 없습니다. Firefox 브라우저는 정상적으로 열릴 수 있습니다. 따라서 디버깅 시에는 Firefox를 사용하거나, 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                 });
的 위의 코드는 그림자 설정과 크기 조정을 제외하면 8자 모양의 텍스트입니다. 이 개발에 자주 참여하신다면 소스 코드 구현을 확인하는 것이 좋습니다. 때로는 가져온 후에도 자료를 볼 수 없는 경우가 있습니다. 우리는 다음과 같은 측면을 고려해야 합니다. 첫 번째 측면은 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으로 문의하세요.