以下文章即Learn Threejs 第三版英文翻譯學習記錄蹭劈,可以到正版書店購買對應書籍喳魏。
如果你想在場景種功能使用動畫,那第一件要做的事情就是先找到繪制場景的時間間隔(就是已特定的周期渲染場景)。在HTML5 和JavaScript Api 出來之前芙贫,使用setInterval方法去處理這件事情,這個方法定義了傍药,我們可以100 毫秒去執(zhí)行一個方法(就是周期函數(shù)磺平,約定某個周期調(diào)用某個函數(shù)一次),但是這個方法沒有考慮到瀏覽器的一些問題拐辽,如果你瀏覽其他的頁面拣挪,這個函數(shù)依然會按照時間周期執(zhí)行。而且俱诸,setInterval方法不是異步刷新屏幕菠劝,它需要更高的CPU使用率、頻率乙埃、獲得較差的性能闸英。
介紹 RequestAnimationFrame
幸運的是,我們可以通過requestAnimationFrame這個函數(shù)來解決問題介袜,通過這個函數(shù)甫何,你可以按照時間間隔調(diào)用,而且不用定義這個時間遇伞。這個時間間隔有瀏覽器定義辙喂。你可以在將你的函數(shù)傳入到這個方法中去處理你的繪制任務,瀏覽器會盡可能平滑鸠珠、高效的處理這個繪制任務巍耗。
function renderScene() {?
requestAnimationFrame(renderScene);?
renderer.render(scene, camera);
}
(就是一個while循環(huán) / 也類似遞歸調(diào)用)
在這個renderScene 函數(shù)中,我們調(diào)用了requestAnimationFrame函數(shù)渐排,來保證動畫的正常運行炬太。你僅需要在創(chuàng)建場景完成后調(diào)用一次rendererScene函數(shù)來啟動函數(shù)。
...
document.getElementById("webgl-output").appendChild(renderer.domElement);
renderScene();
如果你運行這個示例驯耻,你會發(fā)現(xiàn)亲族,和我們之前提供的示例,沒有任何區(qū)別可缚,因為我們還沒有開始設置任何動畫霎迫。在我們添加動畫之前,我們需要添加一個小的插件帘靡,它會為我們提供有關(guān)動畫幀率的相關(guān)信息知给。這個庫是Threejs同一個作者開發(fā)的,渲染一個小的界面,為我們提供相關(guān)信息涩赢。
添加這個靜態(tài)庫戈次,我們需要在head里引入,例如:
<script type="text/javascript" src="../../libs/util/Stats.js"></script>
(我在demo中只發(fā)現(xiàn)了一個stats.min.js)
唯一需要做的事情就是將這個庫初始化筒扒,并添加到頁面中朝扼;
function initStats(type) {
? ? ? ?var stats = new Stats();
? ? ? ?stats.showPanel(type);// 0: fps, 1: ms, 2: mb, 3+: custom
? ? ? ?document.body.appendChild(stats.dom);
? ? ? return stats;
? }
(這個我試過,有一個小窗口霎肯,能顯示fps ms mb,3+什么都沒有榛斯,setMode和showPanel都可以)
通過函數(shù)初始化統(tǒng)計試圖信息观游,并根據(jù)傳入類型變量顯示對應的視圖,可以顯示每秒渲染幀數(shù)(FPS)驮俗、渲染需要的時間(MS)懂缕、內(nèi)存分配相關(guān)信息(MB), 在我們的初始化函數(shù)之前調(diào)用initStats函數(shù),例如:
function init(){
var stats = initStats(); ...
}
Tip:說的意思是他將這些工具類的函數(shù)放到了util.js中王凑,說你要用的話搪柑,就直接引入util.js
<script type="text/javascript" src="../js/util.js"></script>
我們現(xiàn)在唯一要做的事情就是在循環(huán)執(zhí)行的方法中調(diào)用stats的update方法,在renderScene 函數(shù)中索烹,例如:
function renderScene() {
stats.update();
......
equestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
如果你運行了添加的代碼工碾,你將會看到在左上角有一個統(tǒng)計圖,如截圖所示(略百姓,自己試吧)渊额;
開始 立方體 動畫
我們寫好了requestAnimationFrame和狀態(tài)提示插件,我們現(xiàn)在找到一個地方寫我們的動畫代碼垒拢。在這部分旬迹,我們將擴展renderScene方法,通過旋轉(zhuǎn)各個坐標軸來執(zhí)行立方體旋轉(zhuǎn)動畫求类,我們開始奔垦,下邊是代碼:
function renderScene() { ...
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
... requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
看起來很簡單,是吧尸疆?我們要做的是椿猎,在每次renderScene函數(shù)調(diào)用刷新的時候,將每個坐標軸屬性增加0.02仓技,它顯示是一個圍繞所有軸平滑旋轉(zhuǎn)的立方體鸵贬。將藍色的球執(zhí)行彈性動畫也不難。
(https://www.cnblogs.com/jaycethanks/p/12032947.html?這篇文章詳細介紹了脖捻,球的切面什么的阔逼,會解決你做出來的球不圓的問題)
開始 球 動畫
彈球動畫,我們再次向rebderScene函數(shù)中添加了幾行代碼地沮,例如:
var step=0;
function renderScene() {
...
step+=0.04;
sphere.position.x = 20 + 10*(Math.cos(step));
sphere.position.y = 2 + 10*Math.abs(Math.sin(step)); ...
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
在場景中嗜浮,立方體羡亩,我們不斷設置了它的rotation屬性,球體我們設置了position屬性危融。我們希望球體從一個點完美的運動到場景的另一個點畏铆,而且是一個平滑的曲線,下面是我的算法介紹:(圖略)
可以看到吉殃,我們需要修改x軸和y軸的值辞居,數(shù)學函數(shù)Math.cos,Math.sin 函數(shù)可以幫助我們創(chuàng)建一個生成平滑的軌跡可供使用的一個值(就是通過函數(shù)的計算能夠得到平滑曲線上的點的值),在這里我們不需要知道詳細的工作流程〉吧祝現(xiàn)在瓦灶,你只需知道 step+=0.4 定義了球體運動的速度,在第8節(jié)中抱完,Creating and Loading Advanced Meshes and Geometries (應該是一節(jié)內(nèi)容贼陶,就是高級使用技巧),我們可以通過章節(jié)了解如何使用這些動畫函數(shù)巧娱,而且會解釋這些碉怔。下班就是球在空中彈跳的樣子:(略 自己做就好了 沒什么);
在結(jié)束本章之前,我們需要在場景中再添加一些物體禁添,在使用3D場景撮胧、動畫、顏色和屬性的時候老翘,它通常需要一些實驗來驗證顏色或者是速度這些趴樱。如果你能有一個簡單的GUI,允許你動態(tài)地改變這些屬性酪捡,那做實驗就更容易了叁征。
使用GUI 體驗更加
谷歌的幾位員工開發(fā)了一個dat.GUI庫(你可以通過http://code.google.com/p/dat-gui/查看文檔),你可以在代碼中很容易的使用用戶界面組件逛薇,在本章的隊后一部分捺疼,在示例中添加一個用戶界面,允許我們執(zhí)行以下操作:控制彈跳球的速度永罚、控制立方體旋轉(zhuǎn)啤呼。
就像我們做統(tǒng)計一樣,第一步將開源庫添加html的<head>標簽中呢袱,如:
<script type="text/javascript" src="../../libs/util/dat.gui.js"></script>
接下來需要配置JavaScript對象官扣,使用dat.GUI來保存屬性。在JavaScript主方法中羞福,我們添加以下JavaScript對象惕蹄,例如:
var controls = new function() {
?this.rotationSpeed = 0.02;?
this.bouncingSpeed = 0.03;
}
在這個JavaScript對象中,我們定義了兩個屬性:this.rotationSpeed 和 this.bouncingSpeed,而且給他們賦值,下一步卖陵,我們將這個對象傳遞到dat.GUI 對象中遭顶,并定義這兩個屬性的范圍,如下所示:
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', 0, 0.5);
gui.add(controls, 'bouncingSpeed', 0, 0.5);
rotationSpeed 和?bouncingSpeed 屬性都是設置了0-0.5區(qū)間泪蔫,現(xiàn)在我們只需要將操作放入到renderScene 渲染循環(huán)中棒旗。(后邊說的比較復雜,意思就是將你之前加入GUI的兩個屬性撩荣,立刻就會生效了)
function renderScene() {
...
cube.rotation.x += controls.rotationSpeed;
?cube.rotation.y += controls.rotationSpeed;?
cube.rotation.z += controls.rotationSpeed;
step += controls.bouncingSpeed;
sphere.position.x = 20 +(10 * (Math.cos(step)));
?sphere.position.y = 2 +(10 * Math.abs(Math.sin(step)));
...
}
現(xiàn)在铣揉,我們運行示例?05-control-gui.html,你可以看到一個簡單的用戶界面餐曹,用來控制彈性系數(shù)和旋轉(zhuǎn)速度
(其實咋說呢就是提供了一個GUI用戶操作界面老速,操作控制項,還是比較好用的凸主,新版的需要導入dat.gui.min.js)
我們之前幾章寫的HTML代碼,我們導入TrackballControls.js JavaScriypt文件额湘。在這個文件中卿吐,我們可以控制camera 影響渲染結(jié)果,我們會在第9章詳細介紹Camera的動畫和移動锋华。我們只需要添加幾行JavaScript代碼就可以添加這個組件嗡官,初始化球運動的軌跡...(接下來說的意思就是一定要記住將randerer添加到document中)。
document.getElementById("webgl-output").appendChild(renderer.domElement); // add the two lines below
var trackballControls = initTrackballControls(camera, renderer);
var clock = new THREE.Clock();
initTrackballControls 方法在utils.js中已經(jīng)被定義了毯焕,這個我們之前提到過衍腥。在接下來的章節(jié)種功能,我們會介紹更多細節(jié)來說明它是怎么工作的纳猫,現(xiàn)在我們只需要更新render方法婆咸,例如:
function render() {
trackballControls.update(clock.getDelta());
...
}
現(xiàn)在已經(jīng)做完了,如果你再次打開05-control-gui.html 示例芜辕,你可以移動你的鼠標尚骄,或者左擊鼠標來移動視角camera,如果你在移動的時候點擊 ‘s’鍵侵续,你可以放大和縮小;如果按下‘d’倔丈,你可以拖拽那個場景。(我沒找見這個文件)
以后的demo將默認使用這些動畫控制組件状蜗,一邊您能夠更容易的查看渲染結(jié)果需五。
如果你在你的瀏覽器上查看,你可能注意到當你縮放瀏覽器的大小時轧坎,渲染界面不會跟著縮放宏邮,在下一個章節(jié)中,我們將會添加這個(就是想說下幾節(jié)中,解決上述問題)蜀铲。
當瀏覽器尺寸改變時边琉,渲染結(jié)果跟著改變
當瀏覽器尺寸發(fā)生改變的時候,更改camera的操作是很簡單的记劝。第一件事情就是注冊添加時間監(jiān)聽变姨,如下:
window.addEventListener('resize', onResize, false);
現(xiàn)在,當瀏覽器i尺寸發(fā)生變化時厌丑,就會調(diào)用onResize方法定欧,下一步我們需要做的是,當onResize方法調(diào)用時怒竿,我們需要更新camera和渲染砍鸠,例如:
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;?
camera.updateProjectionMatrix();?
renderer.setSize(window.innerWidth, window.innerHeight);
}
對于camera來說,我們需要改變aspect屬性耕驰,讓他始終保持瀏覽器橫縱比爷辱;對于renderer,我們需要改變它的渲染尺寸朦肘;(接下來說的意思就是:把這些代碼封裝到一個init方法中饭弓,以便我們更好的使用它);
var camera;
? var scene;
? var renderer;
function init() { ...
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth /
window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer(); ...
}
總結(jié)
第一章到此結(jié)束媒抠,在這一節(jié)中弟断,我們?yōu)槟故玖巳绾卧O置你的開發(fā)環(huán)境、如何獲取程序代碼趴生、如何從提供的示例中開始阀趴。您進一步了解到Three.js是如何渲染的,第一步創(chuàng)建THREE.Scene 對象苍匆,添加camera刘急、光線light、你想渲染的模型浸踩。我們也向您介紹了如何在基礎(chǔ)的場景里顯示陰影(我就沒加出來排霉,估計日后能加出來吧)、顯示動畫等,最后民轴,我們添加了一些小組件攻柠。我們使用dat.GUI 它可以很快速的為我們創(chuàng)建用戶界面來控制渲染屬性,添加了stats.js(用來觀察渲染情況后裸,如內(nèi)存瑰钮、刷新頻率等)
在下一章節(jié)中,進一步了解Three.js的其他功能微驶。