GltfImporterMaterial.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Importer/GltfImporter.h>
  6. #include <AnKi/Resource/ImageLoader.h>
  7. namespace anki
  8. {
  9. const char* MATERIAL_TEMPLATE = R"(<!-- This file is auto generated by ImporterMaterial.cpp -->
  10. <material shaderProgram="AnKi/Shaders/GBufferGeneric.ankiprog">
  11. <mutation>
  12. <mutator name="DIFFUSE_TEX" value="%diffTexMutator%"/>
  13. <mutator name="SPECULAR_TEX" value="%specTexMutator%"/>
  14. <mutator name="ROUGHNESS_TEX" value="%roughnessTexMutator%"/>
  15. <mutator name="METAL_TEX" value="%metalTexMutator%"/>
  16. <mutator name="NORMAL_TEX" value="%normalTexMutator%"/>
  17. <mutator name="PARALLAX" value="%parallaxMutator%"/>
  18. <mutator name="EMISSIVE_TEX" value="%emissiveTexMutator%"/>
  19. </mutation>
  20. <inputs>
  21. %parallaxInput%
  22. %diff%
  23. %spec%
  24. %roughness%
  25. %metallic%
  26. %normal%
  27. %emission%
  28. %subsurface%
  29. %height%
  30. </inputs>
  31. </material>
  32. )";
  33. const char* RT_MATERIAL_TEMPLATE = R"(
  34. <rtMaterial>
  35. <rayType type="shadows" shaderProgram="AnKi/Shaders/RtShadowsHit.ankiprog">
  36. <mutation>
  37. <mutator name="ALPHA_TEXTURE" value="0"/>
  38. </mutation>
  39. </rayType>
  40. </rtMaterial>)";
  41. static CString getTextureUri(const cgltf_texture_view& view)
  42. {
  43. ANKI_ASSERT(view.texture);
  44. ANKI_ASSERT(view.texture->image);
  45. ANKI_ASSERT(view.texture->image->uri);
  46. return view.texture->image->uri;
  47. }
  48. /// Read the texture and find out if
  49. static Error identifyMetallicRoughnessTexture(CString fname, F32& constantMetalines, F32& constantRoughness,
  50. GenericMemoryPoolAllocator<U8>& alloc)
  51. {
  52. ImageLoader iloader(alloc);
  53. ANKI_CHECK(iloader.load(fname));
  54. ANKI_ASSERT(iloader.getColorFormat() == ImageBinaryColorFormat::RGBA8);
  55. ANKI_ASSERT(iloader.getCompression() == ImageBinaryDataCompression::RAW);
  56. const U8Vec4* data = reinterpret_cast<const U8Vec4*>(&iloader.getSurface(0, 0, 0).m_data[0]);
  57. const F32 epsilon = 1.0f / 255.0f;
  58. for(U32 y = 0; y < iloader.getWidth(); ++y)
  59. {
  60. for(U32 x = 0; x < iloader.getHeight(); ++x)
  61. {
  62. const U8Vec4& pixel = *(data + y * iloader.getWidth() + x);
  63. const F32 m = F32(pixel.z()) / 255.0f;
  64. const F32 r = F32(pixel.y()) / 255.0f;
  65. if(x == 0 && y == 0)
  66. {
  67. // Initialize
  68. constantMetalines = m;
  69. constantRoughness = r;
  70. }
  71. else
  72. {
  73. if(constantMetalines < 0.0f || absolute(m - constantMetalines) > epsilon)
  74. {
  75. constantMetalines = -1.0f;
  76. }
  77. if(constantRoughness < 0.0f || absolute(r - constantRoughness) > epsilon)
  78. {
  79. constantRoughness = -1.0f;
  80. }
  81. }
  82. }
  83. }
  84. return Error::NONE;
  85. }
  86. Error GltfImporter::writeMaterial(const cgltf_material& mtl, RayTypeBit usedRayTypes)
  87. {
  88. StringAuto fname(m_alloc);
  89. fname.sprintf("%s%s.ankimtl", m_outDir.cstr(), mtl.name);
  90. ANKI_IMPORTER_LOGI("Importing material %s", fname.cstr());
  91. if(!mtl.has_pbr_metallic_roughness)
  92. {
  93. ANKI_IMPORTER_LOGE("Expecting PBR metallic roughness");
  94. return Error::USER_DATA;
  95. }
  96. HashMapAuto<CString, StringAuto> extras(m_alloc);
  97. ANKI_CHECK(getExtras(mtl.extras, extras));
  98. StringAuto xml(m_alloc);
  99. xml.append(XML_HEADER);
  100. xml.append("\n");
  101. xml.append(MATERIAL_TEMPLATE);
  102. if(!!(usedRayTypes & RayTypeBit::SHADOWS))
  103. {
  104. xml.append(RT_MATERIAL_TEMPLATE);
  105. }
  106. // Diffuse
  107. if(mtl.pbr_metallic_roughness.base_color_texture.texture)
  108. {
  109. StringAuto uri(m_alloc);
  110. uri.sprintf("%s%s", m_texrpath.cstr(), getTextureUri(mtl.pbr_metallic_roughness.base_color_texture).cstr());
  111. xml.replaceAll("%diff%",
  112. StringAuto{m_alloc}.sprintf("<input shaderVar=\"u_diffTex\" value=\"%s\"/>", uri.cstr()));
  113. xml.replaceAll("%diffTexMutator%", "1");
  114. }
  115. else
  116. {
  117. const F32* diffCol = &mtl.pbr_metallic_roughness.base_color_factor[0];
  118. xml.replaceAll("%diff%", StringAuto{m_alloc}.sprintf("<input shaderVar=\"m_diffColor\" value=\"%f %f %f\"/>",
  119. diffCol[0], diffCol[1], diffCol[2]));
  120. xml.replaceAll("%diffTexMutator%", "0");
  121. }
  122. // Specular color (freshnel)
  123. {
  124. Vec3 specular;
  125. auto it = extras.find("specular");
  126. if(it != extras.getEnd())
  127. {
  128. StringListAuto tokens(m_alloc);
  129. tokens.splitString(it->toCString(), ' ');
  130. if(tokens.getSize() != 3)
  131. {
  132. ANKI_IMPORTER_LOGE("Wrong specular: %s", it->cstr());
  133. return Error::USER_DATA;
  134. }
  135. auto token = tokens.getBegin();
  136. ANKI_CHECK(token->toNumber(specular.x()));
  137. ++token;
  138. ANKI_CHECK(token->toNumber(specular.y()));
  139. ++token;
  140. ANKI_CHECK(token->toNumber(specular.z()));
  141. }
  142. else
  143. {
  144. specular = Vec3(0.04f);
  145. }
  146. xml.replaceAll("%spec%", StringAuto{m_alloc}.sprintf("<input shaderVar=\"m_specColor\" value=\"%f %f %f\"/>",
  147. specular.x(), specular.y(), specular.z()));
  148. xml.replaceAll("%specTexMutator%", "0");
  149. }
  150. // Identify metallic/roughness texture
  151. F32 constantMetaliness = -1.0f, constantRoughness = -1.0f;
  152. if(mtl.pbr_metallic_roughness.metallic_roughness_texture.texture)
  153. {
  154. const CString fname = getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture);
  155. ANKI_CHECK(identifyMetallicRoughnessTexture(fname, constantMetaliness, constantRoughness, m_alloc));
  156. }
  157. // Roughness
  158. if(mtl.pbr_metallic_roughness.metallic_roughness_texture.texture && constantRoughness < 0.0f)
  159. {
  160. StringAuto uri(m_alloc);
  161. uri.sprintf("%s%s", m_texrpath.cstr(),
  162. getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture).cstr());
  163. xml.replaceAll("%roughness%",
  164. StringAuto{m_alloc}.sprintf("<input shaderVar=\"u_roughnessTex\" value=\"%s\"/>", uri.cstr()));
  165. xml.replaceAll("%roughnessTexMutator%", "1");
  166. }
  167. else
  168. {
  169. const F32 roughness = (constantRoughness >= 0.0f)
  170. ? constantRoughness * mtl.pbr_metallic_roughness.roughness_factor
  171. : mtl.pbr_metallic_roughness.roughness_factor;
  172. xml.replaceAll("%roughness%",
  173. StringAuto{m_alloc}.sprintf("<input shaderVar=\"m_roughness\" value=\"%f\"/>", roughness));
  174. xml.replaceAll("%roughnessTexMutator%", "0");
  175. }
  176. // Metallic
  177. if(mtl.pbr_metallic_roughness.metallic_roughness_texture.texture && constantMetaliness < 0.0f)
  178. {
  179. StringAuto uri(m_alloc);
  180. uri.sprintf("%s%s", m_texrpath.cstr(),
  181. getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture).cstr());
  182. xml.replaceAll("%metallic%",
  183. StringAuto{m_alloc}.sprintf("<input shaderVar=\"u_metallicTex\" value=\"%s\"/>", uri.cstr()));
  184. xml.replaceAll("%metalTexMutator%", "1");
  185. }
  186. else
  187. {
  188. const F32 metalines = (constantMetaliness >= 0.0f)
  189. ? constantMetaliness * mtl.pbr_metallic_roughness.metallic_factor
  190. : mtl.pbr_metallic_roughness.metallic_factor;
  191. xml.replaceAll("%metallic%",
  192. StringAuto{m_alloc}.sprintf("<input shaderVar=\"m_metallic\" value=\"%f\"/>", metalines));
  193. xml.replaceAll("%metalTexMutator%", "0");
  194. }
  195. // Normal texture
  196. if(mtl.normal_texture.texture)
  197. {
  198. StringAuto uri(m_alloc);
  199. uri.sprintf("%s%s", m_texrpath.cstr(), getTextureUri(mtl.normal_texture).cstr());
  200. xml.replaceAll("%normal%",
  201. StringAuto{m_alloc}.sprintf("<input shaderVar=\"u_normalTex\" value=\"%s\"/>", uri.cstr()));
  202. xml.replaceAll("%normalTexMutator%", "1");
  203. }
  204. else
  205. {
  206. xml.replaceAll("%normal%", "");
  207. xml.replaceAll("%normalTexMutator%", "0");
  208. }
  209. // Emissive texture
  210. if(mtl.emissive_texture.texture)
  211. {
  212. StringAuto uri(m_alloc);
  213. uri.sprintf("%s%s", m_texrpath.cstr(), getTextureUri(mtl.emissive_texture).cstr());
  214. xml.replaceAll("%emission%",
  215. StringAuto{m_alloc}.sprintf("<input shaderVar=\"u_emissiveTex\" value=\"%s\"/>", uri.cstr()));
  216. xml.replaceAll("%emissiveTexMutator%", "1");
  217. }
  218. else
  219. {
  220. const F32* emissionCol = &mtl.emissive_factor[0];
  221. xml.replaceAll("%emission%", StringAuto{m_alloc}.sprintf("<input shaderVar=\"m_emission\" value=\"%f %f %f\"/>",
  222. emissionCol[0], emissionCol[1], emissionCol[2]));
  223. xml.replaceAll("%emissiveTexMutator%", "0");
  224. }
  225. // Subsurface
  226. {
  227. F32 subsurface;
  228. auto it = extras.find("subsurface");
  229. if(it != extras.getEnd())
  230. {
  231. ANKI_CHECK(it->toNumber(subsurface));
  232. }
  233. else
  234. {
  235. subsurface = 0.0f;
  236. }
  237. xml.replaceAll("%subsurface%",
  238. StringAuto{m_alloc}.sprintf("<input shaderVar=\"m_subsurface\" value=\"%f\"/>", subsurface));
  239. }
  240. // Height texture
  241. auto it = extras.find("height_map");
  242. if(it != extras.getEnd())
  243. {
  244. StringAuto uri(m_alloc);
  245. uri.sprintf("%s%s", m_texrpath.cstr(), it->cstr());
  246. xml.replaceAll("%height%",
  247. StringAuto{m_alloc}.sprintf("<input shaderVar=\"u_heightTex\" value=\"%s\" \"/>\n"
  248. "\t\t<input shaderVar=\"m_heightmapScale\" value=\"0.05\"/>",
  249. uri.cstr()));
  250. xml.replaceAll("%parallaxMutator%", "1");
  251. }
  252. else
  253. {
  254. xml.replaceAll("%height%", "");
  255. xml.replaceAll("%parallaxInput%", "");
  256. xml.replaceAll("%parallaxMutator%", "0");
  257. }
  258. // Replace texture extensions with .anki
  259. xml.replaceAll(".tga", ".ankitex");
  260. xml.replaceAll(".png", ".ankitex");
  261. xml.replaceAll(".jpg", ".ankitex");
  262. xml.replaceAll(".jpeg", ".ankitex");
  263. // Write file
  264. File file;
  265. ANKI_CHECK(file.open(fname.toCString(), FileOpenFlag::WRITE));
  266. ANKI_CHECK(file.writeText("%s", xml.cstr()));
  267. return Error::NONE;
  268. }
  269. } // end namespace anki