MeshPrimitiveReader.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.Xna.Framework.Graphics;
  5. using SharpGLTF.Schema2;
  6. using XY = System.Numerics.Vector2;
  7. using XYZ = System.Numerics.Vector3;
  8. using XYZW = System.Numerics.Vector4;
  9. namespace SharpGLTF.Runtime
  10. {
  11. class MeshPrimitiveReader
  12. {
  13. #region lifecycle
  14. public MeshPrimitiveReader(MeshPrimitive srcPrim, bool doubleSided, MeshNormalsFallback fallbackNormals)
  15. {
  16. _Positions = srcPrim.GetVertexAccessor("POSITION")?.AsVector3Array();
  17. _Normals = srcPrim.GetVertexAccessor("NORMAL")?.AsVector3Array();
  18. if (_Normals == null)
  19. {
  20. _Normals = new XYZ[_Positions.Count];
  21. for (int i = 0; i < _Normals.Count; ++i)
  22. {
  23. _Normals[i] = fallbackNormals.GetNormal(_Positions[i]);
  24. }
  25. }
  26. _Color0 = srcPrim.GetVertexAccessor("COLOR_0")?.AsColorArray();
  27. _TexCoord0 = srcPrim.GetVertexAccessor("TEXCOORD_0")?.AsVector2Array();
  28. _Joints0 = srcPrim.GetVertexAccessor("JOINTS_0")?.AsVector4Array();
  29. _Joints1 = srcPrim.GetVertexAccessor("JOINTS_1")?.AsVector4Array();
  30. _Weights0 = srcPrim.GetVertexAccessor("WEIGHTS_0")?.AsVector4Array();
  31. _Weights1 = srcPrim.GetVertexAccessor("WEIGHTS_1")?.AsVector4Array();
  32. if (_Joints0 == null || _Weights0 == null) { _Joints0 = _Joints1 = _Weights0 = _Weights1 = null; }
  33. if (_Joints1 == null || _Weights1 == null) { _Joints1 = _Weights1 = null; }
  34. if (_Weights0 != null)
  35. {
  36. _Weights0 = _Weights0.ToArray(); // isolate memory to prevent overwriting source glTF.
  37. for (int i = 0; i < _Weights0.Count; ++i)
  38. {
  39. var r = XYZW.Dot(_Weights0[i], XYZW.One);
  40. _Weights0[i] /= r;
  41. }
  42. }
  43. if (doubleSided) // Monogame's effect material does not support double sided materials, so we simulate it by adding reverse faces
  44. {
  45. var front = srcPrim.GetTriangleIndices();
  46. var back = front.Select(item => (item.Item1, item.Item3, item.Item2));
  47. _Triangles = front.Concat(back).ToArray();
  48. }
  49. else
  50. {
  51. _Triangles = srcPrim.GetTriangleIndices().ToArray();
  52. }
  53. }
  54. #endregion
  55. #region data
  56. private readonly (int, int, int)[] _Triangles;
  57. private readonly IList<XYZ> _Positions;
  58. private readonly IList<XYZ> _Normals;
  59. private readonly IList<XYZW> _Color0;
  60. private readonly IList<XY> _TexCoord0;
  61. private readonly IList<XYZW> _Joints0;
  62. private readonly IList<XYZW> _Joints1;
  63. private readonly IList<XYZW> _Weights0;
  64. private readonly IList<XYZW> _Weights1;
  65. #endregion
  66. #region properties
  67. public bool IsSkinned => _Joints0 != null;
  68. public int VertexCount => _Positions?.Count ?? 0;
  69. public (int, int, int)[] TriangleIndices => _Triangles;
  70. #endregion
  71. #region API
  72. public VertexPositionNormalTexture[] ToXnaStatic()
  73. {
  74. var dst = new VertexPositionNormalTexture[_Positions.Count];
  75. for (int i = 0; i < dst.Length; ++i)
  76. {
  77. dst[i].Position = _Positions[i].ToXna();
  78. dst[i].Normal = _Normals[i].ToXna();
  79. if (_TexCoord0 != null) dst[i].TextureCoordinate = _TexCoord0[i].ToXna();
  80. }
  81. return dst;
  82. }
  83. public VertexSkinned[] ToXnaSkinned()
  84. {
  85. var dst = new VertexSkinned[_Positions.Count];
  86. for (int i = 0; i < dst.Length; ++i)
  87. {
  88. dst[i].Position = _Positions[i].ToXna();
  89. dst[i].Normal = _Normals[i].ToXna();
  90. if (_TexCoord0 != null) dst[i].TextureCoordinate = _TexCoord0[i].ToXna();
  91. dst[i].BlendIndices = new Microsoft.Xna.Framework.Graphics.PackedVector.Byte4(_Joints0[i].ToXna());
  92. dst[i].BlendWeight = _Weights0[i].ToXna();
  93. }
  94. return dst;
  95. }
  96. #endregion
  97. }
  98. }