// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include "Exporter.h" #include void Exporter::exportMaterial(const aiMaterial& mtl) const { std::string diffTex; std::string normTex; std::string specColTex; std::string shininessTex; std::string dispTex; std::string emissiveTex; std::string metallicTex; aiString path; std::string name = getMaterialName(mtl); LOGI("Exporting material %s", name.c_str()); // Diffuse texture if(mtl.GetTextureCount(aiTextureType_DIFFUSE) > 0) { if(mtl.GetTexture(aiTextureType_DIFFUSE, 0, &path) == AI_SUCCESS) { diffTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Normal texture if(mtl.GetTextureCount(aiTextureType_NORMALS) > 0) { if(mtl.GetTexture(aiTextureType_NORMALS, 0, &path) == AI_SUCCESS) { normTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Specular color if(mtl.GetTextureCount(aiTextureType_SPECULAR) > 0) { if(mtl.GetTexture(aiTextureType_SPECULAR, 0, &path) == AI_SUCCESS) { specColTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Shininess color if(mtl.GetTextureCount(aiTextureType_SHININESS) > 0) { if(mtl.GetTexture(aiTextureType_SHININESS, 0, &path) == AI_SUCCESS) { shininessTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Height texture if(mtl.GetTextureCount(aiTextureType_DISPLACEMENT) > 0) { if(mtl.GetTexture(aiTextureType_DISPLACEMENT, 0, &path) == AI_SUCCESS) { dispTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Emissive texture if(mtl.GetTextureCount(aiTextureType_EMISSIVE) > 0) { if(mtl.GetTexture(aiTextureType_EMISSIVE, 0, &path) == AI_SUCCESS) { emissiveTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Metallic texture if(mtl.GetTextureCount(aiTextureType_REFLECTION) > 0) { if(mtl.GetTexture(aiTextureType_REFLECTION, 0, &path) == AI_SUCCESS) { metallicTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Write file static const char* diffNormSpecFragTemplate = #include "templates/diffNormSpecFrag.h" ; static const char* simpleVertTemplate = #include "templates/simpleVert.h" ; static const char* tessVertTemplate = #include "templates/tessVert.h" ; static const char* readRgbFromTextureTemplate = R"( %id% vec3 readRgbFromTexture %map% out2 )"; static const char* readRFromTextureTemplate = R"( %id% float readRFromTexture %map% out2 )"; // Compose full template // First geometry part std::string materialStr; materialStr = R"()"; materialStr += "\n\n\t\n"; if(/*dispTex.empty()*/ 1) { materialStr += simpleVertTemplate; } else { materialStr += tessVertTemplate; } materialStr += "\n"; // Then fragment part materialStr += diffNormSpecFragTemplate; materialStr += "\n\t\t"; // Replace strings if(!dispTex.empty()) { materialStr = replaceAllString(materialStr, "%dispMap%", m_texrpath + dispTex); } // Diffuse if(!diffTex.empty()) { materialStr = replaceAllString(materialStr, "%diffuseColorInput%", R"(sampler2DuDiffuseColor)" + m_texrpath + diffTex + R"()"); materialStr = replaceAllString(materialStr, "%diffuseColorFunc%", readRgbFromTextureTemplate); materialStr = replaceAllString(materialStr, "%id%", "10"); materialStr = replaceAllString(materialStr, "%map%", "uDiffuseColor"); materialStr = replaceAllString(materialStr, "%diffuseColorArg%", "out10"); } else { aiColor3D diffCol = {0.0, 0.0, 0.0}; mtl.Get(AI_MATKEY_COLOR_DIFFUSE, diffCol); materialStr = replaceAllString(materialStr, "%diffuseColorInput%", R"(vec3uDiffuseColor)" + std::to_string(diffCol[0]) + " " + std::to_string(diffCol[1]) + " " + std::to_string(diffCol[2]) + R"()"); materialStr = replaceAllString(materialStr, "%diffuseColorFunc%", ""); materialStr = replaceAllString(materialStr, "%diffuseColorArg%", "uDiffuseColor"); } // Normal if(!normTex.empty()) { materialStr = replaceAllString(materialStr, "%normalInput%", R"(sampler2DuNormal)" + m_texrpath + normTex + R"()"); materialStr = replaceAllString(materialStr, "%normalFunc%", R"( 20 vec3 readNormalFromTexture out0 out1 uNormal out2 )"); materialStr = replaceAllString(materialStr, "%normalArg%", "out20"); } else { materialStr = replaceAllString(materialStr, "%normalInput%", " "); materialStr = replaceAllString(materialStr, "%normalFunc%", " "); materialStr = replaceAllString(materialStr, "%normalArg%", "out0"); } // Specular if(!specColTex.empty()) { materialStr = replaceAllString(materialStr, "%specularColorInput%", R"(sampler2DuSpecularColor)" + m_texrpath + specColTex + R"()"); materialStr = replaceAllString(materialStr, "%specularColorFunc%", readRgbFromTextureTemplate); materialStr = replaceAllString(materialStr, "%id%", "50"); materialStr = replaceAllString(materialStr, "%map%", "uSpecularColor"); materialStr = replaceAllString(materialStr, "%specularColorArg%", "out50"); } else { aiColor3D specCol = {0.0, 0.0, 0.0}; mtl.Get(AI_MATKEY_COLOR_SPECULAR, specCol); materialStr = replaceAllString(materialStr, "%specularColorInput%", R"(vec3uSpecularColor)" + std::to_string(specCol[0]) + " " + std::to_string(specCol[1]) + " " + std::to_string(specCol[2]) + R"()"); materialStr = replaceAllString(materialStr, "%specularColorFunc%", ""); materialStr = replaceAllString(materialStr, "%specularColorArg%", "uSpecularColor"); } // Roughness if(!shininessTex.empty()) { materialStr = replaceAllString(materialStr, "%specularPowerInput%", R"(sampler2Droughness)" + m_texrpath + shininessTex + R"()"); materialStr = replaceAllString(materialStr, "%specularPowerValue%", m_texrpath + shininessTex); materialStr = replaceAllString(materialStr, "%specularPowerFunc%", readRFromTextureTemplate); materialStr = replaceAllString(materialStr, "%id%", "60"); materialStr = replaceAllString(materialStr, "%map%", "roughness"); materialStr = replaceAllString(materialStr, "%specularPowerArg%", "out60"); } else { float shininess = 0.0; mtl.Get(AI_MATKEY_SHININESS, shininess); const float MAX_SHININESS = 511.0; shininess = std::min(MAX_SHININESS, shininess); if(shininess > MAX_SHININESS) { LOGW("Shininness exceeds %f", MAX_SHININESS); } shininess = shininess / MAX_SHININESS; materialStr = replaceAllString(materialStr, "%specularPowerInput%", R"(floatroughness1)" + std::to_string(shininess) + R"()"); materialStr = replaceAllString(materialStr, "%specularPowerFunc%", ""); materialStr = replaceAllString(materialStr, "%specularPowerArg%", "roughness"); } materialStr = replaceAllString(materialStr, "%maxSpecularPower%", " "); // Emission aiColor3D emissionCol = {0.0, 0.0, 0.0}; mtl.Get(AI_MATKEY_COLOR_EMISSIVE, emissionCol); float emission = (emissionCol[0] + emissionCol[1] + emissionCol[2]) / 3.0; if(!emissiveTex.empty()) { materialStr = replaceAllString(materialStr, "%emissionInput%", "sampler2DemissionTex" + m_texrpath + emissiveTex + ")\n" + "\t\t\t\tfloatemission" + std::to_string(10.0) + "1"); std::string func = readRFromTextureTemplate; func = replaceAllString(func, "%id%", "71"); func = replaceAllString(func, "%map%", "emissionTex"); func += R"( 70 float mul out71 emission )"; materialStr = replaceAllString(materialStr, "%emissionFunc%", func); materialStr = replaceAllString(materialStr, "%map%", "emissionTex"); materialStr = replaceAllString(materialStr, "%emissionArg%", "out70"); } else { materialStr = replaceAllString(materialStr, "%emissionInput%", R"(floatemission)" + std::to_string(emission) + R"(1)"); materialStr = replaceAllString(materialStr, "%emissionFunc%", ""); materialStr = replaceAllString(materialStr, "%emissionArg%", "emission"); } // Metallic if(!metallicTex.empty()) { materialStr = replaceAllString(materialStr, "%metallicInput%", "sampler2DmetallicTex" + m_texrpath + metallicTex + ""); std::string func = readRFromTextureTemplate; func = replaceAllString(func, "%id%", "80"); func = replaceAllString(func, "%map%", "metallicTex"); materialStr = replaceAllString(materialStr, "%metallicFunc%", func); materialStr = replaceAllString(materialStr, "%map%", "metallicTex"); materialStr = replaceAllString(materialStr, "%metallicArg%", "out80"); } else { float metallic = 0.0; if(mtl.mAnKiProperties.find("metallic") != mtl.mAnKiProperties.end()) { metallic = std::stof(mtl.mAnKiProperties.at("metallic")); } materialStr = replaceAllString(materialStr, "%metallicInput%", R"(floatmetallic)" + std::to_string(metallic) + R"(1)"); materialStr = replaceAllString(materialStr, "%metallicFunc%", ""); materialStr = replaceAllString(materialStr, "%metallicArg%", "metallic"); } // Height to parallax if(!dispTex.empty()) { materialStr = replaceAllString(materialStr, "%heightVertInput%", "mat4anki_mv" "0"); materialStr = replaceAllString(materialStr, "%heightVertFunc%", R"( 2 void writeParallax anki_n anki_mv )"); materialStr = replaceAllString(materialStr, "%heightInput%", "sampler2DheightMap" "" + m_texrpath + dispTex + "\n" "\t\t\t\tfloatheightMapScale" "0.051"); // At this point everyone will have to use out4 as tex coords materialStr = replaceAllString(materialStr, "out2", "out4"); materialStr = replaceAllString(materialStr, "%heightFunc%", R"( 4 vec2 computeTextureCoordParallax heightMap out2 heightMapScale )"); } else { materialStr = replaceAllString(materialStr, "%heightVertInput%", " "); materialStr = replaceAllString(materialStr, "%heightVertFunc%", " "); materialStr = replaceAllString(materialStr, "%heightInput%", " "); materialStr = replaceAllString(materialStr, "%heightFunc%", " "); } // Continue materialStr = replaceAllString(materialStr, "%diffuseMap%", m_texrpath + diffTex); // Subsurface float subsurface = 0.0; if(mtl.mAnKiProperties.find("subsurface") != mtl.mAnKiProperties.end()) { subsurface = std::stof(mtl.mAnKiProperties.at("subsurface")); } materialStr = replaceAllString(materialStr, "%subsurfaceInput%", "floatsubsurface" "1" + std::to_string(subsurface) + ""); materialStr = replaceAllString(materialStr, "%subsurfaceArg%", "subsurface"); // Replace texture extensions with .anki materialStr = replaceAllString(materialStr, ".tga", ".ankitex"); materialStr = replaceAllString(materialStr, ".png", ".ankitex"); materialStr = replaceAllString(materialStr, ".jpg", ".ankitex"); materialStr = replaceAllString(materialStr, ".jpeg", ".ankitex"); // Open and write file std::fstream file; file.open(m_outputDirectory + name + ".ankimtl", std::ios::out); file << materialStr; }