2D变换矩阵

平移矩阵

Screenshot 2023-01-14 at 2.25.40 PM.png

旋转矩阵

Screenshot 2022-12-29 at 8.15.41 PM.png

示例代码

using UnityEngine;

public class Matrix2DTransformDemo : MonoBehaviour
{
 MeshRenderer _renderer;
 MeshFilter _filter;
 Mesh _mesh;

 void Awake()
 {
 if (!TryGetComponent(out _renderer))
 {
 _renderer = gameObject.AddComponent();
 _renderer.sharedMaterial = new Material(Shader.Find("Standard"));
 }
 if (!TryGetComponent(out _filter))
 {
 _filter = gameObject.AddComponent();
 _mesh=GenerateTriangleMesh();
 _filter.sharedMesh = _mesh;
 }
 }
 void FixedUpdate()
 {
 Rotate(_mesh,1);
 }

 private Mesh GenerateTriangleMesh()
 {
 Mesh mesh = new Mesh();
 mesh.vertices = new[]
 {
 new Vector3(0, 0.25f, 0),//0
 new Vector3(0.25f, -0.25f, 0),//1
 new Vector3(-0.25f, -0.25f, 0),//2
 };
 mesh.triangles = new[]
 {0,1,2};
 mesh.RecalculateNormals();
 return mesh;
 }

 private void Rotate(Mesh mesh,int degree)
 {
 float angle = degree * Mathf.PI/180;
 Vector3[] vertices = mesh.vertices;
 for (int i = 0; i < vertices.Length; i++)
 {
 vertices[i]=TransformVertex(vertices[i],angle);
 }
 mesh.SetVertices(vertices);
 mesh.RecalculateNormals();
 }
 private Vector3 TransformVertex(Vector3 vertex,float angle)
 {
 var newX = vertex.x * Mathf.Cos(angle) - vertex.y * Mathf.Sin(angle);
 var newY = vertex.x * Mathf.Sin(angle) + vertex.y * Mathf.Cos(angle);
 vertex.Set(newX,newY,vertex.z);
 return vertex;
 }
}

2D缩放矩阵

Screenshot 2022-12-30 at 9.39.30 PM.png

3D变换矩阵

3D平移矩阵

Screenshot 2023-01-14 at 2.31.15 PM.png

平移矩阵也称位移矩阵,平移矩阵用到了第四列(w列),这也是为什么三维空间变换矩阵为什么是四维的。平移矩阵也比较容易理解,因为可以通过结果看出想x 、y、z确实各自平移了T步。

15.png

3D旋转矩阵

💡 绕不同的坐标轴进行旋转的3D矩阵

RoateMat.png

3D缩放矩阵

Screenshot 2022-12-30 at 10.14.25 PM.png

13.png

3D旋转矩阵与平移矩阵相乘

Screenshot 2023-01-14 at 3.43.45 PM.png

透视投影

Screenshot 2023-01-14 at 3.47.06 PM.png

透视投影矩阵

Screenshot 2023-01-14 at 3.50.15 PM.png

变换的种类

Untitled

Screenshot 2022-12-30 at 10.30.09 PM.png

变换的组合

Screenshot 2022-12-31 at 2.53.04 PM.png

C#顶点变换demo

1.编写矩阵Matrix4x4,与其对应的矩阵乘法方法

internal struct Matrix4x4
 {
 float[,] elements=new float[4,4];

 public Matrix4x4()
 {
 elements[0, 0] = 1;
 elements[1, 1] = 1;
 elements[2, 2] = 1;
 elements[3, 3] = 1;
 }
 public float this[int i, int j]
 {
 get { return elements[i - 1, j - 1]; }
 set {elements[i - 1, j - 1]= value;}
 }

 public Matrix4x4 Mul(Matrix4x4 matrix)
 {
 Matrix4x4 result= new Matrix4x4();

 for (int h = 1; h <= 4; h++)
 {
 for (int l = 1; l <= 4; l++)
 {
 for (int n = 1; n <= 4; n++)
 {
 result[h, l] += this[h, n] * matrix[n, l]; 
 }
 }
 }
 return result;
 }

 public Vector4 Mul(Vector4 vector)
 {
 Vector4 result=new Vector4();
 result.x = this[1, 1] * vector.x + this[1, 2] * vector.y + this[1, 3] * vector.z + this[1, 4] * vector.w;
 result.y = this[2, 1] * vector.x + this[2, 2] * vector.y + this[2, 3] * vector.z + this[2, 4] * vector.w;
 result.z = this[3, 1] * vector.x + this[3, 2] * vector.y + this[3, 3] * vector.z + this[3, 4] * vector.w;
 result.w = this[4, 1] * vector.x + this[4, 2] * vector.y + this[4, 3] * vector.z + this[4, 4] * vector.w;
 return result;
 }
 }

2.编写向量Vector4,与其对应的乘法方法

internal struct Vector4
 {
 public float x, y, z, w;
 public Vector4(float x, float y, float z, float w)
 {
 this.x = x;
 this.y= y;
 this.z = z;
 this.w = w;
 }
 public Vector4 Mul(Matrix4x4 matrix)
 {
 Vector4 result = new Vector4();

 result.x = this.x * matrix[1, 1] + this.y * matrix[2,1]+this.z* matrix[3, 1] + this.w * matrix[4,1];
 result.y = this.x * matrix[1, 2] + this.y * matrix[2, 2] + this.z * matrix[3, 2] + this.w * matrix[4, 2];
 result.z = this.x * matrix[1, 3] + this.y * matrix[2, 3] + this.z * matrix[3, 3] + this.w * matrix[4, 3];
 result.w = this.x * matrix[1, 4] + this.y * matrix[2, 4] + this.z * matrix[3, 4] + this.w * matrix[4, 4];
 return result;
 }
 }
  1. 编写CubeMesh类,初始化顶点数据,编写绘制图形与Transform方法
internal class CubeMesh
 {
 public Vector4[] vertices;

 public Vector4[] vertices_transformed;

 public CubeMesh()
 {
 vertices =new Vector4[8];
 vertices[0] = new Vector4(-0.5f, 0.5f, -0.5f, 1);
 vertices[1] = new Vector4(0.5f, 0.5f, -0.5f, 1);
 vertices[2] = new Vector4(-0.5f, -0.5f, -0.5f, 1);
 vertices[3] = new Vector4(0.5f, -0.5f, -0.5f, 1);

 vertices[4] = new Vector4(-0.5f, 0.5f, 0.5f, 1);
 vertices[5] = new Vector4(0.5f, 0.5f, 0.5f, 1);
 vertices[6] = new Vector4(-0.5f, -0.5f, 0.5f, 1);
 vertices[7] = new Vector4(0.5f, -0.5f, 0.5f, 1);
 vertices_transformed = new Vector4[8];
 }

 public void Transform(Matrix4x4 matrix)
 {
 for (int i = 0; i < vertices.Length; i++)
 {
 vertices_transformed[i] = vertices[i].Mul(matrix);
 }
 }

 private PointF GetPoint( Vector4 vector)
 {
 return new PointF(vector.x/vector.w, vector.y / vector.w);
 }
 public void Draw(Graphics g)
 {

 Pen pen = new Pen(Color.Red);

 g.DrawLine(pen, GetPoint(vertices_transformed[0]), GetPoint(vertices_transformed[1]));
 g.DrawLine(pen, GetPoint(vertices_transformed[1]), GetPoint(vertices_transformed[3]));
 g.DrawLine(pen, GetPoint(vertices_transformed[3]), GetPoint(vertices_transformed[2]));
 g.DrawLine(pen, GetPoint(vertices_transformed[2]),GetPoint(vertices_transformed[0]));

 g.DrawLine(pen, GetPoint(vertices_transformed[4]), GetPoint(vertices_transformed[5]));
 g.DrawLine(pen, GetPoint(vertices_transformed[5]), GetPoint(vertices_transformed[7]));
 g.DrawLine(pen, GetPoint(vertices_transformed[7]), GetPoint(vertices_transformed[6]));
 g.DrawLine(pen, GetPoint(vertices_transformed[6]), GetPoint(vertices_transformed[4]));

 g.DrawLine(pen, GetPoint(vertices_transformed[0]), GetPoint(vertices_transformed[4]));
 g.DrawLine(pen, GetPoint(vertices_transformed[1]), GetPoint(vertices_transformed[5]));
 g.DrawLine(pen, GetPoint(vertices_transformed[2]), GetPoint(vertices_transformed[6]));
 g.DrawLine(pen, GetPoint(vertices_transformed[3]), GetPoint(vertices_transformed[7]));
 }

 }
  1. 编写TransformHelper类,获取对应变换方式的矩阵
internal static class TransformHelper
 {
 public static Matrix4x4 ScaleMatrix4x4(float x,float y,float z)
 { 
 Matrix4x4 matrix= new Matrix4x4();
 matrix[1, 1] = x;
 matrix[2, 2] = y;
 matrix[3, 3] = z;
 matrix[4, 4] = 1;
 return matrix;
 }

 public static Matrix4x4 RotateYMatrix4x4(float angle)
 {
 Matrix4x4 matrix = new Matrix4x4();
 matrix[1, 1] = MathF.Cos(angle);
 matrix[1,3]=MathF.Sin(angle);
 matrix[3, 1] = -MathF.Sin(angle);
 matrix[3,3]=MathF.Cos(angle);
 matrix[2, 2] = 1;
 matrix[4, 4] = 1;
 return matrix;
 }

 public static Matrix4x4 TranslateMatrix4x4(float x,float y,float z)
 {
 Matrix4x4 matrix = new Matrix4x4();
 matrix[1, 1] = 1;
 matrix[2, 2] = 1;
 matrix[3, 3] = 1;
 matrix[4, 4] = 1;

 matrix[4, 1] = x;
 matrix[4, 2] = y;
 matrix[4, 3] = z;

 return matrix;
 }

 public static Matrix4x4 ProjectionMatrix4x4(float fov)
 {
 Matrix4x4 matrix = new Matrix4x4();
 matrix[1, 1] = 1;
 matrix[2, 2] = 1;
 matrix[3, 3] = 1;
 matrix[4, 4] = 1;
 matrix[3, 4] = 1/fov;
 return matrix;
 }

 }

5.主窗体上添加Timer,每一帧中进行矩阵的相乘,并将该矩阵变换于CubeMesh,调用Draw方法绘制

public partial class MainForm : Form
 {

 CubeMesh mesh;

 Matrix4x4 Scale_Matrix;
 Matrix4x4 RotateY_Matrix;

 Matrix4x4 View_Matrix;

 Matrix4x4 Projection_Matrix;

 float angle;
 float distance=500;
 float x,y,z;
 float moveSpeed=100;

 public MainForm()
 {
 InitializeComponent();
 }
 private void MainForm_Load(object sender, EventArgs e)
 {
 mesh = new CubeMesh();
 Scale_Matrix=TransformHelper.ScaleMatrix4x4(500, 500, 500);

 RotateY_Matrix = TransformHelper.RotateYMatrix4x4(0.1f);
 }

 private void MainForm_KeyPress(object sender, KeyPressEventArgs e)
 {
 switch (e.KeyChar)
 {
 case'w':
 z -= moveSpeed;
 break;
 case 's':
 z += moveSpeed;
 break;
 case 'a':
 x += moveSpeed;
 break;
 case 'd':
 x -= moveSpeed;
 break;
 case 'q':
 y -= moveSpeed;
 break;
 case 'e':
 y += moveSpeed;
 break;
 default:
 break;
 }
 //Debug.WriteLine(e.KeyChar);
 }



 private void MainForm_Paint(object sender, PaintEventArgs e)
 {
 e.Graphics.TranslateTransform(this.Width / 2, this.Height / 2);
 mesh.Draw(e.Graphics);
 }

 private void UpdateTimer_Tick(object sender, EventArgs e)
 {

 angle += 0.005f;

 View_Matrix = TransformHelper.TranslateMatrix4x4(x, y, z);

 Projection_Matrix = TransformHelper.ProjectionMatrix4x4(distance);

 RotateY_Matrix = TransformHelper.RotateYMatrix4x4(angle);

 var m = Scale_Matrix.Mul(RotateY_Matrix).Mul(View_Matrix).Mul(Projection_Matrix);


 mesh.Transform(m);

 this.Invalidate();
 }
 }

最终效果

Screenshot 2023-01-20 at 6.03.43 PM.png