矩阵的乘法运算与css的3d变换(transform)

矩阵,乘法,运算,css,3d,变换,transform · 浏览次数 : 49

小编点评

* 生成内容时需要带简单的排版。 * 矩阵乘法运算可以用于简化css3d transform的运算过程。 * 硬件加速可以用于提升css3d transform的性能。 * 矩阵乘法运算可以用于简化css3d transform的运算过程。 * 生成内容时需要带简单的排版。

正文

theme: qklhk-chocolate
  1. 引言:你有没好奇过,在一个使用了transform变换的元素上使用window.getComputedStyle(htmlElement)['transform'] 查询出来的值代表什么?
  1. 为什么硬件加速要使用transform,以及为什么硬件加速会快?

小科普:关于矩阵的乘法

	以两个二阶齐次矩阵相乘为例
	[                 [                      [
	 a11,a12,     *     b11,b12,       =      a11*b11 + a12* b21 , a11*b12 + a12*b22,
	 a21,a22            b21,b22               a21*b11 + a22* b21 , a21*b12 + a22*b22
	]                  ]                      ]

由此,可以看到两个矩阵相乘就是拿第一个的每一行,乘以第二个的每一列,因此两个矩阵相乘也有个规定就是第一个矩阵的列数(每一行元素的个数),要与第二个矩阵的行数(每一列元素的个数)相等才可以发生乘法运算。

首先回答第一个问题: 由window.getComputedStyle(htmlElement)['transform']查询出来的值代表一个matrix3d函数的参数,形如matrix3d(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4)

其中a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3,代表了线性变换,a4 b4 c4 d4代表的是位移变换。若空间中点的表示是一个列向量表示,那么,他的矩阵形式应该是这样的:

  a1 a2 a3 a4
  b1 b2 b3 b4
  c1 c2 c3 c4
  d1 d2 d3 d4

在下边的例子中我们都假定空间中的点是以列向量形式表示的。使用右手坐标系。

(实际这里也可以写成该矩阵的转置形式,在下边进行乘法运算时都分别转置下,然后交换两个矩阵的位置也是可以的,结果是一样的)

3d变换的初始矩阵如下:

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

这是一个单位矩阵,这样的矩阵满足矩阵乘法运算的交换律,且和整数中1的作用一样,乘以任何数还是任何数,因此单位矩阵与其他矩阵的乘法运算不产生任何效果。

translate

translate代表一个位移变换,3d的translate变换矩阵对应的是一个如下的4阶齐次矩阵 T :

 1 0 0 dx
 0 1 0 dy
 0 0 1 dz
 0 0 0 1

假设空间内某个点D的坐标形如:

 x
 y
 z
 1

给他施加一个translate矩阵之后就可以得到的结果为 T*D :

 1*x + 0*y + 0 * z + dx,               x + dx
 0*x + 1*y + 0 * z + dy,         =     y + dy
 0*x + 0*y + 1 * z + dz,               z + dz
 0 +   0   +  0    + 1,                   1

以上的变换写成matrix3d函数的形式就是:
matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, dx, dy, dz, 1)
等价于:
translate3d(x,y,z)

变换矩阵的前三行可以分别看做一个空间坐标系上对某个点要施以某种变换的x,y,z轴上的表示,每一行的前三列代表x,y,z轴上具体要有的变换,比如在位移变换矩阵中第一行代表x轴上该点要做的变换,那么对应的y,z的值为0。(这是我个人的一点思考。可跳过。。。)

scale

scale表示的是一个缩放变换,缩放的具体数值体现在主对角线上,比如一个1.5倍的缩放矩阵S:

1.5   0   0   0
 0   1.5  0   0
 0    0  1.5  0
 0    0   0   1

给上边的点D施加一个缩放矩阵得到的结果是 S*D:

	1.5*x + 0*y   + 0*z  + 0 * 1      1.5x
    0*x  + 1.5*y + 0*z  + 0 * 1   =  1.5y
    0*x +  0*y +  1.5*z + 0 * 1      1.5z
    0*x +  0*y +   0*z  + 1 * 1       1

等价于:
matrix3d(1.5, 0, 0, 0, 0, 1.5, 0, 0, 0, 0, 1.5, 0, 0, 0, 0, 1)
可简写为:
scale3d(1.5, 1.5, 1.5)

rotate

rotate 代表旋转

二维平面的rotate

二维平面的rotate代表某个点绕着某个点旋转,一个二维变换可以使用一个三阶齐次矩阵表示,其矩阵的推导可以这么推导:

  1. 首先是主对角线上的缩放数值,和第三列的位移值,都为默认值1(代表原始大小)和0(代表原始位置):
1 0 0
0 1 0
0 0 1
  1. 我们拿如下二维坐标系举例:
    image

将两个单位向量分别在x y轴上旋转θ角度,得到的A'便是x轴上旋转矩阵的值,得到的B' 便是y轴上旋转矩阵的值,因此2d的旋转矩阵是这样的(图片上的坐标系是以行向量表示的,为了统一 我们进行一次转置):

cos0   -sin0
sin0   cos0

3d空间的rotate

在一个3d空间中,旋转不再是绕某个点的旋转,而是绕某个轴的旋转(x,y,z轴),以绕x轴的旋转举例(这个图有点出入,实际BB'应该与y轴是平行的,AA'与Z轴平行,理解就好,没办法绘画功底实在太差 - -,绕某个轴旋转就是想象该条轴不动然后另一条与他垂直的轴绕着其旋转):
image

因此绕x轴的旋转矩阵可以写成这样:

1    0    0     0
0  cos0  -sin0  0
0  sin0   cos0  0
0    0     0    1

我们可以写一个rotateX(60deg),那么对应的matrix3d的参数就是:
matrix3d(1, 0, 0, 0, 0, 0.5, 0.866025, 0, 0, -0.866025, 0.5, 0, 0, 0, 0, 1)
同理可得出绕z轴和y轴的旋转矩阵:

Z:
cos0 -sin0 0 0
sin0 cos0  0 0
 0    0    1 0
 0    0    0 1
 
 Y:
 cos0   0   sin0   0
  0     1     0    0
 -sin0  0   cos0   0
  0     0     0    1

至此,css中的3d变换大体上讲完了,然后将以上几种矩阵经过不同组合相乘就能得到复合变换,值得注意的是 矩阵乘法一般不满足交换律,所以运算顺序还是比较重要的。

那为什么图形变换在计算机中一般使用矩阵表示呢?据我现在看到的资料来看,就是方便,使用矩阵运算之后,可以将多种变换统一成矩阵的乘法运算,方便计算机流水线式处理。
最后回答一下第二个问题:

2.为什么硬件加速要使用transform,以及为什么硬件加速会快?
第一点是因为css的3d transform属性使用在一个元素上该元素会被提升成一个单独的layer,在一个单独的layer上使用一些变换可以直接跳过浏览器渲染的一般流程layout,paint,直接在计算结束之后进行一次composite ,这是快的第一点, 第二点是因为使用transform变换的元素其运算发生在gpu上,而gpu的多核在处理并发运算的时候本身就要比cpu快 基本是这样。

最后分享一个矩阵的乘法运算,可以验证一下css transform相关的矩阵运算

 // 矩阵相乘
 function multipy(a,b){
        let r = a.length;
        let col = a[0].length;
        let result = [];
        for( let i = 0; i < r; i++ ){

            let row = a[i];
            result[i] = [];

            for( let j = 0; j < r; j++){
                let count = 0;
                for( let x = 0;x < col; x++ ){
                    let item1 = row[x];
                    let item2 = b[x][j]
                    count += (item1*item2)
                }
                result[i].push(count)


            }
        }
        return result;

    }
    const deg45 = Math.PI/4;

后记
image-preview是一款移动端图片浏览器插件,在这个分支得提交中 将变换矩阵直接应用到了实际应用中,基本得图形变换已经全部由变换矩阵实现。

与矩阵的乘法运算与css的3d变换(transform)相似的内容:

矩阵的乘法运算与css的3d变换(transform)

theme: qklhk-chocolate 引言:你有没好奇过,在一个使用了transform变换的元素上使用window.getComputedStyle(htmlElement)['transform'] 查询出来的值代表什么? 为什么硬件加速要使用transform,以及为什么硬件加速会快?

【OpenVINO™】在 C# 中使用OpenVINO™ 部署PP-YOLOE实现物体检测

PP-YOLOE是基于PP-YOLOv2的优秀单级无锚模型,超越了各种流行的YOLO模型。PP-YOLOE有一系列型号,命名为s/m/l/x,通过宽度乘数和深度乘数进行配置。PP-YOLOE避免使用特殊的运算符,如可变形卷积或矩阵NMS,以便友好地部署在各种硬件上。 在本文中,我们将使用OpenVI...

行列式求值,从 $n!$ 优化到 $n^3$

前置知识 \(\sum\) 为累加符号,\(\prod\) 为累乘符号。 上三角矩阵指只有对角线及其右上方有数值其余都是 \(0\) 的矩阵。 如果一个矩阵的对角线全部为 \(1\) 那么这个矩阵为单位矩阵记作 \(I\)。 对于矩阵 \(A_{n,m}\) 和矩阵 \(B_{m,n}\) 满足 \

umich cv-2-1

UMICH CV Linear Classifiers 对于使用线性分类器来进行图片分类,我们可以给出这样的参数化方法: 而对于这样一个式子,我们怎么去理解呢? 首先从代数的角度,这个f(x,W)就是一张图片的得分,我们可以将一张图片所有的像素点输入,乘以一个权重矩阵,再加上一个偏置项b,就得到f(

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用

稀疏矩阵的概念 一个m×n的矩阵是一个由m行n列元素排列成的矩形阵列。矩阵里的元素可以是数字、符号及其他的类型的元素。 一般来说,在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵;与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。定义非零

manim边学边做--Matrix

在代数问题中,矩阵是必不可少的工具,manim中提供了一套展示矩阵(Matrix)的模块,专门用于在动画中显示矩阵格式的数据。关于矩阵的类主要有4个: Matrix:通用的矩阵 IntegerMatrix:元素是整数的矩阵 DecimalMatrix:元素包含小数的矩阵 MobjectMatrix:

CSR格式如何更新? GES图计算引擎HyG揭秘之数据更新

摘要:HyG图计算引擎采用CSR格式来存储图的拓扑信息,CSR格式可以将稀疏矩阵的存储空间压缩,进而大大降低图的存储开销,同时具备访问效率高、格式易转化等优点。 本文分享自华为云社区《CSR格式如何更新? GES图计算引擎HyG揭秘之数据更新》,作者: π 。 HyG图计算引擎采用CSR格式来存储图

umich cv-2-2

UMICH CV Linear Classifiers 在上一篇博文中,我们讨论了利用损失函数来判断一个权重矩阵的好坏,在这节中我们将讨论如何去找到最优的权重矩阵 想象我们要下到一个峡谷的底部,我们自然会选择下降最快的斜坡,换成我们这个问题就是要求权重矩阵相对于损失函数的梯度函数,最简单的方法就是使

【精选】矩阵加速

大家好,我是Weekoder! 今天要讲的内容是矩阵加速! 这时候就有人说了: \(\tiny{\texttt{Weekoder 这么蒻,怎么会矩阵啊。还给我们讲,真是十恶不赦!}}\) 不不不,容我解释。在经过我的研究后,我发现基本的矩阵运算和矩阵加速都并没有那么难。只要继续往下看,相信你也能学会

Pandas 使用教程 Series、DataFrame

[TOC] Pandas 一个强大的分析结构化数据的工具集,基础是 Numpy(提供高性能的矩阵运算) Pandas 可以从各种文件格式比如 CSV、JSON、SQL、Microsoft Excel 导入数据。 Pandas 可以对各种数据进行运算操作,比如归并、再成形、选择,还有数据清洗和数据加工