complete animation

pull/2/head
ink-soul 2023-05-18 11:49:09 +08:00
parent 3532369f08
commit c08f144680
3 changed files with 137 additions and 90 deletions

View File

@ -149,4 +149,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/")
add_subdirectory(base)
add_subdirectory(homework)
# add_subdirectory(examples)

View File

@ -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
*/
@ -457,6 +459,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)
{
if (node->skin > -1)
@ -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);
}
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);
}
}

View File

@ -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);
};