3.第一章3小節(jié) 場景動畫

以下文章即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 控制

(其實咋說呢就是提供了一個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的其他功能微驶。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浪谴,一起剝皮案震驚了整個濱河市开睡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苟耻,老刑警劉巖篇恒,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凶杖,居然都是意外死亡胁艰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門智蝠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腾么,“玉大人,你說我怎么就攤上這事杈湾〗馐” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵漆撞,是天一觀的道長殴泰。 經(jīng)常有香客問我,道長浮驳,這世上最難降的妖魔是什么悍汛? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮抹恳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘署驻。我一直安慰自己奋献,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布旺上。 她就那樣靜靜地躺著瓶蚂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宣吱。 梳的紋絲不亂的頭發(fā)上窃这,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音征候,去河邊找鬼杭攻。 笑死,一個胖子當著我的面吹牛疤坝,可吹牛的內(nèi)容都是我干的兆解。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跑揉,長吁一口氣:“原來是場噩夢啊……” “哼锅睛!你這毒婦竟也來了埠巨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤现拒,失蹤者是張志新(化名)和其女友劉穎辣垒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體印蔬,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡勋桶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了扛点。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哥遮。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖陵究,靈堂內(nèi)的尸體忽然破棺而出眠饮,到底是詐尸還是另有隱情,我是刑警寧澤铜邮,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布仪召,位于F島的核電站,受9級特大地震影響松蒜,放射性物質(zhì)發(fā)生泄漏扔茅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一秸苗、第九天 我趴在偏房一處隱蔽的房頂上張望召娜。 院中可真熱鬧,春花似錦惊楼、人聲如沸玖瘸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雅倒。三九已至,卻和暖如春弧可,著一層夾襖步出監(jiān)牢的瞬間蔑匣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工棕诵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留裁良,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓校套,卻偏偏與公主長得像趴久,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子搔确,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容