css里的3d理念

使用css3的3d transform,就可以在平面的网页里添加炫酷的三维视觉效果,这很令人愉悦。

需要注意的是,3d transform只是css的一部分,它并不是一个三维引擎(3d engine)。三维引擎一般是这样的(游戏引擎Unity3D):

包括JavaScript 3D库three.js在内,简单来说,它们这些可以称为三维引擎的,都会包括:

独立的三维坐标系统。

几何图形和材质贴图。

光照和摄像机。

3d transform和它们相比起来,是缺少这些内容的。毕竟,css的关注点是网页样式,而不是创建虚拟空间。

尽管3d transform的三维空间能力有所不足,但它仍然可以创建出很棒的三维效果。这就需要我们开发者来用心了。

在下面的内容开始之前,如果你还对perspective等3d transform相关的css属性完全不了解,可以阅读我以前写的css三维变换的文章。

3d transform的坐标系统

我们很熟悉的网页是平面的,一个DOM元素,比如一个

,它会有一个初始坐标系(initial coordinate system):

每一个DOM元素都有一个这样的初始坐标系。其中,原点位于元素的左上角,z轴指向观察者(也就是屏幕外的我们)。初始坐标系的z轴并不算是三维空间,而是像z-index那样作为参照,决定网页元素的绘制顺序,绘制顺序靠后的元素将覆盖绘制顺序靠前的。

在使用transform的时候,情况则有所不同。transform所参照的并不是初始坐标系,而是一个新的坐标系:

transform所用的这个坐标系,相比初始坐标系,x、y、z轴的指向都不变,只是原点位置移动到了元素的正中心。如果想要改变这个坐标系的原点位置,使用transform-origin。transform-origin的默认值是50% 50%,因此,默认情况下,transform坐标系的原点位于元素中心。

transform的顺序

我们都可能像transform: rotateY(45deg) translateX(100px);这样使用多个变换函数。这种时候,需要意识到变换函数的顺序。这是因为,每一个变换函数不仅改变了元素,同时也会改变和元素关联的transform坐标系,当变换函数依次执行时,后一个变换函数总是基于前一个变换后的新transform坐标系。

例如,下面一个包含两个变换函数的transform的效果(gif):

如果交换这两个变换函数的顺序,是这样的效果:

可以看到,由于坐标系会随着每一次变换发生改变,因此不同顺序的情况下,元素最终的位置也不同。

对此还有一种解释,即变换函数是通过数学上的矩阵乘法运算完成的,而矩阵的乘法是不满足交换律的。任意坐标空间内的变换函数或者变换函数的组合,都可以转换为一个矩阵(还有一个矩阵小工具可以帮你做这个转换)。

创建三维物体

前面已经提到,3d transform并没有像三维引擎那样为你创建三维场景提供全面的资源。因此,就以创建一个三维物体来说,我们只能利用网页目前已有的内容,自己想办法。

在网页里,你并不能直接定义一系列坐标为(x, y, z)的空间中的点,然后基于这些点来生成三维图形。网页里有的,是平面图形。不管是

还是其他html元素,它们都是平的,没有厚度,像纸片一样。但纸片就可以搭东西,所以,一个DOM元素用作三维物体的一个“面”,把这些“面”有序地组织起来,得到的就是三维物体了!

事实上,在三维引擎里,三维物体也不是实体,它们都是由一系列平面(多边形)所围成的(并可以在平面上添加纹理和贴图)。

正方体

现在来做一个正方体,现在先不用考虑perspective。正方体有六个面,然后需要用一个元素来装这六个面,所以html是:

1
2
3
4
5
6

对应的css是(边长120px,省略浏览器私有前缀,后文同):

.cube{

position: absolute;

transform-style: preserve-3d;

}

.cube .surface{

position: absolute;

width: 120px;

height: 120px;

border: 1px solid #ccc;

background: rgba(255,255,255,0.8);

box-shadow: inset 0 0 20px rgba(0,0,0,0.2);

line-height: 120px;

text-align: center;

color: #333;

font-size: 100px;

}

.cube .surface-1 {

transform: translateZ(60px);

}

.cube .surface-2 {

transform: rotateY(90deg) translateZ(60px);

}

.cube .surface-3 {

transform: rotateX(90deg) translateZ(60px);

}

.cube .surface-4 {

transform: rotateY(180deg) translateZ(60px);

}

.cube .surface-5 {

transform: rotateY(-90deg) translateZ(60px);

}

.cube .surface-6 {

transform: rotateX(-90deg) translateZ(60px);

}

其中,transform-style: preserve-3d;保证所有子元素都处于同一个三维空间(这里是三维渲染上下文3D rendering context)内,也就是告诉浏览器你是想用这些元素做一个三维场景,而不仅仅只是要单个元素的简单三维效果。

position: absolute;是一个习惯做法,因为三维物体并不符合一般平面网页内容的排版,所以我们会比较多地希望它不要占据布局空间。

6个面位置都不一样,但却都有translateZ(60px);,你已经知道这是因为巧妙搭配了在它之前的变换函数。

一旦构成正方体的6个div.surface的位置确定后,就可以操作它们的父元素div.cube来整体移动、旋转这个正方体。

将三维物体添加到可视区域

只是有了这样的一个三维物体,我们就可以说有了一个三维场景了。但是,三维场景和平面图不同,比如这个正方体,我从不同的位置,不同的角度去观察它,我眼里看到的都是不一样的:

那么,这样的三维场景要如何呈现在平面的网页里呢?

这就是三维引擎里的摄像机的概念来源了。就像电影里表现同一个场景会用不同的镜头那样,我们需要定义场景里的摄像机来生成最终呈现在屏幕里的二维画面。比如three.js里的摄像机是这样的感觉:

这个图里标明的是摄像机定义时使用的参数,其中包括视野范围,图像宽高比等。可以感受到还是有很多内容的。

相比之下,网页里的三维场景摄像机就弱多了,你需要用的是perspective和perspective-origin。

perspective定义摄像机(也就是作为观众的我们)到屏幕的距离,perspective-origin定义摄像机观察到的画面中的灭点(vanishing point)的位置。虽然它们并不能方便地让你直接定义摄像机的位置和观察角度等,但只要适当地应用它们,是可以一定程度上控制摄像机的画面效果的。

控制摄像机画面

网页里的摄像机一般是这样用的:

.camera{

position: relative;

perspective: 1200px;

perspective-origin: 50% 50%;

transform-style: preserve-3d;

}

在网页里,无论你搭建了怎样的三维场景,只要你希望它显示出来,就应该像这样把构成场景的三维物体都放在一个容器元素里,然后为容器元素添加摄像机属性(perspective和perspective-origin)。

此外,还需要注意添加transform-style: preserve-3d;以保证多个三维物体都位于同一空间(这样才有三维引擎的味道,对吧?)。

下面这个场景里有三个正方体,然后摄影师正在做弹跳练习(限支持3d transform的浏览器):

这段动作的动画代码是这样:

.camera{

animation: cameraMove 2s ease-out infinite alternate both;

}

@keyframes cameraMove{

0%{

perspective-origin: 50% 180px;

}

100%{

perspective-origin: 50% -200px;

}

}

可以看出,perspective-origin虽然是指三维透视的灭点的位置,但它的确和我们理解的摄像机的位置是紧密关联的。如果摄像机在空间里的位置是(x, y, z)的话,perspective-origin的两个值有一点像指定x和y的感觉。这里只说“有一点像”,是因为灭点位置和摄像机的位置毕竟是不同的概念,这可能还需要多看一些三维空间来体会。

那么,在上面的例子中,摄影师不只是这样跳起来,而是想要向更深处前进,应该怎么做呢?

答案是,在网页里,你不能这样移动摄像机,你需要换一个思路,参照相对运动的关系,改为让整个三维场景向你移动。不过,说到这里,前面提到的摄像机的另一个属性,perspective,为什么它不行呢?

perspective代表摄像机距离屏幕的距离,看上去和z轴深度非常近似。但是,它并不等同于摄像机的z坐标位置(perspective还只能取正值),而是会影响摄像机本身的其他属性。下面用这个图说明perspective的值变化的效果(修改自w3c的配图):

图中d1和d2分别表示两个不同的perspective的值,其中d2小于d1。然后,你会惊奇地发现,一个原本位于屏幕之后(z坐标为负值)的物体,竟然是随着“走近”而变得更小了!显然,这不符合我们在三维空间里运动的基本感受。其原因是,网页的三维投影平面是固定的,perspective在改变摄像机的位置的同时,也同时改变了摄像机本身的其他属性(类似前面的three.js的摄像机那张图里的各种参数)。

所以,一般来说,perspective应维持一个固定的值。想要用3d transform做出在三维空间里自由移动的效果(就像各种3d游戏),应该通过相对运动的方法实现。

其他补充

transform对布局的影响

transform影响的是视觉渲染,而不是布局。因此,除以下情况外,transform不会影响到布局:

这个因为overflow生成滚动条从而影响布局的反例,也发生于position: relative;再进行偏移的情况。

left、top等常规属性对3d transform的影响

相对于transform的translate3d()这类改变空间位置的变换函数,原来css里就有的定位属性left、top似乎会让情况变得很复杂。

对此,有一个比较推荐的分析方式:就三维空间的位置而言,常规属性left、top,甚至margin-left等,是先生效的,它们的效果其实只有一个,就是改变元素的初始位置,从而改变元素的transform-origin的那个原点位置,然后三维空间的transform是后生效的,它会再基于前面的transform-origin继续改变位置。

perspective-origin和transform-origin的区别

现在你已经了解到,perspective-origin是一个摄像机的属性,定义的是透视画面的灭点,而transform-origin是任意元素都有的,定义的是的元素的transform坐标系的原点。

结语

本文是我对目前网页里用3d transform创建三维空间的总结,其中混入了一些三维引擎的知识,并对比着来一一说明。感觉3d transform还是有自己比较明确的定位的,虽然和三维引擎相比很简陋,但它已经足够用来为网页添加吸引人的三维效果。

如果你也想过用3d transform做稍复杂的三维空间,希望本文能有所帮助。

java3d box 坐标,3d transform的坐标空间及位置相关推荐

  1. html 3d坐标,3d transform的坐标空间及位置_html/css_WEB-ITnose

    css里的3d理念 使用css3的3d transform,就可以在平面的网页里添加炫酷的三维视觉效果,这很令人愉悦. 需要注意的是,3d transform只是css的一部分,它并不是一个三维引擎( ...

  2. 3d transform的(x、y、z)坐标空间及位置

    原文出处:http://acgtofe.com/posts/2015/12/xyz-3d-in-css css里的3d理念 使用css3的3d transform,就可以在平面的网页里添加炫酷的三维视 ...

  3. 将3D坐标转成2D坐标的方法

    将3D坐标转成2D坐标的方法.3D坐标在Unity中称作World Space,2D坐标称作Screen Space, 是以pixel为基准,以iPad 1024 x 768(4:3)的解析度为例子: ...

  4. MNI152 坐标空间和 fsaverage 坐标空间相互转换, 如已知fsaverage空间的坐标如何求MNI152 坐标?aparc.a2009s.annot转化到MNI152空间?

    MNI152 坐标空间和 fsaverage 坐标空间相互转换 原理 下载和安装 调用脚本 求aparc.a2009s.annot的MNI152空间的坐标 Step1: 从fsaverage转化到MN ...

  5. threejs 将屏幕坐标转换成3d中的坐标。

    将当前屏幕上的坐标转换成3d中的坐标pos 是当前canvas屏幕上的坐标,targetZ 是物体距离原点的距离 private get3DPosByCanvasPos (pos: THREE.Vec ...

  6. 好吧,CSS3 3D transform变换,不过如此!

    by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=2592 一.写在前面 ...

  7. CSS3 3D transform变换,不过如此

    (这篇关于css 3d的文章算是开启了我的css3d概念了,确实写的很容易理解,小编苦苦寻找的经典好文) 一.写在前面的秋裤 早在去年的去年,我就大肆介绍了2D transform相关内容.看过海贼王 ...

  8. css 3d transform

    原文:大神传送门 一.写在前面的秋裤 早在去年的去年,我就大肆介绍了2D transform相关内容.看过海贼王的都知道,带D的家伙都不是好惹的,2D我辈尚可以应付,3D的话,呵呵,估计我等早就在千里 ...

  9. CSS3 3D transform变换

    transform的坐标是需要了解的特性. 我们的rotateX,rotateY,rotateZ,和translateX,translateY等都是基于相同的坐标系来定位的. 3D的坐标如下入所示: ...

最新文章

  1. A* 算法之父、人工智能先驱Nils Nilsson逝世 | 缅怀
  2. java.lang.Instrument 动态修改替换类代码
  3. css3的动画详解 html直接可以运行
  4. 绘制条形图python_小白学Python(13)——pyecharts 绘制 柱状图/条形图 Bar
  5. python list index方法,Python List.index()方法
  6. html js控制页面蒙版,JavaScript蒙板(model)功能的简单实现代码
  7. .net框架读书笔记---.net文本处理(字符)
  8. 关于计算机犯罪的英语作文,关于信息安全的英语作文范文
  9. (四)Paint函数实现QTableView中增加QCheckBox的方法
  10. 蓝桥杯 PREV-37 历届试题 分巧克力
  11. 深入浅出C/C++中的正则表达式库(一)--GNU Regex Library
  12. Windows服务器:切断默认共享通道七招
  13. mysql 改变 执行计划_诡异的MySql执行计划的更改
  14. 单臂路由实验(子接口的使用)
  15. 如何提升微服务的幸福感 | 凌云时刻
  16. 红旗linux桌面版_瑞星ESM杀毒软件For Linux获红旗兼容性认证
  17. paddlepaddle手写字体识别
  18. linux命令之文件和目录操作
  19. Windows下的conda换源和pip换源
  20. c语言临时内存变量释放,C语言中的内存分配与释放

热门文章

  1. Android应用程序组件Content Provider简要介绍和学习计划
  2. MySQL与MongoDB设计实例对比
  3. 博客订阅代码de制作
  4. Java 修饰符、运算符笔记总结
  5. 导入Excel表里的数据时产生【定义了过多字段】,但有时又是成功的
  6. Oracle面试题及答案整理
  7. jQuery遇见的转化关联数组为json的坑
  8. PHP保留小数三种方法
  9. java文件打包jar文件_Java打包成jar文件,以及将jar文件导出为exe文件方法汇总(图形说明)...
  10. 接口使用jwt返回token_JWT实现token验证