Browse Source

Some more skeletal animation code

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
d292f3b9d0

+ 17 - 0
src/anki/renderer/Dbg.cpp

@@ -9,6 +9,7 @@
 #include <anki/renderer/LightShading.h>
 #include <anki/renderer/FinalComposite.h>
 #include <anki/renderer/DebugDrawer.h>
+#include <anki/renderer/RenderQueue.h>
 #include <anki/Scene.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Enum.h>
@@ -90,6 +91,22 @@ Error Dbg::run(RenderingContext& ctx)
 
 	SceneDebugDrawer sceneDrawer(m_drawer);
 
+	RenderQueueDrawContext dctx;
+	dctx.m_viewMatrix = ctx.m_renderQueue->m_viewMatrix;
+	dctx.m_viewProjectionMatrix = ctx.m_renderQueue->m_viewProjectionMatrix;
+	dctx.m_projectionMatrix = Mat4::getIdentity(); // TODO
+	dctx.m_cameraTransform = ctx.m_renderQueue->m_viewMatrix.getInverse();
+	dctx.m_stagingGpuAllocator = &m_r->getStagingGpuMemoryManager();
+	dctx.m_commandBuffer = cmdb;
+	dctx.m_key = RenderingKey(Pass::GB_FS, 0, 1);
+	dctx.m_debugDraw = true;
+
+	for(const RenderableQueueElement& el : ctx.m_renderQueue->m_renderables)
+	{
+		Array<const void*, 1> a = {{el.m_userData}};
+		el.m_callback(dctx, {&a[0], 1});
+	}
+
 	for(const PointLightQueueElement& plight : ctx.m_renderQueue->m_pointLights)
 	{
 		sceneDrawer.draw(plight);

+ 14 - 5
src/anki/renderer/RenderQueue.h

@@ -24,7 +24,7 @@ public:
 	Mat4 m_viewProjectionMatrix;
 };
 
-/// Context that contains variables for drawing and will be passed to RenderableQueueElementDrawCallback.
+/// Context that contains variables for drawing and will be passed to RenderQueueDrawCallback.
 class RenderQueueDrawContext final : public RenderingMatrices
 {
 public:
@@ -34,14 +34,14 @@ public:
 	Bool m_debugDraw; ///< If true the drawcall should be drawing some kind of debug mesh.
 };
 
-/// Draw callback for the RenderableQueueElement.
-using RenderableQueueElementDrawCallback = void (*)(RenderQueueDrawContext& ctx, WeakArray<const void*> userData);
+/// Draw callback for drawing.
+using RenderQueueDrawCallback = void (*)(RenderQueueDrawContext& ctx, WeakArray<const void*> userData);
 
 /// Render queue element that contains info on items that populate the G-buffer or the forward shading buffer etc.
 class RenderableQueueElement final
 {
 public:
-	RenderableQueueElementDrawCallback m_callback;
+	RenderQueueDrawCallback m_callback;
 	const void* m_userData;
 	U64 m_mergeKey;
 	F32 m_distanceFromCamera;
@@ -61,6 +61,8 @@ public:
 	Vec3 m_specularColor;
 	Array<RenderQueue*, 6> m_shadowRenderQueues;
 	U32 m_textureArrayIndex; ///< Renderer internal.
+	const void* m_userData;
+	RenderQueueDrawCallback m_drawCallback;
 
 	Bool hasShadow() const
 	{
@@ -84,6 +86,8 @@ public:
 	Vec3 m_diffuseColor;
 	Vec3 m_specularColor;
 	RenderQueue* m_shadowRenderQueue;
+	const void* m_userData;
+	RenderQueueDrawCallback m_drawCallback;
 
 	Bool hasShadow() const
 	{
@@ -103,7 +107,8 @@ class ReflectionProbeQueueElement final
 {
 public:
 	ReflectionProbeQueueElementFeedbackCallback m_feedbackCallback;
-	void* m_userData;
+	RenderQueueDrawCallback m_drawCallback;
+	void* m_userData; // TODO Shouldn't be const void*?
 	U64 m_uuid;
 	Vec3 m_worldPosition;
 	F32 m_radius;
@@ -122,6 +127,8 @@ public:
 	Vec2 m_firstFlareSize;
 	Vec4 m_colorMultiplier;
 	Texture* m_texture; ///< Totaly unsafe but we can't have a smart ptr in here since there will be no deletion.
+	const void* m_userData;
+	RenderQueueDrawCallback m_drawCallback;
 };
 
 static_assert(std::is_trivially_destructible<LensFlareQueueElement>::value == true, "Should be trivially destructible");
@@ -130,6 +137,8 @@ static_assert(std::is_trivially_destructible<LensFlareQueueElement>::value == tr
 class DecalQueueElement final
 {
 public:
+	const void* m_userData;
+	RenderQueueDrawCallback m_drawCallback;
 	Texture* m_diffuseAtlas;
 	Texture* m_normalRoughnessAtlas;
 	Vec4 m_diffuseAtlasUv;

+ 1 - 1
src/anki/resource/Skeleton.cpp

@@ -14,7 +14,7 @@ Skeleton::~Skeleton()
 {
 	for(Bone& b : m_bones)
 	{
-		b._destroy(getAllocator());
+		b.destroy(getAllocator());
 	}
 
 	m_bones.destroy(getAllocator());

+ 5 - 8
src/anki/resource/Skeleton.h

@@ -34,20 +34,17 @@ public:
 		return m_transform;
 	}
 
-	/// @privatesection
-	/// @{
-	void _destroy(ResourceAllocator<U8> alloc)
-	{
-		m_name.destroy(alloc);
-	}
-	/// @}
-
 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;
+
+	void destroy(ResourceAllocator<U8> alloc)
+	{
+		m_name.destroy(alloc);
+	}
 };
 
 /// It contains the bones with their position and hierarchy

+ 7 - 0
src/anki/scene/DecalComponent.h

@@ -134,6 +134,8 @@ public:
 		el.m_obbCenter = m_obb.getCenter().xyz();
 		el.m_obbExtend = m_obb.getExtend().xyz();
 		el.m_obbRotation = m_obb.getRotation().getRotationPart();
+		el.m_userData = this;
+		el.m_drawCallback = debugDrawCallback;
 	}
 
 private:
@@ -162,6 +164,11 @@ private:
 	ANKI_USE_RESULT Error setLayer(CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor, LayerType type);
 
 	void updateInternal();
+
+	static void debugDrawCallback(RenderQueueDrawContext& ctx, WeakArray<const void*> userData)
+	{
+		// TODO
+	}
 };
 /// @}
 

+ 7 - 0
src/anki/scene/LensFlareComponent.h

@@ -86,6 +86,8 @@ public:
 		el.m_firstFlareSize = m_firstFlareSize;
 		el.m_colorMultiplier = m_colorMul;
 		el.m_texture = m_tex->getGrTexture().get();
+		el.m_userData = this;
+		el.m_drawCallback = debugDrawCallback;
 	}
 
 private:
@@ -97,6 +99,11 @@ private:
 	Vec2 m_otherFlareSize = Vec2(1.0);
 
 	Vec4 m_worldPosition = Vec4(0.0);
+
+	static void debugDrawCallback(RenderQueueDrawContext& ctx, WeakArray<const void*> userData)
+	{
+		// Do nothing
+	}
 };
 /// @}
 

+ 14 - 0
src/anki/scene/LightComponent.h

@@ -141,6 +141,8 @@ public:
 		el.m_radius = m_radius;
 		el.m_diffuseColor = m_diffColor.xyz();
 		el.m_specularColor = m_specColor.xyz();
+		el.m_userData = this;
+		el.m_drawCallback = pointLightDebugDrawCallback;
 	}
 
 	void setupSpotLightQueueElement(SpotLightQueueElement& el) const
@@ -154,6 +156,8 @@ public:
 		el.m_innerAngle = m_innerAngle;
 		el.m_diffuseColor = m_diffColor.xyz();
 		el.m_specularColor = m_specColor.xyz();
+		el.m_userData = this;
+		el.m_drawCallback = spotLightDebugDrawCallback;
 	}
 
 private:
@@ -181,6 +185,16 @@ private:
 	};
 
 	BitMask<U8> m_flags = BitMask<U8>(DIRTY | TRF_DIRTY);
+
+	static void pointLightDebugDrawCallback(RenderQueueDrawContext& ctx, WeakArray<const void*> userData)
+	{
+		// TODO
+	}
+
+	static void spotLightDebugDrawCallback(RenderQueueDrawContext& ctx, WeakArray<const void*> userData)
+	{
+		// TODO
+	}
 };
 /// @}
 

+ 95 - 1
src/anki/scene/ModelNode.cpp

@@ -213,6 +213,8 @@ Error ModelNode::init(const CString& modelFname)
 		newComponent<MRenderComponent>(this);
 	}
 
+	ANKI_CHECK(getResourceManager().loadResource("programs/SceneDebug.ankiprog", m_dbgProg));
+
 	return ErrorCode::NONE;
 }
 
@@ -305,7 +307,99 @@ void ModelNode::drawCallback(RenderQueueDrawContext& ctx, WeakArray<const void*>
 	}
 	else
 	{
-		ANKI_ASSERT(!"TODO");
+		// Draw the bounding volumes
+
+		// Allocate staging memory
+		StagingGpuMemoryToken vertToken;
+		Vec3* verts = static_cast<Vec3*>(
+			ctx.m_stagingGpuAllocator->allocateFrame(sizeof(Vec3) * 8, StagingGpuMemoryType::VERTEX, vertToken));
+
+		const F32 SIZE = 1.0f;
+		verts[0] = Vec3(SIZE, SIZE, SIZE); // front top right
+		verts[1] = Vec3(-SIZE, SIZE, SIZE); // front top left
+		verts[2] = Vec3(-SIZE, -SIZE, SIZE); // front bottom left
+		verts[3] = Vec3(SIZE, -SIZE, SIZE); // front bottom right
+		verts[4] = Vec3(SIZE, SIZE, -SIZE); // back top right
+		verts[5] = Vec3(-SIZE, SIZE, -SIZE); // back top left
+		verts[6] = Vec3(-SIZE, -SIZE, -SIZE); // back bottom left
+		verts[7] = Vec3(SIZE, -SIZE, -SIZE); // back bottom right
+
+		StagingGpuMemoryToken indicesToken;
+		const U INDEX_COUNT = 12 * 2;
+		U16* indices = static_cast<U16*>(ctx.m_stagingGpuAllocator->allocateFrame(
+			sizeof(U16) * INDEX_COUNT, StagingGpuMemoryType::VERTEX, indicesToken));
+
+		U c = 0;
+		indices[c++] = 0;
+		indices[c++] = 1;
+		indices[c++] = 1;
+		indices[c++] = 2;
+		indices[c++] = 2;
+		indices[c++] = 3;
+		indices[c++] = 3;
+		indices[c++] = 0;
+
+		indices[c++] = 4;
+		indices[c++] = 5;
+		indices[c++] = 5;
+		indices[c++] = 6;
+		indices[c++] = 6;
+		indices[c++] = 7;
+		indices[c++] = 7;
+		indices[c++] = 4;
+
+		indices[c++] = 0;
+		indices[c++] = 4;
+		indices[c++] = 1;
+		indices[c++] = 5;
+		indices[c++] = 2;
+		indices[c++] = 6;
+		indices[c++] = 3;
+		indices[c++] = 7;
+
+		ANKI_ASSERT(c == INDEX_COUNT);
+
+		// Set the uniforms
+		StagingGpuMemoryToken unisToken;
+		Mat4* mvps = static_cast<Mat4*>(ctx.m_stagingGpuAllocator->allocateFrame(
+			sizeof(Mat4) * userData.getSize() + sizeof(Vec4), StagingGpuMemoryType::UNIFORM, unisToken));
+
+		for(U i = 0; i < userData.getSize(); ++i)
+		{
+			const ModelNode& self2 = *static_cast<const ModelNode*>(userData[i]);
+
+			Mat3 rot = self2.m_obb.getRotation().getRotationPart();
+			const Vec4 tsl = self2.m_obb.getCenter().xyz1();
+			const Vec3 scale = self2.m_obb.getExtend().xyz();
+
+			// Set non uniform scale
+			rot(0, 0) *= scale.x();
+			rot(0, 1) *= scale.y();
+			rot(0, 2) *= scale.z();
+
+			*mvps = ctx.m_viewProjectionMatrix * Mat4(tsl, rot, 1.0f);
+			++mvps;
+		}
+
+		Vec4* color = reinterpret_cast<Vec4*>(mvps);
+		*color = Vec4(1.0f, 0.0f, 1.0f, 1.0f);
+
+		// Setup state
+		ShaderProgramResourceMutationInitList<1> mutators(self.m_dbgProg);
+		mutators.add("COLOR_TEXTURE", 0);
+		ShaderProgramResourceConstantValueInitList<1> consts(self.m_dbgProg);
+		consts.add("INSTANCE_COUNT", U32(userData.getSize()));
+		const ShaderProgramResourceVariant* variant;
+		self.m_dbgProg->getOrCreateVariant(mutators.get(), consts.get(), variant);
+		cmdb->bindShaderProgram(variant->getProgram());
+
+		cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
+		cmdb->bindVertexBuffer(0, vertToken.m_buffer, vertToken.m_offset, sizeof(Vec3));
+		cmdb->bindIndexBuffer(indicesToken.m_buffer, indicesToken.m_offset, IndexType::U16);
+
+		cmdb->bindUniformBuffer(0, 0, unisToken.m_buffer, unisToken.m_offset, unisToken.m_range);
+
+		cmdb->drawElements(PrimitiveTopology::LINES, INDEX_COUNT, userData.getSize());
 	}
 }
 

+ 2 - 0
src/anki/scene/ModelNode.h

@@ -79,6 +79,8 @@ private:
 	Obb m_obb;
 	U64 m_mergeKey = 0;
 
+	ShaderProgramResourcePtr m_dbgProg;
+
 	Bool isSinglePatch() const
 	{
 		return m_modelPatches.getSize() == 0;

+ 32 - 22
src/anki/scene/ParticleEmitter.cpp

@@ -280,28 +280,38 @@ void ParticleEmitter::drawCallback(RenderQueueDrawContext& ctx, WeakArray<const
 
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
-	// Program
-	ShaderProgramPtr prog;
-	self.m_particleEmitterResource->getRenderingInfo(ctx.m_key.m_lod, prog);
-	cmdb->bindShaderProgram(prog);
-
-	// Vertex attribs
-	cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
-	cmdb->setVertexAttribute(1, 0, PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT), sizeof(Vec3));
-	cmdb->setVertexAttribute(
-		2, 0, PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT), sizeof(Vec3) + sizeof(F32));
-
-	// Vertex buff
-	cmdb->bindVertexBuffer(
-		0, self.m_vertBuffToken.m_buffer, self.m_vertBuffToken.m_offset, VERTEX_SIZE, VertexStepRate::INSTANCE);
-
-	// Uniforms
-	Array<Mat4, 1> trf = {{Mat4::getIdentity()}};
-	self.getComponent<RenderComponent>().allocateAndSetupUniforms(
-		self.m_particleEmitterResource->getMaterial()->getDescriptorSetIndex(), ctx, trf, *ctx.m_stagingGpuAllocator);
-
-	// Draw
-	cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, self.m_aliveParticlesCount, 0, 0);
+	if(!ctx.m_debugDraw)
+	{
+		// Program
+		ShaderProgramPtr prog;
+		self.m_particleEmitterResource->getRenderingInfo(ctx.m_key.m_lod, prog);
+		cmdb->bindShaderProgram(prog);
+
+		// Vertex attribs
+		cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
+		cmdb->setVertexAttribute(1, 0, PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT), sizeof(Vec3));
+		cmdb->setVertexAttribute(
+			2, 0, PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT), sizeof(Vec3) + sizeof(F32));
+
+		// Vertex buff
+		cmdb->bindVertexBuffer(
+			0, self.m_vertBuffToken.m_buffer, self.m_vertBuffToken.m_offset, VERTEX_SIZE, VertexStepRate::INSTANCE);
+
+		// Uniforms
+		Array<Mat4, 1> trf = {{Mat4::getIdentity()}};
+		self.getComponent<RenderComponent>().allocateAndSetupUniforms(
+			self.m_particleEmitterResource->getMaterial()->getDescriptorSetIndex(),
+			ctx,
+			trf,
+			*ctx.m_stagingGpuAllocator);
+
+		// Draw
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, self.m_aliveParticlesCount, 0, 0);
+	}
+	else
+	{
+		// TODO
+	}
 }
 
 void ParticleEmitter::onMoveComponentUpdate(MoveComponent& move)

+ 6 - 0
src/anki/scene/ReflectionProbeComponent.h

@@ -76,6 +76,7 @@ public:
 		el.m_worldPosition = m_pos.xyz();
 		el.m_radius = m_radius;
 		el.m_textureArrayIndex = MAX_U32;
+		el.m_drawCallback = debugDrawCallback;
 	}
 
 private:
@@ -90,6 +91,11 @@ private:
 		ANKI_ASSERT(userData);
 		static_cast<ReflectionProbeComponent*>(userData)->m_markedForRendering = fillRenderQueuesOnNextFrame;
 	}
+
+	static void debugDrawCallback(RenderQueueDrawContext& ctx, WeakArray<const void*> userData)
+	{
+		// TODO
+	}
 };
 /// @}
 

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

@@ -113,6 +113,7 @@ public:
 		return *m_threadHive;
 	}
 
+	// TODO remove that from here
 	StagingGpuMemoryManager& getStagingGpuMemoryManager()
 	{
 		ANKI_ASSERT(m_stagingAlloc);

+ 52 - 16
tools/scene/Exporter.cpp

@@ -50,13 +50,18 @@ static std::string getMeshName(const aiMesh& mesh)
 }
 
 /// Walk the node hierarchy and find the node.
-static const aiNode* findNodeWithName(const std::string& name, const aiNode* node)
+static const aiNode* findNodeWithName(const std::string& name, const aiNode* node, unsigned* depth = nullptr)
 {
 	if(node == nullptr || node->mName.C_Str() == name)
 	{
 		return node;
 	}
 
+	if(depth)
+	{
+		++(*depth);
+	}
+
 	const aiNode* out = nullptr;
 
 	// Go to children
@@ -298,15 +303,34 @@ void Exporter::exportSkeleton(const aiMesh& mesh) const
 	std::fstream file;
 	LOGI("Exporting skeleton %s", name.c_str());
 
+	// Find the root bone
+	unsigned minDepth = 0xFFFFFFFF;
+	std::string rootBoneName;
+	for(uint32_t i = 0; i < mesh.mNumBones; i++)
+	{
+		const aiBone& bone = *mesh.mBones[i];
+		unsigned depth = 0;
+		const aiNode* node = findNodeWithName(bone.mName.C_Str(), m_scene->mRootNode, &depth);
+		if(!node)
+		{
+			ERROR("Bone \"%s\" was not found in the scene hierarchy", bone.mName.C_Str());
+		}
+
+		if(depth < minDepth)
+		{
+			minDepth = depth;
+			rootBoneName = bone.mName.C_Str();
+		}
+	}
+	assert(!rootBoneName.empty());
+
 	// Open file
-	file.open(m_outputDirectory + name + ".skel", std::ios::out);
+	file.open(m_outputDirectory + name + ".ankiskel", std::ios::out);
 
 	file << XML_HEADER << "\n";
 	file << "<skeleton>\n";
 	file << "\t<bones>\n";
 
-	bool rootBoneFound = false;
-
 	for(uint32_t i = 0; i < mesh.mNumBones; i++)
 	{
 		const aiBone& bone = *mesh.mBones[i];
@@ -316,25 +340,29 @@ void Exporter::exportSkeleton(const aiMesh& mesh) const
 		// <name>
 		file << "\t\t\t<name>" << bone.mName.C_Str() << "</name>\n";
 
-		if(strcmp(bone.mName.C_Str(), "root") == 0)
-		{
-			rootBoneFound = true;
-		}
-
 		// <transform>
+		aiMatrix4x4 akMat = toAnkiMatrix(bone.mOffsetMatrix);
 		file << "\t\t\t<transform>";
-		for(uint32_t j = 0; j < 16; j++)
+		for(unsigned j = 0; j < 4; j++)
 		{
-			file << bone.mOffsetMatrix[j] << " ";
+			for(unsigned i = 0; i < 4; i++)
+			{
+				file << akMat[j][i] << " ";
+			}
 		}
 		file << "</transform>\n";
 
-		file << "\t\t</bone>\n";
-	}
+		// <parent>
+		// Need to find the bone in the scene hierarchy
+		const aiNode* node = findNodeWithName(bone.mName.C_Str(), m_scene->mRootNode);
+		assert(node);
 
-	if(!rootBoneFound)
-	{
-		ERROR("There should be one bone named \"root\"");
+		if(bone.mName.C_Str() != rootBoneName)
+		{
+			file << "\t\t\t<parent>" << node->mParent->mName.C_Str() << "</parent>\n";
+		}
+
+		file << "\t\t</bone>\n";
 	}
 
 	file << "\t</bones>\n";
@@ -395,6 +423,14 @@ void Exporter::exportModel(const Model& model) const
 	file << "\t\t</modelPatch>\n";
 	file << "\t</modelPatches>\n";
 
+	// Skeleton
+	const aiMesh& aimesh = *m_scene->mMeshes[model.m_meshIndex];
+	if(aimesh.HasBones())
+	{
+		exportSkeleton(aimesh);
+		file << "\t<skeleton>" << m_rpath << aimesh.mName.C_Str() << ".ankiskel</skeleton>\n";
+	}
+
 	file << "</model>\n";
 }