对于我在Unity中运行时使用的一小组自定义地形工具,我需要能够“绘制”地形区域以提升和降低它。
要做到这一点,我有这个功能:
public void PaintRaise(Vector3 center, float radius, float power) {
Mesh mesh = this.gameObject.GetComponent<MeshFilter>().sharedMesh;
Vector3[] verts = new Vector3[mesh.vertices.Length];
for (int i = 0; i < mesh.vertices.Length; ++i) {
// method for getting distance, faster then Vector3.Distance
var heading = mesh.vertices[i] - center;
var distance = heading.magnitude;
var direction = heading / distance;
if (heading.sqrMagnitude < radius * radius) {
verts[i] = new Vector3(
mesh.vertices[i].x,
mesh.vertices[i].y + power,
mesh.vertices[i].z);
} else {
verts[i] = mesh.vertices[i];
}
}
mesh.vertices = verts;
}
理论上,它应该可以完美地应用于带有网格的GameObject,它确实可以!但不幸的是,它非常非常缓慢。即使使用improved距离查找方法,处理半径为5个单位也需要大约10秒钟。
它在编辑器和编译版本中运行速度都很慢。
正如您所看到的,探查器显示调用PaintRaise函数的Update()函数需要大约13秒来执行单帧,其中大部分是garabage收集器!
为什么它运行缓慢,如何加快速度(理想情况下需要几毫秒才能执行)?
修改
启用深度分析会让它更加混乱!为什么由于GC而使网格顶点需要13秒?
答案 0 :(得分:1)
在做了一些研究后,我发现顶点是not actually a variable,就像它看起来一样。
新的SetVertices / SetIndices / SetUVs /方法有几个原因。首先,旧的顶点属性不是变量。这个事实让许多用户感到困惑。这是一个财产。实际上有一个get方法和一个set方法,但用法看起来就像一个变量。
最不理解的是getter不会返回对内部数组的引用,而是返回一个副本。这是必要的,因为实际的顶点数据存储在Unity的本机C ++端。
更改我的函数以使用Get()和Set()消除了使用vertices属性创建的额外垃圾收集,并使其运行黄油顺利。
public void PaintRaise(Vector3 center, float radius, float power) {
Vector3 localPoint = transform.InverseTransformPoint(center);
Mesh mesh = this.gameObject.GetComponent<MeshFilter>().sharedMesh;
List<Vector3> verts = new List<Vector3>();
mesh.GetVertices(verts);
for (int i = 0; i < verts.Count; ++i) {
var heading = verts[i] - center;
var distance = heading.magnitude;
var direction = heading / distance;
if (heading.sqrMagnitude < radius * radius) {
verts[i] = new Vector3(
verts[i].x,
verts[i].y + power,
verts[i].z);
}
}
mesh.SetVertices(verts);
}