Quellcode durchsuchen

Adding exporter support for emission

Panagiotis Christopoulos Charitos vor 10 Jahren
Ursprung
Commit
8e2809ba31

+ 3 - 2
shaders/IsLp.frag.glsl

@@ -88,8 +88,9 @@ void main()
 
 	float a2 = pow(max(EPSILON, roughness), 2.0);
 
-	// Ambient color
-	out_color = diffCol * u_lightingUniforms.sceneAmbientColor.rgb + emission;
+	// Ambient and emissive color
+	out_color = diffCol * u_lightingUniforms.sceneAmbientColor.rgb
+		+ diffCol * emission;
 
 	// Get counts and offsets
 	uint k = calcClusterSplit(fragPos.z);

+ 24 - 18
shaders/Pack.glsl

@@ -82,10 +82,13 @@ vec2 unpackUnorm1ToUnorm2(in float c)
 {
 	float temp = c * (255.0 / 16.0);
 	float a = floor(temp);
-	float b = fract(temp);
+	float b = temp - a; // b = fract(temp)
 	return vec2(a, b) * vec2(1.0 / 15.0, 16.0 / 15.0);
 }
 
+// Max emission. Keep as low as possible
+const float MAX_EMISSION = 10.0;
+
 // Populate the G buffer
 void writeGBuffer(
 	in vec3 diffColor,
@@ -98,8 +101,9 @@ void writeGBuffer(
 	out vec4 rt1,
 	out vec4 rt2)
 {
-	rt0 = vec4(diffColor, packUnorm2ToUnorm1(vec2(subsurface, emission)));
-	rt1 = vec4(specColor, roughness);
+	rt0 = vec4(diffColor, subsurface);
+	rt1 = vec4(packUnorm2ToUnorm1(specColor.rg), specColor.b, roughness,
+		emission / MAX_EMISSION);
 	rt2 = vec4(normal * 0.5 + 0.5, 0.0);
 }
 
@@ -108,7 +112,7 @@ void readGBuffer(
 	in sampler2D rt0,
 	in sampler2D rt1,
 	in sampler2D rt2,
-	in vec2 texCoord,
+	in vec2 uv,
 	out vec3 diffColor,
 	out vec3 normal,
 	out vec3 specColor,
@@ -116,39 +120,41 @@ void readGBuffer(
 	out float subsurface,
 	out float emission)
 {
-	vec4 comp = textureLod(rt0, texCoord, 0.0);
-	diffColor = comp.rgb;
-	vec2 tmp = unpackUnorm1ToUnorm2(comp.a);
-	subsurface = tmp.x;
-	emission = tmp.y;
+	vec4 comp = textureLod(rt0, uv, 0.0);
+	diffColor = comp.xyz;
+	subsurface = comp.w;
 
-	comp = textureLod(rt1, texCoord, 0.0);
-	specColor = comp.rgb;
-	roughness = comp.a;
+	comp = textureLod(rt1, uv, 0.0);
+	specColor = vec3(unpackUnorm1ToUnorm2(comp.x), comp.y);
+	roughness = comp.z;
+	emission = comp.w * MAX_EMISSION;
 
-	normal = textureLod(rt2, texCoord, 0.0).rgb;
+	normal = textureLod(rt2, uv, 0.0).xyz;
 	normal = normalize(normal * 2.0 - 1.0);
 }
 
 // Read only normal from G buffer
 void readNormalFromGBuffer(
 	in sampler2D fai2,
-	in vec2 texCoord,
+	in vec2 uv,
 	out vec3 normal)
 {
-	normal = normalize(textureLod(fai2, texCoord, 0.0).rgb * 2.0 - 1.0);
+	normal = normalize(textureLod(fai2, uv, 0.0).rgb * 2.0 - 1.0);
 }
 
 // Read only normal and specular color from G buffer
 void readNormalSpecularColorFromGBuffer(
 	in sampler2D fai1,
 	in sampler2D fai2,
-	in vec2 texCoord,
+	in vec2 uv,
 	out vec3 normal,
 	out vec3 specColor)
 {
-	normal = normalize(textureLod(fai2, texCoord, 0.0).rgb * 2.0 - 1.0);
-	specColor = textureLod(fai1, texCoord, 0.0).rgb;
+	normal = normalize(textureLod(fai2, uv, 0.0).rgb * 2.0 - 1.0);
+
+	vec2 tmp = textureLod(fai1, uv, 0.0).xy;
+	specColor.rg = unpackUnorm1ToUnorm2(tmp.x);
+	specColor.b = tmp.y;
 }
 
 #endif

+ 2 - 2
tools/scene/CMakeLists.txt

@@ -2,5 +2,5 @@ include_directories("../../thirdparty/assimp/include")
 
 add_definitions("-fexceptions")
 
-add_executable(ankisceneimp Main.cpp Common.cpp Exporter.cpp ExporterMesh.cpp)
-target_link_libraries(ankisceneimp ankiassimp) 
+add_executable(ankisceneimp Main.cpp Common.cpp Exporter.cpp ExporterMesh.cpp ExporterMaterial.cpp)
+target_link_libraries(ankisceneimp ankiassimp)

+ 53 - 389
tools/scene/Exporter.cpp

@@ -50,60 +50,6 @@ static aiColor3D computeLightColor(aiColor3D in)
 	return in;
 }
 
-//==============================================================================
-/// Round up the instances count.
-static uint32_t roundUpInstancesCount(uint32_t instances)
-{
-	if(instances == 1)
-	{
-		instances = 1;
-	}
-	else if(instances <= 4)
-	{
-		instances = 4;
-	}
-	else if(instances <= 8)
-	{
-		instances = 8;
-	}
-	else if(instances <= 16)
-	{
-		instances = 16;
-	}
-	else if(instances <= 32)
-	{
-		instances = 32;
-	}
-	else
-	{
-		ERROR("Too many instances %u", instances);
-	}
-
-	return instances;
-}
-
-//==============================================================================
-static std::string getMaterialName(const aiMaterial& mtl, uint32_t instances)
-{
-	aiString ainame;
-	std::string name;
-	if(mtl.Get(AI_MATKEY_NAME, ainame) == AI_SUCCESS)
-	{
-		name = ainame.C_Str();
-
-		if(instances > 1)
-		{
-			name += "_inst" + std::to_string(roundUpInstancesCount(instances));
-		}
-	}
-	else
-	{
-		ERROR("Material's name is missing");
-	}
-
-	return name;
-}
-
 //==============================================================================
 static std::string getMeshName(const aiMesh& mesh)
 {
@@ -186,6 +132,59 @@ static void stringToFloatArray(const std::string& in, Arr& out)
 // Exporter                                                                    =
 //==============================================================================
 
+//==============================================================================
+uint32_t Exporter::roundUpInstancesCount(uint32_t instances)
+{
+	if(instances == 1)
+	{
+		instances = 1;
+	}
+	else if(instances <= 4)
+	{
+		instances = 4;
+	}
+	else if(instances <= 8)
+	{
+		instances = 8;
+	}
+	else if(instances <= 16)
+	{
+		instances = 16;
+	}
+	else if(instances <= 32)
+	{
+		instances = 32;
+	}
+	else
+	{
+		ERROR("Too many instances %u", instances);
+	}
+
+	return instances;
+}
+
+//==============================================================================
+std::string Exporter::getMaterialName(const aiMaterial& mtl, uint32_t instances)
+{
+	aiString ainame;
+	std::string name;
+	if(mtl.Get(AI_MATKEY_NAME, ainame) == AI_SUCCESS)
+	{
+		name = ainame.C_Str();
+
+		if(instances > 1)
+		{
+			name += "_inst" + std::to_string(roundUpInstancesCount(instances));
+		}
+	}
+	else
+	{
+		ERROR("Material's name is missing");
+	}
+
+	return name;
+}
+
 //==============================================================================
 aiMatrix4x4 Exporter::toAnkiMatrix(const aiMatrix4x4& in) const
 {
@@ -367,341 +366,6 @@ void Exporter::exportSkeleton(const aiMesh& mesh) const
 	file << "</skeleton>\n";
 }
 
-//==============================================================================
-void Exporter::exportMaterial(
-	const aiMaterial& mtl,
-	uint32_t instances) const
-{
-	std::string diffTex;
-	std::string normTex;
-	std::string specColTex;
-	std::string shininessTex;
-	std::string dispTex;
-
-	aiString path;
-
-	std::string name = getMaterialName(mtl, instances);
-	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");
-		}
-	}
-
-	// 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"(
-				<operation>
-					<id>%id%</id>
-					<returnType>vec3</returnType>
-					<function>readRgbFromTexture</function>
-					<arguments>
-						<argument>%map%</argument>
-						<argument>out2</argument>
-					</arguments>
-				</operation>)";
-
-	static const char* readRFromTextureTemplate = R"(
-				<operation>
-					<id>%id%</id>
-					<returnType>float</returnType>
-					<function>readRFromTexture</function>
-					<arguments>
-						<argument>%map%</argument>
-						<argument>out2</argument>
-					</arguments>
-				</operation>)";
-
-	// Compose full template
-	// First geometry part
-	std::string materialStr;
-	materialStr = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
-	materialStr += "\n<material>\n\t<programs>\n";
-	if(dispTex.empty())
-	{
-		materialStr += simpleVertTemplate;
-	}
-	else
-	{
-		materialStr += tessVertTemplate;
-	}
-
-	materialStr += "\n";
-
-	// Then fragment part
-	materialStr += diffNormSpecFragTemplate;
-	materialStr += "\n\t</programs>\t</material>";
-
-	// Replace strings
-	if(!dispTex.empty())
-	{
-		materialStr = replaceAllString(materialStr, "%dispMap%",
-			m_texrpath + dispTex);
-	}
-
-	// Diffuse
-	if(!diffTex.empty())
-	{
-		materialStr = replaceAllString(materialStr, "%diffuseColorInput%",
-			R"(<input><type>sampler2D</type><name>uDiffuseColor</name><value>)"
-			+ m_texrpath + diffTex
-			+ R"(</value></input>)");
-
-		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"(<input><type>vec3</type><name>uDiffuseColor</name><value>)"
-			+ std::to_string(diffCol[0]) + " "
-			+ std::to_string(diffCol[1]) + " "
-			+ std::to_string(diffCol[2])
-			+ R"(</value></input>)");
-
-		materialStr = replaceAllString(materialStr, "%diffuseColorFunc%",
-			"");
-
-		materialStr = replaceAllString(materialStr, "%diffuseColorArg%",
-			"uDiffuseColor");
-	}
-
-	// Normal
-	if(!normTex.empty())
-	{
-		materialStr = replaceAllString(materialStr, "%normalInput%",
-			R"(<input><type>sampler2D</type><name>uNormal</name><value>)"
-			+ m_texrpath + normTex
-			+ R"(</value></input>)");
-
-		materialStr = replaceAllString(materialStr, "%normalFunc%",
-				R"(
-				<operation>
-					<id>20</id>
-					<returnType>vec3</returnType>
-					<function>readNormalFromTexture</function>
-					<arguments>
-						<argument>out0</argument>
-						<argument>out1</argument>
-						<argument>uNormal</argument>
-						<argument>out2</argument>
-					</arguments>
-				</operation>)");
-
-		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"(<input><type>sampler2D</type><name>uSpecularColor</name><value>)"
-			+ m_texrpath + specColTex
-			+ R"(</value></input>)");
-
-		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"(<input><type>vec3</type><name>uSpecularColor</name><value>)"
-			+ std::to_string(specCol[0]) + " "
-			+ std::to_string(specCol[1]) + " "
-			+ std::to_string(specCol[2])
-			+ R"(</value></input>)");
-
-		materialStr = replaceAllString(materialStr, "%specularColorFunc%",
-			"");
-
-		materialStr = replaceAllString(materialStr, "%specularColorArg%",
-			"uSpecularColor");
-	}
-
-	if(!shininessTex.empty())
-	{
-		materialStr = replaceAllString(materialStr, "%specularPowerInput%",
-			R"(<input><type>sampler2D</type><name>uSpecularPower</name><value>)"
-			+ m_texrpath + shininessTex
-			+ R"(</value></input>)");
-
-		materialStr = replaceAllString(materialStr, "%specularPowerValue%",
-			m_texrpath + shininessTex);
-
-		materialStr = replaceAllString(materialStr, "%specularPowerFunc%",
-			readRFromTextureTemplate);
-
-		materialStr = replaceAllString(materialStr, "%id%",
-			"60");
-
-		materialStr = replaceAllString(materialStr, "%map%",
-			"uSpecularPower");
-
-		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"(<input><type>float</type><name>uSpecularPower</name><value>)"
-			+ std::to_string(shininess)
-			+ R"(</value></input>)");
-
-		materialStr = replaceAllString(materialStr, "%specularPowerFunc%",
-			"");
-
-		materialStr = replaceAllString(materialStr, "%specularPowerArg%",
-			"uSpecularPower");
-	}
-
-	materialStr = replaceAllString(materialStr, "%maxSpecularPower%", " ");
-
-	materialStr = replaceAllString(materialStr, "%instanced%",
-		(instances > 1) ? "1" : "0");
-	materialStr = replaceAllString(materialStr, "%arraySize%",
-		std::to_string(roundUpInstancesCount(instances)));
-	materialStr = replaceAllString(materialStr, "%diffuseMap%",
-		m_texrpath + diffTex);
-
-	// Subsurface
-	materialStr = replaceAllString(materialStr, "%subsurfaceInput%",
-		"<input><type>float</type><name>subsurface</name>"
-		"<const>1</const><value>0.0</value></input>");
-	materialStr = replaceAllString(materialStr, "%subsurfaceArg%",
-		"subsurface");
-
-	// Emission
-	materialStr = replaceAllString(materialStr, "%emissionInput%",
-		"<input><type>float</type><name>emission</name>"
-		"<const>1</const><value>0.0</value></input>");
-	materialStr = replaceAllString(materialStr, "%emissionArg%",
-		"emission");
-
-	// 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;
-}
-
 //==============================================================================
 void Exporter::exportModel(const Model& model) const
 {

+ 7 - 0
tools/scene/Exporter.h

@@ -152,6 +152,13 @@ private:
 
 	/// Export a static collision mesh.
 	void exportCollisionMesh(uint32_t meshIdx);
+
+	/// Helper.
+	static std::string getMaterialName(const aiMaterial& mtl,
+		uint32_t instances);
+
+	/// Round up the instances count.
+	static uint32_t roundUpInstancesCount(uint32_t instances);
 };
 
 #endif

+ 399 - 0
tools/scene/ExporterMaterial.cpp

@@ -0,0 +1,399 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "Exporter.h"
+#include <iostream>
+
+//==============================================================================
+void Exporter::exportMaterial(
+	const aiMaterial& mtl,
+	uint32_t instances) const
+{
+	std::string diffTex;
+	std::string normTex;
+	std::string specColTex;
+	std::string shininessTex;
+	std::string dispTex;
+	std::string emissiveTex;
+
+	aiString path;
+
+	std::string name = getMaterialName(mtl, instances);
+	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");
+		}
+	}
+
+	// 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"(
+				<operation>
+					<id>%id%</id>
+					<returnType>vec3</returnType>
+					<function>readRgbFromTexture</function>
+					<arguments>
+						<argument>%map%</argument>
+						<argument>out2</argument>
+					</arguments>
+				</operation>)";
+
+	static const char* readRFromTextureTemplate = R"(
+				<operation>
+					<id>%id%</id>
+					<returnType>float</returnType>
+					<function>readRFromTexture</function>
+					<arguments>
+						<argument>%map%</argument>
+						<argument>out2</argument>
+					</arguments>
+				</operation>)";
+
+	// Compose full template
+	// First geometry part
+	std::string materialStr;
+	materialStr = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
+	materialStr += "\n<material>\n\t<programs>\n";
+	if(dispTex.empty())
+	{
+		materialStr += simpleVertTemplate;
+	}
+	else
+	{
+		materialStr += tessVertTemplate;
+	}
+
+	materialStr += "\n";
+
+	// Then fragment part
+	materialStr += diffNormSpecFragTemplate;
+	materialStr += "\n\t</programs>\t</material>";
+
+	// Replace strings
+	if(!dispTex.empty())
+	{
+		materialStr = replaceAllString(materialStr, "%dispMap%",
+			m_texrpath + dispTex);
+	}
+
+	// Diffuse
+	if(!diffTex.empty())
+	{
+		materialStr = replaceAllString(materialStr, "%diffuseColorInput%",
+			R"(<input><type>sampler2D</type><name>uDiffuseColor</name><value>)"
+			+ m_texrpath + diffTex
+			+ R"(</value></input>)");
+
+		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"(<input><type>vec3</type><name>uDiffuseColor</name><value>)"
+			+ std::to_string(diffCol[0]) + " "
+			+ std::to_string(diffCol[1]) + " "
+			+ std::to_string(diffCol[2])
+			+ R"(</value></input>)");
+
+		materialStr = replaceAllString(materialStr, "%diffuseColorFunc%",
+			"");
+
+		materialStr = replaceAllString(materialStr, "%diffuseColorArg%",
+			"uDiffuseColor");
+	}
+
+	// Normal
+	if(!normTex.empty())
+	{
+		materialStr = replaceAllString(materialStr, "%normalInput%",
+			R"(<input><type>sampler2D</type><name>uNormal</name><value>)"
+			+ m_texrpath + normTex
+			+ R"(</value></input>)");
+
+		materialStr = replaceAllString(materialStr, "%normalFunc%",
+				R"(
+				<operation>
+					<id>20</id>
+					<returnType>vec3</returnType>
+					<function>readNormalFromTexture</function>
+					<arguments>
+						<argument>out0</argument>
+						<argument>out1</argument>
+						<argument>uNormal</argument>
+						<argument>out2</argument>
+					</arguments>
+				</operation>)");
+
+		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"(<input><type>sampler2D</type><name>uSpecularColor</name><value>)"
+			+ m_texrpath + specColTex
+			+ R"(</value></input>)");
+
+		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"(<input><type>vec3</type><name>uSpecularColor</name><value>)"
+			+ std::to_string(specCol[0]) + " "
+			+ std::to_string(specCol[1]) + " "
+			+ std::to_string(specCol[2])
+			+ R"(</value></input>)");
+
+		materialStr = replaceAllString(materialStr, "%specularColorFunc%",
+			"");
+
+		materialStr = replaceAllString(materialStr, "%specularColorArg%",
+			"uSpecularColor");
+	}
+
+	if(!shininessTex.empty())
+	{
+		materialStr = replaceAllString(materialStr, "%specularPowerInput%",
+			R"(<input><type>sampler2D</type><name>uSpecularPower</name><value>)"
+			+ m_texrpath + shininessTex
+			+ R"(</value></input>)");
+
+		materialStr = replaceAllString(materialStr, "%specularPowerValue%",
+			m_texrpath + shininessTex);
+
+		materialStr = replaceAllString(materialStr, "%specularPowerFunc%",
+			readRFromTextureTemplate);
+
+		materialStr = replaceAllString(materialStr, "%id%",
+			"60");
+
+		materialStr = replaceAllString(materialStr, "%map%",
+			"uSpecularPower");
+
+		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"(<input><type>float</type><name>uSpecularPower</name><value>)"
+			+ std::to_string(shininess)
+			+ R"(</value></input>)");
+
+		materialStr = replaceAllString(materialStr, "%specularPowerFunc%",
+			"");
+
+		materialStr = replaceAllString(materialStr, "%specularPowerArg%",
+			"uSpecularPower");
+	}
+
+	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%",
+			"<input><type>sampler2D</type><name>emissionTex</name><value>"
+			+ m_texrpath + emissiveTex
+			+ "</value></input>)\n"
+			+ "\t\t\t\t<input><type>float</type><name>emission</name><value>"
+			+ std::to_string(5.0)
+			+ "</value><const>1</const></input>");
+
+		std::string func = readRFromTextureTemplate;
+		func = replaceAllString(func, "%id%", "71");
+		func = replaceAllString(func, "%map%", "emissionTex");
+		func += R"(
+				<operation>
+					<id>70</id>
+					<returnType>float</returnType>
+					<function>mul</function>
+					<arguments>
+						<argument>out71</argument>
+						<argument>emission</argument>
+					</arguments>
+				</operation>)";
+
+		materialStr = replaceAllString(materialStr, "%emissionFunc%", func);
+
+		materialStr = replaceAllString(materialStr, "%map%", "emissionTex");
+
+		materialStr = replaceAllString(materialStr, "%emissionArg%",
+			"out70");
+	}
+	else
+	{
+		materialStr = replaceAllString(materialStr, "%emissionInput%",
+			R"(<input><type>float</type><name>emission</name><value>)"
+			+ std::to_string(emission)
+			+ R"(</value><const>1</const></input>)");
+
+		materialStr = replaceAllString(materialStr, "%emissionFunc%", "");
+
+		materialStr = replaceAllString(materialStr, "%emissionArg%",
+			"emission");
+	}
+
+	materialStr = replaceAllString(materialStr, "%instanced%",
+		(instances > 1) ? "1" : "0");
+	materialStr = replaceAllString(materialStr, "%arraySize%",
+		std::to_string(roundUpInstancesCount(instances)));
+	materialStr = replaceAllString(materialStr, "%diffuseMap%",
+		m_texrpath + diffTex);
+
+	// Subsurface
+	materialStr = replaceAllString(materialStr, "%subsurfaceInput%",
+		"<input><type>float</type><name>subsurface</name>"
+		"<const>1</const><value>0.0</value></input>");
+	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;
+}
+

+ 1 - 0
tools/scene/templates/diffNormSpecFrag.h

@@ -34,6 +34,7 @@ R"(		<program>
 				%normalFunc%
 				%specularColorFunc%
 				%specularPowerFunc%
+				%emissionFunc%
 				<operation>
 					<id>100</id>
 					<returnType>void</returnType>