diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..7313f2b --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,27 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + }, + { + "name": "x64-Clang-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "clang_cl_x64_x64" ], + "variables": [] + } + ] +} \ No newline at end of file diff --git a/homework/homework1/homework1.cpp b/homework/homework1/homework1.cpp index ccae6cd..cc23f34 100644 --- a/homework/homework1/homework1.cpp +++ b/homework/homework1/homework1.cpp @@ -157,26 +157,26 @@ VulkanglTFModel::~VulkanglTFModel() tinygltf::Animation glTFAnimation = input.animations[i]; animations[i].name = glTFAnimation.name; + // Samplers animations[i].samplers.resize(glTFAnimation.samplers.size()); for (size_t j = 0; j < glTFAnimation.samplers.size(); j++) { tinygltf::AnimationSampler glTFSampler = glTFAnimation.samplers[j]; AnimationSampler& dstSampler = animations[i].samplers[j]; dstSampler.interpolation = glTFSampler.interpolation; - //sample keyframes to input + + // Read sampler keyframe input time values { const tinygltf::Accessor& accessor = input.accessors[glTFSampler.input]; const tinygltf::BufferView& bufferView = input.bufferViews[accessor.bufferView]; const tinygltf::Buffer& buffer = input.buffers[bufferView.buffer]; - //data pointer - const void* dataptr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; - const float* buf = static_cast(dataptr); - + const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; + const float* buf = static_cast(dataPtr); for (size_t index = 0; index < accessor.count; index++) { dstSampler.inputs.push_back(buf[index]); } - //switch value for correct start and end time + // Adjust animation's start and end times for (auto input : animations[i].samplers[j].inputs) { if (input < animations[i].start) @@ -189,43 +189,40 @@ VulkanglTFModel::~VulkanglTFModel() } } } - //identify accessor type for keyframes to output translate/rotate/scale values + + // Read sampler keyframe output translate/rotate/scale values { - const tinygltf::Accessor& accessor = input.accessors[glTFSampler.input]; + const tinygltf::Accessor& accessor = input.accessors[glTFSampler.output]; const tinygltf::BufferView& bufferView = input.bufferViews[accessor.bufferView]; const tinygltf::Buffer& buffer = input.buffers[bufferView.buffer]; - //data pointer - const void* dataptr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; - + const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; switch (accessor.type) { - case TINYGLTF_TYPE_VEC3: - { - const glm::vec3* buf = static_cast (dataptr); + case TINYGLTF_TYPE_VEC3: { + const glm::vec3* buf = static_cast(dataPtr); for (size_t index = 0; index < accessor.count; index++) { dstSampler.outputsVec4.push_back(glm::vec4(buf[index], 0.0f)); - } break; } - case TINYGLTF_TYPE_VEC4: - { - const glm::vec4* buf = static_cast(dataptr); + case TINYGLTF_TYPE_VEC4: { + const glm::vec4* buf = static_cast(dataPtr); for (size_t index = 0; index < accessor.count; index++) { dstSampler.outputsVec4.push_back(buf[index]); } break; } - default: - { - std::cout << "unknown type in accessor" << std::endl; + default: { + std::cout << "unknown type" << std::endl; + break; } - break; } } } + + // Channels animations[i].channels.resize(glTFAnimation.channels.size()); for (size_t j = 0; j < glTFAnimation.channels.size(); j++) { @@ -235,7 +232,6 @@ VulkanglTFModel::~VulkanglTFModel() dstChannel.samplerIndex = glTFChannel.sampler; dstChannel.node = nodeFromIndex(glTFChannel.target_node); } - } @@ -273,7 +269,7 @@ VulkanglTFModel::~VulkanglTFModel() { for (size_t i = 0; i < inputNode.children.size(); i++) { - VulkanglTFModel::loadNode(input.nodes[inputNode.children[i]], input, node, inputNode.children[i], indexBuffer, vertexBuffer); + loadNode(input.nodes[inputNode.children[i]], input, node, inputNode.children[i], indexBuffer, vertexBuffer); } } @@ -484,9 +480,9 @@ VulkanglTFModel::~VulkanglTFModel() void VulkanglTFModel::updateAnimation(float deltaTime) { - if (activeAnimation > static_cast(animations.size())-1) + if (activeAnimation > static_cast(animations.size()) - 1) { - std::cout << "no animation with index" << activeAnimation << std::endl; + std::cout << "No animation with index " << activeAnimation << std::endl; return; } Animation& animation = animations[activeAnimation]; @@ -495,17 +491,19 @@ VulkanglTFModel::~VulkanglTFModel() { animation.currentTime -= animation.end; } + for (auto& channel : animation.channels) { - AnimationSampler& sampler = animation.samplers[channel.samplerIndex]; for (size_t i = 0; i < sampler.inputs.size() - 1; i++) { if (sampler.interpolation != "LINEAR") { - std::cout << "sample only supports linear interpolaton" << std::endl; + std::cout << "This sample only supports linear interpolations\n"; continue; } + + // 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]); @@ -515,7 +513,6 @@ VulkanglTFModel::~VulkanglTFModel() } if (channel.path == "rotation") { - //quaternion glm::quat q1; q1.x = sampler.outputsVec4[i].x; q1.y = sampler.outputsVec4[i].y; @@ -523,13 +520,12 @@ VulkanglTFModel::~VulkanglTFModel() q1.w = sampler.outputsVec4[i].w; glm::quat q2; - q2.x = sampler.outputsVec4[i].x; - q2.y = sampler.outputsVec4[i].y; - q2.z = sampler.outputsVec4[i].z; - q2.w = sampler.outputsVec4[i].w; + q2.x = sampler.outputsVec4[i + 1].x; + q2.y = sampler.outputsVec4[i + 1].y; + q2.z = sampler.outputsVec4[i + 1].z; + q2.w = sampler.outputsVec4[i + 1].w; channel.node->rotation = glm::normalize(glm::slerp(q1, q2, a)); - } if (channel.path == "scale") { @@ -563,8 +559,7 @@ 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); - //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) { @@ -806,15 +801,14 @@ void VulkanExample::getEnabledFeatures() */ std::vector poolSizes = { - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), - // One combined image sampler per model image/texture - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast(glTFModel.images.size())), - //initialize descriptor pool size for skin - vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,static_cast(glTFModel.skins.size())), + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + // One combined image sampler per material image/texture + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast(glTFModel.images.size())), + // One ssbo per skin + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, static_cast(glTFModel.skins.size())), }; - - // One set for matrices and one per model image/texture - const uint32_t maxSetCount = static_cast(glTFModel.images.size()) + static_cast(glTFModel.skins.size())+1; + // Number of descriptor sets = One for the scene ubo + one per image + one per skin + const uint32_t maxSetCount = static_cast(glTFModel.images.size()) + static_cast(glTFModel.skins.size()) + 1; VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, maxSetCount); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); @@ -830,22 +824,22 @@ void VulkanExample::getEnabledFeatures() setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.textures)); - //Descriptor set layout for passing skin joint matrices + // Descriptor set layout for passing skin joint matrices setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.jointMatrices)); - // Pipeline layout using three descriptor sets (set 0 = matrices, set 1 = joint matrices, set 3 = material) - std::array setLayouts = - { + // The pipeline layout uses three sets: + // Set 0 = Scene matrices (VS) + // Set 1 = Joint matrices (VS) + // Set 2 = Material texture (FS) + std::array setLayouts = { descriptorSetLayouts.matrices, descriptorSetLayouts.jointMatrices, - descriptorSetLayouts.textures - }; - VkPipelineLayoutCreateInfo pipelineLayoutCI= vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); + descriptorSetLayouts.textures }; + VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); // We will use push constants to push the local matrices of a primitive to the vertex shader VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), 0); - // Push constant ranges are part of the pipeline layout pipelineLayoutCI.pushConstantRangeCount = 1; pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; @@ -857,7 +851,7 @@ void VulkanExample::getEnabledFeatures() VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &shaderData.buffer.descriptor); vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - //Descriptor sets for skin joint matrices + // Descriptor set for glTF model skin joint matrices for (auto& skin : glTFModel.skins) { const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.jointMatrices, 1); @@ -866,14 +860,14 @@ void VulkanExample::getEnabledFeatures() vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } - // Descriptor sets for materials - for (auto& image : glTFModel.images) { + // Descriptor sets for glTF model materials + for (auto& image : glTFModel.images) + { const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &image.descriptorSet)); VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(image.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &image.texture.descriptor); vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } - } @@ -893,13 +887,13 @@ void VulkanExample::getEnabledFeatures() vks::initializers::vertexInputBindingDescription(0, sizeof(VulkanglTFModel::Vertex), VK_VERTEX_INPUT_RATE_VERTEX), }; const std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, pos)), // Location 0: Position - vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, normal)),// Location 1: Normal - vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, uv)), // Location 2: Texture coordinates - vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, color)), // Location 3: Color - vks::initializers::vertexInputAttributeDescription(0, 4, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex,jointIndices)), // Location 4 : jointIndices - vks::initializers::vertexInputAttributeDescription(0, 5, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex,jointWeights)), //Location 5 : jointWeights - + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, pos)}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, normal)}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, uv)}, + {3, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(VulkanglTFModel::Vertex, color)}, + // POI: Per-Vertex Joint indices and weights are passed to the vertex shader + {4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(VulkanglTFModel::Vertex, jointIndices)}, + {5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(VulkanglTFModel::Vertex, jointWeights)}, }; VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks::initializers::pipelineVertexInputStateCreateInfo(); vertexInputStateCI.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size());