在Three.js 初探文中, 我在最後寫了這麼一段程式來渲染整個場景
// 定義渲染器
let renderer = window.WebGLRenderingContext ?
new THREE.WebGLRenderer() : new THREE.CanvasRenderer()
// ... 略
// 渲染
renderer.render(scene, camera)
首先要認識的是, 在three.js中渲染器Render, 我們有以下幾個選擇
在普遍的情況下我們優先考慮WebGLRenderer, 另外兩個Renderer通常是在環境不支援WebGLRenderer時的替代方案, 原因是相較於WebGLRenderer, 其他Renderer可能渲染品質較差, 或是功能較少(例如不支援複雜的材質與陰影)
##requestAnimationFrame
在很久以前, Javascript渲染動畫的方式通常是使用全域計數器window.setInterval搭配CSS屬性來實現
/** css */
#exampleDom {
position: relative;
width: 50px;
height: 50px;
background: green;
display: inline-block;
}
/** JavaScript*/
let el = document.getElementById('exampleDom')
let w = el.clientWidth
let timer = window.setInterval(() => {
w = w += 1
if(w >= 100) clearInterval(timer)
el.style.width = `${w}px`
}, 30)
這樣的方式雖然能夠實現動畫效果, 但實際上會遇到遺失間隔與間隔之間的幀, 進而降低了秒張率FPS, 更多詳細解說可以查看這篇詳細的介紹
因此, 現代瀏覽器為了更好的體驗, 一致的實作requestAnimationFrame, 而我們也將使用此方法來渲染我們的3D內容
// 將原本的渲染放入函式, 在由 requestAnimationFrame 執行
function render() {
renderer.render(scene, camera)
}
function animationRender() {
render()
requestAnimationFrame(animationRender)
}
// 開始執行 animationRender
animationRender()
另外我們可以使用Renderer的setClearColor方法來設定場景背景色
// 將背景色設定為白色
renderer.setClearColor(new THREE.Color('rgb(255, 255, 255)'))
接著我們可以與先前的範例做結合
// 1.建立場景 Scene
let scene = new THREE.Scene()
// 2.建立相機 Camera
let camera = new THREE.PerspectiveCamera(
75, window.innerWidth / window.innerHeight, 0.1, 1000
)
camera.position.x = 3
camera.position.y = 3
camera.position.z = 3
camera.lookAt(new THREE.Vector3(0, 0, 0))
// 3.建立渲染器 Renderer
let renderer = window.WebGLRenderingContext ?
new THREE.WebGLRenderer() : new THREE.CanvasRenderer()
// 4.設定渲染器渲染範圍以及背景顏色
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setClearColor(new THREE.Color('rgb(255, 255, 255)'))
// 5.將渲染元素加入 body
document.body.appendChild(renderer.domElement)
// 6.建立矩形 Geometry
let geometry = new THREE.CubeGeometry(1, 1, 1)
// 7.建立材質 Material
let material = new THREE.MeshNormalMaterial()
// 8.使用以上矩形與材質, 將其實例化成一個方塊
let cube = new THREE.Mesh(geometry, material)
// 9.將方塊加入場景
scene.add(cube)
// 10.執行動畫渲染
animationRender()
// 定義渲染器函數
function render() {
renderer.render(scene, camera)
}
// 定義動畫渲染器
function animationRender() {
cube.rotation.x -= .01
cube.rotation.y -= .01
render()
requestAnimationFrame(animationRender)
}
如果測試這段程式, 畫面中將會呈現一個不停旋轉rotate的方塊cube且背景為白色的3D場景。
方塊cube會旋轉是因為在函式animationRender中我給方塊cube調整了旋轉rotation屬性, 使我們方便觀察出目前的場景已經由requestAnimationFrame不斷的渲染, 驗證動畫渲染的效果。
以上就是渲染器Render的介紹, 以及requestAnimationFrame的why and how,在實際使用的情境中, 我們很少會調整animationRender函式, 因為它的職責僅止於不斷的在每一幀渲染畫面。