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

相关文章
相关标签/搜索