矩阵应用:在 Unity 中,Transform
和矩阵之间的关系非常密切。Transform
组件主要用于描述和控制一个物体在三维空间中的位置、旋转和缩放,而这些操作背后实际上都是通过矩阵来实现的
1. Transform
组件与矩阵的关系
Transform
组件包含以下三个核心属性:
- Position:物体的位置。
- Rotation:物体的旋转(通常以四元数或欧拉角表示)。
- Scale:物体的缩放。
Unity 在计算一个物体在世界空间中的最终位置、旋转和缩放时,会将这些属性组合成一个 4x4 的变换矩阵。
2. 变换矩阵 (Transformation Matrix)
变换矩阵是一个 4x4 矩阵,它可以表示一个物体在三维空间中的所有变换(平移、旋转、缩放)。这个矩阵通常被称为世界矩阵(World Matrix)或模型矩阵(Model Matrix)。
在 Unity 中,这个矩阵由 Transform
的 localToWorldMatrix
属性表示,用于将物体的本地坐标转换到世界坐标系中。
3. Unity 中矩阵的运算过程
当 Unity 计算一个物体在场景中的最终位置时,会依次应用以下矩阵变换:
- 缩放矩阵:描述物体的缩放变换。
- 旋转矩阵:描述物体的旋转变换。
- 平移矩阵:描述物体的位置变换。
4. Transform 矩阵的实际应用
当 Unity 需要将一个物体的本地坐标转换为世界坐标时,它会使用 localToWorldMatrix
进行转换。相反,如果需要将世界坐标转换为物体的本地坐标,Unity 会使用 worldToLocalMatrix
。
原理解析
当一个物体的位置、旋转、缩放分别为 {0, 0, 0}
、{90, 90, 90}
和 {1, 1, 1}
时,它的变换矩阵代表了如何将物体从其本地坐标系变换到世界坐标系。
1. 平移矩阵(Translation Matrix)
位置为 {0, 0, 0}
,意味着物体位于世界坐标系的原点(没有平移)。因此,平移矩阵是一个单位矩阵:
平移公式
2. 旋转矩阵(Rotation Matrix)
旋转为 {90°, 90°, 90°}
,意味着物体在每个轴上都旋转了 90 度。这个旋转由三个矩阵(分别绕 X 轴、Y 轴、Z 轴的旋转)组合而成。
- 绕 X 轴旋转 90 度:
X轴旋转公式
- 绕 Y 轴旋转 90 度:
Y轴旋转公式
- 绕 Z 轴旋转 90 度:
Z轴旋转公式
最终的旋转矩阵是这些矩阵的乘积:
Rotation Matrix=Rotation Matrix (X)×Rotation Matrix (Y)×Rotation Matrix (Z)
3. 缩放矩阵(Scale Matrix)
缩放为 {1, 1, 1}
,意味着物体在所有方向上都没有缩放。缩放矩阵也是单位矩阵
缩放公式
4. 组合变换矩阵
最终的变换矩阵是平移、旋转和缩放矩阵的组合。顺序为缩放 -> 旋转 -> 平移,因此组合矩阵为:
Transformation Matrix=Translation Matrix×Rotation Matrix×Scale Matrix
源码示例(个人写的,基本是这原理吧)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace Ethan
{
public class Matrix4x4
{
private float[,] elements;
// 构造函数
public Matrix4x4()
{
elements = new float[4, 4];
}
// 用于初始化的构造函数
public Matrix4x4(float[,] elements)
{
this.elements = elements;
}
// 单位矩阵
public static Matrix4x4 Identity()
{
return new Matrix4x4(new float[,]
{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
});
}
// 零矩阵
public static Matrix4x4 Zero()
{
return new Matrix4x4(new float[4, 4]);
}
// 矩阵乘法
public static Matrix4x4 operator *(Matrix4x4 a, Matrix4x4 b)
{
Matrix4x4 result = Zero();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
result.elements[i, j] = 0;
for (int k = 0; k < 4; k++)
{
result.elements[i, j] += a.elements[i, k] * b.elements[k, j];
}
}
}
return result;
}
// 平移矩阵
public static Matrix4x4 Translate(float x, float y, float z)
{
return new Matrix4x4(new float[,]
{
{1, 0, 0, x},
{0, 1, 0, y},
{0, 0, 1, z},
{0, 0, 0, 1}
});
}
// 绕X轴旋转矩阵
public static Matrix4x4 RotateX(float angle)
{
float rad = Mathf.Deg2Rad * angle;
return new Matrix4x4(new float[,]
{
{1, 0, 0, 0},
{0, Mathf.Cos(rad), -Mathf.Sin(rad), 0},
{0, Mathf.Sin(rad), Mathf.Cos(rad), 0},
{0, 0, 0, 1}
});
}
// 绕Y轴旋转矩阵
public static Matrix4x4 RotateY(float angle)
{
float rad = Mathf.Deg2Rad * angle;
return new Matrix4x4(new float[,]
{
{Mathf.Cos(rad), 0, Mathf.Sin(rad), 0},
{0, 1, 0, 0},
{-Mathf.Sin(rad), 0, Mathf.Cos(rad), 0},
{0, 0, 0, 1}
});
}
// 绕Z轴旋转矩阵
public static Matrix4x4 RotateZ(float angle)
{
float rad = Mathf.Deg2Rad * angle;
return new Matrix4x4(new float[,]
{
{Mathf.Cos(rad), -Mathf.Sin(rad), 0, 0},
{Mathf.Sin(rad), Mathf.Cos(rad), 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
});
}
// 缩放矩阵
public static Matrix4x4 Scale(float x, float y, float z)
{
return new Matrix4x4(new float[,]
{
{x, 0, 0, 0},
{0, y, 0, 0},
{0, 0, z, 0},
{0, 0, 0, 1}
});
}
// 矩阵与向量相乘
public static Vector3 MultiplyPoint(Matrix4x4 m, Vector3 point)
{
float x = m.elements[0, 0] * point.x + m.elements[0, 1] * point.y + m.elements[0, 2] * point.z + m.elements[0, 3];
float y = m.elements[1, 0] * point.x + m.elements[1, 1] * point.y + m.elements[1, 2] * point.z + m.elements[1, 3];
float z = m.elements[2, 0] * point.x + m.elements[2, 1] * point.y + m.elements[2, 2] * point.z + m.elements[2, 3];
return new Vector3(x, y, z);
}
// 显示矩阵内容
public override string ToString()
{
string result = "";
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
result += elements[i, j] + "\t";
}
result += "\n";
}
return result;
}
}
}
调用示例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Vector3 = Ethan.Vector3;
using Matrix4x4 = Ethan.Matrix4x4;
public class Game : MonoBehaviour
{
void Start()
{
// 创建变换矩阵
Matrix4x4 rotation = Matrix4x4.RotateY(45); // 绕Y轴旋转45度
Matrix4x4 translation = Matrix4x4.Translate(10, 0, 5); // 平移
Matrix4x4 scale = Matrix4x4.Scale(2, 2, 2); // 缩放
// 组合变换
Matrix4x4 transformation = translation * rotation * scale;
// 应用到一个点
Vector3 originalPoint = new Vector3(1, 1, 1);
Vector3 transformedPoint = Matrix4x4.MultiplyPoint(transformation, originalPoint);
// 输出结果
Debug.Log("初始点: " + originalPoint);
Debug.Log("转换点: " + transformedPoint);
Debug.Log("变换矩阵:\n" + transformation);
}
}