依照上一篇 Three.js 3D Library (1) 基本介紹 介紹了製造 3D 圖形的基本元素,接下來進行實作吧!
座標系統
開始實作之前,必須先了解 Three.js 使用 右手座標系統 Right-Hand Coordinate 來定義 3D 空間:
X軸:向右為正方向,Y軸:向上為正方向,Z軸:向外為正方向
        
        
如果對此概念不熟悉也沒關係,Three.js 提供座標輔助:
const axesHelper = new THREE.AxesHelper(10);  scene.add(axesHelper);
 
  | 
 
實作行星自轉畫面,步驟如下:
- 建立場景
 
- 建立相機
 
- 建立渲染器
 
- 建立物體
 
- 建立光源
 
- 渲染場景
 
以下為進階功能:
- 加入軌道控制器
 
- 打造 RWD 響應式畫面
 
建立場景
設定背景底色
const scene = new THREE.Scene(); scene.background = new THREE.Color(0x000000); 
 
  | 
 
建立相機
使用透視相機,設定相機位置跟相機焦點
const camera = new THREE.PerspectiveCamera(     75,     window.innerWidth / window.innerHeight,     0.1,     1000 ); camera.position.set(120, 120, 120);  camera.lookAt(scene.position); 
 
  | 
 
建立渲染器
const renderer = new THREE.WebGLRenderer({     antialias: true,     alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight);
  document.getElementById('container').appendChild(renderer.domElement);
 
  | 
 
建立物體
結構如下:
再次複習一下建立網格(Mesh)或粒子(Points)物體順序:
建立幾何體 → 建立材質 → 建立物體 → 將物體加入場景
行星體(網格物體)
分為球型體跟行星環,軸心旋轉(X軸-30度、Y軸-10度)
輔助座標
首先建立輔助座標,可以協助我們快速理解3D空間
const axesHelper = new THREE.AxesHelper(50); axesHelper.rotation.x = THREE.MathUtils.degToRad(-30);  axesHelper.rotation.y = THREE.MathUtils.degToRad(-10);  scene.add(axesHelper);
 
  | 
 
使用 THREE.MathUtils.degToRad() 運算函式,將角度(degrees)轉換成弧度(radians)
球型體
使用 IcosahedronGeometry(radius, detail) 建立多面體,詳細說明見官方文件
 const sphereGeometry = new THREE.IcosahedronGeometry(20, 1);
  const sphereMaterial = new THREE.MeshPhongMaterial({     color: 0xffffff,     emissive: 0x000000,     specular: 0xffffff,     shininess: 100,     flatShading: true });
  const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
 
  | 
 
行星環
使用 RingGeometry() 建立圓環幾何體,詳細說明見官方文件
 const RingGeometry = new THREE.RingGeometry(42, 28, 30, 30);
  const RingMaterial = new THREE.MeshPhongMaterial({     color: 0xffffff,     emissive: 0x000000,     specular: 0xffffff,     shininess: 100,     flatShading: true,     transparent: true,     opacity: 0.7 });
  const ring = new THREE.Mesh(RingGeometry, RingMaterial);
  ring.rotation.x = THREE.MathUtils.degToRad(90);
 
  | 
 
組合行星體
使用 Group() 建立群組,軸心旋轉(同前面說明:X軸-30度、Y軸-10度)
const planet = new THREE.Group(); planet.add(sphere, ring);  planet.rotation.x = THREE.MathUtils.degToRad(-30); planet.rotation.y = THREE.MathUtils.degToRad(-10);
 
  scene.add(planet);
 
  | 
 
群星背景(粒子物體)

使用 BufferGeometry() 建立幾何體,可以減少 GPU 的消耗,詳細說明見官方文件
 const geometry = new THREE.BufferGeometry(); const particleAmount = 2000;  const vertices = []; for (let i = 0; i < particleAmount; i++) {     const x = 2000 * Math.random() - 1000;     const y = 2000 * Math.random() - 1000;     const z = 2000 * Math.random() - 1000;     vertices.push(x, y, z); } geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
 
 
  const particleTexture = new THREE.TextureLoader().load('https://i.imgur.com/9TwBBHH.png'); const material = new THREE.PointsMaterial({     size: 5,     sizeAttenuation: true,     map: particleTexture,     transparent: true,     alphaTest: 0.5,     color: 0xf3f3af });
 
  const particles = new THREE.Points(geometry, material);
 
  scene.add(particles);
 
  | 
 
建立光源
依序建立三種光源,讓光線看起來更自然:
- 環境光 AmbientLight
 
- 點光源 PointLight
 
- 聚光燈 SpotLight
 
環境光
const ambientLight = new THREE.AmbientLight(0x222222);
 
  | 
 
點光源
const pointLight = new THREE.PointLight(0x777777, 1, 0); pointLight.position.set(100, 100, 0);
 
  | 
 
聚光燈
const spotLight = new THREE.SpotLight(0xffffff, 3, 150, Math.PI / 6, 1, 1); spotLight.position.set(50, 100, -80); spotLight.castShadow = true; spotLight.shadow.mapSize.width = 1024; spotLight.shadow.mapSize.height = 1024; spotLight.shadow.camera.near = 10; spotLight.shadow.camera.far = 200; spotLight.shadow.focus = 1;
 
  | 
 
聚光燈輔助可以更明確地看到光線位置
const lightHelper = new THREE.SpotLightHelper(spotLight); scene.add(lightHelper);
 
  | 
 
最後將光源加入場景
scene.add(ambientLight, pointLight, spotLight);
 
  | 
 
渲染場景
搭配前一篇說明過的 動畫循環渲染 Render Loop 方法
function animate() {     requestAnimationFrame(animate);          planet.rotation.y += 0.01;          renderer.render(scene, camera); } animate();
 
  | 
 
到這裡畫面就完成囉!👏👏👏
接著說明進階的功能
加入軌道控制器
軌道控制器 OrbitControls 讓使用者可以透過滑鼠或是觸控面板來縮放和移動相機,改變場景中的視角和位置,軌道圍繞著前面提到的 camera.lookAt() 相機焦點
軌道控制器也可以啟用自動旋轉功能,詳細請見官方文件
const control = new OrbitControls(camera, renderer.domElement);
 
  | 
 
打造 RWD 響應式畫面
監聽螢幕尺寸變化,讓畫面自適應
window.addEventListener('resize', () => {     camera.aspect = window.innerWidth / window.innerHeight;     camera.updateProjectionMatrix();     renderer.setSize(window.innerWidth, window.innerHeight); });
 
  | 
 
完整範例程式碼
參考資源:
https://ithelp.ithome.com.tw/users/20107572/ironman/1782
https://threejs.org/
https://medium.com/小彥彥的前端五四三/threejs-內建幾何模型-二-3df675ba8315
        
    
     
    
        
評論