diff --git a/CMakeLists.txt b/CMakeLists.txt index f78ddd2..751a347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,4 +149,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/") add_subdirectory(base) add_subdirectory(homework) + # add_subdirectory(examples) diff --git a/homework/homework1/homework1.cpp b/homework/homework1/homework1.cpp index cc23f34..498f666 100644 --- a/homework/homework1/homework1.cpp +++ b/homework/homework1/homework1.cpp @@ -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& indexBuffer, std::vector& 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& 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(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 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(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); + } } diff --git a/homework/homework1/homework1.h b/homework/homework1/homework1.h index ff53750..a4b30be 100644 --- a/homework/homework1/homework1.h +++ b/homework/homework1/homework1.h @@ -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 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& indexBuffer, std::vector& vertexBuffer); glm::mat4 getNodeMatrix(VulkanglTFModel::Node* node); + void updateNodeMatrix(Node* node, std::vector& 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); };