为了在细分大型网格Unity 的主要图形基元。网格构成 3D 世界的很大一部分。Unity 支持三角形或四边形多边形网格。NURBS、NURMS、细分曲面必须转换为多边形。 更多信息
查看 术语表时提高性能,请使用作业系统。这可以防止主线程被长时间阻塞。创建细分作业时,请使用 MeshGenerationContext.AddMeshGenerationJob API 向 UI(用户界面) 允许用户与您的应用程序交互。Unity 目前支持三种 UI 系统。 更多信息
查看 术语表 工具包提供作业句柄。这可确保 UI 工具包在访问网格之前等待作业完成。
如果可以快速计算顶点数或索引数,请使用主线程分配网格并将其添加到绘制序列中。您可以使用以下 API 来执行此操作
注意:您可以在调用 generateVisualContent 期间的任何时间点将网格添加到绘制序列中。
以下示例演示了在主线程上分配的作业化细分,其中作业执行实际的细分。
using System;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.UIElements;
class CheckerboardElement : VisualElement
{
struct CheckerboardJob : IJob
{
[WriteOnly] public NativeSlice<Vertex> vertices;
[WriteOnly] public NativeSlice<ushort> indices;
public int horizontalCount;
public int verticalCount;
public float divisions;
public Color32 color1;
public Color32 color2;
public void Execute()
{
Span<Color32> colors = stackalloc Color32[2];
colors[0] = color1;
colors[1] = color2;
int colorIndex = 0;
int vCount = 0;
int iCount = 0;
float left = 0;
float right = divisions;
for (int i = 0; i < horizontalCount; ++i)
{
float top = 0;
float bottom = divisions;
for (int j = 0; j < verticalCount; ++j)
{
colorIndex = (i ^ j) & 1;
Color32 color = colors[colorIndex];
vertices[vCount + 0] = new Vertex { position = new Vector3(left, bottom), tint = color };
vertices[vCount + 1] = new Vertex { position = new Vector3(left, top), tint = color };
vertices[vCount + 2] = new Vertex { position = new Vector3(right, top), tint = color };
vertices[vCount + 3] = new Vertex { position = new Vector3(right, bottom), tint = color };
indices[iCount + 0] = (ushort)(vCount + 0);
indices[iCount + 1] = (ushort)(vCount + 1);
indices[iCount + 2] = (ushort)(vCount + 2);
indices[iCount + 3] = (ushort)(vCount + 2);
indices[iCount + 4] = (ushort)(vCount + 3);
indices[iCount + 5] = (ushort)(vCount + 0);
vCount += 4;
iCount += 6;
top += divisions;
bottom += divisions;
}
left += divisions;
right += divisions;
}
}
}
int m_Divisions;
Color32 m_Color1;
Color32 m_Color2;
public CheckerboardElement(int divisions, Color32 color1, Color32 color2)
{
generateVisualContent = OnGenerateVisualContent;
m_Divisions = divisions;
m_Color1 = color1;
m_Color2 = color2;
}
void OnGenerateVisualContent(MeshGenerationContext mgc)
{
int horizontalCount = Mathf.FloorToInt(layout.width / m_Divisions);
int verticalCount = Mathf.FloorToInt(layout.height / m_Divisions);
if (horizontalCount == 0 || verticalCount == 0)
return;
var job = new CheckerboardJob
{
horizontalCount = horizontalCount,
verticalCount = verticalCount,
divisions = m_Divisions,
color1 = m_Color1,
color2 = m_Color2
};
int quads = horizontalCount * verticalCount;
mgc.AllocateTempMesh(quads * 4, quads * 6, out job.vertices, out job.indices);
mgc.DrawMesh(job.vertices, job.indices);
JobHandle jobHandle = job.Schedule();
mgc.AddMeshGenerationJob(jobHandle);
}
}
如果计算顶点数或索引数的成本很高,请在绘制序列中插入一个 MeshGenerationNode。然后将节点与 TempMeshAllocator 一同提供给您的作业。您可以使用以下 API 来执行此操作
在这种方法中,请从作业中执行分配。使用 TempMeshAllocator.AllocateTempMesh 从作业中安全地分配临时网格。 MeshGenerationNode.DrawMesh 充当由作业填充的嵌套绘制序列的容器。
以先前的示例为基础,以下示例演示了如何从作业中执行分配和细分
using System;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.UIElements;
class CheckerboardElement_AllocFromJob : VisualElement
{
struct CheckerboardJob : IJob
{
[ReadOnly]
public TempMeshAllocator allocator;
public MeshGenerationNode node;
public int horizontalCount;
public int verticalCount;
public float divisions;
public Color32 color1;
public Color32 color2;
public void Execute()
{
// Let's pretend that the number of vertices/indices is difficult to compute...
int quads = horizontalCount * verticalCount;
int totalVertexCount = quads * 4;
int totalIndexCount = quads * 6;
// Allocate the mesh from the job
allocator.AllocateTempMesh(totalVertexCount, totalIndexCount, out NativeSlice<Vertex> vertices, out NativeSlice<ushort> indices);
Span<Color32> colors = stackalloc Color32[2];
colors[0] = color1;
colors[1] = color2;
int colorIndex = 0;
int vCount = 0;
int iCount = 0;
float left = 0;
float right = divisions;
for (int i = 0; i < horizontalCount; ++i)
{
float top = 0;
float bottom = divisions;
for (int j = 0; j < verticalCount; ++j)
{
colorIndex = (i ^ j) & 1;
Color32 color = colors[colorIndex];
vertices[vCount + 0] = new Vertex { position = new Vector3(left, bottom), tint = color };
vertices[vCount + 1] = new Vertex { position = new Vector3(left, top), tint = color };
vertices[vCount + 2] = new Vertex { position = new Vector3(right, top), tint = color };
vertices[vCount + 3] = new Vertex { position = new Vector3(right, bottom), tint = color };
indices[iCount + 0] = (ushort)(vCount + 0);
indices[iCount + 1] = (ushort)(vCount + 1);
indices[iCount + 2] = (ushort)(vCount + 2);
indices[iCount + 3] = (ushort)(vCount + 2);
indices[iCount + 4] = (ushort)(vCount + 3);
indices[iCount + 5] = (ushort)(vCount + 0);
vCount += 4;
iCount += 6;
top += divisions;
bottom += divisions;
}
left += divisions;
right += divisions;
}
// Add the mesh to the draw sequence of the node
node.DrawMesh(vertices, indices);
}
}
int m_Divisions;
Color32 m_Color1;
Color32 m_Color2;
public CheckerboardElement_AllocFromJob(int divisions, Color32 color1, Color32 color2)
{
generateVisualContent = OnGenerateVisualContent;
m_Divisions = divisions;
m_Color1 = color1;
m_Color2 = color2;
}
void OnGenerateVisualContent(MeshGenerationContext mgc)
{
int horizontalCount = Mathf.FloorToInt(layout.width / m_Divisions);
int verticalCount = Mathf.FloorToInt(layout.height / m_Divisions);
if (horizontalCount == 0 || verticalCount == 0)
return;
var job = new CheckerboardJob
{
horizontalCount = horizontalCount,
verticalCount = verticalCount,
divisions = m_Divisions,
color1 = m_Color1,
color2 = m_Color2
};
mgc.GetTempMeshAllocator(out job.allocator); // Provide the job with the allocator
mgc.InsertMeshGenerationNode(out job.node); // Insert a node in the element draw sequence
JobHandle jobHandle = job.Schedule();
mgc.AddMeshGenerationJob(jobHandle);
}
}