complete animation
							parent
							
								
									3532369f08
								
							
						
					
					
						commit
						c08f144680
					
				| 
						 | 
				
			
			@ -149,4 +149,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/")
 | 
			
		|||
 | 
			
		||||
add_subdirectory(base)
 | 
			
		||||
add_subdirectory(homework)
 | 
			
		||||
 | 
			
		||||
# add_subdirectory(examples)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,10 +20,6 @@
 | 
			
		|||
 | 
			
		||||
#include "homework1.h"
 | 
			
		||||
 | 
			
		||||
glm::mat4 VulkanglTFModel::Node::getLocalMatrix()
 | 
			
		||||
{
 | 
			
		||||
	return glm::translate(glm::mat4(1.0f), translation) * glm::mat4(rotation) * glm::scale(glm::mat4(1.0f), scale) * matrix;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VulkanglTFModel::~VulkanglTFModel()
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -113,39 +109,7 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	//glTF nodes loading helper function
 | 
			
		||||
	//rewrite node loader,simplify logic
 | 
			
		||||
	//Search node from parent to children by index
 | 
			
		||||
	VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index)
 | 
			
		||||
	{
 | 
			
		||||
		Node* nodeFound = nullptr;
 | 
			
		||||
		if (parent->index == index)
 | 
			
		||||
		{
 | 
			
		||||
			return parent;
 | 
			
		||||
		}
 | 
			
		||||
		for (auto &child : parent->children)
 | 
			
		||||
		{
 | 
			
		||||
			nodeFound = findNode(child, index);
 | 
			
		||||
			if (nodeFound)
 | 
			
		||||
			{
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nodeFound;
 | 
			
		||||
}	//iterate vector of nodes to check weather nodes exist or not
 | 
			
		||||
	VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index)
 | 
			
		||||
	{
 | 
			
		||||
		Node* nodeFound = nullptr;
 | 
			
		||||
		for (auto& node : nodes)
 | 
			
		||||
		{
 | 
			
		||||
			nodeFound = findNode(node, index);
 | 
			
		||||
			if (nodeFound)
 | 
			
		||||
			{
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nodeFound;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	//animation loader
 | 
			
		||||
	void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
 | 
			
		||||
| 
						 | 
				
			
			@ -236,6 +200,86 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// load skins from glTF model
 | 
			
		||||
	void VulkanglTFModel::loadSkins(tinygltf::Model& input)
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		skins.resize(input.skins.size());
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < input.skins.size(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			tinygltf::Skin glTFSkin = input.skins[i];
 | 
			
		||||
 | 
			
		||||
			skins[i].name = glTFSkin.name;
 | 
			
		||||
			//follow the tree structure,find the root node of skeleton by index
 | 
			
		||||
			skins[i].skeletonRoot = nodeFromIndex(glTFSkin.skeleton);
 | 
			
		||||
 | 
			
		||||
			//join nodes
 | 
			
		||||
			for (int jointIndex : glTFSkin.joints)
 | 
			
		||||
			{
 | 
			
		||||
				Node* node = nodeFromIndex(jointIndex);
 | 
			
		||||
				if (node)
 | 
			
		||||
				{
 | 
			
		||||
					skins[i].joints.push_back(node);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			//get the inverse bind matrices
 | 
			
		||||
			if (glTFSkin.inverseBindMatrices > -1)
 | 
			
		||||
			{
 | 
			
		||||
				const tinygltf::Accessor& accessor = input.accessors[glTFSkin.inverseBindMatrices];
 | 
			
		||||
				const tinygltf::BufferView& bufferview = input.bufferViews[accessor.bufferView];
 | 
			
		||||
				const tinygltf::Buffer& buffer = input.buffers[bufferview.buffer];
 | 
			
		||||
				skins[i].inverseBindMatrices.resize(accessor.count);
 | 
			
		||||
				memcpy(skins[i].inverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferview.byteOffset], accessor.count * sizeof(glm::mat4));
 | 
			
		||||
 | 
			
		||||
				//create a host visible shader buffer to store inverse bind matrices for this skin
 | 
			
		||||
				VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 | 
			
		||||
					&skins[i].ssbo,
 | 
			
		||||
					sizeof(glm::mat4) * skins[i].inverseBindMatrices.size(),
 | 
			
		||||
					skins[i].inverseBindMatrices.data()));
 | 
			
		||||
				VK_CHECK_RESULT(skins[i].ssbo.map());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//glTF nodes loading helper function
 | 
			
		||||
	//rewrite node loader,simplify logic
 | 
			
		||||
	//Search node from parent to children by index
 | 
			
		||||
	VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index)
 | 
			
		||||
	{
 | 
			
		||||
		Node* nodeFound = nullptr;
 | 
			
		||||
		if (parent->index == index)
 | 
			
		||||
		{
 | 
			
		||||
			return parent;
 | 
			
		||||
		}
 | 
			
		||||
		for (auto& child : parent->children)
 | 
			
		||||
		{
 | 
			
		||||
			nodeFound = findNode(child, index);
 | 
			
		||||
			if (nodeFound)
 | 
			
		||||
			{
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nodeFound;
 | 
			
		||||
	}	//iterate vector of nodes to check weather nodes exist or not
 | 
			
		||||
	VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index)
 | 
			
		||||
	{
 | 
			
		||||
		Node* nodeFound = nullptr;
 | 
			
		||||
		for (auto& node : nodes)
 | 
			
		||||
		{
 | 
			
		||||
			nodeFound = findNode(node, index);
 | 
			
		||||
			if (nodeFound)
 | 
			
		||||
			{
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nodeFound;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	//node loader
 | 
			
		||||
	void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFModel::Node* parent, uint32_t nodeIndex, std::vector<uint32_t>& indexBuffer, std::vector<VulkanglTFModel::Vertex>& vertexBuffer)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -399,49 +443,7 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// load skins from glTF model
 | 
			
		||||
	void VulkanglTFModel::loadSkins(tinygltf::Model& input)
 | 
			
		||||
	{
 | 
			
		||||
		skins.resize(input.skins.size());
 | 
			
		||||
		std::cout << input.skins.size() << std::endl;
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < input.skins.size(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			tinygltf::Skin glTFSkin = input.skins[i];
 | 
			
		||||
 | 
			
		||||
			skins[i].name = glTFSkin.name;
 | 
			
		||||
			//follow the tree structure,find the root node of skeleton by index
 | 
			
		||||
			skins[i].skeletonRoot = nodeFromIndex(glTFSkin.skeleton);
 | 
			
		||||
 | 
			
		||||
			//join nodes
 | 
			
		||||
			for (int jointIndex : glTFSkin.joints)
 | 
			
		||||
			{
 | 
			
		||||
				Node* node = nodeFromIndex(jointIndex);
 | 
			
		||||
				if (node)
 | 
			
		||||
				{
 | 
			
		||||
					skins[i].joints.push_back(node);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			//get the inverse bind matrices
 | 
			
		||||
			if (glTFSkin.inverseBindMatrices > -1)
 | 
			
		||||
			{
 | 
			
		||||
				const tinygltf::Accessor& accessor = input.accessors[glTFSkin.inverseBindMatrices];
 | 
			
		||||
				const tinygltf::BufferView& bufferview = input.bufferViews[accessor.bufferView];
 | 
			
		||||
				const tinygltf::Buffer& buffer = input.buffers[bufferview.buffer];
 | 
			
		||||
				skins[i].inverseBindMatrices.resize(accessor.count);
 | 
			
		||||
				memcpy(skins[i].inverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferview.byteOffset], accessor.count * sizeof(glm::mat4));
 | 
			
		||||
 | 
			
		||||
				//create a host visible shader buffer to store inverse bind matrices for this skin
 | 
			
		||||
				VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 | 
			
		||||
					&skins[i].ssbo,
 | 
			
		||||
					sizeof(glm::mat4) * skins[i].inverseBindMatrices.size(),
 | 
			
		||||
					skins[i].inverseBindMatrices.data()));
 | 
			
		||||
				VK_CHECK_RESULT(skins[i].ssbo.map());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
		vertex skinning functions
 | 
			
		||||
	*/
 | 
			
		||||
| 
						 | 
				
			
			@ -456,6 +458,19 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
		}
 | 
			
		||||
		return nodeMatrix;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void VulkanglTFModel::updateNodeMatrix(Node* node, std::vector<glm::mat4>& nodeMatrics)
 | 
			
		||||
	{
 | 
			
		||||
		if (node->skin <= -1)
 | 
			
		||||
		{
 | 
			
		||||
			nodeMatrics[node->index] = getNodeMatrix(node);
 | 
			
		||||
			for (auto& child : node->children)
 | 
			
		||||
			{
 | 
			
		||||
			updateNodeMatrix(child, nodeMatrics);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -478,7 +493,7 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void VulkanglTFModel::updateAnimation(float deltaTime)
 | 
			
		||||
	void VulkanglTFModel::updateAnimation(float deltaTime,vks::Buffer buffer)
 | 
			
		||||
	{
 | 
			
		||||
		if (activeAnimation > static_cast<uint32_t>(animations.size()) - 1)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -495,7 +510,7 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
		for (auto& channel : animation.channels)
 | 
			
		||||
		{
 | 
			
		||||
			AnimationSampler& sampler = animation.samplers[channel.samplerIndex];
 | 
			
		||||
			for (size_t i = 0; i < sampler.inputs.size() - 1; i++)
 | 
			
		||||
			for (size_t i = 0; i < sampler.inputs.size() - 1; ++i)
 | 
			
		||||
			{
 | 
			
		||||
				if (sampler.interpolation != "LINEAR")
 | 
			
		||||
				{
 | 
			
		||||
| 
						 | 
				
			
			@ -506,10 +521,10 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
				// Get the input keyframe values for the current time stamp
 | 
			
		||||
				if ((animation.currentTime >= sampler.inputs[i]) && (animation.currentTime <= sampler.inputs[i + 1]))
 | 
			
		||||
				{
 | 
			
		||||
					float a = (animation.currentTime - sampler.inputs[i]) / (sampler.inputs[i + 1] - sampler.inputs[i]);
 | 
			
		||||
					float ratio = (animation.currentTime - sampler.inputs[i]) / (sampler.inputs[i + 1] - sampler.inputs[i]);
 | 
			
		||||
					if (channel.path == "translation")
 | 
			
		||||
					{
 | 
			
		||||
						channel.node->translation = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], a);
 | 
			
		||||
						channel.node->translation = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], ratio);
 | 
			
		||||
					}
 | 
			
		||||
					if (channel.path == "rotation")
 | 
			
		||||
					{
 | 
			
		||||
| 
						 | 
				
			
			@ -525,19 +540,25 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
						q2.z = sampler.outputsVec4[i + 1].z;
 | 
			
		||||
						q2.w = sampler.outputsVec4[i + 1].w;
 | 
			
		||||
 | 
			
		||||
						channel.node->rotation = glm::normalize(glm::slerp(q1, q2, a));
 | 
			
		||||
						channel.node->rotation = glm::normalize(glm::slerp(q1, q2, ratio));
 | 
			
		||||
						channel.node->bAnimateNode = true;
 | 
			
		||||
					}
 | 
			
		||||
					if (channel.path == "scale")
 | 
			
		||||
					{
 | 
			
		||||
						channel.node->scale = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], a);
 | 
			
		||||
						channel.node->scale = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], ratio);
 | 
			
		||||
						channel.node->bAnimateNode = true;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		//if no skin in model , update node matrix to update animation stage
 | 
			
		||||
		std::vector<glm::mat4> nodeMatrics(nodeCount);
 | 
			
		||||
		for (auto& node : nodes)
 | 
			
		||||
		{
 | 
			
		||||
			updateJoints(node);
 | 
			
		||||
			updateNodeMatrix(node, nodeMatrics);
 | 
			
		||||
		}
 | 
			
		||||
		buffer.copyTo(nodeMatrics.data(), nodeCount * sizeof(glm::mat4));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -558,8 +579,11 @@ VulkanglTFModel::~VulkanglTFModel()
 | 
			
		|||
			}
 | 
			
		||||
			// Pass the final matrix to the vertex shader using push constants
 | 
			
		||||
			vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &nodeMatrix);
 | 
			
		||||
			if (skins.size() != 0)
 | 
			
		||||
			{
 | 
			
		||||
				vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &skins[node.skin].descriptorSet, 0, nullptr);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &skins[node.skin].descriptorSet, 0, nullptr);
 | 
			
		||||
			
 | 
			
		||||
 | 
			
		||||
			for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) {
 | 
			
		||||
| 
						 | 
				
			
			@ -693,6 +717,7 @@ void VulkanExample::getEnabledFeatures()
 | 
			
		|||
 | 
			
		||||
		if (fileLoaded) 
 | 
			
		||||
		{
 | 
			
		||||
			glTFModel.nodeCount = static_cast<uint32_t>(glTFInput.nodes.size());
 | 
			
		||||
			glTFModel.loadImages(glTFInput);
 | 
			
		||||
			glTFModel.loadMaterials(glTFInput);
 | 
			
		||||
			glTFModel.loadTextures(glTFInput);
 | 
			
		||||
| 
						 | 
				
			
			@ -791,7 +816,7 @@ void VulkanExample::getEnabledFeatures()
 | 
			
		|||
 | 
			
		||||
	void VulkanExample::loadAssets()
 | 
			
		||||
	{
 | 
			
		||||
		loadglTFFile(getAssetPath() + "models/CesiumMan/glTF/CesiumMan.gltf");
 | 
			
		||||
		loadglTFFile(getAssetPath() + "buster_drone/busterDrone.gltf");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void VulkanExample::setupDescriptors()
 | 
			
		||||
| 
						 | 
				
			
			@ -972,7 +997,7 @@ void VulkanExample::getEnabledFeatures()
 | 
			
		|||
		}
 | 
			
		||||
		if (!paused)
 | 
			
		||||
		{
 | 
			
		||||
			glTFModel.updateAnimation(frameTimer);
 | 
			
		||||
			glTFModel.updateAnimation(frameTimer,shaderData.buffer);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -988,6 +1013,10 @@ void VulkanExample::getEnabledFeatures()
 | 
			
		|||
				buildCommandBuffers();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (overlay->header("Animation"))
 | 
			
		||||
		{
 | 
			
		||||
			overlay->checkBox("pause", &paused);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,7 @@ public:
 | 
			
		|||
	// The class requires some Vulkan objects so it can create it's own resources
 | 
			
		||||
	vks::VulkanDevice* vulkanDevice;
 | 
			
		||||
	VkQueue copyQueue;
 | 
			
		||||
	uint32_t nodeCount;
 | 
			
		||||
 | 
			
		||||
	// The vertex layout for the samples' model
 | 
			
		||||
	struct Vertex {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +84,22 @@ public:
 | 
			
		|||
		glm::vec3 scale{ 1.0f };
 | 
			
		||||
		glm::quat rotation{};
 | 
			
		||||
		int32_t             skin = -1;
 | 
			
		||||
		glm::mat4 getLocalMatrix();
 | 
			
		||||
		glm::mat4 getLocalMatrix()
 | 
			
		||||
		{
 | 
			
		||||
			return bAnimateNode ? glm::translate(glm::mat4(1.0f), translation) * glm::mat4(rotation) * glm::scale(glm::mat4(1.0f), scale) : matrix;
 | 
			
		||||
		}
 | 
			
		||||
		glm::mat4 matrix;
 | 
			
		||||
		bool bAnimateNode = false;
 | 
			
		||||
		/*
 | 
			
		||||
		~Node() {
 | 
			
		||||
			for (auto& child : children) {
 | 
			
		||||
				delete child;
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		*/
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +131,7 @@ public:
 | 
			
		|||
		std::vector<Node*> joints;
 | 
			
		||||
		vks::Buffer ssbo;
 | 
			
		||||
		VkDescriptorSet descriptorSet;
 | 
			
		||||
		
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct AnimationSampler
 | 
			
		||||
| 
						 | 
				
			
			@ -170,8 +186,9 @@ public:
 | 
			
		|||
	void      loadAnimations(tinygltf::Model& input);
 | 
			
		||||
	void      loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFModel::Node* parent, uint32_t nodeIndex, std::vector<uint32_t>& indexBuffer, std::vector<VulkanglTFModel::Vertex>& vertexBuffer);
 | 
			
		||||
	glm::mat4 getNodeMatrix(VulkanglTFModel::Node* node);
 | 
			
		||||
	void updateNodeMatrix(Node* node, std::vector<glm::mat4>& nodeMatrics);
 | 
			
		||||
	void      updateJoints(VulkanglTFModel::Node* node);
 | 
			
		||||
	void      updateAnimation(float deltaTime);
 | 
			
		||||
	void      updateAnimation(float deltaTime,vks::Buffer buffer);
 | 
			
		||||
	void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node);
 | 
			
		||||
	void      draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue