LoaderContext.BasicEffect.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Microsoft.Xna.Framework;
  7. using Microsoft.Xna.Framework.Graphics;
  8. using GLTFMATERIAL = SharpGLTF.Schema2.Material;
  9. namespace SharpGLTF.Runtime
  10. {
  11. class BasicEffectsLoaderContext : LoaderContext
  12. {
  13. #region lifecycle
  14. public BasicEffectsLoaderContext(GraphicsDevice device) : base(device) { }
  15. #endregion
  16. #region effects creation
  17. // Monogame's BasicEffect uses Phong's shading, while glTF uses PBR shading, so
  18. // given monogame's limitations, we try to guess the most appropiate values
  19. // to have a reasonably good looking renders.
  20. protected override Effect CreateEffect(GLTFMATERIAL srcMaterial, bool isSkinned)
  21. {
  22. return isSkinned ? CreateSkinnedEffect(srcMaterial) : CreateRigidEffect(srcMaterial);
  23. }
  24. protected virtual Effect CreateRigidEffect(GLTFMATERIAL srcMaterial)
  25. {
  26. var dstMaterial = srcMaterial.Alpha == Schema2.AlphaMode.MASK
  27. ? CreateAlphaTestEffect(srcMaterial)
  28. : CreateBasicEffect(srcMaterial);
  29. return dstMaterial;
  30. }
  31. protected virtual Effect CreateBasicEffect(GLTFMATERIAL srcMaterial)
  32. {
  33. var dstMaterial = new BasicEffect(Device);
  34. dstMaterial.Name = srcMaterial.Name;
  35. dstMaterial.Alpha = GetAlphaLevel(srcMaterial);
  36. dstMaterial.DiffuseColor = GetDiffuseColor(srcMaterial);
  37. dstMaterial.SpecularColor = GetSpecularColor(srcMaterial);
  38. dstMaterial.SpecularPower = GetSpecularPower(srcMaterial);
  39. dstMaterial.EmissiveColor = GeEmissiveColor(srcMaterial);
  40. dstMaterial.Texture = UseDiffuseTexture(srcMaterial);
  41. if (srcMaterial.Unlit)
  42. {
  43. dstMaterial.EmissiveColor = dstMaterial.DiffuseColor;
  44. dstMaterial.SpecularColor = Vector3.Zero;
  45. dstMaterial.SpecularPower = 16;
  46. }
  47. dstMaterial.PreferPerPixelLighting = true;
  48. dstMaterial.TextureEnabled = dstMaterial.Texture != null;
  49. return dstMaterial;
  50. }
  51. protected virtual Effect CreateAlphaTestEffect(GLTFMATERIAL srcMaterial)
  52. {
  53. var dstMaterial = new AlphaTestEffect(Device);
  54. dstMaterial.Name = srcMaterial.Name;
  55. dstMaterial.Alpha = GetAlphaLevel(srcMaterial);
  56. //dstMaterial.AlphaFunction = CompareFunction.GreaterEqual;
  57. dstMaterial.ReferenceAlpha = (int)(srcMaterial.AlphaCutoff * 255);
  58. dstMaterial.DiffuseColor = GetDiffuseColor(srcMaterial);
  59. dstMaterial.Texture = UseDiffuseTexture(srcMaterial);
  60. return dstMaterial;
  61. }
  62. protected virtual Effect CreateSkinnedEffect(GLTFMATERIAL srcMaterial)
  63. {
  64. var dstMaterial = new SkinnedEffect(Device);
  65. dstMaterial.Name = srcMaterial.Name;
  66. dstMaterial.Alpha = GetAlphaLevel(srcMaterial);
  67. dstMaterial.DiffuseColor = GetDiffuseColor(srcMaterial);
  68. dstMaterial.SpecularColor = GetSpecularColor(srcMaterial);
  69. dstMaterial.SpecularPower = GetSpecularPower(srcMaterial);
  70. dstMaterial.EmissiveColor = GeEmissiveColor(srcMaterial);
  71. dstMaterial.Texture = UseDiffuseTexture(srcMaterial);
  72. dstMaterial.WeightsPerVertex = 4;
  73. dstMaterial.PreferPerPixelLighting = true;
  74. // apparently, SkinnedEffect does not support disabling textures, so we set a white texture here.
  75. if (dstMaterial.Texture == null) dstMaterial.Texture = UseTexture(null, null); // creates a dummy white texture.
  76. return dstMaterial;
  77. }
  78. #endregion
  79. #region meshes creation
  80. protected override void WriteMeshPrimitive(MeshPrimitiveReader srcPrimitive, Effect effect)
  81. {
  82. if (srcPrimitive.IsSkinned) WriteMeshPrimitive<VertexSkinned>(effect, srcPrimitive);
  83. else WriteMeshPrimitive<VertexPositionNormalTexture>(effect, srcPrimitive);
  84. }
  85. #endregion
  86. #region gltf helpers
  87. private static float GetAlphaLevel(GLTFMATERIAL srcMaterial)
  88. {
  89. if (srcMaterial.Alpha == Schema2.AlphaMode.OPAQUE) return 1;
  90. var baseColor = srcMaterial.FindChannel("BaseColor");
  91. if (baseColor == null) return 1;
  92. return baseColor.Value.Color.W;
  93. }
  94. private static Vector3 GetDiffuseColor(GLTFMATERIAL srcMaterial)
  95. {
  96. var diffuse = srcMaterial.FindChannel("Diffuse");
  97. if (diffuse == null) diffuse = srcMaterial.FindChannel("BaseColor");
  98. if (diffuse == null) return Vector3.One;
  99. return new Vector3(diffuse.Value.Color.X, diffuse.Value.Color.Y, diffuse.Value.Color.Z);
  100. }
  101. private static Vector3 GetSpecularColor(GLTFMATERIAL srcMaterial)
  102. {
  103. var mr = srcMaterial.FindChannel("MetallicRoughness");
  104. if (mr == null) return Vector3.One; // default value 16
  105. var diffuse = GetDiffuseColor(srcMaterial);
  106. var metallic = mr.Value.Parameter.X;
  107. var roughness = mr.Value.Parameter.Y;
  108. var k = Vector3.Zero;
  109. k += Vector3.Lerp(diffuse, Vector3.Zero, roughness);
  110. k += Vector3.Lerp(diffuse, Vector3.One, metallic);
  111. k *= 0.5f;
  112. return k;
  113. }
  114. private static float GetSpecularPower(GLTFMATERIAL srcMaterial)
  115. {
  116. var mr = srcMaterial.FindChannel("MetallicRoughness");
  117. if (mr == null) return 16; // default value = 16
  118. var metallic = mr.Value.Parameter.X;
  119. var roughness = mr.Value.Parameter.Y;
  120. return 4 + 16 * metallic;
  121. }
  122. private static Vector3 GeEmissiveColor(GLTFMATERIAL srcMaterial)
  123. {
  124. var emissive = srcMaterial.FindChannel("Emissive");
  125. if (emissive == null) return Vector3.Zero;
  126. return new Vector3(emissive.Value.Color.X, emissive.Value.Color.Y, emissive.Value.Color.Z);
  127. }
  128. private Texture2D UseDiffuseTexture(GLTFMATERIAL srcMaterial)
  129. {
  130. var diffuse = srcMaterial.FindChannel("Diffuse");
  131. if (diffuse == null) diffuse = srcMaterial.FindChannel("BaseColor");
  132. if (diffuse == null) return null;
  133. return UseTexture(diffuse, null);
  134. }
  135. #endregion
  136. }
  137. }