BabylonExporter.Material.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.Max;
  4. using BabylonExport.Entities;
  5. namespace Max2Babylon
  6. {
  7. partial class BabylonExporter
  8. {
  9. readonly List<IIGameMaterial> referencedMaterials = new List<IIGameMaterial>();
  10. private void ExportMaterial(IIGameMaterial materialNode, BabylonScene babylonScene)
  11. {
  12. var name = materialNode.MaterialName;
  13. var id = materialNode.MaxMaterial.GetGuid().ToString();
  14. RaiseMessage(name, 1);
  15. // --- prints ---
  16. {
  17. RaiseMessage("materialNode.MaterialClass=" + materialNode.MaterialClass, 2);
  18. RaiseMessage("materialNode.NumberOfTextureMaps=" + materialNode.NumberOfTextureMaps, 2);
  19. var propertyContainer = materialNode.IPropertyContainer;
  20. RaiseMessage("propertyContainer=" + propertyContainer, 2);
  21. if (propertyContainer != null)
  22. {
  23. RaiseMessage("propertyContainer.NumberOfProperties=" + propertyContainer.NumberOfProperties, 3);
  24. for (int i = 0; i < propertyContainer.NumberOfProperties; i++)
  25. {
  26. var prop = propertyContainer.GetProperty(i);
  27. if (prop != null)
  28. {
  29. RaiseMessage("propertyContainer.GetProperty(" + i + ")=" + prop.Name, 3);
  30. switch (prop.GetType_)
  31. {
  32. case PropType.StringProp:
  33. string propertyString = "";
  34. RaiseMessage("prop.GetPropertyValue(ref propertyString, 0)=" + prop.GetPropertyValue(ref propertyString, 0), 4);
  35. RaiseMessage("propertyString=" + propertyString, 4);
  36. break;
  37. case PropType.IntProp:
  38. int propertyInt = 0;
  39. RaiseMessage("prop.GetPropertyValue(ref propertyInt, 0)=" + prop.GetPropertyValue(ref propertyInt, 0), 4);
  40. RaiseMessage("propertyInt=" + propertyInt, 4);
  41. break;
  42. case PropType.FloatProp:
  43. float propertyFloat = 0;
  44. RaiseMessage("prop.GetPropertyValue(ref propertyFloat, 0)=" + prop.GetPropertyValue(ref propertyFloat, 0, true), 4);
  45. RaiseMessage("propertyFloat=" + propertyFloat, 4);
  46. RaiseMessage("prop.GetPropertyValue(ref propertyFloat, 0)=" + prop.GetPropertyValue(ref propertyFloat, 0, false), 4);
  47. RaiseMessage("propertyFloat=" + propertyFloat, 4);
  48. break;
  49. case PropType.Point3Prop:
  50. IPoint3 propertyPoint3 = Loader.Global.Point3.Create(0, 0, 0);
  51. RaiseMessage("prop.GetPropertyValue(ref propertyPoint3, 0)=" + prop.GetPropertyValue(propertyPoint3, 0), 4);
  52. RaiseMessage("propertyPoint3=" + Point3ToString(propertyPoint3), 4);
  53. break;
  54. case PropType.Point4Prop:
  55. IPoint4 propertyPoint4 = Loader.Global.Point4.Create(0,0,0,0);
  56. RaiseMessage("prop.GetPropertyValue(ref propertyPoint4, 0)=" + prop.GetPropertyValue(propertyPoint4, 0), 4);
  57. RaiseMessage("propertyPoint4=" + Point4ToString(propertyPoint4), 4);
  58. break;
  59. case PropType.UnknownProp:
  60. default:
  61. RaiseMessage("Unknown property type", 4);
  62. break;
  63. }
  64. }
  65. else
  66. {
  67. RaiseMessage("propertyContainer.GetProperty(" + i + ") IS NULL", 3);
  68. }
  69. }
  70. }
  71. }
  72. if (materialNode.SubMaterialCount > 0)
  73. {
  74. var babylonMultimaterial = new BabylonMultiMaterial { name = name, id = id };
  75. var guids = new List<string>();
  76. for (var index = 0; index < materialNode.SubMaterialCount; index++)
  77. {
  78. var subMat = materialNode.GetSubMaterial(index);
  79. if (subMat != null)
  80. {
  81. guids.Add(subMat.MaxMaterial.GetGuid().ToString());
  82. if (!referencedMaterials.Contains(subMat))
  83. {
  84. referencedMaterials.Add(subMat);
  85. ExportMaterial(subMat, babylonScene);
  86. }
  87. }
  88. else
  89. {
  90. guids.Add(Guid.Empty.ToString());
  91. }
  92. }
  93. babylonMultimaterial.materials = guids.ToArray();
  94. babylonScene.MultiMaterialsList.Add(babylonMultimaterial);
  95. return;
  96. }
  97. var stdMat = materialNode.MaxMaterial.GetParamBlock(0).Owner as IStdMat2;
  98. if (stdMat != null)
  99. {
  100. var babylonMaterial = new BabylonStandardMaterial
  101. {
  102. name = name,
  103. id = id,
  104. ambient = materialNode.MaxMaterial.GetAmbient(0, false).ToArray(),
  105. diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(),
  106. specular = materialNode.MaxMaterial.GetSpecular(0, false).Scale(materialNode.MaxMaterial.GetShinStr(0, false)),
  107. specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256,
  108. emissive =
  109. materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
  110. ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
  111. : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)),
  112. alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false)
  113. };
  114. babylonMaterial.backFaceCulling = !stdMat.TwoSided;
  115. babylonMaterial.wireframe = stdMat.Wire;
  116. // Textures
  117. BabylonFresnelParameters fresnelParameters;
  118. babylonMaterial.ambientTexture = ExportTexture(stdMat, 0, out fresnelParameters, babylonScene); // Ambient
  119. babylonMaterial.diffuseTexture = ExportTexture(stdMat, 1, out fresnelParameters, babylonScene); // Diffuse
  120. if (fresnelParameters != null)
  121. {
  122. babylonMaterial.diffuseFresnelParameters = fresnelParameters;
  123. }
  124. babylonMaterial.specularTexture = ExportTexture(stdMat, 2, out fresnelParameters, babylonScene); // Specular
  125. babylonMaterial.emissiveTexture = ExportTexture(stdMat, 5, out fresnelParameters, babylonScene); // Emissive
  126. if (fresnelParameters != null)
  127. {
  128. babylonMaterial.emissiveFresnelParameters = fresnelParameters;
  129. if (babylonMaterial.emissive[0] == 0 &&
  130. babylonMaterial.emissive[1] == 0 &&
  131. babylonMaterial.emissive[2] == 0 &&
  132. babylonMaterial.emissiveTexture == null)
  133. {
  134. babylonMaterial.emissive = new float[] { 1, 1, 1 };
  135. }
  136. }
  137. babylonMaterial.opacityTexture = ExportTexture(stdMat, 6, out fresnelParameters, babylonScene, false, true); // Opacity
  138. if (fresnelParameters != null)
  139. {
  140. babylonMaterial.opacityFresnelParameters = fresnelParameters;
  141. if (babylonMaterial.alpha == 1 &&
  142. babylonMaterial.opacityTexture == null)
  143. {
  144. babylonMaterial.alpha = 0;
  145. }
  146. }
  147. babylonMaterial.bumpTexture = ExportTexture(stdMat, 8, out fresnelParameters, babylonScene); // Bump
  148. babylonMaterial.reflectionTexture = ExportTexture(stdMat, 9, out fresnelParameters, babylonScene, true); // Reflection
  149. if (fresnelParameters != null)
  150. {
  151. if (babylonMaterial.reflectionTexture == null)
  152. {
  153. RaiseWarning("Fallout cannot be used with reflection channel without a texture", 2);
  154. }
  155. else
  156. {
  157. babylonMaterial.reflectionFresnelParameters = fresnelParameters;
  158. }
  159. }
  160. // Constraints
  161. if (babylonMaterial.diffuseTexture != null)
  162. {
  163. babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f };
  164. }
  165. if (babylonMaterial.emissiveTexture != null)
  166. {
  167. babylonMaterial.emissive = new float[] { 0, 0, 0 };
  168. }
  169. if (babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture != null &&
  170. babylonMaterial.diffuseTexture.name == babylonMaterial.opacityTexture.name &&
  171. babylonMaterial.diffuseTexture.hasAlpha && !babylonMaterial.opacityTexture.getAlphaFromRGB)
  172. {
  173. // This is a alpha testing purpose
  174. babylonMaterial.opacityTexture = null;
  175. babylonMaterial.diffuseTexture.hasAlpha = true;
  176. RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", 2);
  177. RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", 2);
  178. }
  179. babylonScene.MaterialsList.Add(babylonMaterial);
  180. }
  181. else if (materialNode.MaterialClass == "Physical Material")
  182. {
  183. var propertyContainer = materialNode.IPropertyContainer;
  184. var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial
  185. {
  186. name = name,
  187. id = id
  188. };
  189. // --- Global ---
  190. babylonMaterial.alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false);
  191. // TODO - Add alpha
  192. babylonMaterial.baseColor = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray();
  193. babylonMaterial.metallic = propertyContainer.GetFloatProperty(6);
  194. babylonMaterial.roughness = propertyContainer.GetFloatProperty(4);
  195. if (propertyContainer.GetIntProperty(5) == 1)
  196. {
  197. // Inverse roughness
  198. babylonMaterial.roughness = 1 - babylonMaterial.roughness;
  199. }
  200. // Self illumination is computed from emission color, luminance, temperature and weight
  201. babylonMaterial.emissiveColor = materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
  202. ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
  203. : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false));
  204. // TODO - occlusionStrength - use default? ignored?
  205. // TODO - alphaCutOff - use default?
  206. // TODO - transparencyMode - private or public ?
  207. // TODO - doubleSided - use default?
  208. // --- Textures ---
  209. // TODO - Add alpha
  210. babylonMaterial.baseTexture = ExportPBRTexture(materialNode, 1, babylonScene);
  211. babylonMaterial.metallicRoughnessTexture = ExportMetallicRoughnessTexture(materialNode, babylonMaterial.metallic, babylonMaterial.roughness, babylonScene, name);
  212. // TODO - environmentTexture - as simple as that?
  213. babylonMaterial.environmentTexture = ExportPBRTexture(materialNode, 3, babylonScene);
  214. var normalMapAmount = propertyContainer.GetFloatProperty(91);
  215. babylonMaterial.normalTexture = ExportPBRTexture(materialNode, 30, babylonScene, normalMapAmount);
  216. babylonMaterial.emissiveTexture = ExportPBRTexture(materialNode, 17, babylonScene);
  217. // TODO - occlusionTexture - ignored?
  218. babylonScene.MaterialsList.Add(babylonMaterial);
  219. }
  220. else
  221. {
  222. RaiseWarning("Unsupported material type: " + materialNode.MaterialClass, 2);
  223. }
  224. }
  225. // -------------------------
  226. // --------- Utils ---------
  227. // -------------------------
  228. private string ColorToString(IColor color)
  229. {
  230. if (color == null)
  231. {
  232. return "";
  233. }
  234. return "{ r=" + color.R + ", g=" + color.G + ", b=" + color.B + " }";
  235. }
  236. private string Point3ToString(IPoint3 point)
  237. {
  238. if (point == null)
  239. {
  240. return "";
  241. }
  242. return "{ x=" + point.X + ", y=" + point.Y + ", z=" + point.Z + " }";
  243. }
  244. private string Point4ToString(IPoint4 point)
  245. {
  246. if (point == null)
  247. {
  248. return "";
  249. }
  250. return "{ x=" + point.X + ", y=" + point.Y + ", z=" + point.Z + ", w=" + point.W + " }";
  251. }
  252. }
  253. }