從這裏開始準備攻略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相關的知識,能夠考慮怎樣融入平常的活動或者頁面裏面,增長吸引力。