2D变换矩阵
平移矩阵
旋转矩阵
示例代码
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缩放矩阵
3D变换矩阵
3D平移矩阵
平移矩阵也称位移矩阵,平移矩阵用到了第四列(w列),这也是为什么三维空间变换矩阵为什么是四维的。平移矩阵也比较容易理解,因为可以通过结果看出想x 、y、z确实各自平移了T步。
3D旋转矩阵
💡 绕不同的坐标轴进行旋转的3D矩阵
3D缩放矩阵
3D旋转矩阵与平移矩阵相乘
透视投影
透视投影矩阵
变换的种类
变换的组合
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;
}
}
- 编写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]));
}
}
- 编写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();
}
}
最终效果


...