css3d-engine源碼學習簡析

開始

從這裏開始準備攻略webgl(準備挖新坑),Flutter框架固然也會繼續補充,可是今天學習的不是webgl,而是css3d-engine這個庫,由於以前搞活動看到了一個全景旋轉活動就是使用這個庫完成,頗爲驚豔(一開始覺得是webgl實現的,可是看了代碼才知道用CSS3就能夠完成,雖然以爲仍是應該用webgl作比較合適),抱着好奇心因而學習一下,嗯,這個庫設計至關精簡,整個庫的代碼才800多行,因此代碼看下來沒啥壓力,今天順着一個例子來分析一下。css

全景旋轉

首先學習一下基礎座標系:
圖片描述
這個只要記住一下x,y,z軸各自方向就能夠,下面分析會用到。css3

接下來就是今天分析的例子,也是來自css3d-engine的例子:
圖片描述git

一個不停旋轉的全景圖,固然咱們把鏡頭拉開一點,發現其實它是一個圓柱體不停在旋轉:
圖片描述github

只是咱們的鏡頭恰好在圓柱體的裏面,因此就看到全景圖不停在旋轉了。web

再接着分析構建整個場景的代碼:瀏覽器

var s = new C3D.Stage();
 s.size(window.innerWidth, window.innerHeight).material({
    color: "#cccccc"
 }).update();

這裏會初始化整個舞臺,也會建立默認的攝像機:app

initialize: function (params) {
    ...
    this.el.style[prefix + 'Perspective'] = '800px';
    this.el.style[prefix + 'TransformStyle'] = 'flat';
    this.el.style[prefix + 'Transform'] = '';
    this.el.style.overflow = 'hidden';
    
    this.__rfix = new C3D.Sprite();
    this.el.appendChild(this.__rfix.el);
    
    this.__pfix = new C3D.Sprite();
    this.__rfix.el.appendChild(this.__pfix.el);
    
    this.setCamera(new C3D.Camera());
}

Stage初始化的時候,設置默認的perspective是設爲800px,並且會建立兩個Sprite輔助構建場景(這兩個Sprite做用至關的大,場景旋轉,拉進拉遠都是靠這兩個Sprite),最後設置攝像機;當調起update方法而後會順着調起Stage的updateT方法:框架

updateT: function () {
            this.fov = fixed0(0.5 / Math.tan((this.camera.fov * 0.5) / 180 * Math.PI) * this.height);
            this.el.style[prefix + 'Perspective'] = this.fov + 'px';
            this.__rfix.position(fixed0(this.width / 2), fixed0(this.height / 2), this.fov).rotation(-this.camera.rotationX, -this.camera.rotationY, -this.camera.rotationZ).updateT();
            this.__pfix.position(-this.camera.x, -this.camera.y, -this.camera.z).updateT();
            return this;
        },

這裏能夠算是整個Stage計算的核心了,首先是Stage的fov計算,它依賴了Camera的fov,而Camera的fov默認就是75(由於人的有效視角就是75度),接着整個計算其實就是一個已知角度和對邊求鄰邊的公式:
圖片描述佈局

這裏計算方式其實出自Three.js,github上的討論
回到Stage剛纔初始化的時候,一開始一口氣建立三個嵌套的div:學習

<!--示例,方便分析-->
<div id="stage">
    <div id="__rfix">
        <div id="__pfix"></div>
    </div>
</div>

咱們在stage設置好perspective屬性,在個人電腦(全屏)上計算出來的是619px,根據剛纔的公式,是跟你們的瀏覽器高度有關,而後設置__rfix元素位置:屏幕居中,重點是Z軸位置的設置,能夠看到設置的剛計算出來perspective等於translateZ(619px),因此如今的位置(記住一開始的座標系,往屏幕外的爲正,也就靠近視點):
圖片描述

而後設置__pfix的位置,Z軸方向上,取了攝像機相反的方向,由於咱們通常理解攝像機拉遠拉近都是攝像機在移動,可是整個場景往相反方向移動其實也能夠達到相同效果,因此這裏就是整個場景移動來到作到的:
圖片描述

如今再看,在剛纔代碼能夠看到當camera的x,y,z更新的時候,其實經過位移__pfix來作到的;而camera的rotateX,rotageY,rotateZ更新的時候,則是經過旋轉__rfix來作到的。爲何這樣的設置,咱們剛纔看到__rfix把tranlateZ設置到視點上,其實目的是爲了讓後面的元素能夠以視點爲原點進行佈局,這樣咱們佈局時能夠經過控制跟視點的距離進而控制用戶視野;而旋轉的時候也能夠以視點爲原點進行旋轉,x,y,z移動也是以視點爲原點進行,能夠想象當鏡頭拉遠200px,再沿x軸旋轉45度的場景。

基本舞臺的構建已經明白了,繼續全景旋轉是怎樣作出來的:
首先整個場景是由20張129*1170的圖片組成一個圓柱體,那麼這個圓柱體的半徑是多少尼?經過如下計算:

0.5* 129 / Math.tan(360 / 20 / 2 / 180 * Math.PI)

得出407px,因此代碼上把整個場景放到-400px也是應該根據這個半徑得出來的:

var pano = this.createPano(bgData, panoRect);
  pano.position(0, 0, -400).updateT();

因此如今整個場景是這樣的(可能橢圓更合適一點):
圖片描述

總結

這個庫仍是很不錯的庫,也學習到一些3D相關的知識,能夠考慮怎樣融入平常的活動或者頁面裏面,增長吸引力。

相關文章
相關標籤/搜索