complete animation
parent
3532369f08
commit
c08f144680
|
@ -149,4 +149,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/")
|
||||||
|
|
||||||
add_subdirectory(base)
|
add_subdirectory(base)
|
||||||
add_subdirectory(homework)
|
add_subdirectory(homework)
|
||||||
|
|
||||||
# add_subdirectory(examples)
|
# add_subdirectory(examples)
|
||||||
|
|
|
@ -20,10 +20,6 @@
|
||||||
|
|
||||||
#include "homework1.h"
|
#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()
|
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
|
//animation loader
|
||||||
void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
|
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
|
//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)
|
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
|
vertex skinning functions
|
||||||
*/
|
*/
|
||||||
|
@ -456,6 +458,19 @@ VulkanglTFModel::~VulkanglTFModel()
|
||||||
}
|
}
|
||||||
return nodeMatrix;
|
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)
|
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)
|
if (activeAnimation > static_cast<uint32_t>(animations.size()) - 1)
|
||||||
{
|
{
|
||||||
|
@ -495,7 +510,7 @@ VulkanglTFModel::~VulkanglTFModel()
|
||||||
for (auto& channel : animation.channels)
|
for (auto& channel : animation.channels)
|
||||||
{
|
{
|
||||||
AnimationSampler& sampler = animation.samplers[channel.samplerIndex];
|
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")
|
if (sampler.interpolation != "LINEAR")
|
||||||
{
|
{
|
||||||
|
@ -506,10 +521,10 @@ VulkanglTFModel::~VulkanglTFModel()
|
||||||
// Get the input keyframe values for the current time stamp
|
// Get the input keyframe values for the current time stamp
|
||||||
if ((animation.currentTime >= sampler.inputs[i]) && (animation.currentTime <= sampler.inputs[i + 1]))
|
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")
|
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")
|
if (channel.path == "rotation")
|
||||||
{
|
{
|
||||||
|
@ -525,19 +540,25 @@ VulkanglTFModel::~VulkanglTFModel()
|
||||||
q2.z = sampler.outputsVec4[i + 1].z;
|
q2.z = sampler.outputsVec4[i + 1].z;
|
||||||
q2.w = sampler.outputsVec4[i + 1].w;
|
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")
|
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)
|
for (auto& node : nodes)
|
||||||
{
|
{
|
||||||
updateJoints(node);
|
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
|
// Pass the final matrix to the vertex shader using push constants
|
||||||
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &nodeMatrix);
|
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) {
|
for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) {
|
||||||
|
@ -693,6 +717,7 @@ void VulkanExample::getEnabledFeatures()
|
||||||
|
|
||||||
if (fileLoaded)
|
if (fileLoaded)
|
||||||
{
|
{
|
||||||
|
glTFModel.nodeCount = static_cast<uint32_t>(glTFInput.nodes.size());
|
||||||
glTFModel.loadImages(glTFInput);
|
glTFModel.loadImages(glTFInput);
|
||||||
glTFModel.loadMaterials(glTFInput);
|
glTFModel.loadMaterials(glTFInput);
|
||||||
glTFModel.loadTextures(glTFInput);
|
glTFModel.loadTextures(glTFInput);
|
||||||
|
@ -791,7 +816,7 @@ void VulkanExample::getEnabledFeatures()
|
||||||
|
|
||||||
void VulkanExample::loadAssets()
|
void VulkanExample::loadAssets()
|
||||||
{
|
{
|
||||||
loadglTFFile(getAssetPath() + "models/CesiumMan/glTF/CesiumMan.gltf");
|
loadglTFFile(getAssetPath() + "buster_drone/busterDrone.gltf");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanExample::setupDescriptors()
|
void VulkanExample::setupDescriptors()
|
||||||
|
@ -972,7 +997,7 @@ void VulkanExample::getEnabledFeatures()
|
||||||
}
|
}
|
||||||
if (!paused)
|
if (!paused)
|
||||||
{
|
{
|
||||||
glTFModel.updateAnimation(frameTimer);
|
glTFModel.updateAnimation(frameTimer,shaderData.buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,6 +1013,10 @@ void VulkanExample::getEnabledFeatures()
|
||||||
buildCommandBuffers();
|
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
|
// The class requires some Vulkan objects so it can create it's own resources
|
||||||
vks::VulkanDevice* vulkanDevice;
|
vks::VulkanDevice* vulkanDevice;
|
||||||
VkQueue copyQueue;
|
VkQueue copyQueue;
|
||||||
|
uint32_t nodeCount;
|
||||||
|
|
||||||
// The vertex layout for the samples' model
|
// The vertex layout for the samples' model
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
|
@ -83,8 +84,22 @@ public:
|
||||||
glm::vec3 scale{ 1.0f };
|
glm::vec3 scale{ 1.0f };
|
||||||
glm::quat rotation{};
|
glm::quat rotation{};
|
||||||
int32_t skin = -1;
|
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;
|
glm::mat4 matrix;
|
||||||
|
bool bAnimateNode = false;
|
||||||
|
/*
|
||||||
|
~Node() {
|
||||||
|
for (auto& child : children) {
|
||||||
|
delete child;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,6 +131,7 @@ public:
|
||||||
std::vector<Node*> joints;
|
std::vector<Node*> joints;
|
||||||
vks::Buffer ssbo;
|
vks::Buffer ssbo;
|
||||||
VkDescriptorSet descriptorSet;
|
VkDescriptorSet descriptorSet;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AnimationSampler
|
struct AnimationSampler
|
||||||
|
@ -170,8 +186,9 @@ public:
|
||||||
void loadAnimations(tinygltf::Model& input);
|
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);
|
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);
|
glm::mat4 getNodeMatrix(VulkanglTFModel::Node* node);
|
||||||
|
void updateNodeMatrix(Node* node, std::vector<glm::mat4>& nodeMatrics);
|
||||||
void updateJoints(VulkanglTFModel::Node* node);
|
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 drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node);
|
||||||
void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout);
|
void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue