/ Assets / scripts / MeshAdjacencyBuilder.cs
MeshAdjacencyBuilder.cs
 1  using System.Collections.Generic;
 2  using UnityEngine;
 3  using UnityEngine.Rendering;
 4  
 5  /// <summary>
 6  /// Converts a mesh so its index buffer encodes adjacency information
 7  /// for use with geometry shaders that declare `triangleadj`.
 8  /// </summary>
 9  [RequireComponent(typeof(MeshFilter))]
10  public class MeshAdjacencyBuilder : MonoBehaviour
11  {
12      [ContextMenu("Build Adjacency Mesh")]
13      public void BuildAdjacencyMesh()
14      {
15          MeshFilter mf = GetComponent<MeshFilter>();
16          Mesh original = mf.sharedMesh;
17          if (original == null)
18          {
19              Debug.LogError("No mesh found!");
20              return;
21          }
22  
23          Mesh adjMesh = BuildAdjacency(original);
24          mf.sharedMesh = adjMesh;
25      }
26  
27      Mesh BuildAdjacency(Mesh mesh)
28      {
29          // Get data
30          Vector3[] verts = mesh.vertices;
31          int[] indices = mesh.triangles;
32  
33          // Build edge → opposite vertex map
34          var edgeToVertex = new Dictionary<(int, int), int>();
35          for (int i = 0; i < indices.Length; i += 3)
36          {
37              int v0 = indices[i];
38              int v1 = indices[i + 1];
39              int v2 = indices[i + 2];
40  
41              AddEdge(edgeToVertex, v0, v1, v2);
42              AddEdge(edgeToVertex, v1, v2, v0);
43              AddEdge(edgeToVertex, v2, v0, v1);
44          }
45  
46          // New index buffer: 6 indices per triangle
47          List<int> newIndices = new List<int>();
48          for (int i = 0; i < indices.Length; i += 3)
49          {
50              int v0 = indices[i];
51              int v1 = indices[i + 1];
52              int v2 = indices[i + 2];
53  
54              int a0 = FindAdj(edgeToVertex, v0, v1);
55              int a1 = FindAdj(edgeToVertex, v1, v2);
56              int a2 = FindAdj(edgeToVertex, v2, v0);
57  
58              newIndices.Add(v0); newIndices.Add(a0);
59              newIndices.Add(v1); newIndices.Add(a1);
60              newIndices.Add(v2); newIndices.Add(a2);
61          }
62  
63          // Build new mesh
64          Mesh adjMesh = new Mesh();
65          adjMesh.name = mesh.name + "_Adjacency";
66          adjMesh.vertices = verts;
67          adjMesh.normals = mesh.normals;
68          adjMesh.uv = mesh.uv;
69          adjMesh.uv2 = mesh.uv2;
70          adjMesh.colors = mesh.colors;
71          adjMesh.tangents = mesh.tangents;
72          adjMesh.SetIndices(newIndices.ToArray(), MeshTopology.Triangles, 0);
73          return adjMesh;
74      }
75  
76      void AddEdge(Dictionary<(int, int), int> map, int v0, int v1, int opposite)
77      {
78          var key = (Mathf.Min(v0, v1), Mathf.Max(v0, v1));
79          if (!map.ContainsKey(key))
80              map[key] = opposite;
81      }
82  
83      int FindAdj(Dictionary<(int, int), int> map, int v0, int v1)
84      {
85          var key = (Mathf.Min(v0, v1), Mathf.Max(v0, v1));
86          if (map.TryGetValue(key, out int adj))
87              return adj;
88  
89          // No adjacent triangle (boundary edge) → duplicate one of the edge vertices
90          return v0;
91      }
92  }