Skip to content

Instantly share code, notes, and snippets.

@xabblll
Created June 15, 2024 21:24
Show Gist options
  • Save xabblll/c0e4cfbf025a02e8dfb7a8deb17657f5 to your computer and use it in GitHub Desktop.
Save xabblll/c0e4cfbf025a02e8dfb7a8deb17657f5 to your computer and use it in GitHub Desktop.
Unity3D - Model postprocessor for fixing blend shapes normals and tangents
// Place inside Editor folder
using UnityEditor;
using UnityEngine;
namespace Code.Editor
{
public class MeshPostprocessor : AssetPostprocessor
{
private void OnPostprocessModel(GameObject g)
{
var smrs = g.GetComponentsInChildren<SkinnedMeshRenderer>();
for (int i = 0; i < smrs.Length; i++)
{
FixShapes(smrs[i]);
}
}
private struct ShapeData
{
public string Name;
public float Weight;
public Vector3[] DeltaVertices;
public Vector3[] DeltaNormals;
public Vector3[] DeltaTangents;
}
private static void FixShapes(SkinnedMeshRenderer smr)
{
// Looks OK, but maybe should be increased
const float eps = float.Epsilon;
var mesh = smr.sharedMesh;
var vertexCount = mesh.vertexCount;
var shapeCount = mesh.blendShapeCount;
var shapeDataArray = new ShapeData[shapeCount];
for (int i = 0; i < shapeCount; i++)
{
shapeDataArray[i].Name = mesh.GetBlendShapeName(i);
// Add support for multiple frames in one shape?
shapeDataArray[i].Weight = mesh.GetBlendShapeFrameWeight(i, 0);
shapeDataArray[i].DeltaVertices = new Vector3[vertexCount];
shapeDataArray[i].DeltaNormals = new Vector3[vertexCount];
shapeDataArray[i].DeltaTangents = new Vector3[vertexCount];
mesh.GetBlendShapeFrameVertices(i, 0, shapeDataArray[i].DeltaVertices, shapeDataArray[i].DeltaNormals, shapeDataArray[i].DeltaTangents);
// Clean "empty" vertices
for (int j = 0; j < vertexCount; j++)
{
if (Vector3.SqrMagnitude(shapeDataArray[i].DeltaVertices[j]) < eps)
{
shapeDataArray[i].DeltaVertices[j] = Vector3.zero;
shapeDataArray[i].DeltaNormals [j] = Vector3.zero;
shapeDataArray[i].DeltaTangents[j] = Vector3.zero;
}
}
}
mesh.ClearBlendShapes();
// Add all shapes back
for (int i = 0; i < shapeDataArray.Length; i++)
{
mesh.AddBlendShapeFrame(shapeDataArray[i].Name, shapeDataArray[i].Weight, shapeDataArray[i].DeltaVertices, shapeDataArray[i].DeltaNormals, shapeDataArray[i].DeltaTangents);
}
}
}
}
@xabblll
Copy link
Author

xabblll commented Jun 15, 2024

BlendShapeNormalsFix
Pic: blend shape moves vertices on body, hand vertices shouldn't change

This postprocessor can help fix blend shape artifacts. Basically if you import model with blend shape, some vertices with zero changes will generate garbage data, resulting in incorrect normals and tangents.

If you still having this artifact, try to increasing "eps" value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment