MeshBuilderToolkit.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Numerics;
  5. using System.Text;
  6. using SharpGLTF.Geometry.VertexTypes;
  7. namespace SharpGLTF.Geometry
  8. {
  9. public interface IMeshBuilder<TMaterial>
  10. {
  11. string Name { get; set; }
  12. IEnumerable<TMaterial> Materials { get; }
  13. IReadOnlyCollection<IPrimitiveReader<TMaterial>> Primitives { get; }
  14. IPrimitiveBuilder UsePrimitive(TMaterial material, int primitiveVertexCount = 3);
  15. void Validate();
  16. }
  17. static class MeshBuilderToolkit
  18. {
  19. public static IMeshBuilder<TMaterial> CreateMeshBuilderFromVertexAttributes<TMaterial>(params string[] vertexAttributes)
  20. {
  21. Type meshType = GetMeshBuilderType(typeof(TMaterial), vertexAttributes);
  22. var mesh = Activator.CreateInstance(meshType, string.Empty);
  23. return mesh as IMeshBuilder<TMaterial>;
  24. }
  25. public static Type GetMeshBuilderType(Type materialType, string[] vertexAttributes)
  26. {
  27. var tvg = VertexUtils.GetVertexGeometryType(vertexAttributes);
  28. var tvm = VertexUtils.GetVertexMaterialType(vertexAttributes);
  29. var tvs = VertexUtils.GetVertexSkinningType(vertexAttributes);
  30. var meshType = typeof(MeshBuilder<,,,>);
  31. meshType = meshType.MakeGenericType(materialType, tvg, tvm, tvs);
  32. return meshType;
  33. }
  34. public static IReadOnlyDictionary<Vector3, Vector3> CalculateSmoothNormals<TMaterial>(this IMeshBuilder<TMaterial> srcMesh)
  35. {
  36. var posnrm = new Dictionary<Vector3, Vector3>();
  37. void addDirection(Dictionary<Vector3, Vector3> dict, Vector3 pos, Vector3 dir)
  38. {
  39. if (!dir._IsFinite()) return;
  40. if (!dict.TryGetValue(pos, out Vector3 n)) n = Vector3.Zero;
  41. dict[pos] = n + dir;
  42. }
  43. foreach (var prim in srcMesh.Primitives)
  44. {
  45. foreach (var tri in prim.Triangles)
  46. {
  47. var a = prim.Vertices[tri.Item1].GetGeometry().GetPosition();
  48. var b = prim.Vertices[tri.Item1].GetGeometry().GetPosition();
  49. var c = prim.Vertices[tri.Item1].GetGeometry().GetPosition();
  50. var d = Vector3.Cross(b - a, c - a);
  51. addDirection(posnrm, a, d);
  52. addDirection(posnrm, b, d);
  53. addDirection(posnrm, c, d);
  54. }
  55. }
  56. foreach (var pos in posnrm.Keys.ToList())
  57. {
  58. posnrm[pos] = Vector3.Normalize(posnrm[pos]);
  59. }
  60. return posnrm;
  61. }
  62. public static bool IsEmpty<TMaterial>(this IPrimitiveReader<TMaterial> primitive)
  63. {
  64. if (primitive.Points.Count > 0) return false;
  65. if (primitive.Lines.Count > 0) return false;
  66. if (primitive.Triangles.Count > 0) return false;
  67. return true;
  68. }
  69. public static bool IsEmpty<TMaterial>(this IMeshBuilder<TMaterial> mesh)
  70. {
  71. return mesh.Primitives.All(prim => prim.IsEmpty());
  72. }
  73. }
  74. }