原标题:H5打造3d场景不完全攻略(二): Amazing CSS3D

前言

对的,本文就是着重介绍如何使用CSS3中的3D变换打造出H5中的3D效果。灵感来源于造物节团队的3d引擎,因为使用方法比较复杂,也没有开源的API文档,于是想自己另外造个轮子,便开始了相关内容的学习和实践。

众所周知,目前市面上的H5 3D类库(如Three)、引擎(Egret)、构建工具(kpano、720云)都或存在体积太大、不开源、非免费、学习成本高等问题。对于我们较为熟悉的CSS3,为什么就不对它好好利用一把呢?诚然,CSS3存在我们比较清楚的短板,CSS对平面的渲染能力高,但是对3D建模方面便力不从心了。

我们知道3D的表现形式即让我们通过平面可从不同角度看到真实物体的展示效果。

在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,无数三角形面就能够组成各种形状的物体,如下图。

我们通常把这种网格模型叫做Mesh模型。给物体贴上皮肤,或者专业点就叫做纹理,那么这个物体就活灵活现了。最后无数的物体就组成了我们的3D世界。

Three中模型解析器的原理是将顶点数组将模型的顶点用数组储存起来,再利用three中的face函数取得定点数组中的三个或四个顶点的索引构成空间平面。如此反复,模型就被完整构造出来了。

于是,越复杂的物体就需要越多的网面拼接。而css中是不存在根据坐标建立空间平面的能力的。

(插个题外话,其实css有一个属性与坐标有关,那就是clip-path。这个属性的特性赋予了css3一定的建模能力。实现方法可参考这篇文章)

CSS3实现3D全景

上篇文章介绍了Web3D的一些表现形式,这里着重谈谈怎么以CSS3实现3D全景。下面会探索Three实现全景的方案,因为WebGL门槛和学习成本还是比较高的,不适于用于快速开发。造物节的CSS3d全景已有文章对其进行了技术探秘,但都未深入谈及具体实现方式。

要清晰理解实现方式,必须对CSS3的transform、perspective有一定的认识。

原理方面的东西我就不深入讲了,大家可以先看看这篇文章,对CSS3D有一个大致的概念。

CSS全景可通过建立柱形或者立方体再通过贴图方式实现。也许会有人问,球体行不行?实际上是不行的,球体模型由无数个极小的平面拼接构成连贯曲面,而CSS缺乏使平面扭曲的属性。球体模型我们可以使用上文提过的Clip-3d建造出,但是,贴图问题就解决不了了。

天空盒子

相信很多打造过或有了解过3d全景的同行们都知道这个概念。实际上Skybox就是一个立方体,通过给六个面贴上不同的,边缘可以无缝贴合的图片,再将视角伸入盒子内部。可以想象成我们自己站入了一个巨型立方体盒子内部,移动视角便能看到不同的场景。

1、贴图

来看一张天空盒子的贴图,剪头指向的边缘代表需要无缝贴合的边。

从上图可以看出只要相互贴合的两个面上的图像能够无缝拼接,那么再通过对各个面进行一定的旋转变换,天空盒子就能被打造出来了。

那么问题来了,怎么去拍摄制作这样的图片呢?这就需要通过一些专业软件了.

比如pano2vr,max等。其实,需要用到这些专业工具打造的全景对画质和拼合度的要求都非常高了,而单纯依靠CSS3中的变化给不了它们很好的体验。

但我们今天讨论的是某些运营活动H5打造的全景,此全景不一定真实存在,或者是和真实场景有一定的比例差距。

例如星空、海底。对于这类贴合度可人为改变的全景图的打造,我们可以采用现有的高清图片,再经由PS转换成六面全景图。

贴一篇文章

其实主要思想是

在一张大图上勾画出六个面的选取 >

选择大图中某个面的相邻面将其旋转到需要拼合的盒子的某个面上,使他们完美贴合 >

得到最合理的六面贴图后,观察有无创造出新的边缘,通过蒙版等工具使他们自然融合。

2、构造贴图完成就可以创建立方体了。首先将创建好的六个面切割出来,以front、back、left、right…命名标记位置。

.sence { -webkit-perspective: 1000px; } .cube { width: 500px; height: 500px; margin: 100px auto; transform-style: preserve-3d; } .cube img { width: 130px; height: 130px; position: absolute; } .cube img:nth-child(1) { } .cube img:nth-child(2) { transform: rotateY(180deg); } .cube img:nth-child(3) { transform: rotateY(90deg); } .cube img:nth-child(4) { transform: rotateY(-90deg); } .cube img:nth-child(5) { transform: rotateX(90deg); } .cube img:nth-child(6) { transform: rotateX(-90deg); }

准备好6个面,载入贴图。通过旋转,使得每个面旋转到相印的位置。如左边的面由原本面朝我们的图片绕Y轴逆时针旋转90°得到。(注意Y轴逆时针旋转是正数)

此时会得到下图这样的效果:

但是由于每个面的旋转中心都在其正中位置,因此还不能形成正方体。于是我们需要让每个面产生一定的位移。

贴一张坐标系图以助于大家理解。

现在首先让front位移到应该到的位置,由于全景图的镜头在立方体内部,因此,可以想象一下,我们需要将图片往后移动。移动距离很明显为立方体边长的一半。在这里是65px。得到下图结果。

.cube img:nth-child(1) { transform: translateZ(-65px); }

照这样看,是不是back位移为translateZ(65px),left为translateX(-65px),top translateY(-65px)呢?但结果并不是我们想要的。

重新看回上文空间坐标系的那张贴图,我们会发现,平面旋转后,其对应的三个轴的位置也改变了。如图片绕Y旋转后,Z轴指向为屏幕的水平方向。绕X旋转后,Z轴指向垂直方向。因此我们很容易发现,其实要将贴面移动到正确的位置,都只需要让他们translateZ(-width/2px)就可以了。

为了让大家容易理解,我这里设置了一个较大的perspective。要想得到全景的效果,我们将镜头拉近让它进入到box里面就可以了。

接下来绑定手势,就可以让它动起来啦。

部分代码:

viewer.on('touchstart', function(e) { x1 = e.targetTouches[0].pageX; - $(this).offset().left; y1 = e.targetTouches[0].pageY; - $(this).offset().top;});viewer.on('touchmove',function(){ var dist_x = x2 - x1, dist_y = y2 - y1, deg_x = Math.atan2(dist_y, perspective) / Math.PI * 180, deg_y = -Math.atan2(dist_x, perspective) / Math.PI * 180, i, c_x_deg += deg_x; c_y_deg += deg_y; cube.css('transform', 'rotateX(' + deg_x + 'deg) rotateY(' + deg_y + 'deg)');

})

Math.atan2(y,x) 方法:得到从 x 轴到点 (x,y) 之间的角度。对于空间左边系比较难理解,大家可以想象成一张以空间Z轴为Y轴的平面绕X轴正方向旋转的角度即为cube绕空间Y轴旋转的角度。

柱形

柱形全景也不算复杂。关于圆柱形的打造方法.

大家可以参考下这篇文章

有了这个基础,我们可以写一段函数快速构造柱形全景。

先来看下页面结构

function creCylinder(lenZ,pieceWid,angle,slice){ /* pieceWid 表示单个柱形块状宽度 angle表示柱形内角 slice表示有多少个面拼接 slice越多,拼合的面越接近曲面 */ var l = pieceWid*slice; // 画布全长 var ag = angle/slice // 旋转角度 var html = ''; /* 设置每个面的旋转角度和位移 因为要分割成多个面,所以应该为每个面的背景图设置不同的`background-position` */ for(var i=0,len=slice;i

'; } return html;}function renderPano(pieceWid,angle,slice){ var vw = $(window).width(); var RADIAN = 0.017453293; // 弧度制 将角度转成弧度 var innerAngle = angle/(2*slice); //内角,用来计算translateZ // 这里的原理和上文旋转木马链接一致 var lenZ = -(pieceWid/2)*Math.tan((90-innerAngle)*RADIAN); /* 因为默认是由画布的最左端开始旋转 所以处于我们面前的是画布的最左端和最右端及其连接处 要想画布中央显示再我们面前,这里需要给cube_bg加上一定的绕Y旋转角度 */ var rotate = ((angle/slice)*(slice-1))/2, perspective = -lenZ-5; var cube_bg = $('.cube_bg'), scene = $('.scene'); var cylinder = creCylinder(lenZ,pieceWid,angle,slice); cube_bg.html(cylinder).css('transform','rotateY('+rotate+'deg)'); scence.css('-webkit-perspective',perspective+'px'); //最后调用一下 renderPano(128,360,20);

html5 3d场景设计,H5打造3d场景不完全攻略(二): Amazing CSS3D相关推荐

  1. 什么是次世代游戏?零基础学习次时代游戏场景设计,打造真实场景

    对于刚开始了解建模的小白们来说,次时代建模总是个高大上的东西,很是羡慕那些大神能过做出那么精致的作品.那次时代游戏是什么?有什么特点?下面就和小编一起来了解一下吧~ 什么是次时代游戏? 次世代游戏即下 ...

  2. 一次完整的PWM电磁摆设计实验---含手工制板全攻略

    一次完整的PWM电磁摆设计实验---含手工制板全攻略 前面的话 一.自制电磁铁 1.获取原料,拆变压器 2.绕线圈 3.直接用次级线圈 二.实现电刷版的电磁摆 1.制作支架和摆杆 2.轴的设计 3.电 ...

  3. WeChat:微信小程序设计流程注册完善、设计开发、审核发布之详细攻略

    WeChat:微信小程序设计流程注册&完善.设计&开发.审核&发布之详细攻略 目录 微信小程序设计流程 1.注册 2.小程序信息完善 3.开发小程序 3.1.开发文档 3.2. ...

  4. Andriod界面设计的分辨率和尺寸适配全攻略 转载

    Andriod界面设计的分辨率和尺寸适配全攻略 转载 2016年09月27日 17:45:56 第一.屏幕尺寸: 一般表示是手机的实际物理尺寸,屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.5 ...

  5. CREO:CREO软件之装配设计之常见方法(主控件TOP DOWN设计、骨架模型TOP DOWN设计、记事本模型设计)简介之详细攻略

    CREO:CREO软件之装配设计之常见方法(主控件TOP DOWN设计.骨架模型TOP DOWN设计.记事本模型设计)简介之详细攻略 目录 CREO软件之装配设计之常见方法(主控件TOP DOWN设计 ...

  6. CREO:CREO软件之装配设计之实现四连杆机构设计案例应用(图文教程)之详细攻略

    CREO:CREO软件之装配设计之实现四连杆机构设计案例应用(图文教程)之详细攻略 目录 利用CREO软件实现装配设计之四连杆机构设计案例应用(图文教程) 1.创建四连杆

  7. 次时代游戏场景设计,这些3D游戏建模带你走上次时代巅峰

    对于刚开始了解建模的小白们来说,次时代建模总是个高大上的东西,很是羡慕那些大神能过做出那么精致的作品.那次时代游戏是什么?有什么特点?下面就和小编一起来了解一下吧~ 什么是次时代游戏? 次世代游戏即下 ...

  8. 将H5站点打包成app完美攻略

    文章目录 整理说明 HBuilder介绍 打包方法 问题解决 参考 臭味相投的朋友们,我在这里: 猿in小站:http://www.yuanin.net csdn博客:https://blog.csd ...

  9. 设计聊天机器人技术栈的终极攻略

    本文作者:Sébastien Fourault 原文地址:<The Ultimate Guide To Designing A Chatbot Tech Stack> 翻译:一熊翻译组 M ...

最新文章

  1. Python:新浪网分类资讯爬虫
  2. javascript、jQuery的扩展方法,扩展实例展示代码
  3. 转:AIX 5L 内存性能优化
  4. 结果方程模型(SEM)的理论和基本实现过程
  5. [转] 微软SQL Server 2008故障转移集群概述(Windows Server Failover Clustering (WSFC))
  6. Go -- pprof协程监控
  7. 软件体系结构的风格(转载)
  8. Python小知识: List的赋值方法,不能直接等于
  9. js函数、作用域和闭包
  10. 开源SUP对接API卡盟程序卡信乐v2.0源码
  11. 递增子序列 Increasing Subsequences
  12. clickjacking:X-frame-options header missing 漏洞解决办法
  13. mysql时间函数now()_获得当前日期时间的mysql函数now()
  14. PayPal贝宝工商银行无法提现,怎么办?
  15. 利用openssl之 htps服务端和客户端编写
  16. 史上最全!20/21届春招/秋招 实习/校招 JAVA面试全攻略!复习回顾这一篇就够了!
  17. hiber+spring继续找bug
  18. 数据库管理系统MFC实现
  19. OneDrive登录问题
  20. 《一千年以后》最后一百元

热门文章

  1. fastdfs-client使用
  2. 插入表格,插入图片,界面交互
  3. 证明,当x趋向于0时 sin x/x极限为1
  4. 利用docker部署TF深度学习模型(附件文件较大,并无上传。部署参考步骤即可)
  5. ICMP与DHCP(包含DHCP的全局配置模式与接口配置模式)
  6. 【无人车路径规划】Frenet下的无人车路径规划(Python代码实现)
  7. Python if else条件语句你懂了吗?
  8. 高等数学——微积分中的不定积分
  9. 国产数据库列表(275种)最全名录及产品信息一览
  10. android N 拨打电话流程(MO)