成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用 Three.js 畫個 3D 生日蛋糕送給他(她)

開發 前端
Mesh 比較常用,它是由一個個三角形構成的幾何體,還可以在每個面上貼圖。所以,參數有兩個,幾何體 Geometry 和材質 Material。

[[436426]]

作為整天和 UI 打交道的前端工程師,是否想在他(她)生日的時候用代碼送上一份驚喜呢?

不妨用 Three.js 做個 3D 的蛋糕送給 ta,既浪漫又能展現你技術的魅力。

這篇文章我們就來學習下如何用 Three.js 畫一個蛋糕。

代碼地址:https://github.com/QuarkGluonPlasma/threejs-exercize

Three.js 相關基礎

Three.js 是通過場景 Scene 來管理所有的物體的,加到 Scene 的物體還可以分個組:

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

想要把 Scene 中的所有物體渲染出來,需要指定一個相機 camera,然后用 renderer 來渲染,如果有動畫效果,要用 requestAnimationFrame 來一幀幀不斷渲染。

  1. const renderer = new THREE.WebGLRenderer(); 
  2.  
  3. function render() { 
  4.  
  5. renderer.render(scene, camera); 
  6.  
  7. requestAnimationFrame(render); 
  8.  
  9.  
  10. render(); 

相機 camera 分為從一個點去看的透視相機 PerspectiveCamera,還有從一個面去投影的正交相機 OrthographicCamera。

透視相機的特點是近大遠小,而正交的則不是,就是一個平行投影,大小不變。

三維世界還需要指定一個光源,不然是全黑的,光源種類很多,常用的有這些:

  • 點光源:從一個點發射光線,就像燈泡一樣
  • 平行光:平行的光線
  • 環境光:均勻照射每個地方
  • 聚光燈:舞臺聚光燈的光源

三維場景中的物體有很多種,比如永遠面向相機的平面是 Sprite(我們做“漫天花雨”效果用的那個),還有由三角形構成的物體叫做 Mesh。

Mesh 比較常用,它是由一個個三角形構成的幾何體,還可以在每個面上貼圖。所以,參數有兩個,幾何體 Geometry 和材質 Material。

比如圓柱體就是一個 Mesh,創建它的時候要指定圓柱幾何體 CylinderBufferGeometry 和每個面的材質 Material。

  1. const 圓柱幾何體 = new THREE.CylinderBufferGeometry(上圓半徑, 下圓半徑, 高度, 側面分段數量); 
  2.  
  3. const 側面材質 = new THREE.MeshBasicMaterial({map: 紋理圖片}); 
  4. const 上面材質 = new THREE.MeshBasicMaterial({color: 'red'}); 
  5. const 下面材質 = new THREE.MeshBasicMaterial({color: 'red'}); 
  6.  
  7. const 圓柱 = new THREE.Mesh(圓柱幾何體, [側面材質, 上面材質, 下面材質]); 

MeshBasicMaterial 是基礎的材質,可以通過 color 來指定顏色,也可以通過 map 來指定紋理圖片 texture。

各種 Mesh 中比較特殊是文字,它用的是 TextGeometry,文字需要從一個 xxx.typeface.json 中加載。

而這種 json 文件可以用字體文件 ttf 來轉換得到。用ttf 轉 typeface.json 的這個網站來轉:

之后就可以顯示文字了:

  1. const fontLoader = new THREE.FontLoader(); 
  2.  
  3. fontLoader.load('./font/xxx.typeface.json'function (font) { 
  4.     var textGeometry = new THREE.TextGeometry('文字', 參數); 
  5.     const textMaterial = [ 
  6.         new THREE.MeshBasicMaterial({color: '字體顏色'}), 
  7.         new THREE.MeshBasicMaterial({color: '側面顏色'}), 
  8.     ]; 
  9.  
  10.     const text = new THREE.Mesh(textGeometry, textMaterial); 
  11. }); 

這些就是我們會用到的 Three.js 基礎,簡單做個小結:

  • Three.js 是通過 Scene 來管理各種物體的,物體還可以分下組。
  • 物體中常見的有 Mesh 和 Sprite 等,Sprite 是永遠面向相機的一個平面,Mesh 是由三角形構成的三維物體。Mesh 要指定幾何體Geometry 和材質 Material,常用的材質可以是顏色或者紋理貼圖。其中文字 TextGeometry 比較特殊,需要一個 typeface.json 的文件,這個可以由 ttf 轉換得到。
  • 場景中的物體準備好之后,還需要設置下光源 Light 和相機 Camera,相機主要有從點去看的透視相機和從一個平面去投影的正交相機,之后就可以通過渲染器 Renderer 渲染出來了,結合 requestAnimationFrame 來一幀幀的渲染。

基礎學完之后,正式開始畫蛋糕了。

畫 3D 蛋糕

蛋糕其實就是由 4 個圓柱體加上文字構成的,每個圓柱體都設置了不同的位置,圓柱體的側面和上下面都貼上不同的貼圖,就是一個蛋糕。

我們先準備蛋糕的貼圖:

 

使用紋理加載器 TextureLoader 去加載他們:

  1. const cakeTexture1 = new THREE.TextureLoader().load('img/cake1.png'); 
  2.  
  3. const cakeTexture2 = new THREE.TextureLoader().load('img/cake2.png'); 
  4.  
  5. const cakeTexture3 = new THREE.TextureLoader().load(`img/cake3.png`); 
  6.  
  7. const cakeTexture4 = new THREE.TextureLoader().load('img/cake4.png'); 

然后構成紋理貼圖的材質:

  1. const cakeMaterail1 = new THREE.MeshBasicMaterial({map: cakeTexture1}); 
  2.  
  3. const cakeMaterail2 = new THREE.MeshBasicMaterial({map: cakeTexture2}); 
  4.  
  5. const cakeMaterail3 = new THREE.MeshBasicMaterial({map: cakeTexture3}); 
  6.  
  7. const cakeMaterail4 = new THREE.MeshBasicMaterial({map: cakeTexture4}); 

除了紋理貼圖的材質外,再準備個顏色構成的材質:

  1. const pinkMaterial = new THREE.MeshBasicMaterial({color: 'pink'}); 

然后創建 4 個圓柱體的物體(Mesh),使用不同的貼圖材質和顏色材質:

  1. const cakeGeometry1 = new THREE.CylinderBufferGeometry(100, 100, 70, 40); 
  2.  
  3. const cakePart1 = new THREE.Mesh(cakeGeometry1, [cakeMaterail1, pinkMaterial, pinkMaterial]); 

圓柱體的幾何體 CylinderBufferGeometry 的參數分別是上面圓的半徑,下面圓的半徑,高度,側面的分割次數。

上面圓半徑保持一致,這樣才是圓柱體。側面分割次數設置為 40,這樣比較圓滑。

之后還設置下位移,然后就可以加到蛋糕分組里了。

我們用同樣的方式創建四個圓柱體,設置不同的大小和位置,貼不同的圖:

  1. const cakeGeometry1 = new THREE.CylinderBufferGeometry(100, 100, 70, 40); 
  2. const cakePart1 = new THREE.Mesh(cakeGeometry1, [cakeMaterail1, pinkMaterial, pinkMaterial]); 
  3. cakePart1.translateY(45) 
  4.  
  5. const cakeGeometry2 = new THREE.CylinderBufferGeometry(120, 120, 70, 40); 
  6. const cakePart2 = new THREE.Mesh(cakeGeometry2,[cakeMaterail3, pinkMaterial, pinkMaterial]); 
  7. cakePart2.translateY(-25) 
  8.  
  9. const cakeGeometry3 = new THREE.CylinderBufferGeometry(140, 140, 60, 40); 
  10. const cakePart3 = new THREE.Mesh(cakeGeometry3, [cakeMaterail2, pinkMaterial, pinkMaterial]); 
  11. cakePart3.translateY(-90) 
  12.  
  13. const cakeGeometry4 = new THREE.CylinderBufferGeometry(160, 160, 10, 40); 
  14. const cakePart4 = new THREE.Mesh(cakeGeometry4, [cakeMaterail4, cakeMaterail4, cakeMaterail4]); 
  15. cakePart4.translateY(-120) 
  16.  
  17. cake.add(cakePart1) 
  18. cake.add(cakePart2) 
  19. cake.add(cakePart3) 
  20. cake.add(cakePart4) 

如果對坐標位置拿不準,可以在 Scene 中加上一個坐標的輔助工具 AxisHelper。參數是坐標軸長度。

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

然后是文字的部分,這個要先通過字體文件 ttf 轉成 typeface.json 的文件,然后用 fontLoader 來加載,之后創建相應的 Mesh:

  1. fontLoader.load('./font/guang.typeface.json'function (font) { 
  2.     var textGeometry = new THREE.TextGeometry('光光', { 
  3.         font: font, 
  4.         size: 30, 
  5.         height: 5, 
  6.         bevelEnabled: true
  7.         bevelSize: 10, 
  8.     }); 
  9.     const textMaterial = ['white''red'].map(color => new THREE.MeshBasicMaterial({color})); 
  10.  
  11.     const text = new THREE.Mesh(textGeometry, textMaterial); 
  12.     text.translateY(90) 
  13.     text.translateX(-45) 
  14.  
  15.     cake.add(text);  
  16. }); 

TextGeometry 需要設置的參數有字體大小 size,厚度 height,以及邊緣是否是曲面 bevelEnabled,和曲面的大小 bevelSize。

我們這里的效果是需要開啟曲面的。

4 個圓柱體畫完了,文字也畫完了,那蛋糕就算是畫完了,之后設置下光源、相機,就可以用 Renderer 渲染了。

光源使用環境光,因為要均勻的照射:

  1. const light = new THREE.AmbientLight(0xCCCCCC); 
  2.  
  3. scene.add(light); 

相機使用正交相機,因為不需要近大遠小的透視效果:

  1. const width = window.innerWidth; 
  2. const height = window.innerHeight; 
  3. //窗口寬高比 
  4. const k = width / height; 
  5. //三維場景顯示范圍的高度 
  6. const s = 200; 
  7.  
  8. const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); 
  9.  
  10. camera.position.set(0, 100, 500) 
  11. camera.lookAt(scene.position); 

正交相機的參數分別是左右上下遠近的三維視野范圍,我們指定高度為 200,然后根據窗口的寬高比算出寬度。遠近可以設置一個比較大的范圍。

之后就可以用 Renderer 來渲染了。把渲染出的 canvas 的 dom 掛載到 body 上。

  1. const renderer = new THREE.WebGLRenderer(); 
  2.  
  3. renderer.setSize(width, height); 
  4. //設置背景顏色 
  5. renderer.setClearColor(0xFFFFFF, 1); 
  6. document.body.appendChild(renderer.domElement); 
  7.  
  8. function render() {         
  9.     renderer.render(scene, camera); 
  10.  
  11.     cake.rotation.y += 0.005; 
  12.  
  13.     requestAnimationFrame(render) 
  14. render() 

在每幀 render 之前,還做了個圍繞 y 軸的自動旋轉。

還要支持手動的旋轉,這個直接使用 Three.js 的軌道控制器 OrbitControls 就行。

  1. const controls = new THREE.OrbitControls(camera); 

參數是相機,因為這種視野的改變就是通過改變相機位置和朝向來實現的。

創建了 Scene 中的蛋糕的每一部分,設置好了光源、相機,用渲染器做了一幀幀的渲染,并且添加了用鼠標來改變視角的軌道控制器之后,就完成了 3D 蛋糕的制作。

我們來看下效果:

代碼地址:https://github.com/QuarkGluonPlasma/threejs-exercize

全部代碼:

  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.js"></script> 
  13.     <script src="./js/OrbitControls.js"></script> 
  14. </head> 
  15. <body> 
  16. <script> 
  17.     const width = window.innerWidth; 
  18.     const height = window.innerHeight; 
  19.     //窗口寬高比 
  20.     const k = width / height; 
  21.     //三維場景顯示范圍的寬度 
  22.     const s = 200; 
  23.  
  24.     const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); 
  25.  
  26.     const fontLoader = new THREE.FontLoader(); 
  27.  
  28.     const scene = new THREE.Scene(); 
  29.  
  30.     const cake = new THREE.Group(); 
  31.  
  32.     const renderer = new THREE.WebGLRenderer(); 
  33.  
  34.  
  35.     function create() { 
  36.         renderer.setSize(width, height); 
  37.         //設置背景顏色 
  38.         renderer.setClearColor(0xFFFFFF, 1); 
  39.         document.body.appendChild(renderer.domElement); 
  40.  
  41.         camera.position.set(0, 100, 500) 
  42.         camera.lookAt(scene.position); 
  43.  
  44.         const light = new THREE.AmbientLight(0xCCCCCC); 
  45.         scene.add(light); 
  46.  
  47.         const axisHelper = new THREE.AxisHelper(2500); 
  48.         scene.add(axisHelper); 
  49.  
  50.         const cakeTexture1 = new THREE.TextureLoader().load('img/cake1.png'); 
  51.         const cakeTexture2 = new THREE.TextureLoader().load('img/cake2.png'); 
  52.         const cakeTexture3 = new THREE.TextureLoader().load(`img/cake3.png`); 
  53.         const cakeTexture4 = new THREE.TextureLoader().load('img/cake4.png'); 
  54.  
  55.         const cakeMaterail1 = new THREE.MeshBasicMaterial({map: cakeTexture1}); 
  56.         const cakeMaterail2 = new THREE.MeshBasicMaterial({map: cakeTexture2}); 
  57.         const cakeMaterail3 = new THREE.MeshBasicMaterial({map: cakeTexture3}); 
  58.         const cakeMaterail4 = new THREE.MeshBasicMaterial({map: cakeTexture4});  
  59.  
  60.         const pinkMaterial = new THREE.MeshBasicMaterial({color: 'pink'}); 
  61.  
  62.         const cakeGeometry1 = new THREE.CylinderBufferGeometry(100, 100, 70, 40); 
  63.         const cakePart1 = new THREE.Mesh(cakeGeometry1, [cakeMaterail1, pinkMaterial, pinkMaterial]); 
  64.         cakePart1.translateY(45) 
  65.   
  66.         const cakeGeometry2 = new THREE.CylinderBufferGeometry(120, 120, 70, 40); 
  67.         const cakePart2 = new THREE.Mesh(cakeGeometry2,[cakeMaterail3, pinkMaterial, pinkMaterial]); 
  68.         cakePart2.translateY(-25) 
  69.  
  70.         const cakeGeometry3 = new THREE.CylinderBufferGeometry(140, 140, 60, 40); 
  71.         const cakePart3 = new THREE.Mesh(cakeGeometry3, [cakeMaterail2, pinkMaterial, pinkMaterial]); 
  72.         cakePart3.translateY(-90) 
  73.  
  74.         const cakeGeometry4 = new THREE.CylinderBufferGeometry(160, 160, 10, 40); 
  75.         const cakePart4 = new THREE.Mesh(cakeGeometry4, [cakeMaterail4, cakeMaterail4, cakeMaterail4]); 
  76.         cakePart4.translateY(-120) 
  77.  
  78.         cake.add(cakePart1) 
  79.         cake.add(cakePart2) 
  80.         cake.add(cakePart3) 
  81.         cake.add(cakePart4) 
  82.  
  83.         fontLoader.load('./font/guang.typeface.json'function (font) { 
  84.             var textGeometry = new THREE.TextGeometry('光光', { 
  85.                 font: font, 
  86.                 size: 30, 
  87.                 height: 5, 
  88.                 bevelEnabled: true
  89.                 bevelSize: 10, 
  90.             }); 
  91.             const textMaterial = ['white''red'].map(color => new THREE.MeshBasicMaterial({color})); 
  92.  
  93.             const text = new THREE.Mesh(textGeometry, textMaterial); 
  94.             text.translateY(90) 
  95.             text.translateX(-45) 
  96.             cake.add(text);  
  97.         }); 
  98.  
  99.         scene.add(cake); 
  100.     } 
  101.  
  102.  
  103.     function render() {         
  104.         renderer.render(scene, camera); 
  105.  
  106.         cake.rotation.y += 0.005; 
  107.  
  108.         requestAnimationFrame(render) 
  109.     } 
  110.  
  111.     create() 
  112.     render() 
  113.  
  114.     const controls = new THREE.OrbitControls(camera); 
  115. </script> 
  116. </body> 
  117. </html> 

總結

本文我們用 Three.js 來實現了 3D 蛋糕的效果。

首先我們學習了下 Three.js 的基礎:通過 Scene 來管理物體,物體可以分組,物體包括 Mesh、Sprite 等,Mesh 是三角形構成的 3D 物體,要分別指定幾何體 Geometry 和材質 Material。材質可以是紋理(Texture)貼圖、也可以是顏色。其中文字的 Mesh 需要做 ttf 到 typeface.json 的轉換,加載這個 json 才能顯示文字。

物體創建完了之后,還要設置相機、燈光等,然后通過渲染器來一幀幀的渲染。

調試的時候還可以添加 AxisHelper 坐標系輔助工具來輔助開發。

然后我們實現了 3D 蛋糕:

通過 4 個圓柱體 + 文字來畫的,圓柱體用了不同的紋理貼圖材質,設置了不同的位置,然后組成蛋糕的 group。

設置了環境光,使用了正交相機,還啟用了軌道控制器 OrbitControls,來實現鼠標拖拽改變相機位置,進而改變視野角度的效果。 

下個他(她)的生日,不妨試試用 Three.js 畫個蛋糕送給他(她),或許會有不一樣的收獲哦。

 

責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2019-11-29 09:30:37

Three.js3D前端

2024-07-18 06:58:36

2022-01-16 19:23:25

Three.js粒子動畫群星送福

2021-11-27 10:42:01

Three.js3D可視化AudioContex

2023-07-13 10:48:22

web 3DThree.jsBlender

2021-04-23 16:40:49

Three.js前端代碼

2025-06-30 09:15:47

2016-06-01 09:19:08

開發3D游戲

2022-03-07 09:20:00

JavaScripThree.jsNFT

2021-04-21 09:20:15

three.js3d前端

2023-08-04 09:56:15

2024-02-26 00:00:00

前端工具Space.js

2023-09-01 09:30:22

Three.js3D 圖形庫

2022-07-15 13:09:33

Three.js前端

2021-11-22 06:14:45

Three.js3D 渲染花瓣雨

2017-05-08 11:41:37

WebGLThree.js

2025-06-17 08:15:00

VTK.jsThree.js3D

2025-05-15 08:45:00

開源前端手勢

2021-09-16 07:52:18

SwiftUScroll效果

2021-12-14 11:44:37

可視化Three.js 信息
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九亚洲| 免费精品久久久久久中文字幕 | 成人精品一区二区三区中文字幕 | 亚洲va在线va天堂va狼色在线 | 国产精品久久久久久亚洲调教 | 一区二区久久精品 | 成人在线免费观看av | 久久精品小视频 | 国产精品中文在线 | 精品中文字幕在线观看 | 中文字幕啪啪 | 国产亚洲欧美另类一区二区三区 | 国产精品综合一区二区 | 久久久高清| 国产在线中文字幕 | 久久9999久久| 精久久久久| 蜜桃一区二区三区 | 在线一级片 | av高清毛片 | 日韩精品一区二区三区视频播放 | 国产精品国产馆在线真实露脸 | 亚洲一区二区三区四区五区中文 | 一区二区三区欧美在线观看 | 精品久久久久久亚洲精品 | 中文字幕亚洲精品在线观看 | 久久久久久免费毛片精品 | 国产视频在线观看一区二区三区 | 亚洲成人av一区二区 | 成年人网站国产 | 久久综合狠狠综合久久综合88 | 成人av电影免费在线观看 | 久久人人网| 精国产品一区二区三区 | 日韩一级 | 中文字幕日韩欧美一区二区三区 | 亚洲视频免费观看 | 午夜精品一区二区三区在线视 | 91精品国产乱码久久久久久久 | 天天操夜夜爽 | 一区二区三区精品 |