Three.js
使用 Three.js 在網頁上建立3D場景有幾個注意的步驟:
- 引入
three
套件 - 建立場景
Scene
- 建立渲染
Renderer
- 設定畫布尺寸
innerWidth、innerHeight
- 建立攝影機
Camera
- 建立/載入物體
Mesh
/loop
- 建立燈光
Light
- 循環渲染
基本安裝 :
這裡使用的是 Vite ( Vue ) 環境。
cmd
npm install --save-dev vite
引入 Three 套件 :
基本上這裡視所要渲染或建立的內容來引入,固定匯入有 Scene
、Camera
、WebGLRenderer
。
html
<html>
<head>
<style>
body{
overflow: hidden;
margin: 0px;
}
</style>
</head>
<body></body>
</html>
場景 Scene 建立
js
const scene=new Scene()
設定渲染 Renderer + 畫面範圍設定
這裡將畫面範圍設定與 window 相同
js
const render=new WebGLRenderer()
render.setSize( window.innerWidth, window.innerHeight )
document.body.appendChild( render.domElement );
建立攝影機(相機) Camera
一般攝影鏡頭(相機)有分許多種,大多使用PerspectiveCamera
透視法,與現實中的35mm鏡頭焦距一樣。
建立物體
引入或建立model時需要注意幾個要點:
- 顏色
color
- 表面材質
material
- 實體或線條表現
mesh
- 放置的位置
position
,這裡應該說是與鏡頭的距離 - 尺寸大小 ( 長, 寬, 高 )
- 放到場景內
scene.add()
物體本身在Three中有需多方式建立,包含點、線、面、基本幾何圖形(方體、柱體、球體...等等),在實際網頁中當然是以自己建立的model為主,初步學習則可運用內建物體來練習。
再來是表面材質表現的 MeshBasicMaterial
、MeshStandardMaterial
,這兩個材質渲染會針對光線的反應有所不同。
js
// 尺寸
const geometry=new BoxGeometry(1,1,1)
// 顏色與材質
const material=new MeshStandardMaterial( { color: 0x00ff00 } );
// 實體或線條
const cube=new Mesh(geometry, material)
// 建立物體
scene.add(cube)
// 放置的位置
cube.position.set(-10,10,10)
// 物體的方向
cube.rotation.x += 0.01;
這邊是載入3D Model (.gltf/.glb) 的外掛 Addons
建立燈光
( 圖片是 Blender所設定的4種燈光 )
Three 燈光種類很多,依據3D場景設計的角度來看,常用的有 : AmbientLight環境光
、DirectionalLight定向光(平行光)
、PointLight單點光
、spotLight聚光燈
。
基本設定有 : color顏色
、intensity強度
、distance光照範圍
、decay光線衰退變量
、position位置
。
js
const light=new PointLight(0x404040, 1, 100)
light.position.set(10,10,10)
scene.add(light)
當然有光就有影子,Three也有幾個影子的設定項目,不過除非是要在網頁上建立真實的互動場景,否則通常都使用預設,不會刻意設定影子。<LightShadow影子設定>
循環檢視(渲染)
一般3D模型中不可能只渲染一個面,在 Three.js
中使用所謂的 animate 動畫
方式,其實是告訴程式持續渲染,這樣才能看到物體的各面向外觀。
js
function animate() {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
互動設計
js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
const controls = new OrbitControls( camera, renderer.domElement )