第一人稱在 3D 中的用法要參考第一人稱在射擊遊戲中的使用,第一人稱射擊遊戲(FPS)是以第一人稱視角爲中心圍繞槍和其餘武器爲基礎的視頻遊戲類型 ; 也就是說,玩家經過主角的眼睛來體驗動做。自從流派開始以來,先進的 3D 和僞 3D 圖形已經對硬件發展提出了挑戰,而多人遊戲已經不可或缺。html
Doom 的截圖,這個流派的突破遊戲之一,展現了第一人稱射擊遊戲的典型視角json
如今博物館或者公司也常用到 3D 動畫作宣傳片等等,3D 動畫演繹最大的優點,即是在於內容與形式上給人的真實感覺。它比平面做品更直觀,比 2D 動畫更真實,因此更能給觀賞者以置身於廣告環境當中的感覺,大大加強廣告的說服力。3D 技術的發展甚至挑戰受衆的分辨能力,使受衆的判斷遊離於與虛擬和現實之間。
並且 3D 特效的應用爲創意提供了更加廣闊的思惟空間,併成爲創意執行的可靠保證,並豐富了創意的形式和風格手段。根據廣告主題的表現訴求,能夠營造出夢幻般的神奇氛圍來刺激打動受衆,從而起到與受衆溝通的目的。
3D動畫宣傳片將 3D 動畫、特效鏡頭、企業視頻、照片、將來前景等內容經過後期合成、配音、解說造成一部直觀、生動、喜聞樂見的高品位的企業廣告宣傳片,讓社會不一樣層面的人士對企業產生正面的、積極的、良好的印象,從而創建對企業的好感與信任,並信賴該企業的產品或服務。
如今 3D 發展地如此迅速也要感謝人類對於「現實」的追求,因此學好用好 3D 是將來成功必不可少的一部分。
本文例子的思路是進入一個機房參觀,打開門的動做是再生動不過了, 再加上適當地轉彎,基本上徹底模擬了人在機房中參觀的效果。還有一個好處就是,若是要演示給領導看而又不用操做,這種炫酷的效果領導必定會很滿意!
http://www.hightopo.com/demo/...
界面上的「reset」和「start」兩個按鈕是直接加在 body 體中的 button,並在這兩個按鈕上添加點擊事件:ide
<div class="button" style="right: 50px;background-image: url(run.png);" onclick="startAnim();"></div> <div class="button" style="right: 100px;background-image: url(reset.png);" onclick="reset();"></div>
整個場景由 HT 封裝的 3D 組件搭建造成的,構造這麼大的場景是須要必定量的代碼的,爲了簡化,我把場景單獨拿出來,並用 HT 封裝的 ht.JSONSerializer 類將場景序列化爲 json,代碼中只引入了生成後的 json 文件,爲了讓你們更明確,我這邊作個示例,假設已經搭建好 3D 場景了:函數
dm = new ht.DataModel(); g3d = new ht.graph3d.Graph3dView(dm); //.......構建好場景 dm.serialize();//能夠填入number參數,做爲空格縮進值
既然咱們已經搭建好環境,轉成了 json 文件,代碼中很差控制,這種狀況下咱們會將 DataModel 數據模型再反序列化,這個函數的功能就是將 json 格式轉成對象,並將反序列化的對象傳入到 DataModel 數據模型中,詳情請參考 HT for Web 序列化手冊:動畫
var g3d = window.g3d = new ht.graph3d.Graph3dView(), dataModel = g3d.dm(), view = g3d.getView(), path = null; g3d.setMovableFunc(function(data) { return false; }); g3d.setVisibleFunc(function(data) { if (data.getName() === "path") { return false; } return true; }); g3d.setEye([523, 5600, 8165]); g3d.setFar(60000); dataModel.deserialize(json);
咱們目前須要操做場景中的「門」、以及咱們將要走的路線「path」,遍歷 DataModel 數據模型,獲取這兩個數據:ui
for (var i = 0; i < dataModel.size(); i++) { var data = dataModel.getDatas().get(i); if (data.getName() === "門") {//json中設置的名稱 window.door = data; } if (data.getName() === "path") { path = data; } if (window.door && path) {//獲取到door 和 path 的data以後就跳出循環 break; } }
這個例子中簡單來講就只有四個動做,「重置」回到原點、「開始動做」、「向前移動」,「中止」。點擊「開始」按鈕,在「開始動做」中咱們只作了一個動做,「開門」動做,動做結束以後調用「forward」函數向前移動:url
function startAnim() { if (window.isAnimationRunning) { return; } reset(); window.isAnimationRunning = true;//動畫是否正在進行 ht.Default.startAnim({ frames: 30, // 動畫幀數,默認採用`ht.Default.animFrames`。 interval: 20, // 動畫幀間隔,默認採用`ht.Default.animInterval`。 finishFunc: function() {// 動畫結束後調用的函數。 forward(); }, action: function(t){ // action函數必須提供,實現動畫過程當中的屬性變化。 door.setRotationY(-120 * Math.PI / 180 * t); } }); }
這邊的「reset」函數就是「重置」回到原點的功能,咱們經過這個函數將全部變化過的都恢復初始的位置,包括「門」的位置:spa
function reset() { if (window.isAnimationRunning) { return; } g3d.setCenter([0,0,0]); g3d.setEye([523, 5600, 8165]); window.forwardIndex = 0; door.setRotationY(0); }
要「移動」,確定須要走路的「路徑」,也就是咱們剛剛獲取到的「path」,經過 window.points = path.getPoints()._as; 獲取「path」中的全部元素,初始化 window.forwardIndex = 0; 經過控制「path」中先後兩點來設置 3D 場景中的 Eye 和 Center,這樣就能營造一個咱們是第一人的效果:3d
var point1 = points[forwardIndex], point2 = points[forwardIndex + 1]; var distanceX = (point2.x - point1.x), distanceY = (point2.y - point1.y), distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY)-200;//兩點之間的距離經過三角形勾股定理計算 怕碰牆因此-200 g3d.setEye([point1.x, 1600, point1.y]);//眼睛 g3d.setCenter([point2.x, 1600, point2.y]);//我
HT 中 3D 組件有一個 walk(step, anim, firstPersonMode) 方法,該函數同時改變eye和center的位置,也就是eye和center在兩點創建的矢量方向上同時移動相同的偏移量。step爲偏移的矢量長度值。firstPersonMode參數爲空時則默認採用Graph3dView#isFirstPersonMode()當前值, 若是爲第一人稱模式調用walk操做,該函數會考慮Graph3dView#getBoundaries()邊界限制。code
g3d.walk(distance, { frames: 50, interval: 30, easing: function(t) {return t; }, finishFunc: function() { forwardIndex += 1; if (points.length - 2 > forwardIndex) {//points.length = 5 g3d.setCenter([point2.x, 1600, point2.y]);//把結束點變成起始點 g3d.rotate(Math.PI / 2, 0, { frames: 30, interval: 30, easing: function(t) {return t;}, finishFunc:function() { forward();} }); } else { var lastPoint = points[points.length - 1];//json 中path的points 的最後一個點 g3d.setCenter([lastPoint.x, 1400, lastPoint.y]); g3d.rotate(-Math.PI / 2, 0, { frames: 30, interval: 30, finishFunc: function() { window.isAnimationRunning = false; } }); } } });
無論「path」的點有多少個,這個判斷語句仍是能運做,只在最後一個點是跳出 finishFunc 動畫結束後調用的函數,並將 window.isAnimationRunning 值設爲 false 中止 startAnim 函數。若是不是最後一個點,用戶「旋轉」以後,回調 forward 函數。至此,所有代碼解釋完畢,很短的代碼量,卻作出了這麼大的工程!