clang format

This commit is contained in:
Sascha Willems 2020-06-06 11:05:56 +02:00
parent a1afaf3de5
commit 9e96aeaa5f
2 changed files with 521 additions and 421 deletions

View file

@ -30,7 +30,8 @@
Get a node's local matrix from the current translation, rotation and scale values Get a node's local matrix from the current translation, rotation and scale values
These are calculated from the current animation an need to be calculated dynamically These are calculated from the current animation an need to be calculated dynamically
*/ */
glm::mat4 VulkanglTFModel::Node::getLocalMatrix() { glm::mat4 VulkanglTFModel::Node::getLocalMatrix()
{
return glm::translate(glm::mat4(1.0f), translation) * glm::mat4(rotation) * glm::scale(glm::mat4(1.0f), scale) * matrix; return glm::translate(glm::mat4(1.0f), translation) * glm::mat4(rotation) * glm::scale(glm::mat4(1.0f), scale) * matrix;
} }
@ -43,7 +44,8 @@ VulkanglTFModel::~VulkanglTFModel()
vkFreeMemory(vulkanDevice->logicalDevice, vertices.memory, nullptr); vkFreeMemory(vulkanDevice->logicalDevice, vertices.memory, nullptr);
vkDestroyBuffer(vulkanDevice->logicalDevice, indices.buffer, nullptr); vkDestroyBuffer(vulkanDevice->logicalDevice, indices.buffer, nullptr);
vkFreeMemory(vulkanDevice->logicalDevice, indices.memory, nullptr); vkFreeMemory(vulkanDevice->logicalDevice, indices.memory, nullptr);
for (Image image : images) { for (Image image : images)
{
vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr); vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr);
vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr); vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr);
vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr); vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr);
@ -62,32 +64,37 @@ void VulkanglTFModel::loadImages(tinygltf::Model& input)
// Images can be stored inside the glTF (which is the case for the sample model), so instead of directly // Images can be stored inside the glTF (which is the case for the sample model), so instead of directly
// loading them from disk, we fetch them from the glTF loader and upload the buffers // loading them from disk, we fetch them from the glTF loader and upload the buffers
images.resize(input.images.size()); images.resize(input.images.size());
for (size_t i = 0; i < input.images.size(); i++) { for (size_t i = 0; i < input.images.size(); i++)
{
tinygltf::Image &glTFImage = input.images[i]; tinygltf::Image &glTFImage = input.images[i];
// Get the image data from the glTF loader // Get the image data from the glTF loader
unsigned char *buffer = nullptr; unsigned char *buffer = nullptr;
VkDeviceSize bufferSize = 0; VkDeviceSize bufferSize = 0;
bool deleteBuffer = false; bool deleteBuffer = false;
// We convert RGB-only images to RGBA, as most devices don't support RGB-formats in Vulkan // We convert RGB-only images to RGBA, as most devices don't support RGB-formats in Vulkan
if (glTFImage.component == 3) { if (glTFImage.component == 3)
{
bufferSize = glTFImage.width * glTFImage.height * 4; bufferSize = glTFImage.width * glTFImage.height * 4;
buffer = new unsigned char[bufferSize]; buffer = new unsigned char[bufferSize];
unsigned char *rgba = buffer; unsigned char *rgba = buffer;
unsigned char *rgb = &glTFImage.image[0]; unsigned char *rgb = &glTFImage.image[0];
for (size_t i = 0; i < glTFImage.width * glTFImage.height; ++i) { for (size_t i = 0; i < glTFImage.width * glTFImage.height; ++i)
{
memcpy(rgba, rgb, sizeof(unsigned char) * 3); memcpy(rgba, rgb, sizeof(unsigned char) * 3);
rgba += 4; rgba += 4;
rgb += 3; rgb += 3;
} }
deleteBuffer = true; deleteBuffer = true;
} }
else { else
{
buffer = &glTFImage.image[0]; buffer = &glTFImage.image[0];
bufferSize = glTFImage.image.size(); bufferSize = glTFImage.image.size();
} }
// Load texture from image buffer // Load texture from image buffer
images[i].texture.fromBuffer(buffer, bufferSize, VK_FORMAT_R8G8B8A8_UNORM, glTFImage.width, glTFImage.height, vulkanDevice, copyQueue); images[i].texture.fromBuffer(buffer, bufferSize, VK_FORMAT_R8G8B8A8_UNORM, glTFImage.width, glTFImage.height, vulkanDevice, copyQueue);
if (deleteBuffer) { if (deleteBuffer)
{
delete[] buffer; delete[] buffer;
} }
} }
@ -96,7 +103,8 @@ void VulkanglTFModel::loadImages(tinygltf::Model& input)
void VulkanglTFModel::loadTextures(tinygltf::Model &input) void VulkanglTFModel::loadTextures(tinygltf::Model &input)
{ {
textures.resize(input.textures.size()); textures.resize(input.textures.size());
for (size_t i = 0; i < input.textures.size(); i++) { for (size_t i = 0; i < input.textures.size(); i++)
{
textures[i].imageIndex = input.textures[i].source; textures[i].imageIndex = input.textures[i].source;
} }
} }
@ -104,15 +112,18 @@ void VulkanglTFModel::loadTextures(tinygltf::Model& input)
void VulkanglTFModel::loadMaterials(tinygltf::Model &input) void VulkanglTFModel::loadMaterials(tinygltf::Model &input)
{ {
materials.resize(input.materials.size()); materials.resize(input.materials.size());
for (size_t i = 0; i < input.materials.size(); i++) { for (size_t i = 0; i < input.materials.size(); i++)
{
// We only read the most basic properties required for our sample // We only read the most basic properties required for our sample
tinygltf::Material glTFMaterial = input.materials[i]; tinygltf::Material glTFMaterial = input.materials[i];
// Get the base color factor // Get the base color factor
if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end()) { if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end())
{
materials[i].baseColorFactor = glm::make_vec4(glTFMaterial.values["baseColorFactor"].ColorFactor().data()); materials[i].baseColorFactor = glm::make_vec4(glTFMaterial.values["baseColorFactor"].ColorFactor().data());
} }
// Get base color texture index // Get base color texture index
if (glTFMaterial.values.find("baseColorTexture") != glTFMaterial.values.end()) { if (glTFMaterial.values.find("baseColorTexture") != glTFMaterial.values.end())
{
materials[i].baseColorTextureIndex = glTFMaterial.values["baseColorTexture"].TextureIndex(); materials[i].baseColorTextureIndex = glTFMaterial.values["baseColorTexture"].TextureIndex();
} }
} }
@ -120,25 +131,32 @@ void VulkanglTFModel::loadMaterials(tinygltf::Model& input)
// Helper functions for locating glTF nodes // Helper functions for locating glTF nodes
VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index) { VulkanglTFModel::Node *VulkanglTFModel::findNode(Node *parent, uint32_t index)
{
Node *nodeFound = nullptr; Node *nodeFound = nullptr;
if (parent->index == index) { if (parent->index == index)
{
return parent; return parent;
} }
for (auto& child : parent->children) { for (auto &child : parent->children)
{
nodeFound = findNode(child, index); nodeFound = findNode(child, index);
if (nodeFound) { if (nodeFound)
{
break; break;
} }
} }
return nodeFound; return nodeFound;
} }
VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index) { VulkanglTFModel::Node *VulkanglTFModel::nodeFromIndex(uint32_t index)
{
Node *nodeFound = nullptr; Node *nodeFound = nullptr;
for (auto& node : nodes) { for (auto &node : nodes)
{
nodeFound = findNode(node, index); nodeFound = findNode(node, index);
if (nodeFound) { if (nodeFound)
{
break; break;
} }
} }
@ -150,7 +168,8 @@ void VulkanglTFModel::loadSkins(tinygltf::Model& input)
{ {
skins.resize(input.skins.size()); skins.resize(input.skins.size());
for (size_t i = 0; i < input.skins.size(); i++) { for (size_t i = 0; i < input.skins.size(); i++)
{
tinygltf::Skin glTFSkin = input.skins[i]; tinygltf::Skin glTFSkin = input.skins[i];
skins[i].name = glTFSkin.name; skins[i].name = glTFSkin.name;
@ -158,15 +177,18 @@ void VulkanglTFModel::loadSkins(tinygltf::Model& input)
skins[i].skeletonRoot = nodeFromIndex(glTFSkin.skeleton); skins[i].skeletonRoot = nodeFromIndex(glTFSkin.skeleton);
// Find joint nodes // Find joint nodes
for (int jointIndex : glTFSkin.joints) { for (int jointIndex : glTFSkin.joints)
{
Node *node = nodeFromIndex(jointIndex); Node *node = nodeFromIndex(jointIndex);
if (node) { if (node)
{
skins[i].joints.push_back(node); skins[i].joints.push_back(node);
} }
} }
// Get the inverse bind matrices from the buffer associated to this skin // Get the inverse bind matrices from the buffer associated to this skin
if (glTFSkin.inverseBindMatrices > -1) { if (glTFSkin.inverseBindMatrices > -1)
{
const tinygltf::Accessor & accessor = input.accessors[glTFSkin.inverseBindMatrices]; const tinygltf::Accessor & accessor = input.accessors[glTFSkin.inverseBindMatrices];
const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer]; const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer];
@ -191,13 +213,15 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
{ {
animations.resize(input.animations.size()); animations.resize(input.animations.size());
for (size_t i = 0; i < input.animations.size(); i++) { for (size_t i = 0; i < input.animations.size(); i++)
{
tinygltf::Animation glTFAnimation = input.animations[i]; tinygltf::Animation glTFAnimation = input.animations[i];
animations[i].name = glTFAnimation.name; animations[i].name = glTFAnimation.name;
// Samplers // Samplers
animations[i].samplers.resize(glTFAnimation.samplers.size()); animations[i].samplers.resize(glTFAnimation.samplers.size());
for (size_t j = 0; j < glTFAnimation.samplers.size(); j++) { for (size_t j = 0; j < glTFAnimation.samplers.size(); j++)
{
tinygltf::AnimationSampler glTFSampler = glTFAnimation.samplers[j]; tinygltf::AnimationSampler glTFSampler = glTFAnimation.samplers[j];
AnimationSampler & dstSampler = animations[i].samplers[j]; AnimationSampler & dstSampler = animations[i].samplers[j];
dstSampler.interpolation = glTFSampler.interpolation; dstSampler.interpolation = glTFSampler.interpolation;
@ -209,14 +233,18 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer]; const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer];
const void * dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; const void * dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
const float * buf = static_cast<const float *>(dataPtr); const float * buf = static_cast<const float *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
dstSampler.inputs.push_back(buf[index]); dstSampler.inputs.push_back(buf[index]);
} }
for (auto input : animations[i].samplers[j].inputs) { for (auto input : animations[i].samplers[j].inputs)
if (input < animations[i].start) { {
if (input < animations[i].start)
{
animations[i].start = input; animations[i].start = input;
}; };
if (input > animations[i].end) { if (input > animations[i].end)
{
animations[i].end = input; animations[i].end = input;
} }
} }
@ -228,17 +256,20 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer]; const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer];
const void * dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; const void * dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
switch (accessor.type) { switch (accessor.type)
{
case TINYGLTF_TYPE_VEC3: { case TINYGLTF_TYPE_VEC3: {
const glm::vec3 *buf = static_cast<const glm::vec3 *>(dataPtr); const glm::vec3 *buf = static_cast<const glm::vec3 *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
dstSampler.outputsVec4.push_back(glm::vec4(buf[index], 0.0f)); dstSampler.outputsVec4.push_back(glm::vec4(buf[index], 0.0f));
} }
break; break;
} }
case TINYGLTF_TYPE_VEC4: { case TINYGLTF_TYPE_VEC4: {
const glm::vec4 *buf = static_cast<const glm::vec4 *>(dataPtr); const glm::vec4 *buf = static_cast<const glm::vec4 *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
dstSampler.outputsVec4.push_back(buf[index]); dstSampler.outputsVec4.push_back(buf[index]);
} }
break; break;
@ -253,7 +284,8 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
// Channels // Channels
animations[i].channels.resize(glTFAnimation.channels.size()); animations[i].channels.resize(glTFAnimation.channels.size());
for (size_t j = 0; j < glTFAnimation.channels.size(); j++) { for (size_t j = 0; j < glTFAnimation.channels.size(); j++)
{
tinygltf::AnimationChannel glTFChannel = glTFAnimation.channels[j]; tinygltf::AnimationChannel glTFChannel = glTFAnimation.channels[j];
AnimationChannel & dstChannel = animations[i].channels[j]; AnimationChannel & dstChannel = animations[i].channels[j];
dstChannel.path = glTFChannel.target_path; dstChannel.path = glTFChannel.target_path;
@ -273,33 +305,41 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
// Get the local node matrix // Get the local node matrix
// It's either made up from translation, rotation, scale or a 4x4 matrix // It's either made up from translation, rotation, scale or a 4x4 matrix
if (inputNode.translation.size() == 3) { if (inputNode.translation.size() == 3)
{
node->translation = glm::make_vec3(inputNode.translation.data()); node->translation = glm::make_vec3(inputNode.translation.data());
} }
if (inputNode.rotation.size() == 4) { if (inputNode.rotation.size() == 4)
{
glm::quat q = glm::make_quat(inputNode.rotation.data()); glm::quat q = glm::make_quat(inputNode.rotation.data());
node->rotation = glm::mat4(q); node->rotation = glm::mat4(q);
} }
if (inputNode.scale.size() == 3) { if (inputNode.scale.size() == 3)
{
node->scale = glm::make_vec3(inputNode.scale.data()); node->scale = glm::make_vec3(inputNode.scale.data());
} }
if (inputNode.matrix.size() == 16) { if (inputNode.matrix.size() == 16)
{
node->matrix = glm::make_mat4x4(inputNode.matrix.data()); node->matrix = glm::make_mat4x4(inputNode.matrix.data());
}; };
// Load node's children // Load node's children
if (inputNode.children.size() > 0) { if (inputNode.children.size() > 0)
for (size_t i = 0; i < inputNode.children.size(); i++) { {
for (size_t i = 0; i < inputNode.children.size(); i++)
{
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);
} }
} }
// If the node contains mesh data, we load vertices and indices from the the buffers // If the node contains mesh data, we load vertices and indices from the the buffers
// In glTF this is done via accessors and buffer views // In glTF this is done via accessors and buffer views
if (inputNode.mesh > -1) { if (inputNode.mesh > -1)
{
const tinygltf::Mesh mesh = input.meshes[inputNode.mesh]; const tinygltf::Mesh mesh = input.meshes[inputNode.mesh];
// Iterate through all primitives of this node's mesh // Iterate through all primitives of this node's mesh
for (size_t i = 0; i < mesh.primitives.size(); i++) { for (size_t i = 0; i < mesh.primitives.size(); i++)
{
const tinygltf::Primitive &glTFPrimitive = mesh.primitives[i]; const tinygltf::Primitive &glTFPrimitive = mesh.primitives[i];
uint32_t firstIndex = static_cast<uint32_t>(indexBuffer.size()); uint32_t firstIndex = static_cast<uint32_t>(indexBuffer.size());
uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size()); uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
@ -315,21 +355,24 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
size_t vertexCount = 0; size_t vertexCount = 0;
// Get buffer data for vertex normals // Get buffer data for vertex normals
if (glTFPrimitive.attributes.find("POSITION") != glTFPrimitive.attributes.end()) { if (glTFPrimitive.attributes.find("POSITION") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("POSITION")->second]; const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("POSITION")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
positionBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); positionBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
vertexCount = accessor.count; vertexCount = accessor.count;
} }
// Get buffer data for vertex normals // Get buffer data for vertex normals
if (glTFPrimitive.attributes.find("NORMAL") != glTFPrimitive.attributes.end()) { if (glTFPrimitive.attributes.find("NORMAL") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("NORMAL")->second]; const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("NORMAL")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
normalsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); normalsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
} }
// Get buffer data for vertex texture coordinates // Get buffer data for vertex texture coordinates
// glTF supports multiple sets, we only load the first one // glTF supports multiple sets, we only load the first one
if (glTFPrimitive.attributes.find("TEXCOORD_0") != glTFPrimitive.attributes.end()) { if (glTFPrimitive.attributes.find("TEXCOORD_0") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("TEXCOORD_0")->second]; const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("TEXCOORD_0")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
texCoordsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); texCoordsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
@ -337,13 +380,15 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
// POI: Get buffer data required for vertex skinning // POI: Get buffer data required for vertex skinning
// Get vertex joint indices // Get vertex joint indices
if (glTFPrimitive.attributes.find("JOINTS_0") != glTFPrimitive.attributes.end()) { if (glTFPrimitive.attributes.find("JOINTS_0") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("JOINTS_0")->second]; const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("JOINTS_0")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
jointIndicesBuffer = reinterpret_cast<const uint16_t *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); jointIndicesBuffer = reinterpret_cast<const uint16_t *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
} }
// Get vertex joint weights // Get vertex joint weights
if (glTFPrimitive.attributes.find("WEIGHTS_0") != glTFPrimitive.attributes.end()) { if (glTFPrimitive.attributes.find("WEIGHTS_0") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("WEIGHTS_0")->second]; const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("WEIGHTS_0")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
jointWeightsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); jointWeightsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
@ -352,7 +397,8 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
hasSkin = (jointIndicesBuffer && jointWeightsBuffer); hasSkin = (jointIndicesBuffer && jointWeightsBuffer);
// Append data to model's vertex buffer // Append data to model's vertex buffer
for (size_t v = 0; v < vertexCount; v++) { for (size_t v = 0; v < vertexCount; v++)
{
Vertex vert{}; Vertex vert{};
vert.pos = glm::vec4(glm::make_vec3(&positionBuffer[v * 3]), 1.0f); vert.pos = glm::vec4(glm::make_vec3(&positionBuffer[v * 3]), 1.0f);
vert.normal = glm::normalize(glm::vec3(normalsBuffer ? glm::make_vec3(&normalsBuffer[v * 3]) : glm::vec3(0.0f))); vert.normal = glm::normalize(glm::vec3(normalsBuffer ? glm::make_vec3(&normalsBuffer[v * 3]) : glm::vec3(0.0f)));
@ -372,11 +418,13 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
indexCount += static_cast<uint32_t>(accessor.count); indexCount += static_cast<uint32_t>(accessor.count);
// glTF supports different component types of indices // glTF supports different component types of indices
switch (accessor.componentType) { switch (accessor.componentType)
{
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
uint32_t *buf = new uint32_t[accessor.count]; uint32_t *buf = new uint32_t[accessor.count];
memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(uint32_t)); memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(uint32_t));
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
indexBuffer.push_back(buf[index] + vertexStart); indexBuffer.push_back(buf[index] + vertexStart);
} }
break; break;
@ -384,7 +432,8 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
uint16_t *buf = new uint16_t[accessor.count]; uint16_t *buf = new uint16_t[accessor.count];
memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(uint16_t)); memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(uint16_t));
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
indexBuffer.push_back(buf[index] + vertexStart); indexBuffer.push_back(buf[index] + vertexStart);
} }
break; break;
@ -392,7 +441,8 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
uint8_t *buf = new uint8_t[accessor.count]; uint8_t *buf = new uint8_t[accessor.count];
memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(uint8_t)); memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(uint8_t));
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
indexBuffer.push_back(buf[index] + vertexStart); indexBuffer.push_back(buf[index] + vertexStart);
} }
break; break;
@ -410,10 +460,12 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
} }
} }
if (parent) { if (parent)
{
parent->children.push_back(node); parent->children.push_back(node);
} }
else { else
{
nodes.push_back(node); nodes.push_back(node);
} }
} }
@ -423,10 +475,12 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
*/ */
// POI: Traverse the node hierarchy to the top-most parent to get the local matrix of the given node // POI: Traverse the node hierarchy to the top-most parent to get the local matrix of the given node
glm::mat4 VulkanglTFModel::getNodeMatrix(VulkanglTFModel::Node* node) { glm::mat4 VulkanglTFModel::getNodeMatrix(VulkanglTFModel::Node *node)
{
glm::mat4 nodeMatrix = node->getLocalMatrix(); glm::mat4 nodeMatrix = node->getLocalMatrix();
VulkanglTFModel::Node *currentParent = node->parent; VulkanglTFModel::Node *currentParent = node->parent;
while (currentParent) { while (currentParent)
{
nodeMatrix = currentParent->getLocalMatrix() * nodeMatrix; nodeMatrix = currentParent->getLocalMatrix() * nodeMatrix;
currentParent = currentParent->parent; currentParent = currentParent->parent;
} }
@ -434,8 +488,10 @@ glm::mat4 VulkanglTFModel::getNodeMatrix(VulkanglTFModel::Node* node) {
} }
// POI: Update the joint matrices from the current animation frame and pass them to the GPU // POI: Update the joint matrices from the current animation frame and pass them to the GPU
void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) { void VulkanglTFModel::updateJoints(VulkanglTFModel::Node *node)
if (node->skin > -1) { {
if (node->skin > -1)
{
glm::mat4 m = getNodeMatrix(node); glm::mat4 m = getNodeMatrix(node);
// Update joint matrices // Update joint matrices
glm::mat4 inverseTransform = glm::inverse(m); glm::mat4 inverseTransform = glm::inverse(m);
@ -443,7 +499,8 @@ void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
size_t numJoints = (uint32_t) skin.joints.size(); size_t numJoints = (uint32_t) skin.joints.size();
std::vector<glm::mat4> jointMatrices(numJoints); std::vector<glm::mat4> jointMatrices(numJoints);
// @todo: bail out if model has more joints than shader can handle // @todo: bail out if model has more joints than shader can handle
for (size_t i = 0; i < numJoints; i++) { for (size_t i = 0; i < numJoints; i++)
{
jointMatrices[i] = getNodeMatrix(skin.joints[i]) * skin.inverseBindMatrices[i]; jointMatrices[i] = getNodeMatrix(skin.joints[i]) * skin.inverseBindMatrices[i];
jointMatrices[i] = inverseTransform * jointMatrices[i]; jointMatrices[i] = inverseTransform * jointMatrices[i];
} }
@ -451,7 +508,8 @@ void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
skin.ssbo.copyTo(jointMatrices.data(), jointMatrices.size() * sizeof(glm::mat4)); skin.ssbo.copyTo(jointMatrices.data(), jointMatrices.size() * sizeof(glm::mat4));
} }
for (auto& child : node->children) { for (auto &child : node->children)
{
updateJoints(child); updateJoints(child);
} }
} }
@ -459,33 +517,42 @@ void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
// POI: Update the current animation // POI: Update the current animation
void VulkanglTFModel::updateAnimation(float deltaTime) void VulkanglTFModel::updateAnimation(float deltaTime)
{ {
if (activeAnimation > static_cast<uint32_t>(animations.size()) - 1) { if (activeAnimation > static_cast<uint32_t>(animations.size()) - 1)
{
std::cout << "No animation with index " << activeAnimation << std::endl; std::cout << "No animation with index " << activeAnimation << std::endl;
return; return;
} }
Animation &animation = animations[activeAnimation]; Animation &animation = animations[activeAnimation];
animation.currentTime += deltaTime; animation.currentTime += deltaTime;
if (animation.currentTime > animation.end) { if (animation.currentTime > animation.end)
{
animation.currentTime -= animation.end; animation.currentTime -= animation.end;
} }
bool updated = false; bool updated = false;
for (auto& channel : animation.channels) { for (auto &channel : animation.channels)
{
AnimationSampler &sampler = animation.samplers[channel.samplerIndex]; AnimationSampler &sampler = animation.samplers[channel.samplerIndex];
if (sampler.inputs.size() > sampler.outputsVec4.size()) { if (sampler.inputs.size() > sampler.outputsVec4.size())
{
continue; continue;
} }
for (size_t i = 0; i < sampler.inputs.size() - 1; i++) { for (size_t i = 0; i < sampler.inputs.size() - 1; i++)
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 u = std::max(0.0f, animation.currentTime - sampler.inputs[i]) / (sampler.inputs[i + 1] - sampler.inputs[i]); float u = std::max(0.0f, animation.currentTime - sampler.inputs[i]) / (sampler.inputs[i + 1] - sampler.inputs[i]);
if (u <= 1.0f) { if (u <= 1.0f)
if (channel.path == "translation") { {
if (channel.path == "translation")
{
glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u); glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
channel.node->translation = glm::vec3(trans); channel.node->translation = glm::vec3(trans);
updated = true; updated = true;
} }
if (channel.path == "rotation") { if (channel.path == "rotation")
{
glm::quat q1; glm::quat q1;
q1.x = sampler.outputsVec4[i].x; q1.x = sampler.outputsVec4[i].x;
q1.y = sampler.outputsVec4[i].y; q1.y = sampler.outputsVec4[i].y;
@ -499,7 +566,8 @@ void VulkanglTFModel::updateAnimation(float deltaTime)
channel.node->rotation = glm::normalize(glm::slerp(q1, q2, u)); channel.node->rotation = glm::normalize(glm::slerp(q1, q2, u));
updated = true; updated = true;
} }
if (channel.path == "scale") { if (channel.path == "scale")
{
glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u); glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
channel.node->scale = glm::vec3(trans); channel.node->scale = glm::vec3(trans);
updated = true; updated = true;
@ -508,8 +576,10 @@ void VulkanglTFModel::updateAnimation(float deltaTime)
} }
} }
} }
if (updated) { if (updated)
for (auto& node : nodes) { {
for (auto &node : nodes)
{
updateJoints(node); updateJoints(node);
} }
} }
@ -522,12 +592,14 @@ void VulkanglTFModel::updateAnimation(float deltaTime)
// Draw a single node including child nodes (if present) // Draw a single node including child nodes (if present)
void VulkanglTFModel::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node) void VulkanglTFModel::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node)
{ {
if (node.mesh.primitives.size() > 0) { if (node.mesh.primitives.size() > 0)
{
// Pass the node's matrix via push constanst // Pass the node's matrix via push constanst
// Traverse the node hierarchy to the top-most parent to get the final matrix of the current node // Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
glm::mat4 nodeMatrix = node.matrix; glm::mat4 nodeMatrix = node.matrix;
VulkanglTFModel::Node *currentParent = node.parent; VulkanglTFModel::Node *currentParent = node.parent;
while (currentParent) { while (currentParent)
{
nodeMatrix = currentParent->matrix * nodeMatrix; nodeMatrix = currentParent->matrix * nodeMatrix;
currentParent = currentParent->parent; currentParent = currentParent->parent;
} }
@ -535,8 +607,10 @@ void VulkanglTFModel::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout p
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);
// Bind SSBO with skin data for this node to set 1 // Bind SSBO with skin data for this node to set 1
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)
if (primitive.indexCount > 0) { {
if (primitive.indexCount > 0)
{
// Get the texture index for this primitive // Get the texture index for this primitive
VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex]; VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex];
// Bind the descriptor for the current primitive's texture to set 2 // Bind the descriptor for the current primitive's texture to set 2
@ -545,7 +619,8 @@ void VulkanglTFModel::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout p
} }
} }
} }
for (auto& child : node.children) { for (auto &child : node.children)
{
drawNode(commandBuffer, pipelineLayout, *child); drawNode(commandBuffer, pipelineLayout, *child);
} }
} }
@ -558,19 +633,20 @@ void VulkanglTFModel::draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipel
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32);
// Render all nodes at top-level // Render all nodes at top-level
for (auto& node : nodes) { for (auto &node : nodes)
{
drawNode(commandBuffer, pipelineLayout, *node); drawNode(commandBuffer, pipelineLayout, *node);
} }
} }
/* /*
Vulkan Example class Vulkan Example class
*/ */
VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample::VulkanExample() :
VulkanExampleBase(ENABLE_VALIDATION)
{ {
title = "glTF vertex skinning"; title = "glTF vertex skinning";
camera.type = Camera::CameraType::lookat; camera.type = Camera::CameraType::lookat;
@ -584,7 +660,8 @@ VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
VulkanExample::~VulkanExample() VulkanExample::~VulkanExample()
{ {
vkDestroyPipeline(device, pipelines.solid, nullptr); vkDestroyPipeline(device, pipelines.solid, nullptr);
if (pipelines.wireframe != VK_NULL_HANDLE) { if (pipelines.wireframe != VK_NULL_HANDLE)
{
vkDestroyPipeline(device, pipelines.wireframe, nullptr); vkDestroyPipeline(device, pipelines.wireframe, nullptr);
} }
@ -598,7 +675,8 @@ VulkanExample::~VulkanExample()
void VulkanExample::getEnabledFeatures() void VulkanExample::getEnabledFeatures()
{ {
// Fill mode non solid is required for wireframe display // Fill mode non solid is required for wireframe display
if (deviceFeatures.fillModeNonSolid) { if (deviceFeatures.fillModeNonSolid)
{
enabledFeatures.fillModeNonSolid = VK_TRUE; enabledFeatures.fillModeNonSolid = VK_TRUE;
}; };
} }
@ -608,7 +686,8 @@ void VulkanExample::buildCommandBuffers()
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VkClearValue clearValues[2]; VkClearValue clearValues[2];
clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 1.0f } };; clearValues[0].color = {{0.25f, 0.25f, 0.25f, 1.0f}};
;
clearValues[1].depthStencil = {1.0f, 0}; clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
@ -662,23 +741,27 @@ void VulkanExample::loadglTFFile(std::string filename)
std::vector<uint32_t> indexBuffer; std::vector<uint32_t> indexBuffer;
std::vector<VulkanglTFModel::Vertex> vertexBuffer; std::vector<VulkanglTFModel::Vertex> vertexBuffer;
if (fileLoaded) { if (fileLoaded)
{
glTFModel.loadImages(glTFInput); glTFModel.loadImages(glTFInput);
glTFModel.loadMaterials(glTFInput); glTFModel.loadMaterials(glTFInput);
glTFModel.loadTextures(glTFInput); glTFModel.loadTextures(glTFInput);
const tinygltf::Scene &scene = glTFInput.scenes[0]; const tinygltf::Scene &scene = glTFInput.scenes[0];
for (size_t i = 0; i < scene.nodes.size(); i++) { for (size_t i = 0; i < scene.nodes.size(); i++)
{
const tinygltf::Node node = glTFInput.nodes[scene.nodes[i]]; const tinygltf::Node node = glTFInput.nodes[scene.nodes[i]];
glTFModel.loadNode(node, glTFInput, nullptr, scene.nodes[i], indexBuffer, vertexBuffer); glTFModel.loadNode(node, glTFInput, nullptr, scene.nodes[i], indexBuffer, vertexBuffer);
} }
glTFModel.loadSkins(glTFInput); glTFModel.loadSkins(glTFInput);
glTFModel.loadAnimations(glTFInput); glTFModel.loadAnimations(glTFInput);
// Calculate initial pose // Calculate initial pose
for (auto node : glTFModel.nodes) { for (auto node : glTFModel.nodes)
{
glTFModel.updateJoints(node); glTFModel.updateJoints(node);
} }
} }
else { else
{
vks::tools::exitFatal("Could not open the glTF file.\n\nThe file is part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1); vks::tools::exitFatal("Could not open the glTF file.\n\nThe file is part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
return; return;
} }
@ -688,7 +771,8 @@ void VulkanExample::loadglTFFile(std::string filename)
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t); size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
glTFModel.indices.count = static_cast<uint32_t>(indexBuffer.size()); glTFModel.indices.count = static_cast<uint32_t>(indexBuffer.size());
struct StagingBuffer { struct StagingBuffer
{
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VkDeviceMemory memory;
} vertexStaging, indexStaging; } vertexStaging, indexStaging;
@ -781,8 +865,7 @@ void VulkanExample::setupDescriptors()
std::array<VkDescriptorSetLayout, 3> setLayouts = { std::array<VkDescriptorSetLayout, 3> setLayouts = {
descriptorSetLayouts.matrices, descriptorSetLayouts.matrices,
descriptorSetLayouts.jointMatrices, descriptorSetLayouts.jointMatrices,
descriptorSetLayouts.textures descriptorSetLayouts.textures};
};
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast<uint32_t>(setLayouts.size())); VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast<uint32_t>(setLayouts.size()));
// We will use push constants to push the local matrices of a primitive to the vertex shader // We will use push constants to push the local matrices of a primitive to the vertex shader
@ -799,7 +882,8 @@ void VulkanExample::setupDescriptors()
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
// Descriptor set for glTF model skin joint matrices // Descriptor set for glTF model skin joint matrices
for (auto& skin : glTFModel.skins) { for (auto &skin : glTFModel.skins)
{
const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.jointMatrices, 1); const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.jointMatrices, 1);
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &skin.descriptorSet)); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &skin.descriptorSet));
VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(skin.descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, &skin.ssbo.descriptor); VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(skin.descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, &skin.ssbo.descriptor);
@ -807,7 +891,8 @@ void VulkanExample::setupDescriptors()
} }
// Descriptor sets for glTF model materials // Descriptor sets for glTF model materials
for (auto& image : glTFModel.images) { for (auto &image : glTFModel.images)
{
const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1); const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1);
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &image.descriptorSet)); 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); VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(image.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &image.texture.descriptor);
@ -848,8 +933,7 @@ void VulkanExample::preparePipelines()
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = { const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {
loadShader(getShadersPath() + "gltfskinning/skinnedmodel.vert.spv", VK_SHADER_STAGE_VERTEX_BIT), loadShader(getShadersPath() + "gltfskinning/skinnedmodel.vert.spv", VK_SHADER_STAGE_VERTEX_BIT),
loadShader(getShadersPath() + "gltfskinning/skinnedmodel.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT) loadShader(getShadersPath() + "gltfskinning/skinnedmodel.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT)};
};
VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0);
pipelineCI.pVertexInputState = &vertexInputStateCI; pipelineCI.pVertexInputState = &vertexInputStateCI;
@ -867,7 +951,8 @@ void VulkanExample::preparePipelines()
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.solid)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.solid));
// Wire frame rendering pipeline // Wire frame rendering pipeline
if (deviceFeatures.fillModeNonSolid) { if (deviceFeatures.fillModeNonSolid)
{
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_LINE; rasterizationStateCI.polygonMode = VK_POLYGON_MODE_LINE;
rasterizationStateCI.lineWidth = 1.0f; rasterizationStateCI.lineWidth = 1.0f;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.wireframe)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.wireframe));
@ -907,19 +992,23 @@ void VulkanExample::prepare()
void VulkanExample::render() void VulkanExample::render()
{ {
renderFrame(); renderFrame();
if (camera.updated) { if (camera.updated)
{
updateUniformBuffers(); updateUniformBuffers();
} }
// POI: Advance animation // POI: Advance animation
if (!paused) { if (!paused)
{
glTFModel.updateAnimation(frameTimer); glTFModel.updateAnimation(frameTimer);
} }
} }
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay *overlay) void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay *overlay)
{ {
if (overlay->header("Settings")) { if (overlay->header("Settings"))
if (overlay->checkBox("Wireframe", &wireframe)) { {
if (overlay->checkBox("Wireframe", &wireframe))
{
buildCommandBuffers(); buildCommandBuffers();
} }
} }

View file

@ -15,10 +15,10 @@
* If you are looking for a complete glTF implementation, check out https://github.com/SaschaWillems/Vulkan-glTF-PBR/ * If you are looking for a complete glTF implementation, check out https://github.com/SaschaWillems/Vulkan-glTF-PBR/
*/ */
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <vector> #include <vector>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
@ -35,9 +35,9 @@
#endif #endif
#include "tiny_gltf.h" #include "tiny_gltf.h"
#include <vulkan/vulkan.h>
#include "vulkanexamplebase.h"
#include "VulkanTexture.hpp" #include "VulkanTexture.hpp"
#include "vulkanexamplebase.h"
#include <vulkan/vulkan.h>
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
@ -53,12 +53,14 @@ public:
Base glTF structures, see gltfscene sample for details Base glTF structures, see gltfscene sample for details
*/ */
struct Vertices { struct Vertices
{
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VkDeviceMemory memory;
} vertices; } vertices;
struct Indices { struct Indices
{
int count; int count;
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VkDeviceMemory memory;
@ -66,54 +68,56 @@ public:
struct Node; struct Node;
struct Material { struct Material
{
glm::vec4 baseColorFactor = glm::vec4(1.0f); glm::vec4 baseColorFactor = glm::vec4(1.0f);
uint32_t baseColorTextureIndex; uint32_t baseColorTextureIndex;
}; };
struct Image { struct Image
{
vks::Texture2D texture; vks::Texture2D texture;
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet;
}; };
struct Texture { struct Texture
{
int32_t imageIndex; int32_t imageIndex;
}; };
struct Primitive { struct Primitive
{
uint32_t firstIndex; uint32_t firstIndex;
uint32_t indexCount; uint32_t indexCount;
int32_t materialIndex; int32_t materialIndex;
}; };
struct Mesh { struct Mesh
{
std::vector<Primitive> primitives; std::vector<Primitive> primitives;
}; };
struct Node { struct Node
{
Node * parent; Node * parent;
uint32_t index; uint32_t index;
std::vector<Node *> children; std::vector<Node *> children;
Mesh mesh; Mesh mesh;
// Matrix components are stored separately as they are affected by animations
glm::vec3 translation{}; glm::vec3 translation{};
glm::vec3 scale{1.0f}; glm::vec3 scale{1.0f};
glm::quat rotation{}; glm::quat rotation{};
// Index of the skin for this node
int32_t skin = -1; int32_t skin = -1;
glm::mat4 matrix; glm::mat4 matrix;
// Gets the current local matrix based on translation, rotation and scale, which can all be affected by animations
glm::mat4 getLocalMatrix(); glm::mat4 getLocalMatrix();
}; };
struct Vertex { struct Vertex
{
glm::vec3 pos; glm::vec3 pos;
glm::vec3 normal; glm::vec3 normal;
glm::vec2 uv; glm::vec2 uv;
glm::vec3 color; glm::vec3 color;
// Contains indices of the joints that effect this vertex
glm::vec4 jointIndices; glm::vec4 jointIndices;
// Contains the weights that define how strongly this vertex is affected by above joints
glm::vec4 jointWeights; glm::vec4 jointWeights;
}; };
@ -121,12 +125,12 @@ public:
Skin structure Skin structure
*/ */
struct Skin { struct Skin
{
std::string name; std::string name;
Node * skeletonRoot = nullptr; Node * skeletonRoot = nullptr;
std::vector<glm::mat4> inverseBindMatrices; std::vector<glm::mat4> inverseBindMatrices;
std::vector<Node *> joints; std::vector<Node *> joints;
// The joint matrices for this skin are stored in an shader storage buffer
vks::Buffer ssbo; vks::Buffer ssbo;
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet;
}; };
@ -135,19 +139,22 @@ public:
Animation related structures Animation related structures
*/ */
struct AnimationSampler { struct AnimationSampler
{
std::string interpolation; std::string interpolation;
std::vector<float> inputs; std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4; std::vector<glm::vec4> outputsVec4;
}; };
struct AnimationChannel { struct AnimationChannel
{
std::string path; std::string path;
Node * node; Node * node;
uint32_t samplerIndex; uint32_t samplerIndex;
}; };
struct Animation { struct Animation
{
std::string name; std::string name;
std::vector<AnimationSampler> samplers; std::vector<AnimationSampler> samplers;
std::vector<AnimationChannel> channels; std::vector<AnimationChannel> channels;
@ -186,9 +193,11 @@ class VulkanExample : public VulkanExampleBase
public: public:
bool wireframe = false; bool wireframe = false;
struct ShaderData { struct ShaderData
{
vks::Buffer buffer; vks::Buffer buffer;
struct Values { struct Values
{
glm::mat4 projection; glm::mat4 projection;
glm::mat4 model; glm::mat4 model;
glm::vec4 lightPos = glm::vec4(5.0f, 5.0f, 5.0f, 1.0f); glm::vec4 lightPos = glm::vec4(5.0f, 5.0f, 5.0f, 1.0f);
@ -196,12 +205,14 @@ public:
} shaderData; } shaderData;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
struct Pipelines { struct Pipelines
{
VkPipeline solid; VkPipeline solid;
VkPipeline wireframe = VK_NULL_HANDLE; VkPipeline wireframe = VK_NULL_HANDLE;
} pipelines; } pipelines;
struct DescriptorSetLayouts { struct DescriptorSetLayouts
{
VkDescriptorSetLayout matrices; VkDescriptorSetLayout matrices;
VkDescriptorSetLayout textures; VkDescriptorSetLayout textures;
VkDescriptorSetLayout jointMatrices; VkDescriptorSetLayout jointMatrices;