GltfImporterMaterial.cpp 9.0 KB

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