从这里开始准备攻略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相关的知识,能够考虑怎样融入平常的活动或者页面里面,增长吸引力。