Skip to content

Commit

Permalink
chore: improve support for multi pass rendering with multiple materials
Browse files Browse the repository at this point in the history
  • Loading branch information
anatawa12 committed Oct 30, 2023
1 parent f7c97bf commit 9f4384f
Showing 1 changed file with 76 additions and 28 deletions.
104 changes: 76 additions & 28 deletions Editor/Processors/SkinnedMeshes/MeshInfo2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,30 @@ public MeshInfo2(MeshRenderer renderer)

private void SetMaterials(Renderer renderer)
{
if (SubMeshes.Count == 0) return;

var sourceMaterials = renderer.sharedMaterials;

if (sourceMaterials.Length < SubMeshes.Count)
SubMeshes.RemoveRange(sourceMaterials.Length, SubMeshes.Count - sourceMaterials.Length);

for (var i = 0; i < SubMeshes.Count; i++)
SubMeshes[i].SharedMaterial = sourceMaterials[i];
var verticesForLastSubMesh =
SubMeshes.Count == 0 ? new List<Vertex>() : SubMeshes[SubMeshes.Count - 1].Triangles;
for (var i = SubMeshes.Count; i < sourceMaterials.Length; i++)
SubMeshes.Add(new SubMesh(verticesForLastSubMesh.ToList(), sourceMaterials[i]));
if (SubMeshes.Count == sourceMaterials.Length)
{
for (var i = 0; i < SubMeshes.Count; i++)
SubMeshes[i].SharedMaterial = sourceMaterials[i];
}
else
{
// there are multi pass rendering
for (var i = 0; i < SubMeshes.Count - 1; i++)
SubMeshes[i].SharedMaterial = sourceMaterials[i];

var lastMeshMaterials = new Material[sourceMaterials.Length - SubMeshes.Count + 1];

for (int i = SubMeshes.Count - 1, j = 0; i < sourceMaterials.Length; i++, j++)
lastMeshMaterials[j] = sourceMaterials[i];
SubMeshes[SubMeshes.Count - 1].SharedMaterials = lastMeshMaterials;
}
}

[Conditional("UNITY_ASSERTIONS")]
Expand Down Expand Up @@ -391,6 +404,9 @@ public void WriteToMesh(Mesh destMesh)
Optimize();
destMesh.Clear();

// if mesh is empty, clearing mesh is enough!
if (SubMeshes.Count == 0) return;

Profiler.BeginSample("Write to Mesh");

Profiler.BeginSample("Vertices and Normals");
Expand Down Expand Up @@ -480,33 +496,58 @@ public void WriteToMesh(Mesh destMesh)
for (var i = 0; i < Vertices.Count; i++)
vertexIndices.Add(Vertices[i], i);

var triangles = new int[SubMeshes.Sum(x => x.Triangles.Count)];
var subMeshDescriptors = new SubMeshDescriptor[SubMeshes.Count];
var trianglesIndex = 0;
for (var i = 0; i < SubMeshes.Count; i++)
var totalTriangles = 0;
var totalSubMeshes = 0;
for (var i = 0; i < SubMeshes.Count - 1; i++)
{
var subMesh = SubMeshes[i];
var existingIndex = SubMeshes.FindIndex(0, i, sm => sm.Triangles.SequenceEqual(subMesh.Triangles));
if (existingIndex != -1)
{
subMeshDescriptors[i] = subMeshDescriptors[existingIndex];
}
else
// for non-last submesh, we have to duplicate submesh for multi pass rendering
for (var j = 0; j < SubMeshes[i].SharedMaterials.Length; j++)
{
subMeshDescriptors[i] = new SubMeshDescriptor(trianglesIndex, SubMeshes[i].Triangles.Count);
foreach (var triangle in SubMeshes[i].Triangles)
triangles[trianglesIndex++] = vertexIndices[triangle];
totalTriangles += SubMeshes[i].Triangles.Count;
totalSubMeshes++;
}
}
{
// for last submesh, we can use single submesh for multi pass reendering
totalTriangles += SubMeshes[SubMeshes.Count - 1].Triangles.Count;
totalSubMeshes++;
}

triangles = triangles.Length == trianglesIndex
? triangles
: triangles.AsSpan().Slice(0, trianglesIndex).ToArray();
var triangles = new int[totalTriangles];
var subMeshDescriptors = new SubMeshDescriptor[totalSubMeshes];
var trianglesIndex = 0;
var submeshIndex = 0;

for (var i = 0; i < SubMeshes.Count - 1; i++)
{
var subMesh = SubMeshes[i];
var descriptor = new SubMeshDescriptor(trianglesIndex, subMesh.Triangles.Count);
foreach (var triangle in subMesh.Triangles)
triangles[trianglesIndex++] = vertexIndices[triangle];

// general case: for non-last submesh, we have to duplicate submesh for multi pass rendering
for (var j = 0; j < subMesh.SharedMaterials.Length; j++)
subMeshDescriptors[submeshIndex++] = descriptor;
}

{
var subMesh = SubMeshes[SubMeshes.Count - 1];

var descriptor = new SubMeshDescriptor(trianglesIndex, subMesh.Triangles.Count);
foreach (var triangle in subMesh.Triangles)
triangles[trianglesIndex++] = vertexIndices[triangle];

// for last submesh, we can use single submesh for multi pass reendering
subMeshDescriptors[submeshIndex++] = descriptor;
}

Debug.Assert(subMeshDescriptors.Length == submeshIndex);
Debug.Assert(triangles.Length == trianglesIndex);

destMesh.indexFormat = Vertices.Count <= ushort.MaxValue ? IndexFormat.UInt16 : IndexFormat.UInt32;
destMesh.triangles = triangles;
destMesh.subMeshCount = SubMeshes.Count;
for (var i = 0; i < SubMeshes.Count; i++)
destMesh.subMeshCount = submeshIndex;
for (var i = 0; i < subMeshDescriptors.Length; i++)
destMesh.SetSubMesh(i, subMeshDescriptors[i]);
}
Profiler.EndSample();
Expand Down Expand Up @@ -593,7 +634,7 @@ public void WriteToSkinnedMeshRenderer(SkinnedMeshRenderer targetRenderer)
targetRenderer.sharedMesh = mesh;
for (var i = 0; i < BlendShapes.Count; i++)
targetRenderer.SetBlendShapeWeight(i, BlendShapes[i].weight);
targetRenderer.sharedMaterials = SubMeshes.Select(x => x.SharedMaterial).ToArray();
targetRenderer.sharedMaterials = SubMeshes.SelectMany(x => x.SharedMaterials).ToArray();
targetRenderer.bones = Bones.Select(x => x.Transform).ToArray();

targetRenderer.rootBone = RootBone;
Expand All @@ -610,7 +651,7 @@ public void WriteToMeshRenderer(MeshRenderer targetRenderer)
var meshFilter = targetRenderer.GetComponent<MeshFilter>();
WriteToMesh(mesh);
meshFilter.sharedMesh = mesh;
targetRenderer.sharedMaterials = SubMeshes.Select(x => x.SharedMaterial).ToArray();
targetRenderer.sharedMaterials = SubMeshes.SelectMany(x => x.SharedMaterials).ToArray();
});
}
}
Expand All @@ -619,7 +660,14 @@ internal class SubMesh
{
// size of this must be 3 * n
public readonly List<Vertex> Triangles = new List<Vertex>();
public Material SharedMaterial;

public Material SharedMaterial
{
get => SharedMaterials[0];
set => SharedMaterials[0] = value;
}

public Material[] SharedMaterials = { null };

public SubMesh()
{
Expand Down

0 comments on commit 9f4384f

Please sign in to comment.