sundway / blog

oh~~
110 stars 6 forks source link

矩阵变换 #5

Open sundway opened 7 years ago

sundway commented 7 years ago

矩阵变化是一个常用的概念,常用多个参数值同时变化,例如《SVG滤镜对图片调色》 这篇文章中对颜色 rgb 的转换就是利用的矩阵变换。同时,CSS、SVG 中的缩放,旋转以及形变底层其实就是依赖的矩阵变换。

2D 中的矩阵变换

首先,看一个比较简单的 2D 中的矩阵转换,明白 2D 的矩阵转换原理之后,3D 的也是同样的思路。现在有一个二维空间的点A(x, y, 1) 坐标为:x, y。需要对这个点进行一个位移变换,那么可以利用一个矩阵可以对左边进行偏移,矩阵为:[1, 0, x', 0, 1, y', 0, 0, 1]。上面的两个矩阵相乘的一个结果就是:(x + x', y + y', 1)。那么,通过设置 x', y' 就可以对坐标 A 进行一个偏移。

缩放

通过上面的矩阵乘法 [a, c, e, b, d, f, 0, 0, 1] 与左边点进行运算,我们可以得到新坐标:(ax + cy + e, bx + dy + f, 1)。根据上面的公式我们可以轻松的发现要实现对坐标进行缩放,只需要让 c, e, b, f 等于 0 即可。那么得到的结果就是 (ax, dy, 1),a 和 d 分别控制对 x, y 的缩放。

旋转

旋转会稍微复杂一点,二维空间的旋转都是绕 z 轴旋转。那么,坐标 A(x, y)旋转之后的坐边关系可以用公式表示:[consθ, sinθ, -sinθ, conθ, 0, 0, 0, 0, 1]。具体的推到公式可以参考这篇文章

3D 中的矩阵变换

理解了 2D 中的矩阵变换之后,3D 中的矩阵变换就很容易理解了,这里可以直接参考 three.js 的源码

scale: function ( v ) {

    var te = this.elements;
    var x = v.x, y = v.y, z = v.z;

    te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
    te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
    te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
    te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;

    return this;

}

上面的 this.elements 初始化值是一个不做任何转换的矩阵[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]。所以上面的操作其实就是相当于矩阵重新赋值[v, 0, 0, 0, 0, v, 0, 0, 0, 0, v, 0, 0, 0, 0, v]之后,再与左边进行矩阵运算。接下来看看位移矩阵:

makeTranslation: function ( x, y, z ) {
    this.set(
        1, 0, 0, x,
        0, 1, 0, y,
        0, 0, 1, z,
        0, 0, 0, 1
    );
    return this;
}

很明显的看出这个跟上面解释的 2D 的矩阵变换同理,最后得到的坐标为:x' = x(原坐标) + x, y' = y(原坐标) + y, z' = z(原坐标) + z。旋转的代码就不贴了,分别对应三个轴进行一个三角函数的变换计算出对应的矩阵。

其它

矩阵很方便的时间这些变换,还可以定义很多复杂变换的矩阵。threejs 还封装了很多常见的矩阵,比如绕任意轴进行旋转,如果用简单的变换进行组合会比较复杂。但是理解矩阵之后,就会发现矩阵实现这些效果简单而强大。