Created
May 4, 2024 23:42
-
-
Save Chaosed0/a0b7a70b53988d87c08358374084144b to your computer and use it in GitHub Desktop.
A Unity asset postprocessor for sorting mesh triangles back-to-front
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEditor; | |
// This sorts the triangles within a mesh back-to-front based on Wizgun's fixed camera | |
// angle, solving mesh self-sorting issues when transparent shaders are used. | |
// Normally, these objects are opaque, but when TintedUnlitShaderReveal is swapped in | |
// to reveal what is behind the object, depth sorting is turned off. We need Unity to | |
// draw the mesh in the correct order so that the triangles' depths are respected. | |
// Note that this asset postprocessor does not change the asset on disk. It only changes | |
// the internal representation (in Unity's library) of the Mesh objects that get | |
// generated from our FBX files. | |
public class SortMeshTrianglesAssetPostprocessor : AssetPostprocessor | |
{ | |
private const string PROPS_PATH = "Assets/Art/Environment/Props"; | |
private const float CAMERA_PITCH = 40; | |
private List<Triangle> _cachedTriangles = new List<Triangle>(); | |
private List<Vector3> _cachedVertices = new List<Vector3>(); | |
private List<int> _cachedTriangleIndices = new List<int>(); | |
private List<int> _cachedNewTriangleIndices = new List<int>(); | |
private struct Triangle | |
{ | |
public int index; | |
public float dot; | |
} | |
// Called by Unity | |
private void OnPostprocessModel(GameObject go) | |
{ | |
if (!assetPath.StartsWith(PROPS_PATH)) | |
{ | |
return; | |
} | |
foreach (MeshFilter filter in go.GetComponentsInChildren<MeshFilter>()) | |
{ | |
Mesh mesh = filter.sharedMesh; | |
Vector3 sortAxis = Quaternion.AngleAxis(CAMERA_PITCH, Vector3.right) * Vector3.forward; | |
SortMeshTriangles(mesh, sortAxis); | |
} | |
foreach (SkinnedMeshRenderer skinnedMeshRenderer in go.GetComponentsInChildren<SkinnedMeshRenderer>()) | |
{ | |
Mesh mesh = skinnedMeshRenderer.sharedMesh; | |
// Truth be told, I have no clue why this needs to be reversed for skinned mesh renderers. | |
// Does Unity draw them in the reverse order from normal meshes? | |
Vector3 sortAxis = Quaternion.AngleAxis(-CAMERA_PITCH, Vector3.right) * Vector3.back; | |
SortMeshTriangles(mesh, sortAxis); | |
} | |
} | |
private void SortMeshTriangles(Mesh mesh, Vector3 sortAxis) | |
{ | |
_cachedVertices.Clear(); | |
mesh.GetVertices(_cachedVertices); | |
for (int i = 0; i < mesh.subMeshCount; i++) | |
{ | |
SortSubmeshTriangles(mesh, i, sortAxis); | |
} | |
} | |
private void SortSubmeshTriangles(Mesh mesh, int submeshIndex, Vector3 sortAxis) | |
{ | |
_cachedTriangles.Clear(); | |
_cachedTriangleIndices.Clear(); | |
mesh.GetTriangles(_cachedTriangleIndices, submeshIndex); | |
int baseVertex = (int)mesh.GetBaseVertex(submeshIndex); | |
for (int i = 0; i < _cachedTriangleIndices.Count / 3; i++) | |
{ | |
Vector3 v1 = _cachedVertices[baseVertex + _cachedTriangleIndices[i * 3]]; | |
Vector3 v2 = _cachedVertices[baseVertex + _cachedTriangleIndices[i * 3 + 1]]; | |
Vector3 v3 = _cachedVertices[baseVertex + _cachedTriangleIndices[i * 3 + 2]]; | |
Vector3 avg = (v1 + v2 + v3) / 3f; | |
Triangle triangle = default; | |
triangle.index = i; | |
triangle.dot = Vector3.Dot(avg, sortAxis); | |
_cachedTriangles.Add(triangle); | |
} | |
_cachedTriangles.Sort((x, y) => y.dot.CompareTo(x.dot)); | |
_cachedNewTriangleIndices.Clear(); | |
foreach (Triangle triangle in _cachedTriangles) | |
{ | |
_cachedNewTriangleIndices.Add(_cachedTriangleIndices[triangle.index * 3]); | |
_cachedNewTriangleIndices.Add(_cachedTriangleIndices[triangle.index * 3 + 1]); | |
_cachedNewTriangleIndices.Add(_cachedTriangleIndices[triangle.index * 3 + 2]); | |
} | |
mesh.SetTriangles(_cachedNewTriangleIndices.ToArray(), submeshIndex); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment