3D图形在Unity中究竟是如何得到的。本篇我们会使用C#结合Shader来自制一个类似于UnityObjectToClipPos
函数功能来帮助我们对底层的3D图形实现有一个更深刻的理解。
1. MVP矩阵
MVP矩阵(Model-View-Projection Matrix)是3D图形渲染中的一个核心概念,代表了一个将物体从模型空间(局部空间)转换到裁剪空间所需的变换矩阵,它通过 投影矩阵(Projection Matrix)× 视图矩阵(View Matrix)× 模型矩阵(Model Matrix)得到,如代码所示:
// 计算 mvp 矩阵
Matrix4x4 mvp = Camera.main.projectionMatrix *
Camera.main.worldToCameraMatrix *
transform.localToWorldMatrix;
2. 利用MVP矩阵实现3D图形
MVP可以直接乘以物体的顶点坐标,将它们从模型空间转换到裁剪空间,就产生了一个3D图形的视觉效果,我们在Shader代码中声明一个可被外界修改的MVP矩阵变量:
uniform float4x4 mvp;
然后将其与顶点坐标相乘:
v2f outData;
// 模型空间 转 裁剪空间
outData.pos = mul(mvp, appData.vertex);
接下来我们要把C#中的mvp矩阵传递给Shader中的mvp矩阵:
GetComponent<Renderer>().material.SetMatrix("mvp", mvp);
这样,我们就能够实现与UnityObjectToClipPos函数相同的效果了。
3. 在MVP矩阵基础上实现物体旋转
如何我们需要通过矩阵变换来让物体进行旋转,那么只需让mvp矩阵乘上一个旋转矩阵即可,例如,我想让物体绕Y轴旋转,C#实现代码如下:
void Update()
{
Matrix4x4 rm = new Matrix4x4(); // 旋转矩阵
// 设置为 绕Y轴旋转
rm[0, 0] = Mathf.Cos(Time.realtimeSinceStartup);
rm[0, 2] = Mathf.Sin(Time.realtimeSinceStartup);
rm[1, 1] = 1;
rm[2, 0] = -Mathf.Sin(Time.realtimeSinceStartup);
rm[2, 2] = Mathf.Cos(Time.realtimeSinceStartup);
rm[3, 3] = 1;
// 计算 mvp 矩阵
Matrix4x4 mvp = Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix * transform.localToWorldMatrix;
// 让物体绕Y轴旋转
mvp *= rm;
// 传递给Shader中的mvp矩阵
GetComponent<Renderer>().material.SetMatrix("mvp", mvp);
}
运行项目后的效果如下:
除此之外,我们还可以在mvp矩阵的基础上使用缩放矩阵实现对物体的缩放等,总而言之,在三维世界中,我们所看到的这些三维图形的立体效果,都是基于mvp矩阵得到的。