Browse Source

Skeleton: More work

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
8fe01006c2

+ 79 - 0
programs/SceneDebug.ankiprog

@@ -0,0 +1,79 @@
+<!-- 
+Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+All rights reserved.
+Code licensed under the BSD License.
+http://www.anki3d.org/LICENSE
+-->
+<shaderProgram>
+	<mutators>
+		<mutator name="COLOR_TEXTURE" values="0 1"/>
+	</mutators>
+
+	<inputs>
+		<input name="INSTANCE_COUNT" type="uint" const="1"/>
+	</inputs>
+
+	<shaders>
+		<shader type="vert">
+			<source><![CDATA[
+#include "shaders/Common.glsl"
+
+layout(location = 0) in vec3 in_position;
+#if COLOR_TEXTURE == 1
+layout(location = 1) in vec2 in_uv;
+layout(location = 0) out vec2 out_uv;
+#endif
+
+layout(ANKI_UBO_BINDING(0, 0), row_major) uniform u0_
+{
+	mat4 u_mvp[INSTANCE_COUNT];
+#if COLOR_TEXTURE == 0
+	vec4 u_color;
+#endif
+};
+
+out gl_PerVertex
+{
+	vec4 gl_Position;
+};
+
+void main()
+{
+#if COLOR_TEXTURE == 1
+	out_uv = in_uv;
+#endif
+	gl_Position = u_mvp[gl_InstanceID] * vec4(in_position, 1.0);
+}
+			]]></source>
+		</shader>
+
+		<shader type="frag">
+			<source><![CDATA[
+#include "shaders/Common.glsl"
+
+#if COLOR_TEXTURE == 1
+layout(location = 0) in vec2 in_uv;
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_tex;
+#else
+layout(ANKI_UBO_BINDING(0, 0), row_major) uniform u0_
+{
+	mat4 u_mvp[INSTANCE_COUNT];
+	vec4 u_color;
+};
+#endif
+
+layout(location = 0) out vec4 out_color;
+
+void main()
+{
+#if COLOR_TEXTURE == 1
+	out_color = texture(u_tex, in_uv);
+#else
+	out_color = u_color;
+#endif
+}
+			]]></source>
+		</shader>
+	</shaders>
+</shaderProgram>
+

+ 10 - 0
src/anki/resource/Model.cpp

@@ -252,6 +252,16 @@ Error Model::load(const ResourceFilename& filename, Bool async)
 		ANKI_CHECK(modelPatchEl.getNextSiblingElement("modelPatch", modelPatchEl));
 	} while(modelPatchEl);
 
+	// <skeleton>
+	XmlElement skeletonEl;
+	ANKI_CHECK(rootEl.getChildElementOptional("skeleton", skeletonEl));
+	if(skeletonEl)
+	{
+		CString fname;
+		ANKI_CHECK(skeletonEl.getText(fname));
+		ANKI_CHECK(getManager().loadResource(fname, m_skeleton));
+	}
+
 	// Calculate compound bounding volume
 	RenderingKey key;
 	key.m_lod = 0;

+ 58 - 0
src/anki/resource/Skeleton.cpp

@@ -40,6 +40,8 @@ Error Skeleton::load(const ResourceFilename& filename, Bool async)
 
 	m_bones.create(getAllocator(), bonesCount);
 
+	StringListAuto boneParents(getAllocator());
+
 	// Load every bone
 	bonesCount = 0;
 	do
@@ -58,10 +60,66 @@ Error Skeleton::load(const ResourceFilename& filename, Bool async)
 		ANKI_CHECK(boneEl.getChildElement("transform", trfEl));
 		ANKI_CHECK(trfEl.getMat4(bone.m_transform));
 
+		// <boneTransform>
+		XmlElement btrfEl;
+		ANKI_CHECK(boneEl.getChildElement("boneTransform", btrfEl));
+		ANKI_CHECK(btrfEl.getMat4(bone.m_boneTrf));
+
+		// <parent>
+		XmlElement parentEl;
+		ANKI_CHECK(boneEl.getChildElementOptional("parent", parentEl));
+		if(parentEl)
+		{
+			CString parentName;
+			ANKI_CHECK(parentEl.getText(parentName));
+			boneParents.pushBack(parentName);
+		}
+		else
+		{
+			boneParents.pushBack("");
+		}
+
 		// Advance
 		ANKI_CHECK(boneEl.getNextSiblingElement("bone", boneEl));
 	} while(boneEl);
 
+	// Resolve the parents
+	auto it = boneParents.getBegin();
+	for(U i = 0; i < m_bones.getSize(); ++i)
+	{
+		Bone& bone = m_bones[i];
+
+		if(!it->isEmpty())
+		{
+			for(U j = 0; j < m_bones.getSize(); ++j)
+			{
+				if(m_bones[j].m_name == *it)
+				{
+					bone.m_parent = &m_bones[j];
+					break;
+				}
+			}
+
+			if(bone.m_parent == nullptr)
+			{
+				ANKI_RESOURCE_LOGE(
+					"Bone \"%s\" is referencing an unknown parent \"%s\"", &bone.m_name[0], &it->toCString()[0]);
+				return ErrorCode::USER_DATA;
+			}
+
+			if(bone.m_parent->m_childrenCount >= MAX_CHILDREN_PER_BONE)
+			{
+				ANKI_RESOURCE_LOGE(
+					"Bone \"%s\" cannot have more that %u children", &bone.m_parent->m_name[0], MAX_CHILDREN_PER_BONE);
+				return ErrorCode::USER_DATA;
+			}
+
+			bone.m_parent->m_children[bone.m_parent->m_childrenCount++] = &bone;
+		}
+
+		++it;
+	}
+
 	return ErrorCode::NONE;
 }
 

+ 11 - 4
src/anki/resource/Skeleton.h

@@ -14,6 +14,8 @@ namespace anki
 /// @addtogroup resource
 /// @{
 
+const U32 MAX_CHILDREN_PER_BONE = 8;
+
 /// Skeleton bone
 struct Bone
 {
@@ -36,10 +38,13 @@ public:
 
 private:
 	String m_name; ///< The name of the bone
-	static const U32 MAX_CHILDS_PER_BONE = 4; ///< Please dont change this
 
-	// see the class notes
-	Mat4 m_transform;
+	Mat4 m_transform; ///< See the class notes.
+	Mat4 m_boneTrf;
+
+	Bone* m_parent = nullptr;
+	Array<Bone*, MAX_CHILDREN_PER_BONE> m_children = {};
+	U8 m_childrenCount = 0;
 
 	void destroy(ResourceAllocator<U8> alloc)
 	{
@@ -56,7 +61,9 @@ private:
 /// 	<bones>
 /// 		<bone>
 /// 			<name>X</name>
-/// 			<transform></transform>
+/// 			<transform>16 floats</transform>
+/// 			<boneTransform>16 floats</boneTransform>
+/// 			[<parent>bone_name</parent>]
 /// 		<bone>
 ///         ...
 /// 	</bones>

+ 1 - 0
src/anki/scene/SceneComponent.h

@@ -34,6 +34,7 @@ enum class SceneComponentType : U16
 	REFLECTION_PROXY,
 	OCCLUDER,
 	DECAL,
+	SKIN,
 	PLAYER_CONTROLLER,
 
 	COUNT,

+ 11 - 0
src/anki/scene/SkinComponent.cpp

@@ -0,0 +1,11 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/scene/SkinComponent.h>
+
+namespace anki
+{
+
+} // end namespace anki

+ 23 - 0
src/anki/scene/SkinComponent.h

@@ -0,0 +1,23 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/scene/SceneComponent.h>
+
+namespace anki
+{
+
+/// @addtogroup scene
+/// @{
+
+/// Skin component.
+class SkinComponent : public SceneComponent
+{
+public:
+};
+/// @}
+
+} // end namespace anki

+ 16 - 5
tools/scene/Exporter.cpp

@@ -340,9 +340,9 @@ void Exporter::exportSkeleton(const aiMesh& mesh) const
 		// <name>
 		file << "\t\t\t<name>" << bone.mName.C_Str() << "</name>\n";
 
-		// <transform>
+		// <bontTransform>
 		aiMatrix4x4 akMat = toAnkiMatrix(bone.mOffsetMatrix);
-		file << "\t\t\t<transform>";
+		file << "\t\t\t<boneTransform>";
 		for(unsigned j = 0; j < 4; j++)
 		{
 			for(unsigned i = 0; i < 4; i++)
@@ -350,13 +350,24 @@ void Exporter::exportSkeleton(const aiMesh& mesh) const
 				file << akMat[j][i] << " ";
 			}
 		}
-		file << "</transform>\n";
+		file << "</boneTransform>\n";
 
-		// <parent>
-		// Need to find the bone in the scene hierarchy
+		// <transform>
 		const aiNode* node = findNodeWithName(bone.mName.C_Str(), m_scene->mRootNode);
 		assert(node);
 
+		akMat = toAnkiMatrix(node->mTransformation);
+		file << "\t\t\t<transform>";
+		for(unsigned j = 0; j < 4; j++)
+		{
+			for(unsigned i = 0; i < 4; i++)
+			{
+				file << akMat[j][i] << " ";
+			}
+		}
+		file << "</transform>\n";
+
+		// <parent>
 		if(bone.mName.C_Str() != rootBoneName)
 		{
 			file << "\t\t\t<parent>" << node->mParent->mName.C_Str() << "</parent>\n";