MeshNormalsFallback.cs 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. using System.Collections.Generic;
  2. using XYZ = System.Numerics.Vector3;
  3. namespace SharpGLTF.Runtime
  4. {
  5. /// <summary>
  6. /// Helper class used to calculate smooth Normals on glTF meshes with missing normals.
  7. /// </summary>
  8. class MeshNormalsFallback
  9. {
  10. #region lifecycle
  11. public MeshNormalsFallback(Schema2.Mesh mesh)
  12. {
  13. foreach (var srcPrim in mesh.Primitives)
  14. {
  15. var accessor = srcPrim.GetVertexAccessor("POSITION");
  16. if (accessor == null) continue;
  17. var positions = accessor.AsVector3Array();
  18. foreach (var srcTri in srcPrim.GetTriangleIndices())
  19. {
  20. var a = positions[srcTri.A];
  21. var b = positions[srcTri.B];
  22. var c = positions[srcTri.C];
  23. var d = XYZ.Cross(b - a, c - a);
  24. AddWeightedNormal(a, d);
  25. AddWeightedNormal(b, d);
  26. AddWeightedNormal(c, d);
  27. }
  28. }
  29. }
  30. #endregion
  31. #region data
  32. private readonly Dictionary<XYZ, XYZ> _WeightedNormals = new Dictionary<XYZ, XYZ>();
  33. #endregion
  34. #region API
  35. private void AddWeightedNormal(XYZ p, XYZ d)
  36. {
  37. if (_WeightedNormals.TryGetValue(p, out XYZ ddd)) ddd += d;
  38. else ddd = d;
  39. _WeightedNormals[p] = ddd;
  40. }
  41. public XYZ GetNormal(XYZ position)
  42. {
  43. if (!_WeightedNormals.TryGetValue(position, out XYZ normal)) normal = position;
  44. return normal == XYZ.Zero ? XYZ.UnitX : XYZ.Normalize(normal);
  45. }
  46. #endregion
  47. }
  48. }