Shader编程学习笔记(十六)—— 3D数学基础4 - 矩阵和行列式


1、引言

  本篇涉及知识点:

  • 2D旋转矩阵
  • 3D旋转矩阵
  • C#顶点变换demo

2、内容详情

  平时开发程序,免不了要对图像做各种变换处理。有的时候变换可能比较复杂,比如平移之后又旋转,旋转之后又平移,又缩放借助矩阵变换和矩阵乘法,可以将多个矩阵合成一个,最后用一个矩阵对每个顶点做一次处理就可以实现想要的效果,十分方便。 另外,矩阵乘法一般有硬件支持,比如3D 图形加速卡,处理3D变换中的大量矩阵运算,比普通CPU 要快上1000倍。

2.1、2D矩阵转换

  下面是3类基本的2D图形变换。

2.1.1、2D平移矩阵

  设某点向 x x x方向移动 d x d_x dx, y y y方向移动 d y d_y dy [ x y ] \begin{bmatrix} x& y \\ \end{bmatrix} [xy]为变换前坐标, [ X Y ] \begin{bmatrix} X&Y \\ \end{bmatrix} [XY]为变换后坐标。
X = x + d x , Y = y + d y X = x+d_x,Y = y+d_y X=x+dxY=y+dy

以矩阵表示如下
[ x y 1 ] × [ 1 0 0 0 1 0 d x d y 1 ] = [ x × 1 + y × 0 + 1 × d x x × 0 + y × 1 + 1 × d y x × 0 + y × 0 + 1 × 1 ] \begin{bmatrix} x& y &1 \\ \end{bmatrix}\times\begin{bmatrix} 1&0& 0 \\ 0&1&0\\ d_x&d_y&1 \\ \end{bmatrix} =\begin{bmatrix} x\times1 +y\times0 + 1\times d_x& x\times0+ y\times1+1\times d_y&x\times0+y\times0+1\times1 \\ \end{bmatrix} [xy1]×10dx01dy001=[x×1+y×0+1×dxx×0+y×1+1×dyx×0+y×0+1×1]
                = [ x + d x y + d y 1 ] =\begin{bmatrix} x + d_x& y+ d_y&1 \\ \end{bmatrix} =[x+dxy+dy1]
                = [ X Y 1 ] =\begin{bmatrix} X& Y &1 \\ \end{bmatrix} =[XY1]
那么平移转换矩阵为
[ 1 0 0 0 1 0 d x d y 1 ] \begin{bmatrix} 1&0& 0 \\ 0&1&0\\ d_x&d_y&1 \\ \end{bmatrix} 10dx01dy001

2.1.2、2D旋转矩阵

  在2D环境中,物体只能绕着某点旋转,因为现在暂时不考虑平移。这里我们进一步限制,使其只绕某点旋转。2D中绕原点的旋转只有一个参数:角度 α \alpha α,它描述了旋转量。通常逆时针经常被认为是正方向,顺时针是负方向。旋转相比平移稍稍复杂。

2.1.2.1、2D旋转矩阵公式

   设某点与原点连线和 X X X轴夹角为 β \beta β度,以原点为圆心,逆时针转过 α \alpha α度 , 原点与该点连线长度为R, [ x y ] \begin{bmatrix} x&y\\ \end{bmatrix} [xy]为变换前坐标, [ X Y ] \begin{bmatrix} X&Y\\ \end{bmatrix} [XY]为变换后坐标。

x = R × cos ⁡ ( β ) x=R\times\cos(\beta) x=R×cos(β)

y = R × sin ⁡ ( β ) y=R\times\sin(\beta) y=R×sin(β)

X = R × cos ⁡ ( α + β ) = R × cos ⁡ ( α ) × cos ⁡ ( β ) − R × sin ⁡ ( α ) × sin ⁡ ( β ) = x × cos ⁡ ( α ) − y × sin ⁡ ( α ) X=R\times\cos(\alpha+\beta)=R\times\cos(\alpha)\times\cos(\beta)-R\times\sin(\alpha)\times\sin(\beta)=x\times\cos(\alpha)-y\times\sin(\alpha) X=R×cos(α+β)=R×cos(α)×cos(β)R×sin(α)×sin(β)=x×cos(α)y×sin(α)

Y = R × sin ⁡ ( α + β ) = R × sin ⁡ ( α ) × cos ⁡ ( β ) + R × cos ⁡ ( α ) × sin ⁡ ( β ) = x × sin ⁡ ( α ) + y × cos ⁡ ( α ) Y=R\times\sin(\alpha+\beta)=R\times\sin(\alpha)\times\cos(\beta)+R\times\cos(\alpha)\times\sin(\beta)=x\times\sin(\alpha)+y\times\cos(\alpha) Y=R×sin(α+β)=R×sin(α)×cos(β)+R×cos(α)×sin(β)=x×sin(α)+y×cos(α)

用矩阵表示
[ x y ] × [ cos ⁡ ( α ) sin ⁡ ( α ) − sin ⁡ ( α ) cos ⁡ ( α ) ] = [ x × cos ⁡ ( α ) − y × sin ⁡ ( α ) x × sin ⁡ ( α ) + y × cos ⁡ ( α ) ] = [ X Y ] \begin{bmatrix} x& y \\ \end{bmatrix}\times\begin{bmatrix} \cos(\alpha)& \sin(\alpha) \\ -\sin(\alpha) & \cos(\alpha) \\ \end{bmatrix} =\begin{bmatrix}x\times\cos(\alpha)-y\times\sin(\alpha)& x\times\sin(\alpha)+y\times\cos(\alpha) \\\end{bmatrix}=\begin{bmatrix} X& Y \\ \end{bmatrix} [xy]×[cos(α)sin(α)sin(α)cos(α)]=[x×cos(α)y×sin(α)x×sin(α)+y×cos(α)]=[XY]
2D旋转矩阵的公式
    绕坐标中心(自转)旋转 α \alpha α角度
[ cos ⁡ ( α ) sin ⁡ ( α ) − sin ⁡ ( α ) cos ⁡ ( α ) ] \begin{bmatrix} \cos(\alpha)& \sin(\alpha) \\ -\sin(\alpha) & \cos(\alpha) \\ \end{bmatrix} [cos(α)sin(α)sin(α)cos(α)]
   任一点的旋转(自转)就是这个点与上面公式的乘法,即向量的乘法(行向量 × \times ×公式=旋转后的向量)。

2.1.2.1、C#2D旋转矩阵Demo

  开始之前我们现在这里放一个效果图:
在这里插入图片描述
任务目标:利用C#创建一个窗体应用程序。来绘制三角形,利用上面的2D旋转矩阵旋转公式来让三角形旋转。
创建一个名为MatrixTransform的C#窗体应用程序,添加三角形类Triangle,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace MatrixTransform
{
    /// <summary>
    /// 三角形
    /// </summary>
    class Triangle
    {
        PointF A, B, C;

        public Triangle(PointF A,PointF B,PointF C)
        {
            this.A = A;
            this.B = B;
            this.C = C;
        }

        /// <summary>
        /// 画三角形
        /// </summary>
        public void Draw(Graphics g)
        {
            Pen p = new Pen(Color.Red, 2);
            g.DrawLine(p,this.A,this.B);//直线AB
            g.DrawLine(p, this.B, this.C);//直线BC
            g.DrawLine(p, this.C, this.A);//直线CA

        }

        /// <summary>
        /// 旋转
        /// </summary>
        /// <param name="degree">角度</param>
        public void Rotate(int degree)
        {
            
            float angle = (float)(degree / 360.0f * Math.PI);//角度制转弧度制,需要注意的是这里的360.0f,如果是360可能无法旋转
            
            //根据旋转公式 点坐标(看成向量)和旋转公式相乘

            //A点
            float newX = (float)(A.X * Math.Cos(angle) - A.Y * Math.Sin(angle));
            float newY = (float)(A.X * Math.Sin(angle) + A.Y * Math.Cos(angle));
            A.X = newX;
            A.Y = newY;

            //B点
            newX = (float)(B.X * Math.Cos(angle) - B.Y * Math.Sin(angle));
            newY = (float)(B.X * Math.Sin(angle) + B.Y * Math.Cos(angle));
            B.X = newX;
            B.Y = newY;

            //C点
            newX = (float)(C.X * Math.Cos(angle) - C.Y * Math.Sin(angle));
            newY = (float)(C.X * Math.Sin(angle) + C.Y * Math.Cos(angle));
            C.X = newX;
            C.Y = newY;
        }
    }
}

   添加一个定时器用于刷新三角形,注意设置定时器启用,并设置50ms调用一次。
在窗体中添加以下方法:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MatrixTransform
{
    public partial class Form1 : Form
    {
        Triangle t;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.TranslateTransform(300, 300);
            t.Draw(e.Graphics);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Point A = new Point(0,-200);
            Point B = new Point(200, 200);
            Point C = new Point(-200, 200);
            t = new Triangle(A, B, C);
        }
		//事件
        private void timer1_Tick(object sender, EventArgs e)
        {
            t.Rotate(2);
            this.Invalidate();//设置时间无效已重新执行该事件,来从新绘制
        }
    }
}

   然后运行项目,发现三角形开始旋转了。如果觉得三角形有闪烁的感觉可以打开帧缓冲(double buffered)。

2.1.3、2D缩放矩阵
2.1.3.1、2D缩放矩阵公式1

   设某点坐标,在 x x x轴方向扩大 s x s_x sx倍, y y y轴方向扩大 s y s_y sy倍, [ x y ] \begin{bmatrix} x&amp; y \\ \end{bmatrix} [xy]为变换前坐标, [ X Y ] \begin{bmatrix} X&amp;Y \\ \end{bmatrix} [XY]为变换后坐标。

   X = s x × x X=s_x\times x X=sx×x

   Y = s y × y Y=s_y\times y Y=sy×y
用矩阵表示
[ x y ] × [ s x 0 0 s y ] = [ x × s x + y × 0 x × 0 + y × s y ] = [ x × s x y × s y ] = [ X Y 1 ] \begin{bmatrix} x&amp; y\\ \end{bmatrix}\times\begin{bmatrix} s_x&amp;0 \\ 0&amp;s_y\\ \end{bmatrix}=\begin{bmatrix} x\times s_x +y\times0&amp; x\times0+ y\times s_y \\ \end{bmatrix}=\begin{bmatrix} x\times s_x &amp; y\times s_y \\ \end{bmatrix}=\begin{bmatrix} X&amp; Y &amp;1 \\ \end{bmatrix} [xy]×[sx00sy]=[x×sx+y×0x×0+y×sy]=[x×sxy×sy]=[XY1]

那么缩放矩阵为
[ s x 0 0 s y ] \begin{bmatrix} s_x&amp;0 \\ 0&amp;s_y\\ \end{bmatrix} [sx00sy]

2.1.3.2、2D缩放矩阵公式2

那么沿任意轴 S S S缩放,其中 k k k为缩放因子, s x s y s_xs_y sxsy为缩放分量,缩放矩阵为
[ 1 + ( k − 1 ) × s x 2 ( k − 1 ) × s x × s y ( k − 1 ) × s x × s y 1 + ( k − 1 ) × s y 2 ] \begin{bmatrix} 1+(k-1)\times s_x^2&amp;(k-1)\times s_x\times s_y \\ (k-1)\times s_x\times s_y &amp;1+(k-1)\times s_y^2\\ \end{bmatrix} [1+(k1)×sx2(k1)×sx×sy(k1)×sx×sy1+(k1)×sy2]

2D基本的模型视图变换,就只有上面这3种,所有的复杂2D模型视图变换,都可以分解成上述3个。
比如某个变换,先经过平移,对应平移矩阵A, 再旋转, 对应旋转矩阵B,再经过缩放,对应缩放矩阵C.
则最终变换矩阵 T = ABC. 即3个矩阵按变换先后顺序依次相乘(矩阵乘法不满足交换律,因此先后顺序一定要讲究)。

2.2、3D矩阵转换

2.2.1、3D平移矩阵

那么平移转换矩阵为
[ 1 0 0 0 0 1 0 0 0 0 1 0 d x d y d z 1 ] \begin{bmatrix} 1&amp;0&amp; 0&amp;0 \\ 0&amp;1&amp;0&amp;0\\0&amp;0&amp;1&amp;0\\ d_x&amp;d_y&amp;d_z&amp;1 \\ \end{bmatrix} 100dx010dy001dz0001

2.2.2、3D旋转矩阵

沿 x x x轴旋转:
[ 1 0 0 0 cos ⁡ ( α ) sin ⁡ ( α ) 0 − sin ⁡ ( α ) cos ⁡ ( α ) ] \begin{bmatrix}1&amp;0&amp; 0 \\ 0&amp;\cos(\alpha)&amp; \sin(\alpha) \\0&amp; -\sin(\alpha) &amp; \cos(\alpha) \\ \end{bmatrix} 1000cos(α)sin(α)0sin(α)cos(α)
沿 y y y轴旋转:
[ cos ⁡ ( α ) 0 sin ⁡ ( α ) 0 1 0 − sin ⁡ ( α ) 0 cos ⁡ ( α ) ] \begin{bmatrix}\cos(\alpha)&amp;0&amp; \sin(\alpha)\\ 0&amp;1&amp;0\\-\sin(\alpha)&amp; 0&amp; \cos(\alpha) \\ \end{bmatrix} cos(α)0sin(α)010sin(α)0cos(α)
沿 z z z轴旋转:
[ cos ⁡ ( α ) sin ⁡ ( α ) 0 − sin ⁡ ( α ) cos ⁡ ( α ) 0 0 0 1 ] \begin{bmatrix} \cos(\alpha)&amp; \sin(\alpha)&amp;0 \\ -\sin(\alpha) &amp; \cos(\alpha) &amp;0\\ 0&amp;0 &amp;1\\ \end{bmatrix} cos(α)sin(α)0sin(α)cos(α)0001

2.2.3、3D缩放矩阵

沿任意轴 s s s轴缩放, k k k为缩放因子:
N ( s , k ) = [ p ′ q ′ r ′ ] = [ 1 + ( k − 1 ) × s x 2 ( k − 1 ) × s x × s y ( k − 1 ) × s x × s z ( k − 1 ) × s x × s y 1 + ( k − 1 ) × s y 2 ( k − 1 ) × s y × s z ( k − 1 ) × s x × s z ( k − 1 ) × s z × s y 1 + ( k − 1 ) × s z 2 ] N(s,k)=\begin{bmatrix} p&#x27; \\q&#x27; \\ r&#x27;\\ \end{bmatrix}=\begin{bmatrix}1+(k-1)\times s_x^2&amp;(k-1)\times s_x\times s_y &amp; (k-1)\times s_x\times s_z \\ (k-1)\times s_x\times s_y &amp;1+(k-1)\times s_y^2&amp;(k-1)\times s_y\times s_z \\(k-1)\times s_x\times s_z&amp;(k-1)\times s_z\times s_y &amp;1+(k-1)\times s_z^2 \\ \end{bmatrix} N(s,k)=pqr=1+(k1)×sx2(k1)×sx×sy(k1)×sx×sz(k1)×sx×sy1+(k1)×sy2(k1)×sz×sy(k1)×sx×sz(k1)×sy×sz1+(k1)×sz2

2.2.4、3D透视投影矩阵

透视投影矩阵: [ x y z 1 ] × [ 1 0 0 0 0 1 0 0 0 0 1 1 / d 0 0 0 0 ] = [ x y z z / d ] \begin{bmatrix} x&amp; y&amp;z&amp;1\\ \end{bmatrix}\times\begin{bmatrix} 1&amp;0&amp;0&amp;0 \\ 0&amp;1&amp;0&amp;0\\ 0&amp;0&amp;1&amp;1/d\\ 0&amp;0&amp;0&amp;0\\ \end{bmatrix}=\begin{bmatrix} x&amp; y&amp;z &amp;z/d \\ \end{bmatrix} [xyz1]×100001000010001/d0=[xyzz/d]
$$$$

2.3、变换的种类

2.3.1、变换的种类

在这里插入图片描述

2.3.2、变换的组合

其中 P P P表示点, M M M表示矩阵:

P 世 界 = P 物 体 × M 物 体 → 世 界 P_{世界} =P_{物体}\times M_{物体\rightarrow世界} P=P×M

P 相 机 = P 世 界 × M 世 界 → 相 机 P_{相机}=P_{世界}\times M_{世界\rightarrow相机} P=P×M
    = ( P 物 体 × M 物 体 → 世 界 ) × M 世 界 → 相 机 =(P_{物体}\times M_{物体\rightarrow世界})\times M_{世界\rightarrow相机} =(P×M)×M

由数学知识:矩阵满足乘法的结合律

P 相 机 = ( P 物 体 × M 物 体 → 世 界 ) × M 世 界 → 相 机 P_{相机}=(P_{物体}\times M_{物体\rightarrow世界})\times M_{世界\rightarrow相机} P=(P×M)×M
    = ( P 物 体 × M 物 体 → 世 界 ) × M 世 界 → 相 机 =(P_{物体}\times M_{物体\rightarrow世界})\times M_{世界\rightarrow相机} =(P×M)×M

而:

M 物 体 → 相 机 = M 物 体 → 世 界 × M 世 界 → 相 机 M_{物体\rightarrow相机}=M_{物体\rightarrow世界}\times M_{世界\rightarrow相机} M=M×M

P 相 机 = P 物 体 × M 物 体 → 相 机 P_{相机}=P_{物体}\times M_{物体\rightarrow相机} P=P×M

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

对酒当歌﹏✍

您的鼓励是我写作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值