Three.js是在網頁上渲染3D場景及物件的知名模組之一,已有許多使用者用Three.js做出各種網頁3D效果(請參考Example),讓我們來看看如何應用它。
1. 安裝
官方文件提供了兩種安裝方式
選項1. npm安裝
# 安裝three
npm install --save three
# 安裝vite
npm install --save-dev vite
#運作vite
npx vite
選項2. CDN連結
本篇介紹以CDN連結方式為主,記得把<version>替換為版本號碼,例如v0.164.1。
雖然官方安裝教學寫著CDN連結要加在<head></head>標籤之間,<style>元件之後,但本人實測沒有卵用,加在<body>標籤結束之前,運作上沒問題。
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@<version>/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@<version>/examples/jsm/"
}
}
</script>
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
2. 初始化
匯入three核心組件
<script type="module">
import * as THREE from 'three';
//將場景、相機、渲染、物件、動畫等其餘程式碼添加於此...
//...
</script>
創建第一個場景及相機,並設定渲染範圍。
先將範圍渲染在整個<body>上,並占滿視窗的寬(window.innerWidth)高(window.innerHeight)。
antialias: true 是反鋸齒的意思,使圖形邊緣變得更加平滑。
//創建場景
const scene = new THREE.Scene();
//創建相機
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
//相機位置設定
camera.position.z = 5;
//設定渲染範圍的尺寸
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
//指定渲染位置
document.body.appendChild( renderer.domElement);
3. 加入物件
定義形狀及材質,作為參數填入新物件(cube)後,加入場景中,目前套用基本的立方體構造(BoxGeometry),以及帶有金屬光澤的標準材質(MeshStandardMaterial)。
//定義形狀(geometry)
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
//定義材質(material)
const material = new THREE.MeshStandardMaterial({
roughness: 0,
metalness: 1,
color:0xffffff,
});
//創建物件
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
4. 光源
AmbientLight 指的是環境光,均勻照射所有物件,沒有方向性故不能投射陰影。
// 添加環境光
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
DirectionalLight 指的是平行光,看起來像無限遠,適合模擬太陽光。
const directionalLight = new THREE.DirectionalLight("yellow", 1);
directionalLight.position.set(5, 5, 5);
// 讓光源能夠投射陰影
directionalLight.castShadow = true;
scene.add(directionalLight);
// 調整光源陰影的解析度
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
還有其他類型的光源,例如半球光(HemisphereLight)、點光源(PointLight)、面光源(RectAreaLight)、聚光燈(SpotLight),詳細需要獨立開篇來講。
5.動畫
最後,設定動畫函數,使動畫運作。
//動畫函數
function animate() {
requestAnimationFrame( animate );
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
6. 互動(OrbitControls)
想像玩遊戲一樣讓訪客與畫面互動,轉動相機視角,你可以使用OrbitControls。
首先,匯入OrbitControls模組。
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
</script>
OrbitControls屬性設置
關於OrbitControls的屬性說明請看官方介紹
enableDamping
:漸變阻尼效果,使相機移動更平滑。dampingFactor
:阻尼系數,控制阻尼效果的強度。screenSpacePanning
:設為false使相機只能繞目標旋轉。- enablePan:設為false禁止相機左右移動。
- enableZoom:設為false禁止鏡頭縮放。
minDistance
/maxDistance
:設置相機的最小和最大縮放距離。maxPolarAngle
:設置相機的最大垂直旋轉角度,以防止相機移動到地面以下。- autoRotate:設為true自動旋轉。
- autoRotateSpeed:自動旋轉速度。
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.screenSpacePanning = false;
controls.minDistance = 1;
controls.maxDistance = 5;
controls.maxPolarAngle = Math.PI / 2
在動畫中更新OrbitControls
也就是在animate函數中增加這行controls.update();
function animate() {
requestAnimationFrame(animate);
cube.rotation.y += 0.01;
controls.update(); // 更新OrbitControls
renderer.render(scene, camera);
}
7. 視窗縮放
渲染範圍的寬高只會在載入網頁時初始化一次,之後縮放視窗不會重新載入渲染範圍的寬高。為了使網頁運作得更好,我們需要加入resize監聽事件,確保縮放視窗的同時,渲染範圍也能及時更新。
對視窗加入resize監聽事件,若觸發resize動作,則更新視窗寬高數字。
window.addEventListener("resize", () => {
//更新相機
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
//更新渲染範圍
renderer.setSize(window.innerWidth, window.innerHeight);
});