资讯专栏INFORMATION COLUMN

css3d-engine源码学习简析

魏宪会 / 1700人阅读

摘要:全景旋转首先学习一下基础坐标系这个只要记住一下轴各自方向就可以,下面分析会用到。

开始

从这里开始准备攻略webgl(准备挖新坑),Flutter框架当然也会继续补充,但是今天学习的不是webgl,而是css3d-engine这个库,因为之前搞活动看到了一个全景旋转活动就是使用这个库完成,颇为惊艳(一开始以为是webgl实现的,但是看了代码才知道用CSS3就可以完成,虽然觉得还是应该用webgl做比较合适),抱着好奇心于是学习一下,嗯,这个库设计相当精简,整个库的代码才800多行,所以代码看下来没啥压力,今天顺着一个例子来分析一下。

全景旋转

首先学习一下基础坐标系:

这个只要记住一下x,y,z轴各自方向就可以,下面分析会用到。

接下来就是今天分析的例子,也是来自css3d-engine的例子:

一个不停旋转的全景图,当然我们把镜头拉开一点,发现其实它是一个圆柱体不停在旋转:

只是我们的镜头刚好在圆柱体的里面,所以就看到全景图不停在旋转了。

再接着分析构建整个场景的代码:

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

这里会初始化整个舞台,也会创建默认的摄像机:

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:


我们在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相关的知识,可以考虑怎样融入日常的活动或者页面里面,增加吸引力。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/112782.html

相关文章

  • css3d-engine源码学习简析

    摘要:全景旋转首先学习一下基础坐标系这个只要记住一下轴各自方向就可以,下面分析会用到。 开始 从这里开始准备攻略webgl(准备挖新坑),Flutter框架当然也会继续补充,但是今天学习的不是webgl,而是css3d-engine这个库,因为之前搞活动看到了一个全景旋转活动就是使用这个库完成,颇为惊艳(一开始以为是webgl实现的,但是看了代码才知道用CSS3就可以完成,虽然觉得还是应该用...

    pinecone 评论0 收藏0
  • css3d-engine源码学习简析

    摘要:全景旋转首先学习一下基础坐标系这个只要记住一下轴各自方向就可以,下面分析会用到。 开始 从这里开始准备攻略webgl(准备挖新坑),Flutter框架当然也会继续补充,但是今天学习的不是webgl,而是css3d-engine这个库,因为之前搞活动看到了一个全景旋转活动就是使用这个库完成,颇为惊艳(一开始以为是webgl实现的,但是看了代码才知道用CSS3就可以完成,虽然觉得还是应该用...

    Amio 评论0 收藏0
  • Loader学习简析babel-loader

    摘要:用来转换内容,内部调用了方法进行转换,这里简单介绍一下的原理将代码解析成,对进行转译,得到新的,新的通过转换成,核心方法在中的方法,有兴趣可以去了解一下。将函数传入参数和归并,得到。通常我们是用不上的,估计在某些中可能会使用到。 什么是Loader? 继上两篇文章webpack工作原理介绍(上篇、下篇),我们了解到Loader:模块转换器,也就是将模块的内容按照需求装换成新内容,而且每...

    wpw 评论0 收藏0
  • Vue源码解析(5)-virtual-dom 实现简析

    传送门vdom原理

    darcrand 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<