BabylonExporter.GLTFExporter.Material.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. using BabylonExport.Entities;
  2. using GLTFExport.Entities;
  3. using System;
  4. using System.Drawing;
  5. using System.IO;
  6. namespace Max2Babylon
  7. {
  8. partial class BabylonExporter
  9. {
  10. private void ExportMaterial(BabylonMaterial babylonMaterial, GLTF gltf)
  11. {
  12. var name = babylonMaterial.name;
  13. var id = babylonMaterial.id;
  14. RaiseMessage("GLTFExporter.Material | Export material named: " + name, 1);
  15. if (babylonMaterial.GetType() == typeof(BabylonStandardMaterial))
  16. {
  17. var babylonStandardMaterial = babylonMaterial as BabylonStandardMaterial;
  18. // --- prints ---
  19. RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
  20. RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
  21. RaiseMessage("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
  22. RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
  23. RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
  24. // Ambient
  25. for (int i = 0; i < babylonStandardMaterial.ambient.Length; i++)
  26. {
  27. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambient[" + i + "]=" + babylonStandardMaterial.ambient[i], 3);
  28. }
  29. // Diffuse
  30. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse.Length=" + babylonStandardMaterial.diffuse.Length, 3);
  31. for (int i = 0; i < babylonStandardMaterial.diffuse.Length; i++)
  32. {
  33. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse[" + i + "]=" + babylonStandardMaterial.diffuse[i], 3);
  34. }
  35. if (babylonStandardMaterial.diffuseTexture == null)
  36. {
  37. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture=null", 3);
  38. }
  39. else
  40. {
  41. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture.name=" + babylonStandardMaterial.diffuseTexture.name, 3);
  42. }
  43. // Normal / bump
  44. if (babylonStandardMaterial.bumpTexture == null)
  45. {
  46. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.bumpTexture=null", 3);
  47. }
  48. else
  49. {
  50. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.bumpTexture.name=" + babylonStandardMaterial.bumpTexture.name, 3);
  51. }
  52. // Opacity
  53. if (babylonStandardMaterial.opacityTexture == null)
  54. {
  55. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.opacityTexture=null", 3);
  56. }
  57. else
  58. {
  59. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.opacityTexture.name=" + babylonStandardMaterial.opacityTexture.name, 3);
  60. }
  61. // Specular
  62. for (int i = 0; i < babylonStandardMaterial.specular.Length; i++)
  63. {
  64. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specular[" + i + "]=" + babylonStandardMaterial.specular[i], 3);
  65. }
  66. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularPower=" + babylonStandardMaterial.specularPower, 3);
  67. if (babylonStandardMaterial.specularTexture == null)
  68. {
  69. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularTexture=null", 3);
  70. }
  71. else
  72. {
  73. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularTexture.name=" + babylonStandardMaterial.specularTexture.name, 3);
  74. }
  75. // Occlusion
  76. if (babylonStandardMaterial.ambientTexture == null)
  77. {
  78. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambientTexture=null", 3);
  79. }
  80. else
  81. {
  82. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambientTexture.name=" + babylonStandardMaterial.ambientTexture.name, 3);
  83. }
  84. // Emissive
  85. for (int i = 0; i < babylonStandardMaterial.emissive.Length; i++)
  86. {
  87. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissive[" + i + "]=" + babylonStandardMaterial.emissive[i], 3);
  88. }
  89. if (babylonStandardMaterial.emissiveTexture == null)
  90. {
  91. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture=null", 3);
  92. }
  93. else
  94. {
  95. RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture.name=" + babylonStandardMaterial.emissiveTexture.name, 3);
  96. }
  97. // --------------------------------
  98. // --------- gltfMaterial ---------
  99. // --------------------------------
  100. RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
  101. var gltfMaterial = new GLTFMaterial
  102. {
  103. name = name
  104. };
  105. gltfMaterial.id = babylonMaterial.id;
  106. gltfMaterial.index = gltf.MaterialsList.Count;
  107. gltf.MaterialsList.Add(gltfMaterial);
  108. // Alpha
  109. string alphaMode;
  110. float? alphaCutoff;
  111. getAlphaMode(babylonStandardMaterial, out alphaMode, out alphaCutoff);
  112. gltfMaterial.alphaMode = alphaMode;
  113. gltfMaterial.alphaCutoff = alphaCutoff;
  114. // DoubleSided
  115. gltfMaterial.doubleSided = !babylonMaterial.backFaceCulling;
  116. // Normal
  117. gltfMaterial.normalTexture = ExportTexture(babylonStandardMaterial.bumpTexture, gltf);
  118. // Occulison
  119. gltfMaterial.occlusionTexture = ExportTexture(babylonStandardMaterial.ambientTexture, gltf);
  120. // Emissive
  121. gltfMaterial.emissiveFactor = babylonStandardMaterial.emissive;
  122. gltfMaterial.emissiveTexture = ExportTexture(babylonStandardMaterial.emissiveTexture, gltf);
  123. // --------------------------------
  124. // --- gltfPbrMetallicRoughness ---
  125. // --------------------------------
  126. RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
  127. var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
  128. gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;
  129. // --- Global ---
  130. SpecularGlossiness _specularGlossiness = new SpecularGlossiness
  131. {
  132. diffuse = new BabylonColor3(babylonStandardMaterial.diffuse),
  133. opacity = babylonMaterial.alpha,
  134. specular = new BabylonColor3(babylonStandardMaterial.specular),
  135. glossiness = babylonStandardMaterial.specularPower / 256
  136. };
  137. MetallicRoughness _metallicRoughness = ConvertToMetallicRoughness(_specularGlossiness, true);
  138. // Base color
  139. gltfPbrMetallicRoughness.baseColorFactor = new float[4]
  140. {
  141. _metallicRoughness.baseColor.r,
  142. _metallicRoughness.baseColor.g,
  143. _metallicRoughness.baseColor.b,
  144. _metallicRoughness.opacity
  145. };
  146. // Metallic roughness
  147. gltfPbrMetallicRoughness.metallicFactor = _metallicRoughness.metallic;
  148. gltfPbrMetallicRoughness.roughnessFactor = _metallicRoughness.roughness;
  149. // --- Textures ---
  150. if (babylonStandardMaterial.diffuseTexture != null)
  151. {
  152. Func<string, Bitmap> loadTextureFromOutput = delegate (string textureName)
  153. {
  154. return LoadTexture(Path.Combine(gltf.OutputFolder, textureName));
  155. };
  156. Bitmap diffuseBitmap = loadTextureFromOutput(babylonStandardMaterial.diffuseTexture.name);
  157. if (diffuseBitmap != null)
  158. {
  159. Bitmap specularBitmap = null;
  160. if (babylonStandardMaterial.specularTexture != null)
  161. {
  162. specularBitmap = loadTextureFromOutput(babylonStandardMaterial.specularTexture.name);
  163. }
  164. Bitmap opacityBitmap = null;
  165. if (babylonStandardMaterial.diffuseTexture.hasAlpha == false && babylonStandardMaterial.opacityTexture != null)
  166. {
  167. opacityBitmap = loadTextureFromOutput(babylonStandardMaterial.opacityTexture.name);
  168. }
  169. // Retreive dimensions
  170. int width = 0;
  171. int height = 0;
  172. var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, diffuseBitmap, specularBitmap, opacityBitmap);
  173. if (!haveSameDimensions)
  174. {
  175. RaiseWarning("Diffuse, specular and opacity maps should have same dimensions", 2);
  176. }
  177. // Create base color and metallic+roughness maps
  178. Bitmap baseColorBitmap = new Bitmap(width, height);
  179. Bitmap metallicRoughnessBitmap = new Bitmap(width, height);
  180. var hasAlpha = false;
  181. for (int x = 0; x < width; x++)
  182. {
  183. for (int y = 0; y < height; y++)
  184. {
  185. var diffuse = diffuseBitmap.GetPixel(x, y);
  186. SpecularGlossiness specularGlossinessTexture = new SpecularGlossiness
  187. {
  188. diffuse = new BabylonColor3(diffuse),
  189. opacity = babylonStandardMaterial.diffuseTexture.hasAlpha? diffuse.A / 255.0f :
  190. opacityBitmap != null && babylonStandardMaterial.opacityTexture.getAlphaFromRGB ? opacityBitmap.GetPixel(x, y).R / 255.0f :
  191. opacityBitmap != null && babylonStandardMaterial.opacityTexture.getAlphaFromRGB == false ? opacityBitmap.GetPixel(x, y).A / 255.0f :
  192. 1,
  193. specular = specularBitmap != null ? new BabylonColor3(specularBitmap.GetPixel(x, y)) :
  194. new BabylonColor3(),
  195. glossiness = babylonStandardMaterial.useGlossinessFromSpecularMapAlpha && specularBitmap != null ? specularBitmap.GetPixel(x, y).A / 255.0f :
  196. 0
  197. };
  198. var displayPrints = x == width / 2 && y == height / 2;
  199. MetallicRoughness metallicRoughnessTexture = ConvertToMetallicRoughness(specularGlossinessTexture, displayPrints);
  200. Color colorBase = Color.FromArgb(
  201. (int)(metallicRoughnessTexture.opacity * 255),
  202. (int)(metallicRoughnessTexture.baseColor.r * 255),
  203. (int)(metallicRoughnessTexture.baseColor.g * 255),
  204. (int)(metallicRoughnessTexture.baseColor.b * 255)
  205. );
  206. baseColorBitmap.SetPixel(x, y, colorBase);
  207. if (metallicRoughnessTexture.opacity != 1)
  208. {
  209. hasAlpha = true;
  210. }
  211. // The metalness values are sampled from the B channel.
  212. // The roughness values are sampled from the G channel.
  213. // These values are linear. If other channels are present (R or A), they are ignored for metallic-roughness calculations.
  214. Color colorMetallicRoughness = Color.FromArgb(
  215. 0,
  216. (int)(metallicRoughnessTexture.roughness * 255),
  217. (int)(metallicRoughnessTexture.metallic * 255)
  218. );
  219. metallicRoughnessBitmap.SetPixel(x, y, colorMetallicRoughness);
  220. }
  221. }
  222. // Export maps and textures
  223. var baseColorFileName = babylonMaterial.name + "_baseColor" + (hasAlpha ? ".png" : ".jpg");
  224. gltfPbrMetallicRoughness.baseColorTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, baseColorBitmap, baseColorFileName, gltf);
  225. if (specularBitmap != null)
  226. {
  227. gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, metallicRoughnessBitmap, babylonMaterial.name + "_metallicRoughness" + ".jpg", gltf);
  228. }
  229. }
  230. }
  231. }
  232. else if (babylonMaterial.GetType() == typeof(BabylonPBRMetallicRoughnessMaterial))
  233. {
  234. var babylonPBRMetallicRoughnessMaterial = babylonMaterial as BabylonPBRMetallicRoughnessMaterial;
  235. // --- prints ---
  236. RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
  237. RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
  238. RaiseMessage("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
  239. RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
  240. RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
  241. // Global
  242. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights=" + babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights, 3);
  243. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.disableLighting=" + babylonPBRMetallicRoughnessMaterial.disableLighting, 3);
  244. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.alphaCutOff=" + babylonPBRMetallicRoughnessMaterial.alphaCutOff, 3);
  245. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.transparencyMode=" + babylonPBRMetallicRoughnessMaterial.transparencyMode, 3);
  246. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.doubleSided=" + babylonPBRMetallicRoughnessMaterial.doubleSided, 3);
  247. // Base color
  248. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor.Length=" + babylonPBRMetallicRoughnessMaterial.baseColor.Length, 3);
  249. for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.baseColor.Length; i++)
  250. {
  251. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.baseColor[i], 3);
  252. }
  253. if (babylonPBRMetallicRoughnessMaterial.baseTexture == null)
  254. {
  255. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseTexture=null", 3);
  256. }
  257. // Metallic+roughness
  258. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallic=" + babylonPBRMetallicRoughnessMaterial.metallic, 3);
  259. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.roughness=" + babylonPBRMetallicRoughnessMaterial.roughness, 3);
  260. if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture == null)
  261. {
  262. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture=null", 3);
  263. }
  264. // Environment
  265. if (babylonPBRMetallicRoughnessMaterial.environmentTexture == null)
  266. {
  267. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.environmentTexture=null", 3);
  268. }
  269. // Normal / bump
  270. if (babylonPBRMetallicRoughnessMaterial.normalTexture == null)
  271. {
  272. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.normalTexture=null", 3);
  273. }
  274. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapX=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapX, 3);
  275. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapY=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapY, 3);
  276. // Emissive
  277. for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.emissiveColor.Length; i++)
  278. {
  279. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.emissiveColor[i], 3);
  280. }
  281. if (babylonPBRMetallicRoughnessMaterial.emissiveTexture == null)
  282. {
  283. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveTexture=null", 3);
  284. }
  285. // Ambient occlusion
  286. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionStrength=" + babylonPBRMetallicRoughnessMaterial.occlusionStrength, 3);
  287. if (babylonPBRMetallicRoughnessMaterial.occlusionTexture == null)
  288. {
  289. RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionTexture=null", 3);
  290. }
  291. // --------------------------------
  292. // --------- gltfMaterial ---------
  293. // --------------------------------
  294. RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
  295. var gltfMaterial = new GLTFMaterial
  296. {
  297. name = name
  298. };
  299. gltfMaterial.id = babylonMaterial.id;
  300. gltfMaterial.index = gltf.MaterialsList.Count;
  301. gltf.MaterialsList.Add(gltfMaterial);
  302. // Alpha
  303. string alphaMode;
  304. float? alphaCutoff;
  305. getAlphaMode(babylonPBRMetallicRoughnessMaterial, out alphaMode, out alphaCutoff);
  306. gltfMaterial.alphaMode = alphaMode;
  307. gltfMaterial.alphaCutoff = alphaCutoff;
  308. // DoubleSided
  309. gltfMaterial.doubleSided = babylonPBRMetallicRoughnessMaterial.doubleSided;
  310. // Normal
  311. gltfMaterial.normalTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.normalTexture, gltf);
  312. // Occulison
  313. gltfMaterial.occlusionTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.occlusionTexture, gltf);
  314. // Emissive
  315. gltfMaterial.emissiveFactor = babylonPBRMetallicRoughnessMaterial.emissiveColor;
  316. gltfMaterial.emissiveTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.emissiveTexture, gltf);
  317. // --------------------------------
  318. // --- gltfPbrMetallicRoughness ---
  319. // --------------------------------
  320. RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
  321. var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
  322. gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;
  323. // --- Global ---
  324. // Base color
  325. // TODO - Unclear if alpha must be retreived from 'alpha' property of BABYLON.Material
  326. // or from alpha channel of 'baseColor' of BABYLON.PBRMetallicRoughnessMaterial
  327. gltfPbrMetallicRoughness.baseColorFactor = new float[4]
  328. {
  329. babylonPBRMetallicRoughnessMaterial.baseColor[0],
  330. babylonPBRMetallicRoughnessMaterial.baseColor[1],
  331. babylonPBRMetallicRoughnessMaterial.baseColor[2],
  332. babylonPBRMetallicRoughnessMaterial.alpha
  333. };
  334. gltfPbrMetallicRoughness.baseColorTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.baseTexture, gltf);
  335. // Metallic roughness
  336. gltfPbrMetallicRoughness.metallicFactor = babylonPBRMetallicRoughnessMaterial.metallic;
  337. gltfPbrMetallicRoughness.roughnessFactor = babylonPBRMetallicRoughnessMaterial.roughness;
  338. gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture, gltf);
  339. }
  340. else
  341. {
  342. RaiseWarning("GLTFExporter.Material | Unsupported material type: " + babylonMaterial.GetType(), 2);
  343. }
  344. }
  345. private void getAlphaMode(BabylonStandardMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
  346. {
  347. if (babylonMaterial.alpha != 1.0f ||
  348. (babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.hasAlpha) ||
  349. babylonMaterial.opacityTexture != null)
  350. {
  351. // Babylon standard material is assumed to useAlphaFromDiffuseTexture. If not, the alpha mode is a mask.
  352. alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
  353. }
  354. else
  355. {
  356. alphaMode = null; // glTF alpha mode default value is "OPAQUE"
  357. }
  358. alphaCutoff = null;
  359. }
  360. private void getAlphaMode(BabylonPBRMetallicRoughnessMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
  361. {
  362. alphaMode = null;
  363. alphaCutoff = null;
  364. switch (babylonMaterial.transparencyMode)
  365. {
  366. case (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.OPAQUE:
  367. alphaMode = null; // glTF alpha mode default value is "OPAQUE"
  368. break;
  369. case (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND:
  370. alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
  371. break;
  372. case (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST:
  373. alphaCutoff = babylonMaterial.alphaCutOff;
  374. alphaMode = GLTFMaterial.AlphaMode.MASK.ToString();
  375. break;
  376. case (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATESTANDBLEND:
  377. RaiseWarning("GLTFExporter.Material | Alpha test and blend mode is not supported in glTF. Alpha blend is used instead.", 3);
  378. alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
  379. break;
  380. default:
  381. RaiseWarning("GLTFExporter.Material | Unsupported transparency mode: " + babylonMaterial.transparencyMode, 3);
  382. break;
  383. }
  384. }
  385. BabylonColor3 dielectricSpecular = new BabylonColor3(0.04f, 0.04f, 0.04f);
  386. const float epsilon = 1e-6f;
  387. private MetallicRoughness ConvertToMetallicRoughness(SpecularGlossiness specularGlossiness, bool displayPrints = false)
  388. {
  389. var diffuse = specularGlossiness.diffuse;
  390. var opacity = specularGlossiness.opacity;
  391. var specular = specularGlossiness.specular;
  392. var glossiness = specularGlossiness.glossiness;
  393. var oneMinusSpecularStrength = 1 - specular.getMaxComponent();
  394. var metallic = solveMetallic(diffuse.getPerceivedBrightness(), specular.getPerceivedBrightness(), oneMinusSpecularStrength);
  395. var diffuseScaleFactor = oneMinusSpecularStrength / (1 - dielectricSpecular.r) / Math.Max(1 - metallic, epsilon);
  396. var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
  397. var baseColorFromSpecular = specular.subtract(dielectricSpecular.scale(1 - metallic)).scale(1 / Math.Max(metallic, epsilon));
  398. var baseColor = BabylonColor3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic).clamp();
  399. //var baseColor = baseColorFromDiffuse.clamp();
  400. if (displayPrints)
  401. {
  402. RaiseMessage("-----------------------", 3);
  403. RaiseMessage("diffuse=" + diffuse, 3);
  404. RaiseMessage("opacity=" + opacity, 3);
  405. RaiseMessage("specular=" + specular, 3);
  406. RaiseMessage("glossiness=" + glossiness, 3);
  407. RaiseMessage("oneMinusSpecularStrength=" + oneMinusSpecularStrength, 3);
  408. RaiseMessage("metallic=" + metallic, 3);
  409. RaiseMessage("diffuseScaleFactor=" + diffuseScaleFactor, 3);
  410. RaiseMessage("baseColorFromDiffuse=" + baseColorFromDiffuse, 3);
  411. RaiseMessage("baseColorFromSpecular=" + baseColorFromSpecular, 3);
  412. RaiseMessage("metallic * metallic=" + metallic * metallic, 3);
  413. RaiseMessage("baseColor=" + baseColor, 3);
  414. RaiseMessage("-----------------------", 3);
  415. }
  416. return new MetallicRoughness
  417. {
  418. baseColor = baseColor,
  419. opacity = opacity,
  420. metallic = metallic,
  421. roughness = 1 - glossiness
  422. };
  423. }
  424. private float solveMetallic(float diffuse, float specular, float oneMinusSpecularStrength)
  425. {
  426. if (specular < dielectricSpecular.r)
  427. {
  428. return 0;
  429. }
  430. var a = dielectricSpecular.r;
  431. var b = diffuse * oneMinusSpecularStrength / (1 - dielectricSpecular.r) + specular - 2 * dielectricSpecular.r;
  432. var c = dielectricSpecular.r - specular;
  433. var D = b * b - 4 * a * c;
  434. return ClampScalar((float)(-b + Math.Sqrt(D)) / (2 * a), 0, 1);
  435. }
  436. /**
  437. * Returns the value itself if it's between min and max.
  438. * Returns min if the value is lower than min.
  439. * Returns max if the value is greater than max.
  440. */
  441. private static float ClampScalar(float value, float min = 0, float max = 1)
  442. {
  443. return Math.Min(max, Math.Max(min, value));
  444. }
  445. private class SpecularGlossiness
  446. {
  447. public BabylonColor3 diffuse;
  448. public float opacity;
  449. public BabylonColor3 specular;
  450. public float glossiness;
  451. }
  452. private class MetallicRoughness
  453. {
  454. public BabylonColor3 baseColor;
  455. public float opacity;
  456. public float metallic;
  457. public float roughness;
  458. }
  459. }
  460. }