自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

通過(guò)漫天花雨來(lái)入門 Three.js

開發(fā) 前端
Three.js 用于渲染一個(gè) 3D 的場(chǎng)景,里面會(huì)有很多物體,比如立方體、圓柱、圓環(huán)、圓錐等各種幾何體(以 Geometry 為后綴),比如點(diǎn)(Points)線(Line)面(Sprite)等基礎(chǔ)物體。

[[436062]]

隨著元宇宙概念的火爆,3D 渲染相關(guān)的技術(shù)頻繁被提及,而 Three.js 是基于 WebGL 的 api 封裝的用于簡(jiǎn)化 3D 場(chǎng)景的開發(fā)的框架, 是入門 3D 的不錯(cuò)的抓手,今天我們就來(lái)入門下 Three.js。

我們基于 Three.js 來(lái)實(shí)現(xiàn)一個(gè)花瓣雨的效果。

Three.js 的基礎(chǔ)

Three.js 用于渲染一個(gè) 3D 的場(chǎng)景,里面會(huì)有很多物體,比如立方體、圓柱、圓環(huán)、圓錐等各種幾何體(以 Geometry 為后綴),比如點(diǎn)(Points)線(Line)面(Sprite)等基礎(chǔ)物體。這些所有的物體怎么管理呢?

用一個(gè)場(chǎng)景 Scene 來(lái)承載,所有的物體都會(huì)被添加到 Scene 里。

所以有這樣的 api:

  1. const scene = new THREE.Scene(); 
  2.  
  3. scene.add(xxx); 
  4. scene.add(yyy); 

當(dāng)然,物體之間可以做分組 Group,組內(nèi)的物體可以統(tǒng)一管理,之后再添加到 Scene 里。

  1. const scene = new THREE.Scene(); 
  2.  
  3. const group = new THREE.Group(); 
  4.  
  5. group.add(xxx); 
  6. group.add(yyy); 
  7.  
  8. scene.add(group); 

這種場(chǎng)景、物體、分組的概念,在很多游戲引擎中也有類似的 api,大家都是這么來(lái)管理的。

可以添加到 Scene 中的物體,除了幾何體(Geometry)、點(diǎn)線面等,還有輔助工具,比如坐標(biāo)系工具(AxisHelper)。其實(shí)這些工具也是用集合體、點(diǎn)線面封裝出來(lái)的,只不過(guò)是作為工具來(lái)臨時(shí)添加到 Scene 中。

  1. const axisHelper = new THREE.AxisHelper(max); 
  2. scene.add(axisHelper) 

有了場(chǎng)景和場(chǎng)景中的各種物體,怎么渲染出來(lái)呢?

調(diào)用 Renderer,這個(gè)類是專門負(fù)責(zé)渲染 Scene 中各種物體的。

但是還有個(gè)問(wèn)題,三維的世界(scene)怎么渲染到二維的屏幕呢?

如圖,從一個(gè)點(diǎn)找個(gè)角度來(lái)看三維世界,或者從一個(gè)平面來(lái)平行的看三維世界,看到的就是二維的。

這兩種方式,第一種叫做透視、第二種叫做正交。

生成二維圖像,就像照相機(jī)的功能一樣,所以這種概念叫做 Camera。

在 Three.js 里面有 PerspectiveCamera (透視相機(jī))和 OrthographicCamera(正交相機(jī)),分別對(duì)應(yīng)上面兩種三維轉(zhuǎn)二維的方式。

這兩個(gè) Camera 的參數(shù)還是挺多的,但是理解了也挺簡(jiǎn)單:

  1. new Three.PerspectiveCamera( fov, aspect, near, far ) 
  2. new Three.OrthographicCamera( leftrighttop, bottom, near, far ) 

先看透視相機(jī)的,它要看三維世界,那就要有一個(gè)最近和最遠(yuǎn)兩個(gè)位置,然后從一個(gè)點(diǎn)看過(guò)去會(huì)有一個(gè)視野的角度,看到的畫面還有個(gè)寬高比。

這就是為什么 PerspectCamera 有 near、far、fov、aspect 這四個(gè)參數(shù)。

正交相機(jī)的參數(shù)也是差不多的意思,不過(guò)因?yàn)椴皇菑囊粋€(gè)點(diǎn),看的,而是從一個(gè)面做的投影,那么就沒(méi)有角度的參數(shù),而是有上下左右的四個(gè)面位置的參數(shù)。

正交相機(jī)的上下左右位置也不是隨便的,比例要和畫面的寬高比一樣,所以一般都是這么算:

  1. const width = window.innerWidth; 
  2. const height = window.innerHeight; 
  3. //窗口寬高比 
  4. const k = width / height; 
  5. //三維場(chǎng)景的顯示的上下范圍 
  6. const s = 200; 
  7.  
  8. // 上下范圍 s 再乘以寬高比 k 就是左右的范圍,而遠(yuǎn)近隨便設(shè)置一個(gè)數(shù)就行 
  9. const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); 

上面的正交相機(jī)的參數(shù)里面,遠(yuǎn)近可以設(shè)置為 1 和 1000,上下設(shè)置為 200,左右就可以根據(jù)寬高比算出來(lái)。這就是相機(jī)所看到的二維畫面的范圍。

有了場(chǎng)景 Scene 中的各種物體,有了照相機(jī) Camera,就可以用渲染器 Renderer 渲染出畫面來(lái)了。

  1. const renderer = new THREE.WebGLRenderer(); 
  2. //設(shè)置渲染區(qū)域尺寸 
  3. renderer.setSize(width, height) 
  4.  
  5. renderer.render(scene, camera) 

不過(guò),一般不會(huì)只渲染一幀,有動(dòng)畫效果的話,會(huì)使用 requestAnimationFrame 的 api 一幀幀的不停渲染。

  1. function render() { 
  2.     renderer.render(scene, camera) 
  3.  
  4.     requestAnimationFrame(render) 
  5. render(); 

這就是 Three.js 的大概流程:Scene 中有幾何體Geometry、點(diǎn)線面、輔助工具等各種物體,物體還可以做分組,然后通過(guò)正交或者透視相機(jī)來(lái)設(shè)置看到的二維畫面,之后用 Renderer 渲染出來(lái)。有動(dòng)畫效果的話,要用 requestAnimationFrame 來(lái)一幀幀的渲染。

下面我們來(lái)實(shí)現(xiàn)一下花瓣雨的效果。

花瓣雨實(shí)現(xiàn)

首先我們要?jiǎng)?chuàng)建場(chǎng)景 Scene 中的物體,也就是各種花瓣,這個(gè)需要顯示的是一個(gè)平面,可以用 Sprite。

Sprite 是精靈的意思,在 Three.js 中,它就是一個(gè)永遠(yuǎn)面向相機(jī)的二維平面。

我們給 Sprite 貼上花瓣的紋理就可以了。

我們先準(zhǔn)備一些花瓣的貼圖,類似這種:

花瓣的數(shù)量有很多,我們生成 400 個(gè),加到花瓣分組里,然后添加到場(chǎng)景中:

  1. const scene = new THREE.Scene(); 
  2. /** 
  3.  * 花瓣分組 
  4.  */ 
  5. const petal = new THREE.Group(); 
  6.  
  7. function create() { 
  8.     var texture1 = new THREE.TextureLoader().load("img/h1.png"); 
  9.     var texture2 = new THREE.TextureLoader().load("img/h2.png"); 
  10.     var texture3 = new THREE.TextureLoader().load("img/h3.png"); 
  11.     var texture4 = new THREE.TextureLoader().load("img/h4.png"); 
  12.     var texture5 = new THREE.TextureLoader().load("img/h5.png"); 
  13.     var imageList = [texture1, texture2, texture3, texture4, texture5]; 
  14.  
  15.     for (let i = 0; i < 400; i++) { 
  16.         var spriteMaterial = new THREE.SpriteMaterial({ 
  17.             map: imageList[Math.floor(Math.random() * imageList.length)],//設(shè)置精靈紋理貼圖 
  18.         }); 
  19.         var sprite = new THREE.Sprite(spriteMaterial); 
  20.         petal.add(sprite); 
  21.  
  22.         sprite.scale.set(40, 50, 1);  
  23.         sprite.position.set(2000 * (Math.random() - 0.5), 2000 * Math.random(), 0) 
  24.     } 
  25.     scene.add(petal) 
  26.  
  27. create(); 

400 個(gè) Sprite 隨機(jī)貼上了不同的花瓣的紋理貼圖,然后設(shè)置了下放縮,之后隨機(jī)設(shè)置了一個(gè)在場(chǎng)景中的位置。

我們?cè)?Scene 中加入坐標(biāo)系輔助工具來(lái)看下坐標(biāo):

  1. const axisHelper = new THREE.AxisHelper(1000); 
  2. scene.add(axisHelper) 

紅色是 x 軸,向右是遞增的,綠色是 y 軸,向上是遞增的。z 軸我們暫時(shí)用不到。

所以,根據(jù)代碼,花瓣的 x 的范圍就是隨機(jī)的 -1000 到 1000,y 的范圍就是 0 到 2000。

然后,我們創(chuàng)建正交相機(jī):

  1. const width = window.innerWidth; 
  2. const height = window.innerHeight; 
  3. //窗口寬高比 
  4. const k = width / height; 
  5. //三維場(chǎng)景的顯示的上下范圍 
  6. const s = 200; 
  7. const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); 

設(shè)置下相機(jī)的位置和方向:

  1. camera.position.set(0, 200, 500) 
  2. camera.lookAt(scene.position) 

我們創(chuàng)建相機(jī)的時(shí)候指定了二維能顯示的范圍,相機(jī)在這個(gè)范圍內(nèi)的哪個(gè)位置都行。

然后創(chuàng)建渲染器,設(shè)置下大小和背景顏色,把渲染到的 canvas 元素插入到 dom 中。

  1. const renderer = new THREE.WebGLRenderer(); 
  2. //設(shè)置渲染區(qū)域尺寸 
  3. renderer.setSize(width, height) 
  4. //設(shè)置背景顏色 
  5. renderer.setClearColor(0xFFFFFF, 1) 
  6. //body元素中插入canvas對(duì)象 
  7. document.body.appendChild(renderer.domElement) 

之后就用 requestAnimation 不斷地一幀幀渲染就行了。

  1. function render() { 
  2.     petal.children.forEach(sprite => { 
  3.         sprite.position.y -= 1; 
  4.         sprite.position.x += 0.5; 
  5.         if (sprite.position.y < -400) { 
  6.             sprite.position.y = 800; 
  7.         } 
  8.         if (sprite.position.x > 1000) { 
  9.             sprite.position.x = -1000 
  10.         } 
  11.     }); 
  12.  
  13.     renderer.render(scene, camera) 
  14.  
  15.     requestAnimationFrame(render) 

每次重新渲染之前,我們修改下花瓣的位置,產(chǎn)生下落效果,如果超出了范圍,就移到上面去重新開始落,這樣就是不間斷的花瓣雨效果。

完整代碼如下:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <meta charset="UTF-8"
  5.     <title>花瓣雨</title> 
  6.     <style> 
  7.         body { 
  8.             margin: 0; 
  9.             overflow: hidden; 
  10.         } 
  11.     </style> 
  12.     <script src="js/three.min.js"></script> 
  13. </head> 
  14. <body> 
  15. <script> 
  16.  
  17.     const scene = new THREE.Scene(); 
  18.     /** 
  19.      * 花瓣分組 
  20.      */ 
  21.     const petal = new THREE.Group(); 
  22.  
  23.     const width = window.innerWidth; 
  24.     const height = window.innerHeight; 
  25.     //窗口寬高比 
  26.     const k = width / height; 
  27.     //三維場(chǎng)景的顯示的上下范圍 
  28.     const s = 200; 
  29.     const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); 
  30.  
  31.     const renderer = new THREE.WebGLRenderer(); 
  32.  
  33.     function create() { 
  34.         //設(shè)置相機(jī)位置 
  35.         camera.position.set(0, 200, 500) 
  36.         camera.lookAt(scene.position) 
  37.      
  38.         //設(shè)置渲染區(qū)域尺寸 
  39.         renderer.setSize(width, height) 
  40.         //設(shè)置背景顏色 
  41.         renderer.setClearColor(0xFFFFFF, 1) 
  42.         //body元素中插入canvas對(duì)象 
  43.         document.body.appendChild(renderer.domElement) 
  44.  
  45.         // const axisHelper = new THREE.AxisHelper(1000); 
  46.         // scene.add(axisHelper) 
  47.  
  48.         var textureTree1 = new THREE.TextureLoader().load("img/h1.png"); 
  49.         var textureTree2 = new THREE.TextureLoader().load("img/h2.png"); 
  50.         var textureTree3 = new THREE.TextureLoader().load("img/h3.png"); 
  51.         var textureTree4 = new THREE.TextureLoader().load("img/h4.png"); 
  52.         var textureTree5 = new THREE.TextureLoader().load("img/h5.png"); 
  53.         var imageList = [textureTree1, textureTree2, textureTree3, textureTree4, textureTree5]; 
  54.  
  55.         for (let i = 0; i < 400; i++) { 
  56.             var spriteMaterial = new THREE.SpriteMaterial({ 
  57.                 map: imageList[Math.floor(Math.random() * imageList.length)],//設(shè)置精靈紋理貼圖 
  58.             }); 
  59.             var sprite = new THREE.Sprite(spriteMaterial); 
  60.             petal.add(sprite); 
  61.  
  62.             sprite.scale.set(40, 50, 1);  
  63.             sprite.position.set(2000 * (Math.random() - 0.5), 2000 * Math.random(), 0) 
  64.         } 
  65.         scene.add(petal) 
  66.     } 
  67.  
  68.  
  69.     function render() { 
  70.         petal.children.forEach(sprite => { 
  71.             sprite.position.y -= 1; 
  72.             sprite.position.x += 0.5; 
  73.             if (sprite.position.y < -400) { 
  74.                 sprite.position.y = 800; 
  75.             } 
  76.             if (sprite.position.x > 1000) { 
  77.                 sprite.position.x = -1000 
  78.             } 
  79.         }); 
  80.  
  81.         renderer.render(scene, camera) 
  82.  
  83.         requestAnimationFrame(render) 
  84.     } 
  85.  
  86.     create() 
  87.     render() 
  88. </script> 
  89. </body> 
  90. </html> 

總結(jié)

Three.js 是為了簡(jiǎn)化 3D 渲染的框架,它提供了場(chǎng)景 Scene 的 api,里面可以包含各種可渲染的物體:立方體、圓錐等各種幾何體 Geometry、點(diǎn)線面、坐標(biāo)系等輔助工具。這些物體還可以通過(guò) Group 分組來(lái)統(tǒng)一管理。

Sence 要渲染出來(lái)需要指定一個(gè)相機(jī),分為從點(diǎn)去看的透視相機(jī) PerspectiveCamera,從平面去投影的正交相機(jī) OrthographicCamera。理解了它們的原理才能理解 Camera 的參數(shù)。

之后通過(guò) Renderer 渲染出來(lái),如果有動(dòng)畫需要用 requestAnimationFrame 來(lái)一幀幀的渲染。

這是 Three.js 的大概渲染流程。

之后我們實(shí)現(xiàn)了一個(gè)花瓣雨的案例。用到了 Sprite 這種物體,它是一個(gè)永遠(yuǎn)面向相機(jī)的平面,用來(lái)做這種效果很合適。

當(dāng)然,Three.js 的東西還是比較多的,這篇文章只是入下門,后面我們會(huì)繼續(xù)深入,做更多的有意思的 3D 場(chǎng)景和效果。

 

責(zé)任編輯:姜華 來(lái)源: 神光的編程秘籍
相關(guān)推薦

2017-05-08 11:41:37

WebGLThree.js

2021-04-23 16:40:49

Three.js前端代碼

2019-11-29 09:30:37

Three.js3D前端

2022-07-15 13:09:33

Three.js前端

2024-07-18 06:58:36

2021-04-21 09:20:15

three.js3d前端

2021-12-14 11:44:37

可視化Three.js 信息

2022-03-07 09:20:00

JavaScripThree.jsNFT

2022-01-16 19:23:25

Three.js粒子動(dòng)畫群星送福

2021-12-03 07:27:30

全景瀏覽Three.js

2022-07-08 10:39:09

Three.js元宇宙VR

2025-03-13 10:54:18

2021-11-23 22:50:14

.js 3D幾何體

2020-11-23 07:43:18

JS

2021-11-27 10:42:01

Three.js3D可視化AudioContex

2021-12-07 13:44:43

Three.js3D可視化3D 游戲

2023-07-13 10:48:22

web 3DThree.jsBlender

2017-12-26 17:42:12

前端WebGLThree.js

2024-02-26 00:00:00

前端工具Space.js

2023-08-04 09:56:15

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)