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