WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

栏目: 编程工具 · 发布时间: 5年前

内容简介:本节内容来自于小册WebGL 入门与实践第24节。前面介绍了 3D 变换的原理和算法实现,并通过一些简单的 demo 演示了变换效果,但这些 demo 都是使用 WebGL 技术渲染。本节我们暂时不使用 WebGL,而是改用前端同学最熟悉的 CSS 技术来实现 3D 效果,并进一步了解 CSS 中的 3D 属性和 WebGL 中 3D 概念的异同之处。下面是 CSS3 中的几个很重要的 3D 属性:

本节内容来自于小册WebGL 入门与实践第24节。

前面介绍了 3D 变换的原理和算法实现,并通过一些简单的 demo 演示了变换效果,但这些 demo 都是使用 WebGL 技术渲染。本节我们暂时不使用 WebGL,而是改用前端同学最熟悉的 CSS 技术来实现 3D 效果,并进一步了解 CSS 中的 3D 属性和 WebGL 中 3D 概念的异同之处。

CSS 中的 3D 属性

下面是 CSS3 中的几个很重要的 3D 属性:

  • transform:对 DOM 进行变换,相当于 WebGL 中对模型进行的变换。
  • transform-origin:设置变换的中心点。
  • perspective-origin:视点,相当于 WebGL 中摄像机的 X、Y 轴坐标。
  • perspective:视距,启用该属性相当于在 WebGL 中设置摄像机和 DOM 元素之间在 Z 轴方向上的距离,设置该属性不等于 0 时会自动启用透视投影效果。
  • transform-style:是否启用 3D 变换。
  • backface-visibility:背面是否可见。

本节我们主要讲述 CSS 中的变换属性 transform ,变换分为 基本变换矩阵变换 ,基本变换大家都比较熟悉了,本节不做过多介绍,我们主要介绍 矩阵变换组合变换

变换:transform

transform 是大家最常用的一个属性,我们经常会使用它实现一像素的边框和以及容器或者内容的水平、垂直居中,又或者利用它实现强制 GPU 渲染,提升动画性能。

transform 分为 2D 和 3D 变换,3D 变换只是在 2D 的基础上增加了 Z 轴方向的变换。

一般情况下,如果对一个 DOM 施加变换,那么变换的中心往往是 DOM 的中心位置,类比到 WebGL 中,也就是模型的中心,我们可以把 CSS 中的 DOM 看做 WebGL 中的模型。

transform 包含四个基本变换属性值: translaterotateskewscale ,对应的 3D 变换属性值为 translate3drotate3dscale3d

注意,skew 没有对应的 3D 变换设置。

基本变换大家应该都很熟悉了,后面重点要讲解的是 matrixmatrix3d 的计算与使用,以及 组合变换 的使用技巧。

当然,下面我们还是先回顾一下 transform 的基本用法。

平移

平移的使用方法:

  • translate(tx, ty)
  • translate3d(tx, ty, tz)
  • translateX(tx)
  • translateY(ty)
  • translateZ(tz)

将 dom 元素分别沿着 X、Y、Z 轴向平移 30 px。

/* 分别沿 X 轴和 Y 轴平移 30 px。*/
transform: translate(30px, 30px);
/* 分别沿 X 轴、 Y 轴、Z 轴平移 30 px。*/
transform: translate3d(30px, 30px, 30px);
/* 沿 X 轴平移 30 px。*/
transform: translateX(30px);
/* 沿 Y 轴平移 30 px。*/
transform: translateY(30px);
/* 沿 Z 轴平移 30 px。*/
transform: translateZ(30px);
复制代码

旋转

旋转用法也比较简单,在此不做过多描述。

  • rotate(angle),绕 Z 轴旋转。
  • rotate3d(x, y, z, angle)。绕轴 axis = {x:x, y:y, z:z} 旋转指定角度 angle
  • rotateX(angle),绕 X 轴旋转。
  • rotateY(angle),绕 Y 轴旋转。
  • rotateZ(angle),绕 Z 轴旋转。
/*绕 X 轴旋转 45 deg。*/
transform: rotate(45deg);
/* 将第一个参数设置为 1, 代表绕 X 轴旋转 45 deg。*/
transform: rotate3d(1, 0, 0, 45deg);
/* 将第二个参数设置为 1, 代表绕 Y 轴旋转 45 deg。*/
transform: rotate3d(0, 1, 0, 45deg);
/* 将第三个参数设置为 1, 代表绕 Y 轴旋转 45 deg。*/
transform: rotate3d(0, 0, 1, 45deg);
/* 将三个参数都设置为 1, 代表绕 Y 轴旋转 45 deg。*/
transform: rotateZ(45deg);
复制代码

绕任意轴的旋转。

关于旋转,我想说明一下 rotate3d 的使用方式,它接收一个 轴向量 和一个 角度 ,代表绕 轴向量 旋转某个 角度

举个例子来说,我们想让模型绕轴 axis= {x: 1,y: 1,z: 1}进行旋转,那么用rotate3d表示如下:

.box{
    animation: rotate 3s infinite linear;
}
@keyframes rotate{
    0% {
        transform:rotate3d(1, 1, 1, 0deg);
    }
    100% {
        transform:rotate3d(1, 1, 1, 360deg);
    }
}
复制代码
WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

变换参照点 transform-origin

根据上图的例子,你会发现,默认的旋转是绕着模型的中心位置进行的,这个位置是浏览器默认的。但事实上,CSS 仍然提供了对变换中心的设置功能,通过设置 transform-origin 来实现。

  • transform-origin 包含 X、Y、Z 轴坐标的设置。
  • transform-origin 接收百分比数值时,是以自身尺寸为基准的。

比如,我们让一个 DOM 元素沿着上边沿进行进行旋转,只需要将 transform-origin 的 Y 轴分量设置为 0% 或者 0 即可。

transform-origin: 50% 0%;
transform: rotateX(90deg);
复制代码
WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

这个概念比较简单,但是很灵活。利用它我们能实现很多有意思的 3D 效果,比如 CSS 版的 魔方

缩放

缩放的使用方法也很简单。

  • scale(sx, sy),沿 X 轴方向缩放 sx 倍,沿 Y 轴方向缩放 sy 倍。
  • scale(sx),沿 X 轴方向和 Y 轴方向缩放 sx 倍。
  • scale3d(sx, sy, sz),分别沿 X、Y、Z 轴方向缩放 sx、sy、sz 倍。
  • scaleX(sx),沿 X 轴方向缩放 sx 倍。
  • scaleY(sy),沿 Y 轴方向缩放 sy 倍。

代码示例:

/* 沿 X 轴和 Y 轴 放大两倍。*/
transform: scale(2);
/* 沿 X 轴方向当大 3 倍,沿 Y 轴方向放大 2 倍。*/
transform: scale(3, 2);
/* 分别在 X 、Y、 Z 轴方向放大 2倍、3倍、4倍。*/
transform: scale3d(2, 3, 4);
/* 在 X 轴方向放大两倍。*/
transform: scaleX(2);
/* 在 Y 轴方向放大两倍。*/
transform: scaleY(2);
复制代码

斜切

斜切的使用方法:

  • skew(xAngle, yAngle),DOM 元素沿着 X 方向切变 xAngle 度,沿 Y 轴方向切变 yAngle 度。
  • skewX(xAngle),沿 X 轴方向切变 xAngle 度。
  • skewY(yAngle),沿 Y 轴方向切变 yAngle 度。

斜切可以理解为将 DOM 元素沿 X 轴或者 Y 轴拉伸,切变会改变物体的形状。

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

代码示例:

/* 沿 X 轴切变 30 度。*/
transform: skew(30deg);
/* 沿 X 轴切变 30 度,沿 Y 轴切变 40 度。*/
transform: skew(30deg, 40deg);
/* 沿 X 轴方向切变 30 度。*/
transform: skewX(30deg);
/* 沿 Y 轴方向切变 40 度。*/
transform: skewY(40deg);
复制代码

以上就是 transform 的常见用法,接下来我们开始讲重点了: 组合变换matrix

组合变换

组合变换 就是在 transform 的属性值中附加多个变换效果,而不只是单一的变换。

比如下面这个变换样式:

transform: rotateX(60deg) rotateY(60deg);
复制代码

这个样式的作用是先让 DOM 元素绕着 X 轴旋转 60 度,注意此时 DOM 元素的坐标系改变了,再绕变换后的坐标系的 Y 轴旋转 60 度。

需要谨记的是:

动态坐标系变换
静态坐标系变换

至于多个变换是基于动态坐标系进行构思,还是基于静态的世界坐标系进行构思,取决于每个人的理解习惯,但最终的变换效果都是一样的。

在欧拉角章节我们也讲过了多个矩阵相乘时,从前往后和从后往前理解变换所基于的坐标系是不同的。transform 多个变换理解顺序和前面所讲的保持一致。

再举个比较明显的例子,我们先让 DOM 旋转 60 度,然后将其沿 X 轴平移 200 像素,大家觉得 DOM 会按照怎样的轨迹变换?

我们看一下:

transform: rotateX(60) translateX(200px);
复制代码

为了更方便观察 3D 组合变换的效果,我将图片外层容器的 视点 设置在了右上方:

.imgWrapper{
    perspective: 300px;
    margin-top:300px;
    position: relative;
    perspective-origin: 100% -100px;
}
复制代码

关于视点 perspective-origin 和 视距 perspective 我们放在下一节讲述。

从前往后理解变换,需要按照 模型坐标系 理解:

下图,白色坐标轴是图片默认的坐标系,当图片绕 X 轴旋转 60 度后,坐标系变成红色坐标轴的指向。

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

接着沿当前图片坐标系的红色 X' 轴平移 200 像素,此时,应该朝向屏幕里侧和右侧移动。

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

从后往前理解多个变换,需按照世界坐标系理解

请注意, CSS 中的 世界坐标系 就是 施加变换的 DOM 节点(本例为图片)最开始的坐标系,即图中的白色坐标轴。

  • 首先沿着 X 轴平移 200 像素。
  • 接着绕世界坐标系的 Y 轴旋转 60 度。
WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

可以看出,无论我们按照哪种坐标系理解,最终变换效果都是一样的,看下图:

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

这就是 组合变换 要注意的地方,了解了组合变换的规律,我们才能做出很有意思的特效,比如照片墙:

照片墙的核心原理就是先将图片沿着 Z 轴方向移动一定距离,之后绕世界坐标系的Y 轴旋转指定角度。

transform: rotateY(30deg) 200px;
复制代码

当然,这只是核心原理,事实上我们还需要做如下几步:

  • 让图片能够显示出 3D 效果,这一步需要让图片父容器的 transform-style 属性设置为 preserve-3d
  • 为父容器加上透视属性 perspective ,设置为透视投影,并调整合适的视距 ,这样才能实现近大远小的效果。

这几个属性我们下节细讲,先贴下照片墙的效果:

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

具体的实现我们在讲视点和视距属性时再分析。

又比如 3D 盒效果:

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

这是一个立方体盒子,每个面上都对应一张图片,当然,你也可以根据自己的需要往各个面上放置自己的内容。

立方体盒子的原理也是利用组合变换实现的:

  • 前面:沿着 Z 轴往前(朝向屏幕外)平移指定像素。
  • 后面,沿着 Z 轴往后(朝向屏幕里)平移指定像素。
  • 上面,沿着 Y 轴往上平移,接着绕 X 轴旋转 90 度。
  • 下面,沿着 Y 轴往下平移,接着绕 X 轴旋转 90 度。
  • 左面,沿着 X 轴往左平移,接着绕 Y 轴旋转 90 度。
  • 右面,沿着 X 轴往右平移,接着绕 Y 轴旋转 90 度。

当然,为了实现 3D 效果,也要在图片的父容器上设置 transform-stylepreserve-3d 才可以。

这里主要展示组合变换顺序的理解与强大,不对实现做分析, 实现过程 留在下一节和 视点 以及 视距 一起介绍。

我们还是先把变换讲完,接下来介绍 transform 的另一个重要用法, matrixmatrix3d

matrix

transform 除了提供一些基本变换,还提供了 matrixmatrix3d 属性值,这两个属性值是做什么的呢?

matrix 是矩阵的意思,transform 是变换属性,所以 matrix 就是对 DOM 执行变换的矩阵,这和我们前面讲的 WebGL 的变换矩阵概念相同。

根据前面的学习,我们知道 2 维平面的变换矩阵,是一个 3 阶矩阵,包含 9 个数字:

按照我们之前章节坐标系变换的原理分析:

  • x0、x1 代表变换之后的 X 轴基向量在原坐标系中的表示。
  • y0、y1 代表变换之后的 Y 轴基向量在原坐标系中的表示。
  • tx、ty 代表坐标原点的偏移量。

如果没有看之前章节的话,可能不太理解基向量的含义以及坐标系的概念,大家可以去看一下,理解一下坐标系变换的原理。

你会看到第三行的数值是固定的 0 0 1 ,所以,浏览器为了简化赋值,规定 transform 中的 matrix 只接受 3 阶矩阵的前两行参数,共 6 个数字。

请记住,matrix 的参数顺序对应上面的矩阵元素如下:

transform: matrix(x0, x1, y0, y1, tx, ty);
复制代码

前面章节我们推导过基本变换的矩阵表示:

  • 平移

沿 X 轴平移 tx 像素,沿 Y 轴平移 ty 像素:

  • 缩放

沿 X 轴方向缩放 sx 倍, 沿 Y 轴缩放 sy 倍:

也就是说基本变换我们都可以用 matrix 来表示。

  • 斜切 沿着 X 轴倾斜 α 度,沿着 Y 轴倾斜 θ 度:
  • 旋转

绕 Z 轴旋转 θ 角度:

  • 绕 Z 轴旋转 60 度。

用 rotateZ 表示上面的旋转很简单,我们看下用 matrix 如何表示:

将这两个数字代入 matrix 公式,得出变换样式为:

transform: matrix(0.5, 0.866, -0.866, 0.5, 0, 0);
复制代码

你会发现无论我们是用 rotateZ 表示,还是用 matrix 表示,变换效果都是一样的。

matrix3d

matrix3d,顾名思义,代表 3 维变换,它是一个 4 阶矩阵,需要 16 个数字来表示。

可以看到,每一个基向量都增加了一个 Z 轴方向分量 x2、y2、z2、tz。

事实上,3D 的基本变换都可以用 matrix 或者 matrix3d 来表示,但是一些复杂变换只能使用 matrix 或者 matrix3d 来实现。

matrix 对我们来说有什么用呢?

这是一个很关键的问题,大家会觉得,基本变换的用法更容易理解,更方便书写,matrix 需要的参数太多,而且参数值需要计算,更糟糕的是,我们往往不知道怎么计算,那 matrix 有什么用呢?

这是个好问题,但我想说的是 matrix 能完成基本变换不能完成的变换,能做出基本变换完成不了的效果。

这时你就该考虑使用 matrix 了。

紧跟而来的问题是,matrix 如何求得呢?

我们前面章节讲述了 matrix 矩阵的求法,一旦你确定了需要的变换,你就可以计算变换后的基向量,然后将基向量的各个分量代入矩阵的各个位置即可求出变换矩阵,有了变换矩阵,也就有了 matrix 所需要的各个元素,将矩阵转化成 matrix 或者 matrix3d 所需要的字符串就轻而易举了。

  • 镜像效果

镜像效果,采用基本变换是实现不了的,只能借助于矩阵。 比如左右镜像,左右镜像无非就是 Y 轴基向量不变,X 轴坐标对调,原坐标与新坐标关系如下:

所以有:

将这些值,代入 matrix公式中,可以得出变换:

transform: matrix(-1,0,0,1,0,0);
复制代码

我们看下效果:

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

当然大家也可以举一反三,比如上下镜像:

transfom: matrix(1,0,0,-1,0,0)
复制代码
WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform
  • 绕任意轴旋转。

绕任意轴的旋转,除了可以使用 rotate3d 来实现,还可以使用 matrix3d。这个旋转矩阵该如何计算呢?

还记得基本变换章节我们推导出的绕固定轴旋转的矩阵方法 axisRotation 吗?

axisRotation(axis, angle) ,其中 axis 是一个三维向量,angle 是一个弧度值。

这里我不准备举绕基本轴旋转的例子,因为它们不需要matrix3d 出手,我们想绕 {x:1, y: 1, z: 1} 的倾斜轴旋转,上面的 axisRotation 方法该出场了,它会为我们提供变换矩阵,但是我们还需要将变换矩阵转化为 css 样式,我们先封装一个矩阵转 css 的方法:

function matrix2css(mt){
    var transformStyle = 'matrix(';
    if(mt.length == 16){
        css = 'matrix3d('
    }
    for(let i =0; i< mt.length; i++){
        transformStyle += mt[i];
        if(i !== mt.length - 1){
            transformStyle += ','
        }else{
            transformStyle +=')'
        }
    }
    return transformStyle;
}
复制代码

接着可以通过 axisRotation 方法计算出变换矩阵了,比如旋转 90 度。

let mt = matrix.axisRotation({x:1, y:1, z:1}, Math.PI / 180 * 90)
复制代码

在这里我用绕轴向量 axis = {x:1, y:1, z:1} 不停旋转的动画演示:

function render(){
    if(!playing){
        return;
    }
    angle ++;
    mt = matrix.axisRotation({x: 1,y: 1,z: 1}, Math.PI / 180 * angle);
    let css = matrix2css(mt);
    $$('.box')[0].style.transform = css;
    requestAnimationFrame(render);
}
document.body.addEventListener('click',function(){
  playing = !playing;
  render();
})
复制代码
WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

是不是很简单呢?

总结

transform 中的基本变换都可以使用 matrix 和 matrix3d 来表示,只有当基本变换表示不了我们的变换时,我们才考虑使用 matrix 或者 matrix3d 。

可见,即使不做 WebGL 开发,我们之前学到的内容也会对普通开发者大有帮助,掌握变换原理,配合 CSS3 中的 3D 属性,一样可以做出很酷炫的 3D 动画效果。

回顾

本节讲述了 CSS 中的 3D 变换,以及它们与 WebGL 变换的相同之处。总的来说,基本原理都是一样的,之前封装的数学矩阵库,不仅可以用在 WebGL 领域,也可以用在 css 领域。

下一节,我们讲述 CSS 中 3D 变换 的其它几个重要属性, 变换类型(transform-style)视点(perspective-origin)视距(perspective)

小册

这一系列的内容来自于小册 WebGL 3D 入门与实践,如果大家对进阶知识感兴趣,可以到小册中去学习: 小册:WebGL 3D 入门与实践

小册内容除了包含 WebGL 相关的基础练习,还包括 3D 图形概念与相关数学的原理与推导,旨在帮助大家建立图形学的技术轮廓。这部分图形学知识独立于 WebGL,除了可以适用于 WebGL,还适用于 OpenGL 等。

当然,本小册主要目的还是帮助 Web 前端同学学习 3D 技术,除了介绍适用 WebGL 实现 3D 效果以外,还对 CSS3 中的 3D 技术相关属性进行了深入剖析,并演示了与数学库的结合使用,希望能够让前端同学不仅仅局限于一般的二维平面开发,也能够在 3D 开发上更近一步~

WebGL 3D 入门系列:深入研究 --- CSS 与 3D 之 transform

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

仿生智能计算

仿生智能计算

科学出版社 / 2011-1 / 50.00元

《仿生智能计算》系统、深入地介绍了仿生智能计算的起源、原理、模型、理论及其应用,力图概括国内外的最新研究进展。全书共分12章,主要包括仿生智能计算的思想起源、研究现状及机制原理,仿生智能计算的数学基础;蚁群算法、微粒群算法、人工蜂群算法、微分进化算法、Memetic算法、文化算法、人工免疫算法、DNA计算的原理、模型、理论和典型应用,以及仿生硬件、仿生智能计算研究前沿与展望。附录给出了各章算法的程......一起来看看 《仿生智能计算》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具