#c# #optimization #unity3d #unityscript #uv-mapping
#c# #оптимизация #unity3d #unityscript #uv-отображение
Вопрос:
Я пытаюсь создать UVs @ runtime, я использую UVs типа BOX (аналогичный BOX UVW в 3ds max) и основываю свои вычисления на ориентации лица.
Я знаю, что это не очень хороший вариант для создания среды выполнения, но у меня нет выбора: (он сохраняется после вычисления, поэтому я сделал это один раз.
НО я беру 40 секунд на 30000 вершин… слишком долго
Есть ли какая-либо оптимизация в моем коде, которую можно сделать?
.
Вот мой код, который вы можете использовать, если у вас <5000 вершин сетки:
public static void CreateUV(ref Mesh mesh)
{
int i = 0;
Vector3 p = Vector3.up;
Vector3 u = Vector3.Cross(p, Vector3.forward);
if (Vector3.Dot(u, u) < 0.001f)
{
u = Vector3.right;
}
else
{
u = Vector3.Normalize(u);
}
Vector3 v = Vector3.Normalize(Vector3.Cross(p, u));
Vector2[] uvs = new Vector2[mesh.vertices.Length];
for (i = 0; i < mesh.triangles.Length; i = 3)
{
Vector3 a = mesh.vertices[mesh.triangles[i]];
Vector3 b = mesh.vertices[mesh.triangles[i 1]];
Vector3 c = mesh.vertices[mesh.triangles[i 2]];
Vector3 side1 = b - a;
Vector3 side2 = c - a;
Vector3 N = Vector3.Cross(side1, side2);
N = new Vector3(Mathf.Abs(N.normalized.x), Mathf.Abs(N.normalized.y), Mathf.Abs(N.normalized.z));
if (N.x > N.y amp;amp; N.x > N.z)
{
uvs[mesh.triangles[i]] = new Vector2(mesh.vertices[mesh.triangles[i]].z, mesh.vertices[mesh.triangles[i]].y);
uvs[mesh.triangles[i 1]] = new Vector2(mesh.vertices[mesh.triangles[i 1]].z, mesh.vertices[mesh.triangles[i 1]].y);
uvs[mesh.triangles[i 2]] = new Vector2(mesh.vertices[mesh.triangles[i 2]].z, mesh.vertices[mesh.triangles[i 2]].y);
}
else if (N.y > N.x amp;amp; N.y > N.z)
{
uvs[mesh.triangles[i]] = new Vector2(mesh.vertices[mesh.triangles[i]].x, mesh.vertices[mesh.triangles[i]].z);
uvs[mesh.triangles[i 1]] = new Vector2(mesh.vertices[mesh.triangles[i 1]].x, mesh.vertices[mesh.triangles[i 1]].z);
uvs[mesh.triangles[i 2]] = new Vector2(mesh.vertices[mesh.triangles[i 2]].x, mesh.vertices[mesh.triangles[i 2]].z);
}
else if (N.z > N.x amp;amp; N.z > N.y)
{
uvs[mesh.triangles[i]] = new Vector2(mesh.vertices[mesh.triangles[i]].x, mesh.vertices[mesh.triangles[i]].y);
uvs[mesh.triangles[i 1]] = new Vector2(mesh.vertices[mesh.triangles[i 1]].x, mesh.vertices[mesh.triangles[i 1]].y);
uvs[mesh.triangles[i 2]] = new Vector2(mesh.vertices[mesh.triangles[i 2]].x, mesh.vertices[mesh.triangles[i 2]].y);
}
}
mesh.uv = uvs;
Debug.Log("Finish");
}
Ответ №1:
Я бы настоятельно рекомендовал кэшировать копию mesh.vertices
.
В документации для vertices
свойства частично указано:
Возвращает копию позиций вершин или присваивает новый массив позиций вершин.
Обратите внимание, что «возвращает копию» — вы обращаетесь к этому свойству 22 раза внутри вашего цикла, так что это создаст примерно 22n / 3
копии этого массива. Для сетки с 30 000 вершинами это более 200 000 ненужных операций копирования, выполняемых в фоновом режиме.
Если вы создадите временный массив для хранения данных вершин (как вы уже делаете с mesh.uvs
), вы должны увидеть значительное улучшение производительности.
Вы также можете проверить, выполняется ли mesh.triangles
операция копирования. Я предполагаю, что это может быть, но в документах не указано.
Ответ №2:
вот мой код, оптимизированный благодаря @rutter
public static Vector2[] CreateUV(ref Mesh mesh)
{
int i = 0;
Vector3 p = Vector3.up;
Vector3 u = Vector3.Cross(p, Vector3.forward);
if (Vector3.Dot(u, u) < 0.001f)
{
u = Vector3.right;
}
else
{
u = Vector3.Normalize(u);
}
Vector3 v = Vector3.Normalize(Vector3.Cross(p, u));
Vector3[] vertexs = mesh.vertices;
int[] tris = mesh.triangles;
Vector2[] uvs = new Vector2[vertexs.Length];
for (i = 0; i < tris.Length; i = 3)
{
Vector3 a = vertexs[tris[i]];
Vector3 b = vertexs[tris[i 1]];
Vector3 c = vertexs[tris[i 2]];
Vector3 side1 = b - a;
Vector3 side2 = c - a;
Vector3 N = Vector3.Cross(side1, side2);
N = new Vector3(Mathf.Abs(N.normalized.x), Mathf.Abs(N.normalized.y), Mathf.Abs(N.normalized.z));
if (N.x > N.y amp;amp; N.x > N.z)
{
uvs[tris[i]] = new Vector2(vertexs[tris[i]].z, vertexs[tris[i]].y);
uvs[tris[i 1]] = new Vector2(vertexs[tris[i 1]].z, vertexs[tris[i 1]].y);
uvs[tris[i 2]] = new Vector2(vertexs[tris[i 2]].z, vertexs[tris[i 2]].y);
}
else if (N.y > N.x amp;amp; N.y > N.z)
{
uvs[tris[i]] = new Vector2(vertexs[tris[i]].x, vertexs[tris[i]].z);
uvs[tris[i 1]] = new Vector2(vertexs[tris[i 1]].x, vertexs[tris[i 1]].z);
uvs[tris[i 2]] = new Vector2(vertexs[tris[i 2]].x, vertexs[tris[i 2]].z);
}
else if (N.z > N.x amp;amp; N.z > N.y)
{
uvs[tris[i]] = new Vector2(vertexs[tris[i]].x, vertexs[tris[i]].y);
uvs[tris[i 1]] = new Vector2(vertexs[tris[i 1]].x, vertexs[tris[i 1]].y);
uvs[tris[i 2]] = new Vector2(vertexs[tris[i 2]].x, vertexs[tris[i 2]].y);
}
}
mesh.uv = uvs;
return uvs;
}