Browse Source

Some work on the GLTF importer

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
1e2f3fbca8

BIN
samples/simple_scene/assets/column.ankimesh


+ 1 - 2
samples/simple_scene/assets/columnroom-material.ankimdl → samples/simple_scene/assets/column_walls.ankimdl

@@ -1,9 +1,8 @@
-<?xml version="1.0" encoding="UTF-8" ?>
 <model>
 	<modelPatches>
 		<modelPatch>
 			<mesh>assets/column.ankimesh</mesh>
-			<material>assets/room-material.ankimtl</material>
+			<material>assets/walls.ankimtl</material>
 		</modelPatch>
 	</modelPatches>
 </model>

+ 0 - 31
samples/simple_scene/assets/room-material.ankimtl

@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!-- This file is auto generated by ExporterMaterial.cpp -->
-<material shaderProgram="shaders/GBufferGeneric.glslp">
-
-	<mutators>
-		<mutator name="DIFFUSE_TEX" value="0"/>
-		<mutator name="SPECULAR_TEX" value="0"/>
-		<mutator name="ROUGHNESS_TEX" value="0"/>
-		<mutator name="METAL_TEX" value="0"/>
-		<mutator name="NORMAL_TEX" value="0"/>
-		<mutator name="PARALLAX" value="0"/>
-		<mutator name="EMISSIVE_TEX" value="0"/>
-	</mutators>
-
-	<inputs>
-		<input shaderInput="mvp" builtin="MODEL_VIEW_PROJECTION_MATRIX"/>
-		<input shaderInput="prevMvp" builtin="PREVIOUS_MODEL_VIEW_PROJECTION_MATRIX"/>
-		<input shaderInput="rotationMat" builtin="ROTATION_MATRIX"/>
-		<input shaderInput="globalSampler" builtin="GLOBAL_SAMPLER"/>
-		
-
-		<input shaderInput="diffColor" value="0.799988 0.635542 0.640324"/>
-		<input shaderInput="specColor" value="0.500000 0.500000 0.500000"/>
-		<input shaderInput="roughness" value="0.097847" />
-		<input shaderInput="metallic" value="0.000000"/>
-		
-		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
-		<input shaderInput="subsurface" value="0.000000"/>
-		
-	</inputs>
-</material>

BIN
samples/simple_scene/assets/room.ankimesh


+ 1 - 2
samples/simple_scene/assets/roomroom-material.ankimdl → samples/simple_scene/assets/room_walls.ankimdl

@@ -1,9 +1,8 @@
-<?xml version="1.0" encoding="UTF-8" ?>
 <model>
 	<modelPatches>
 		<modelPatch>
 			<mesh>assets/room.ankimesh</mesh>
-			<material>assets/room-material.ankimtl</material>
+			<material>assets/walls.ankimtl</material>
 		</modelPatch>
 	</modelPatches>
 </model>

+ 32 - 46
samples/simple_scene/assets/scene.lua

@@ -1,85 +1,71 @@
 local scene = getSceneGraph()
 local events = getEventManager()
-local rot
-local node
-local inst
-local lcomp
 
-node = scene:newModelNode("roomroom-materialnone0", "assets/roomroom-material.ankimdl")
-trf = Transform.new()
-trf:setOrigin(Vec4.new(0, 0, 0, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newModelNode("columnroom-materialnone1", "assets/columnroom-material.ankimdl")
+node = scene:newPerspectiveCameraNode("Camera_Orientation")
+scene:setActiveCameraNode(node:getSceneNodeBase())
+frustumc = node:getSceneNodeBase():getFrustumComponent()
+frustumc:setPerspective(0.100000, 1000.000000, getMainRenderer():getAspectRatio() * 1.024779, 1.024779)
 trf = Transform.new()
-trf:setOrigin(Vec4.new(4.90187, 5.43441, -4.52919, 0))
+trf:setOrigin(Vec4.new(0.000000, 4.311547, 5.946665, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
-node = scene:newModelNode("sectorportal-materialnone2", "assets/sectorportal-material.ankimdl")
+node = scene:newModelNode("column.003", "assets/column_walls.ankimdl")
 trf = Transform.new()
-trf:setOrigin(Vec4.new(0, 0, 0, 0))
+trf:setOrigin(Vec4.new(4.950977, 5.434409, 4.790287, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1.16458)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
-node = scene:newModelNode("columnroom-materialnone3", "assets/columnroom-material.ankimdl")
+node = scene:newModelNode("column.002", "assets/column_walls.ankimdl")
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-4.59369, 5.43441, -4.49454, 0))
+trf:setOrigin(Vec4.new(-4.611011, 5.434409, 4.790287, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
-node = scene:newModelNode("columnroom-materialnone4", "assets/columnroom-material.ankimdl")
+node = scene:newModelNode("column.001", "assets/column_walls.ankimdl")
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-4.61101, 5.43441, 4.79029, 0))
+trf:setOrigin(Vec4.new(-4.593688, 5.434409, -4.494543, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
-node = scene:newModelNode("columnroom-materialnone5", "assets/columnroom-material.ankimdl")
+node = scene:newModelNode("column", "assets/column_walls.ankimdl")
 trf = Transform.new()
-trf:setOrigin(Vec4.new(4.95098, 5.43441, 4.79029, 0))
+trf:setOrigin(Vec4.new(4.901871, 5.434409, -4.529187, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 node = scene:newPointLightNode("Point")
 lcomp = node:getSceneNodeBase():getLightComponent()
-lcomp:setDiffuseColor(Vec4.new(10, 10, 10, 1))
-lcomp:setRadius(12.77)
+lcomp:setDiffuseColor(Vec4.new(10.000000, 10.000000, 10.000000, 1))
+lcomp:setRadius(31.622776)
 trf = Transform.new()
-trf:setOrigin(Vec4.new(0.0680842, 9.57987, 0.0302386, 0))
+trf:setOrigin(Vec4.new(0.068084, 9.579867, 0.030239, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 4.63287e-05, 1, 0, 0, -1, 4.63287e-05, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, -1.000000, 0.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-lcomp:setShadowEnabled(1)
 
-node = scene:newPerspectiveCameraNode("Camera")
-scene:setActiveCameraNode(node:getSceneNodeBase())
-frustumc = node:getSceneNodeBase():getFrustumComponent()
-frustumc:setPerspective(0.1, 100, 1.5708, 1.0 / getMainRenderer():getAspectRatio() * 1.5708)
+node = scene:newModelNode("room", "assets/room_walls.ankimdl")
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-0.0971127, 3.80237, 5.98675, 0))
+trf:setOrigin(Vec4.new(0.000000, 0.000000, 0.000000, 0))
 rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, -4.63724e-05, 0, 0, 4.63724e-05, 1, 0)
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000)
 trf:setRotation(rot)
-trf:setScale(1)
+trf:setScale(1.000000)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)

BIN
samples/simple_scene/assets/sector.ankimesh


+ 0 - 9
samples/simple_scene/assets/sectorportal-material.ankimdl

@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<model>
-	<modelPatches>
-		<modelPatch>
-			<mesh>assets/sector.ankimesh</mesh>
-			<material>assets/portal-material.ankimtl</material>
-		</modelPatch>
-	</modelPatches>
-</model>

BIN
samples/simple_scene/assets/simple_scene.blend


+ 4 - 5
samples/simple_scene/assets/portal-material.ankimtl → samples/simple_scene/assets/walls.ankimtl

@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8" ?>
 <!-- This file is auto generated by ExporterMaterial.cpp -->
 <material shaderProgram="shaders/GBufferGeneric.glslp">
 
@@ -19,10 +18,10 @@
 		<input shaderInput="globalSampler" builtin="GLOBAL_SAMPLER"/>
 		
 
-		<input shaderInput="diffColor" value="0.006933 0.000000 0.640000"/>
-		<input shaderInput="specColor" value="0.500000 0.500000 0.500000"/>
-		<input shaderInput="roughness" value="0.097847" />
-		<input shaderInput="metallic" value="0.000000"/>
+		<input shaderInput="diffColor" value="0.510773 0.800000 0.000000"/>
+		<input shaderInput="specColor" value="0.04 0.04 0.04"/>
+		<input shaderInput="roughness" value="0.215909" />
+		<input shaderInput="metallic" value="0.000000" />
 		
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 98 - 56
tools/gltf_importer/Importer.cpp

@@ -8,7 +8,7 @@
 namespace anki
 {
 
-static Error getUniformScale(const Mat4& m, F32& out)
+static ANKI_USE_RESULT Error getUniformScale(const Mat4& m, F32& out)
 {
 	const F32 SCALE_THRESHOLD = 0.01f; // 1 cm
 
@@ -42,6 +42,44 @@ static void removeScale(Mat4& m)
 	m.setRotationPart(rot);
 }
 
+static ANKI_USE_RESULT Error getNodeTransform(const cgltf_node& node, Transform& trf)
+{
+	trf = Transform::getIdentity();
+	if(node.has_matrix)
+	{
+		Mat4 mat = Mat4(node.matrix).getTransposed();
+		F32 scale;
+		ANKI_CHECK(getUniformScale(mat, scale));
+		removeScale(mat);
+		trf = Transform(mat);
+	}
+	else
+	{
+		if(node.has_translation)
+		{
+			trf.setOrigin(Vec4(node.translation[0], node.translation[1], node.translation[2], 0.0f));
+		}
+
+		if(node.has_rotation)
+		{
+			trf.setRotation(Mat3x4(Quat(node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3])));
+		}
+
+		if(node.has_scale)
+		{
+			if(node.scale[0] != node.scale[1] || node.scale[0] != node.scale[2])
+			{
+				ANKI_GLTF_LOGE("Expecting uniform scale");
+				return Error::USER_DATA;
+			}
+
+			trf.setScale(node.scale[0]);
+		}
+	}
+
+	return Error::NONE;
+}
+
 Importer::Importer()
 {
 	m_hive = m_alloc.newInstance<ThreadHive>(getCpuCoresCount(), m_alloc, true);
@@ -101,12 +139,14 @@ Error Importer::writeAll()
 	sceneFname.sprintf("%sscene.lua", m_outDir.cstr());
 	ANKI_CHECK(m_sceneFile.open(sceneFname.toCString(), FileOpenFlag::WRITE));
 
+	ANKI_CHECK(m_sceneFile.writeText("local scene = getSceneGraph()\nlocal events = getEventManager()\n"));
+
 	// Nodes
 	for(const cgltf_scene* scene = m_gltf->scenes; scene < m_gltf->scenes + m_gltf->scenes_count; ++scene)
 	{
 		for(cgltf_node* const* node = scene->nodes; node < scene->nodes + scene->nodes_count; ++node)
 		{
-			ANKI_CHECK(visitNode(*(*node)));
+			ANKI_CHECK(visitNode(*(*node), Transform::getIdentity()));
 		}
 	}
 
@@ -115,7 +155,26 @@ Error Importer::writeAll()
 
 Error Importer::getExtras(const cgltf_extras& extras, HashMapAuto<StringAuto, StringAuto>& out)
 {
-	// TODO
+	cgltf_size extrasSize;
+	cgltf_copy_extras_json(m_gltf, &extras, nullptr, &extrasSize);
+	if(extrasSize == 0)
+	{
+		return Error::NONE;
+	}
+
+	DynamicArrayAuto<char> json(m_alloc);
+	json.create(extrasSize + 1);
+	cgltf_result res = cgltf_copy_extras_json(m_gltf, &extras, &json[0], &extrasSize);
+	if(res != cgltf_result_success)
+	{
+		ANKI_GLTF_LOGE("cgltf_copy_extras_json failed: %d", res);
+		return Error::FUNCTION_FAILED;
+	}
+
+	json[json.getSize() - 1] = '\0';
+
+	printf("%s\n", &json[0]);
+
 	return Error::NONE;
 }
 
@@ -150,8 +209,15 @@ Error Importer::parseArrayOfNumbers(CString str, DynamicArrayAuto<F64>& out, con
 	return Error::NONE;
 }
 
-Error Importer::visitNode(const cgltf_node& node)
+Error Importer::visitNode(const cgltf_node& node, const Transform& parentTrf)
 {
+	Transform localTrf;
+	ANKI_CHECK(getNodeTransform(node, localTrf));
+	const Transform finalTrf = parentTrf.combineTransformations(localTrf);
+
+	Transform newParentTrf = Transform::getIdentity();
+	HashMapAuto<StringAuto, StringAuto> parentExtras(m_alloc);
+	Bool writeTrf = true;
 	if(node.light)
 	{
 		ANKI_CHECK(writeLight(node));
@@ -167,53 +233,35 @@ Error Importer::visitNode(const cgltf_node& node)
 	}
 	else
 	{
-		ANKI_GLTF_LOGW("Ignoring node %s", node.name);
+		ANKI_GLTF_LOGW("Ignoring node %s. Assuming transform node", node.name);
+		newParentTrf = finalTrf;
+		ANKI_CHECK(getExtras(node.extras, parentExtras));
+		writeTrf = false;
 	}
 
-	return Error::NONE;
-}
-
-Error Importer::writeTransform(const cgltf_node& node)
-{
-	Transform trf = Transform::getIdentity();
-	if(node.has_matrix)
+	// Write transform
+	if(writeTrf)
 	{
-		Mat4 mat = Mat4(node.matrix).getTransposed();
-		F32 scale;
-		ANKI_CHECK(getUniformScale(mat, scale));
-		removeScale(mat);
-		trf = Transform(mat);
+		ANKI_CHECK(writeTransform(finalTrf));
 	}
-	else
-	{
-		if(node.has_translation)
-		{
-			trf.setOrigin(Vec4(node.translation[0], node.translation[1], node.translation[2], 0.0f));
-		}
-
-		if(node.has_rotation)
-		{
-			trf.setRotation(Mat3x4(Quat(node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3])));
-		}
-
-		if(node.has_scale)
-		{
-			if(node.scale[0] != node.scale[1] || node.scale[0] != node.scale[2])
-			{
-				ANKI_GLTF_LOGE("Expecting uniform scale");
-				return Error::USER_DATA;
-			}
 
-			trf.setScale(node.scale[0]);
-		}
+	// Visit children
+	for(cgltf_node* const* c = node.children; c < node.children + node.children_count; ++c)
+	{
+		ANKI_CHECK(visitNode(*(*c), newParentTrf));
 	}
 
+	return Error::NONE;
+}
+
+Error Importer::writeTransform(const Transform& trf)
+{
 	ANKI_CHECK(m_sceneFile.writeText("trf = Transform.new()\n"));
 	ANKI_CHECK(m_sceneFile.writeText(
-		"trf:setOrigin(%f, %f, %f, 0)\n", trf.getOrigin().x(), trf.getOrigin().y(), trf.getOrigin().z()));
+		"trf:setOrigin(Vec4.new(%f, %f, %f, 0))\n", trf.getOrigin().x(), trf.getOrigin().y(), trf.getOrigin().z()));
 
 	ANKI_CHECK(m_sceneFile.writeText("rot = Mat3x4.new()\n"));
-	ANKI_CHECK(m_sceneFile.writeText("rot:setAll(\n"));
+	ANKI_CHECK(m_sceneFile.writeText("rot:setAll("));
 	for(U i = 0; i < 12; i++)
 	{
 		ANKI_CHECK(m_sceneFile.writeText((i != 11) ? "%f, " : "%f)\n", trf.getRotation()[i]));
@@ -265,8 +313,8 @@ Error Importer::writeModel(const cgltf_mesh& mesh)
 	}
 	else
 	{
-		ANKI_CHECK(
-			file.writeText("\t\t\t<material>%s%s</material>\n", m_rpath.cstr(), mesh.primitives[0].material->name));
+		ANKI_CHECK(file.writeText(
+			"\t\t\t<material>%s%s.ankimtl</material>\n", m_rpath.cstr(), mesh.primitives[0].material->name));
 	}
 
 	ANKI_CHECK(file.writeText("\t\t</modelPatch>\n"));
@@ -308,6 +356,7 @@ Error Importer::writeLight(const cgltf_node& node)
 	ANKI_CHECK(m_sceneFile.writeText("lcomp = node:getSceneNodeBase():getLightComponent()\n"));
 
 	Vec3 color(light.color[0], light.color[1], light.color[2]);
+	color *= light.intensity;
 	ANKI_CHECK(
 		m_sceneFile.writeText("lcomp:setDiffuseColor(Vec4.new(%f, %f, %f, 1))\n", color.x(), color.y(), color.z()));
 
@@ -398,14 +447,12 @@ Error Importer::writeLight(const cgltf_node& node)
 		}
 	}
 
-	ANKI_CHECK(writeTransform(node));
-
 	return Error::NONE;
 }
 
 Error Importer::writeCamera(const cgltf_node& node)
 {
-	if(node.camera->type != cgltf_camera_type_orthographic)
+	if(node.camera->type != cgltf_camera_type_perspective)
 	{
 		ANKI_GLTF_LOGW("Unsupported camera type: %s", node.name);
 		return Error::NONE;
@@ -414,18 +461,15 @@ Error Importer::writeCamera(const cgltf_node& node)
 	const cgltf_camera_perspective& cam = node.camera->perspective;
 	ANKI_GLTF_LOGI("Exporting camera %s", node.name);
 
-	ANKI_CHECK(m_sceneFile.writeText("\nnode = scene:newPerspectiveCameraNode(\"%s\")", node.name));
+	ANKI_CHECK(m_sceneFile.writeText("\nnode = scene:newPerspectiveCameraNode(\"%s\")\n", node.name));
 	ANKI_CHECK(m_sceneFile.writeText("scene:setActiveCameraNode(node:getSceneNodeBase())\n"));
 	ANKI_CHECK(m_sceneFile.writeText("frustumc = node:getSceneNodeBase():getFrustumComponent()\n"));
 
-	ANKI_CHECK(
-		m_sceneFile.writeText("frustumc:setPerspective(%f, %f, %f, 1.0 / getMainRenderer():getAspectRatio() * %f)\n",
-			cam.znear,
-			cam.zfar,
-			cam.yfov,
-			cam.yfov));
-
-	ANKI_CHECK(writeTransform(node));
+	ANKI_CHECK(m_sceneFile.writeText("frustumc:setPerspective(%f, %f, getMainRenderer():getAspectRatio() * %f, %f)\n",
+		cam.znear,
+		cam.zfar,
+		cam.yfov,
+		cam.yfov));
 
 	return Error::NONE;
 }
@@ -439,8 +483,6 @@ Error Importer::writeModelNode(const cgltf_node& node)
 
 	ANKI_CHECK(m_sceneFile.writeText("\nnode = scene:newModelNode(\"%s\", \"%s\")\n", node.name, modelFname.cstr()));
 
-	ANKI_CHECK(writeTransform(node));
-
 	// TODO: collision mesh
 
 	return Error::NONE;

+ 4 - 3
tools/gltf_importer/Importer.h

@@ -33,7 +33,7 @@ private:
 
 	cgltf_data* m_gltf = nullptr;
 
-	F32 m_normalsMergeCosAngle = cos(toRad(30.0f));
+	F32 m_normalsMergeAngle = toRad(30.0f);
 
 	ThreadHive* m_hive = nullptr;
 
@@ -55,8 +55,9 @@ private:
 	ANKI_USE_RESULT Error writeMaterial(const cgltf_material& mtl);
 	ANKI_USE_RESULT Error writeModel(const cgltf_mesh& mesh);
 
-	ANKI_USE_RESULT Error visitNode(const cgltf_node& node);
-	ANKI_USE_RESULT Error writeTransform(const cgltf_node& node);
+	// Scene
+	ANKI_USE_RESULT Error writeTransform(const Transform& trf);
+	ANKI_USE_RESULT Error visitNode(const cgltf_node& node, const Transform& parentTrf);
 	ANKI_USE_RESULT Error writeLight(const cgltf_node& node);
 	ANKI_USE_RESULT Error writeCamera(const cgltf_node& node);
 	ANKI_USE_RESULT Error writeModelNode(const cgltf_node& node);

+ 35 - 15
tools/gltf_importer/ImporterMaterial.cpp

@@ -8,13 +8,14 @@
 namespace anki
 {
 
-const char* MATERIAL_TEMPLATE = R"(<?xml version="1.0" encoding="UTF-8" ?>
-<!-- This file is auto generated by ImporterMaterial.cpp -->
+const char* MATERIAL_TEMPLATE = R"(<!-- This file is auto generated by ExporterMaterial.cpp -->
 <material shaderProgram="shaders/GBufferGeneric.glslp">
+
 	<mutators>
 		<mutator name="DIFFUSE_TEX" value="%diffTexMutator%"/>
 		<mutator name="SPECULAR_TEX" value="%specTexMutator%"/>
-		<mutator name="METALLIC_ROUGHNESS_TEX" value="%metallicRoughnessTexMutator%"/>
+		<mutator name="ROUGHNESS_TEX" value="%roughnessTexMutator%"/>
+		<mutator name="METAL_TEX" value="%metalTexMutator%"/>
 		<mutator name="NORMAL_TEX" value="%normalTexMutator%"/>
 		<mutator name="PARALLAX" value="%parallaxMutator%"/>
 		<mutator name="EMISSIVE_TEX" value="%emissiveTexMutator%"/>
@@ -29,7 +30,8 @@ const char* MATERIAL_TEMPLATE = R"(<?xml version="1.0" encoding="UTF-8" ?>
 
 		%diff%
 		%spec%
-		%metallicRoughness%
+		%roughness%
+		%metallic%
 		%normal%
 		%emission%
 		%subsurface%
@@ -107,30 +109,48 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		xml = replaceAllString(xml, "%specTexMutator%", "0");
 	}
 
-	// Roughness & metallic
+	// Roughness
 	if(mtl.pbr_metallic_roughness.metallic_roughness_texture.texture)
 	{
 		StringAuto uri(m_alloc);
 		uri.sprintf(
 			"%s%s", m_texrpath.cstr(), getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture).cstr());
 
-		xml = replaceAllString(xml,
-			"%metallicRoughness%",
-			"<input shaderInput=\"metallicRoughnessTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
+		xml = replaceAllString(
+			xml, "%roughness%", "<input shaderInput=\"roughnessTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
 
-		xml = replaceAllString(xml, "%metallicRoughnessTexMutator%", "1");
+		xml = replaceAllString(xml, "%roughnessTexMutator%", "1");
 	}
 	else
 	{
-		const F32 roughness = mtl.pbr_metallic_roughness.roughness_factor;
-		const F32 metallic = mtl.pbr_metallic_roughness.metallic_factor;
+		xml = replaceAllString(xml,
+			"%roughness%",
+			"<input shaderInput=\"roughness\" value=\"" + std::to_string(mtl.pbr_metallic_roughness.roughness_factor)
+				+ "\" />");
 
+		xml = replaceAllString(xml, "%roughnessTexMutator%", "0");
+	}
+
+	// Metallic
+	if(mtl.pbr_metallic_roughness.metallic_roughness_texture.texture)
+	{
+		StringAuto uri(m_alloc);
+		uri.sprintf(
+			"%s%s", m_texrpath.cstr(), getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture).cstr());
+
+		xml = replaceAllString(
+			xml, "%metallic%", "<input shaderInput=\"metallicTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
+
+		xml = replaceAllString(xml, "%metalTexMutator%", "1");
+	}
+	else
+	{
 		xml = replaceAllString(xml,
-			"%metallicRoughness%",
-			"<input shaderInput=\"metallic\" value=\"" + std::to_string(metallic) + "\"/>\n"
-				+ "<input shaderInput=\"roughness\" value=\"" + std::to_string(roughness) + "\"/>");
+			"%metallic%",
+			"<input shaderInput=\"metallic\" value=\"" + std::to_string(mtl.pbr_metallic_roughness.metallic_factor)
+				+ "\" />");
 
-		xml = replaceAllString(xml, "%metallicRoughnessTexMutator%", "0");
+		xml = replaceAllString(xml, "%metalTexMutator%", "0");
 	}
 
 	// Normal texture

+ 5 - 5
tools/gltf_importer/ImporterMesh.cpp

@@ -68,7 +68,7 @@ static Error appendAttribute(const cgltf_attribute& attrib, DynamicArrayAuto<T>&
 	const U8* base = static_cast<const U8*>(attrib.data->buffer_view->buffer->data) + attrib.data->offset
 					 + attrib.data->buffer_view->offset;
 
-	const PtrSize stride = (attrib.data->stride == 0) ? calcImplicitStride(attrib) : attrib.data->stride == 0;
+	const PtrSize stride = (attrib.data->stride == 0) ? calcImplicitStride(attrib) : attrib.data->stride;
 
 	const U count = attrib.data->count;
 
@@ -152,7 +152,7 @@ Error Importer::writeMesh(const cgltf_mesh& mesh)
 			{
 				appendAttribute(*attrib, submesh.m_positions, [&](const Vec3& pos) {
 					submesh.m_aabbMin = submesh.m_aabbMin.min(pos);
-					submesh.m_aabbMax = submesh.m_aabbMax.min(pos);
+					submesh.m_aabbMax = submesh.m_aabbMax.max(pos);
 				});
 			}
 			else if(attrib->type == cgltf_attribute_type_normal)
@@ -173,7 +173,7 @@ Error Importer::writeMesh(const cgltf_mesh& mesh)
 		}
 
 		aabbMin = aabbMin.min(submesh.m_aabbMin);
-		aabbMax = aabbMax.min(submesh.m_aabbMax);
+		aabbMax = aabbMax.max(submesh.m_aabbMax);
 
 		const U vertCount = submesh.m_positions.getSize();
 		if(submesh.m_positions.getSize() == 0)
@@ -215,8 +215,8 @@ Error Importer::writeMesh(const cgltf_mesh& mesh)
 
 				// Check angle of the normals
 				Vec3& otherNormal = submesh.m_normals[prevV];
-				const F32 cosAng = otherNormal.dot(normal);
-				if(cosAng > m_normalsMergeCosAngle)
+				const F32 ang = acos(otherNormal.dot(normal));
+				if(ang > m_normalsMergeAngle)
 				{
 					continue;
 				}