Shader編程學習筆記(十六)—— 3D數學基礎4 - 矩陣和行列式


1、引言

  本篇涉及知識點:

  • 2D旋轉矩陣
  • 3D旋轉矩陣
  • C#頂點變換demo

2、內容詳情

  平時開發程序,免不了要對圖像做各種變換處理。有的時候變換可能比較複雜,比如平移之後又旋轉,旋轉之後又平移,又縮放藉助矩陣變換和矩陣乘法,可以將多個矩陣合成一個,最後用一個矩陣對每個頂點做一次處理就可以實現想要的效果,十分方便。 另外,矩陣乘法一般有硬件支持,比如3D 圖形加速卡,處理3D變換中的大量矩陣運算,比普通CPU 要快上1000倍。

2.1、2D矩陣轉換

  下面是3類基本的2D圖形變換。

2.1.1、2D平移矩陣

  設某點向xx方向移動 dxd_x,yy方向移動 dyd_y[xy]\begin{bmatrix} x& y \\ \end{bmatrix}爲變換前座標, [XY]\begin{bmatrix} X&Y \\ \end{bmatrix}爲變換後坐標。
X=x+dxY=y+dyX = x+d_x,Y = y+d_y

以矩陣表示如下
[xy1]×[100010dxdy1]=[x×1+y×0+1×dxx×0+y×1+1×dyx×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}
               =[x+dxy+dy1]=\begin{bmatrix} x + d_x& y+ d_y&1 \\ \end{bmatrix}
               =[XY1]=\begin{bmatrix} X& Y &1 \\ \end{bmatrix}
那麼平移轉換矩陣爲
[100010dxdy1]\begin{bmatrix} 1&0& 0 \\ 0&1&0\\ d_x&d_y&1 \\ \end{bmatrix}

2.1.2、2D旋轉矩陣

  在2D環境中,物體只能繞着某點旋轉,因爲現在暫時不考慮平移。這裏我們進一步限制,使其只繞某點旋轉。2D中繞原點的旋轉只有一個參數:角度α\alpha,它描述了旋轉量。通常逆時針經常被認爲是正方向,順時針是負方向。旋轉相比平移稍稍複雜。

2.1.2.1、2D旋轉矩陣公式

   設某點與原點連線和XX軸夾角爲β\beta度,以原點爲圓心,逆時針轉過α\alpha度 , 原點與該點連線長度爲R,[xy]\begin{bmatrix} x&y\\ \end{bmatrix}爲變換前座標, [XY]\begin{bmatrix} X&Y\\ \end{bmatrix}爲變換後坐標。

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

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

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)

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)

用矩陣表示
[xy]×[cos(α)sin(α)sin(α)cos(α)]=[x×cos(α)y×sin(α)x×sin(α)+y×cos(α)]=[XY] \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}
2D旋轉矩陣的公式
    繞座標中心(自轉)旋轉α\alpha角度
[cos(α)sin(α)sin(α)cos(α)] \begin{bmatrix} \cos(\alpha)& \sin(\alpha) \\ -\sin(\alpha) & \cos(\alpha) \\ \end{bmatrix}
   任一點的旋轉(自轉)就是這個點與上面公式的乘法,即向量的乘法(行向量×\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

   設某點座標,在xx軸方向擴大 sxs_x倍,yy軸方向擴大sys_y倍,[xy]\begin{bmatrix} x&amp; y \\ \end{bmatrix}爲變換前座標, [XY]\begin{bmatrix} X&amp;Y \\ \end{bmatrix}爲變換後坐標。

   X=sx×xX=s_x\times x

   Y=sy×yY=s_y\times y
用矩陣表示
[xy]×[sx00sy]=[x×sx+y×0x×0+y×sy]=[x×sxy×sy]=[XY1] \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}

那麼縮放矩陣爲
[sx00sy]\begin{bmatrix} s_x&amp;0 \\ 0&amp;s_y\\ \end{bmatrix}

2.1.3.1、2D縮放矩陣公式2

那麼沿任意軸SS縮放,其中kk爲縮放因子,sxsys_xs_y爲縮放分量,縮放矩陣爲
[1+(k1)×sx2(k1)×sx×sy(k1)×sx×sy1+(k1)×sy2]\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}

2D基本的模型視圖變換,就只有上面這3種,所有的複雜2D模型視圖變換,都可以分解成上述3個。
比如某個變換,先經過平移,對應平移矩陣A, 再旋轉, 對應旋轉矩陣B,再經過縮放,對應縮放矩陣C.
則最終變換矩陣 T = ABC. 即3個矩陣按變換先後順序依次相乘(矩陣乘法不滿足交換律,因此先後順序一定要講究)。

2.2、3D矩陣轉換

2.2.1、3D矩陣平移矩陣

那麼平移轉換矩陣爲
[100001000010dxdydz1]\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}

2.2.2、3D矩陣旋轉矩陣

沿xx軸旋轉:
[1000cos(α)sin(α)0sin(α)cos(α)] \begin{bmatrix}1&amp;0&amp; 0 \\ 0&amp;\cos(\alpha)&amp; \sin(\alpha) \\0&amp; -\sin(\alpha) &amp; \cos(\alpha) \\ \end{bmatrix}
沿yy軸旋轉:
[cos(α)0sin(α)010sin(α)0cos(α)] \begin{bmatrix}\cos(\alpha)&amp;0&amp; \sin(\alpha)\\ 0&amp;1&amp;0\\-\sin(\alpha)&amp; 0&amp; \cos(\alpha) \\ \end{bmatrix}
沿zz軸旋轉:
[cos(α)sin(α)0sin(α)cos(α)0001] \begin{bmatrix} \cos(\alpha)&amp; \sin(\alpha)&amp;0 \\ -\sin(\alpha) &amp; \cos(\alpha) &amp;0\\ 0&amp;0 &amp;1\\ \end{bmatrix}

2.2.3、3D矩陣縮放矩陣

沿任意軸ss軸縮放,kk爲縮放因子:
N(s,k)=[pqr]=[1+(k1)×sx2(k1)×sx×sy(k1)×sx×sz(k1)×sx×sy1+(k1)×sy2(k1)×sy×sz(k1)×sx×sz(k1)×sz×sy1+(k1)×sz2] 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}

2.3、變換的種類

2.3.1、變換的種類

在這裏插入圖片描述

2.3.2、變換的組合

其中PP表示點,MM表示矩陣:

P=P×MP_{世界} =P_{物體}\times M_{物體\rightarrow世界}

P=P×MP_{相機}=P_{世界}\times M_{世界\rightarrow相機}
   =(P×M)×M=(P_{物體}\times M_{物體\rightarrow世界})\times M_{世界\rightarrow相機}

由數學知識:矩陣滿足乘法的結合律

P=(P×M)×MP_{相機}=(P_{物體}\times M_{物體\rightarrow世界})\times M_{世界\rightarrow相機}
   =(P×M)×M=(P_{物體}\times M_{物體\rightarrow世界})\times M_{世界\rightarrow相機}

而:

M=M×MM_{物體\rightarrow相機}=M_{物體\rightarrow世界}\times M_{世界\rightarrow相機}

P=P×MP_{相機}=P_{物體}\times M_{物體\rightarrow相機}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章