前言:我假定我的读者对 C# 和 Unity 引擎有初步的了解,并且还保有关于高中数学的记忆,不会为几何形体相关的计算感到疑惑。涉及到的术语和复杂概念会被尽可能向着简单易懂的方向解释。
最近疯狂摸鱼,看到了一则 Unity 程序的测试题。题目长这样:
- 在摄像机视线范围内,以代码的方式生成四个大小随机,位置随机,角度随机,颜色随机的正四面体(注意不是立方体)。
- 以鼠标指针为起点对世界空间做射线检测,检测每个四面体的指针进入(执行一次),保持(持续执行),点击(指针在物体上并按下鼠标左键),以及退出事件(执行一次),并将触发的事件打印到屏幕上。注意:不能使用OnMouseEnter,OnMouseOver 等 Unity 自带函数。
那几个随机基本随手就能写,不是主要问题。关键点有这么几个:
- 绘制正四面体的形状。
- 确保正四面体在镜头视野内。
- 为正四面体添加碰撞体使其可被射线检测。
画面,画,面
Mesh 是 Unity 中 可从脚本创建或者修改网格的类。Unity 提供了生成自定义 Mesh 的方法,简单说来就是先 new 一个 Mesh 出来,然后分别设定网格的顶点、分配三角形顶点的次序。如果有必要,还可以设置其 UV——网格的基础纹理坐标。这个测试题只要求改变颜色,UV 倒不用特意设置。
网格的基本单元是三角形。首先尝试用一个脚本在某个位置绘制一个三角形。在 Unity 新建一个脚本:
using UnityEngine;
public class MeshTest : MonoBehaviour
{
MeshRenderer meshRenderer;
public Mesh thisMesh;
Vector3[] newVerticles;
Vector2[] newUV;
int[] newTriangles;
void Start()
{
meshRenderer = gameObject.AddComponent<MeshRenderer>();
meshRenderer.material.color = Color.white;
var meshFilter = gameObject.AddComponent<MeshFilter>();
SingleMesh();
thisMesh = new Mesh()
{
vertices = newVerticles,
uv = newUV,
triangles = newTriangles
};
meshFilter.mesh = thisMesh;
}
void SingleMesh()
{
newVerticles = new Vector3[] {
new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0)
};
newUV = new Vector2[] {
new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1)
};
newTriangles = new int[] { 0, 1, 2 };
}
}
把新写的脚本挂在一个生成的空节点上,开始游戏,你应该能看到一个三角形出现在画面中。而这个三角形应当是“单面”的。这和绘制三角形的点顺序有关,当一个三角形的正面朝向你的时候,三个点的次序呈逆时针,点的次序由 triangles 控制,triangles 是一个整型数组,它的长度必须为 3 的整数倍。
面构成体
在知道了如何绘制一个三角形之后,我们就可以开始着手绘制正四面体了。正四面体的四个面都是正三角形,结合一些高中立体几何知识我们可以很快得到正四面体四个顶点的位置关系。
出于绘图方便的考虑,不妨将其中一个顶点放在原点位置,而相邻的另一点放在 z 轴上,这样有一条边被固定在轴上。
假设边长为1,那么计算得到的四个顶点坐标是:
(0, 0, 0), (0, 0, 1), (√3/2, 0, 1/2), (√3/6, √6/3, 1/2)
而这个正四面体的几何中心坐标是 (√3/6, √6/12, 1/2)
根据这些信息新建一个脚本,内容是在原地绘制一个正四面体。
using System.Collections;
using UnityEngine;
public class Fr