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

@ -17,7 +17,7 @@
#include "gltfskinning.h"
/*
/*
glTF model class
@ -26,11 +26,12 @@
*/
/*
/*
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
*/
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;
}
@ -43,7 +44,8 @@ VulkanglTFModel::~VulkanglTFModel()
vkFreeMemory(vulkanDevice->logicalDevice, vertices.memory, nullptr);
vkDestroyBuffer(vulkanDevice->logicalDevice, indices.buffer, nullptr);
vkFreeMemory(vulkanDevice->logicalDevice, indices.memory, nullptr);
for (Image image : images) {
for (Image image : images)
{
vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr);
vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr);
vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr);
@ -57,62 +59,71 @@ VulkanglTFModel::~VulkanglTFModel()
The following functions take a glTF input model loaded via tinyglTF and converts all required data into our own structures
*/
void VulkanglTFModel::loadImages(tinygltf::Model& input)
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
// loading them from disk, we fetch them from the glTF loader and upload the buffers
images.resize(input.images.size());
for (size_t i = 0; i < input.images.size(); i++) {
tinygltf::Image& glTFImage = input.images[i];
for (size_t i = 0; i < input.images.size(); i++)
{
tinygltf::Image &glTFImage = input.images[i];
// Get the image data from the glTF loader
unsigned char* buffer = nullptr;
unsigned char *buffer = nullptr;
VkDeviceSize bufferSize = 0;
bool deleteBuffer = false;
// 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;
buffer = new unsigned char[bufferSize];
unsigned char* rgba = buffer;
unsigned char* rgb = &glTFImage.image[0];
for (size_t i = 0; i < glTFImage.width * glTFImage.height; ++i) {
unsigned char *rgba = buffer;
unsigned char *rgb = &glTFImage.image[0];
for (size_t i = 0; i < glTFImage.width * glTFImage.height; ++i)
{
memcpy(rgba, rgb, sizeof(unsigned char) * 3);
rgba += 4;
rgb += 3;
}
deleteBuffer = true;
}
else {
else
{
buffer = &glTFImage.image[0];
bufferSize = glTFImage.image.size();
}
// Load texture from image buffer
images[i].texture.fromBuffer(buffer, bufferSize, VK_FORMAT_R8G8B8A8_UNORM, glTFImage.width, glTFImage.height, vulkanDevice, copyQueue);
if (deleteBuffer) {
if (deleteBuffer)
{
delete[] buffer;
}
}
}
void VulkanglTFModel::loadTextures(tinygltf::Model& input)
void VulkanglTFModel::loadTextures(tinygltf::Model &input)
{
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;
}
}
void VulkanglTFModel::loadMaterials(tinygltf::Model& input)
void VulkanglTFModel::loadMaterials(tinygltf::Model &input)
{
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
tinygltf::Material glTFMaterial = input.materials[i];
// 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());
}
// 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();
}
}
@ -120,25 +131,32 @@ void VulkanglTFModel::loadMaterials(tinygltf::Model& input)
// Helper functions for locating glTF nodes
VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index) {
Node* nodeFound = nullptr;
if (parent->index == index) {
VulkanglTFModel::Node *VulkanglTFModel::findNode(Node *parent, uint32_t index)
{
Node *nodeFound = nullptr;
if (parent->index == index)
{
return parent;
}
for (auto& child : parent->children) {
for (auto &child : parent->children)
{
nodeFound = findNode(child, index);
if (nodeFound) {
if (nodeFound)
{
break;
}
}
return nodeFound;
}
VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index) {
Node* nodeFound = nullptr;
for (auto& node : nodes) {
VulkanglTFModel::Node *VulkanglTFModel::nodeFromIndex(uint32_t index)
{
Node *nodeFound = nullptr;
for (auto &node : nodes)
{
nodeFound = findNode(node, index);
if (nodeFound) {
if (nodeFound)
{
break;
}
}
@ -146,11 +164,12 @@ VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index) {
}
// POI: Load the skins from the glTF model
void VulkanglTFModel::loadSkins(tinygltf::Model& input)
void VulkanglTFModel::loadSkins(tinygltf::Model &input)
{
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];
skins[i].name = glTFSkin.name;
@ -158,18 +177,21 @@ void VulkanglTFModel::loadSkins(tinygltf::Model& input)
skins[i].skeletonRoot = nodeFromIndex(glTFSkin.skeleton);
// Find joint nodes
for (int jointIndex : glTFSkin.joints) {
Node* node = nodeFromIndex(jointIndex);
if (node) {
for (int jointIndex : glTFSkin.joints)
{
Node *node = nodeFromIndex(jointIndex);
if (node)
{
skins[i].joints.push_back(node);
}
}
// Get the inverse bind matrices from the buffer associated to this skin
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];
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));
@ -187,36 +209,42 @@ void VulkanglTFModel::loadSkins(tinygltf::Model& input)
}
// POI: Load the animations from the glTF model
void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
void VulkanglTFModel::loadAnimations(tinygltf::Model &input)
{
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];
animations[i].name = glTFAnimation.name;
// Samplers
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];
AnimationSampler& dstSampler = animations[i].samplers[j];
AnimationSampler & dstSampler = animations[i].samplers[j];
dstSampler.interpolation = glTFSampler.interpolation;
// Read sampler 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];
const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
const float* buf = static_cast<const float*>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) {
const tinygltf::Accessor & accessor = input.accessors[glTFSampler.input];
const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer];
const void * dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
const float * buf = static_cast<const float *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++)
{
dstSampler.inputs.push_back(buf[index]);
}
for (auto input : animations[i].samplers[j].inputs) {
if (input < animations[i].start) {
for (auto input : animations[i].samplers[j].inputs)
{
if (input < animations[i].start)
{
animations[i].start = input;
};
if (input > animations[i].end) {
if (input > animations[i].end)
{
animations[i].end = input;
}
}
@ -224,21 +252,24 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
// Read sampler output Translate/rotate/scale values
{
const tinygltf::Accessor& accessor = input.accessors[glTFSampler.output];
const tinygltf::BufferView& bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer& buffer = input.buffers[bufferView.buffer];
const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
switch (accessor.type) {
const tinygltf::Accessor & accessor = input.accessors[glTFSampler.output];
const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer];
const void * dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
switch (accessor.type)
{
case TINYGLTF_TYPE_VEC3: {
const glm::vec3* buf = static_cast<const glm::vec3*>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) {
const glm::vec3 *buf = static_cast<const glm::vec3 *>(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<const glm::vec4*>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) {
const glm::vec4 *buf = static_cast<const glm::vec4 *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++)
{
dstSampler.outputsVec4.push_back(buf[index]);
}
break;
@ -253,9 +284,10 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
// Channels
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];
AnimationChannel& dstChannel = animations[i].channels[j];
AnimationChannel & dstChannel = animations[i].channels[j];
dstChannel.path = glTFChannel.target_path;
dstChannel.samplerIndex = glTFChannel.sampler;
dstChannel.node = nodeFromIndex(glTFChannel.target_node);
@ -263,9 +295,9 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
}
}
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)
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)
{
VulkanglTFModel::Node* node = new VulkanglTFModel::Node{};
VulkanglTFModel::Node *node = new VulkanglTFModel::Node{};
node->parent = parent;
node->matrix = glm::mat4(1.0f);
node->index = nodeIndex;
@ -273,86 +305,100 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
// Get the local node 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());
}
if (inputNode.rotation.size() == 4) {
if (inputNode.rotation.size() == 4)
{
glm::quat q = glm::make_quat(inputNode.rotation.data());
node->rotation = glm::mat4(q);
}
if (inputNode.scale.size() == 3) {
if (inputNode.scale.size() == 3)
{
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());
};
// Load node's children
if (inputNode.children.size() > 0) {
for (size_t i = 0; i < inputNode.children.size(); i++) {
if (inputNode.children.size() > 0)
{
for (size_t i = 0; i < inputNode.children.size(); i++)
{
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
// 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];
// Iterate through all primitives of this node's mesh
for (size_t i = 0; i < mesh.primitives.size(); i++) {
const tinygltf::Primitive& glTFPrimitive = mesh.primitives[i];
for (size_t i = 0; i < mesh.primitives.size(); i++)
{
const tinygltf::Primitive &glTFPrimitive = mesh.primitives[i];
uint32_t firstIndex = static_cast<uint32_t>(indexBuffer.size());
uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
uint32_t indexCount = 0;
bool hasSkin = false;
// Vertices
{
const float* positionBuffer = nullptr;
const float* normalsBuffer = nullptr;
const float* texCoordsBuffer = nullptr;
const uint16_t* jointIndicesBuffer = nullptr;
const float* jointWeightsBuffer = nullptr;
const float * positionBuffer = nullptr;
const float * normalsBuffer = nullptr;
const float * texCoordsBuffer = nullptr;
const uint16_t *jointIndicesBuffer = nullptr;
const float * jointWeightsBuffer = nullptr;
size_t vertexCount = 0;
// Get buffer data for vertex normals
if (glTFPrimitive.attributes.find("POSITION") != glTFPrimitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("POSITION")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
positionBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
if (glTFPrimitive.attributes.find("POSITION") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("POSITION")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
positionBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
vertexCount = accessor.count;
}
// Get buffer data for vertex normals
if (glTFPrimitive.attributes.find("NORMAL") != glTFPrimitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("NORMAL")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
normalsBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
if (glTFPrimitive.attributes.find("NORMAL") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("NORMAL")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
normalsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
}
// Get buffer data for vertex texture coordinates
// glTF supports multiple sets, we only load the first one
if (glTFPrimitive.attributes.find("TEXCOORD_0") != glTFPrimitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("TEXCOORD_0")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
texCoordsBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
if (glTFPrimitive.attributes.find("TEXCOORD_0") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("TEXCOORD_0")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
texCoordsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
}
// POI: Get buffer data required for vertex skinning
// Get vertex joint indices
if (glTFPrimitive.attributes.find("JOINTS_0") != glTFPrimitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("JOINTS_0")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
jointIndicesBuffer = reinterpret_cast<const uint16_t*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
if (glTFPrimitive.attributes.find("JOINTS_0") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("JOINTS_0")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
jointIndicesBuffer = reinterpret_cast<const uint16_t *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
}
// Get vertex joint weights
if (glTFPrimitive.attributes.find("WEIGHTS_0") != glTFPrimitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("WEIGHTS_0")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
jointWeightsBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
if (glTFPrimitive.attributes.find("WEIGHTS_0") != glTFPrimitive.attributes.end())
{
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.attributes.find("WEIGHTS_0")->second];
const tinygltf::BufferView &view = input.bufferViews[accessor.bufferView];
jointWeightsBuffer = reinterpret_cast<const float *>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
}
hasSkin = (jointIndicesBuffer && jointWeightsBuffer);
// 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{};
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)));
@ -365,34 +411,38 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
}
// Indices
{
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.indices];
const tinygltf::BufferView& bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer& buffer = input.buffers[bufferView.buffer];
const tinygltf::Accessor & accessor = input.accessors[glTFPrimitive.indices];
const tinygltf::BufferView &bufferView = input.bufferViews[accessor.bufferView];
const tinygltf::Buffer & buffer = input.buffers[bufferView.buffer];
indexCount += static_cast<uint32_t>(accessor.count);
// glTF supports different component types of indices
switch (accessor.componentType) {
switch (accessor.componentType)
{
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));
for (size_t index = 0; index < accessor.count; index++) {
for (size_t index = 0; index < accessor.count; index++)
{
indexBuffer.push_back(buf[index] + vertexStart);
}
break;
}
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));
for (size_t index = 0; index < accessor.count; index++) {
for (size_t index = 0; index < accessor.count; index++)
{
indexBuffer.push_back(buf[index] + vertexStart);
}
break;
}
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));
for (size_t index = 0; index < accessor.count; index++) {
for (size_t index = 0; index < accessor.count; index++)
{
indexBuffer.push_back(buf[index] + vertexStart);
}
break;
@ -410,10 +460,12 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
}
}
if (parent) {
if (parent)
{
parent->children.push_back(node);
}
else {
else
{
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
glm::mat4 VulkanglTFModel::getNodeMatrix(VulkanglTFModel::Node* node) {
glm::mat4 VulkanglTFModel::getNodeMatrix(VulkanglTFModel::Node *node)
{
glm::mat4 nodeMatrix = node->getLocalMatrix();
VulkanglTFModel::Node* currentParent = node->parent;
while (currentParent) {
VulkanglTFModel::Node *currentParent = node->parent;
while (currentParent)
{
nodeMatrix = currentParent->getLocalMatrix() * nodeMatrix;
currentParent = currentParent->parent;
}
@ -434,16 +488,19 @@ glm::mat4 VulkanglTFModel::getNodeMatrix(VulkanglTFModel::Node* node) {
}
// POI: Update the joint matrices from the current animation frame and pass them to the GPU
void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
if (node->skin > -1) {
void VulkanglTFModel::updateJoints(VulkanglTFModel::Node *node)
{
if (node->skin > -1)
{
glm::mat4 m = getNodeMatrix(node);
// Update joint matrices
glm::mat4 inverseTransform = glm::inverse(m);
Skin skin = skins[node->skin];
size_t numJoints = (uint32_t)skin.joints.size();
size_t numJoints = (uint32_t) skin.joints.size();
std::vector<glm::mat4> jointMatrices(numJoints);
// @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] = inverseTransform * jointMatrices[i];
}
@ -451,7 +508,8 @@ void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
skin.ssbo.copyTo(jointMatrices.data(), jointMatrices.size() * sizeof(glm::mat4));
}
for (auto& child : node->children) {
for (auto &child : node->children)
{
updateJoints(child);
}
}
@ -459,33 +517,42 @@ void VulkanglTFModel::updateJoints(VulkanglTFModel::Node* node) {
// POI: Update the current animation
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;
return;
}
Animation& animation = animations[activeAnimation];
Animation &animation = animations[activeAnimation];
animation.currentTime += deltaTime;
if (animation.currentTime > animation.end) {
if (animation.currentTime > animation.end)
{
animation.currentTime -= animation.end;
}
bool updated = false;
for (auto& channel : animation.channels) {
AnimationSampler& sampler = animation.samplers[channel.samplerIndex];
if (sampler.inputs.size() > sampler.outputsVec4.size()) {
for (auto &channel : animation.channels)
{
AnimationSampler &sampler = animation.samplers[channel.samplerIndex];
if (sampler.inputs.size() > sampler.outputsVec4.size())
{
continue;
}
for (size_t i = 0; i < sampler.inputs.size() - 1; i++) {
if ((animation.currentTime >= sampler.inputs[i]) && (animation.currentTime <= sampler.inputs[i + 1])) {
for (size_t i = 0; i < sampler.inputs.size() - 1; i++)
{
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]);
if (u <= 1.0f) {
if (channel.path == "translation") {
if (u <= 1.0f)
{
if (channel.path == "translation")
{
glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
channel.node->translation = glm::vec3(trans);
updated = true;
}
if (channel.path == "rotation") {
if (channel.path == "rotation")
{
glm::quat q1;
q1.x = sampler.outputsVec4[i].x;
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));
updated = true;
}
if (channel.path == "scale") {
if (channel.path == "scale")
{
glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
channel.node->scale = glm::vec3(trans);
updated = true;
@ -508,8 +576,10 @@ void VulkanglTFModel::updateAnimation(float deltaTime)
}
}
}
if (updated) {
for (auto& node : nodes) {
if (updated)
{
for (auto &node : nodes)
{
updateJoints(node);
}
}
@ -522,12 +592,14 @@ void VulkanglTFModel::updateAnimation(float deltaTime)
// Draw a single node including child nodes (if present)
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
// Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
glm::mat4 nodeMatrix = node.matrix;
VulkanglTFModel::Node* currentParent = node.parent;
while (currentParent) {
VulkanglTFModel::Node *currentParent = node.parent;
while (currentParent)
{
nodeMatrix = currentParent->matrix * nodeMatrix;
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);
// 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);
for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) {
if (primitive.indexCount > 0) {
for (VulkanglTFModel::Primitive &primitive : node.mesh.primitives)
{
if (primitive.indexCount > 0)
{
// Get the texture index for this primitive
VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex];
// 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);
}
}
@ -554,37 +629,39 @@ void VulkanglTFModel::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout p
void VulkanglTFModel::draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout)
{
// All vertices and indices are stored in single buffers, so we only need to bind once
VkDeviceSize offsets[1] = { 0 };
VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32);
// Render all nodes at top-level
for (auto& node : nodes) {
for (auto &node : nodes)
{
drawNode(commandBuffer, pipelineLayout, *node);
}
}
/*
Vulkan Example class
*/
VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
VulkanExample::VulkanExample() :
VulkanExampleBase(ENABLE_VALIDATION)
{
title = "glTF vertex skinning";
camera.type = Camera::CameraType::lookat;
camera.flipY = true;
camera.setPosition(glm::vec3(0.0f, 0.75f, -2.0f));
camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f);
camera.setPerspective(60.0f, (float) width / (float) height, 0.1f, 256.0f);
settings.overlay = true;
}
VulkanExample::~VulkanExample()
{
vkDestroyPipeline(device, pipelines.solid, nullptr);
if (pipelines.wireframe != VK_NULL_HANDLE) {
if (pipelines.wireframe != VK_NULL_HANDLE)
{
vkDestroyPipeline(device, pipelines.wireframe, nullptr);
}
@ -598,7 +675,8 @@ VulkanExample::~VulkanExample()
void VulkanExample::getEnabledFeatures()
{
// Fill mode non solid is required for wireframe display
if (deviceFeatures.fillModeNonSolid) {
if (deviceFeatures.fillModeNonSolid)
{
enabledFeatures.fillModeNonSolid = VK_TRUE;
};
}
@ -608,8 +686,9 @@ void VulkanExample::buildCommandBuffers()
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VkClearValue clearValues[2];
clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 1.0f } };;
clearValues[1].depthStencil = { 1.0f, 0 };
clearValues[0].color = {{0.25f, 0.25f, 0.25f, 1.0f}};
;
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
renderPassBeginInfo.renderPass = renderPass;
@ -620,7 +699,7 @@ void VulkanExample::buildCommandBuffers()
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
const VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
const VkViewport viewport = vks::initializers::viewport((float) width, (float) height, 0.0f, 1.0f);
const VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
@ -662,23 +741,27 @@ void VulkanExample::loadglTFFile(std::string filename)
std::vector<uint32_t> indexBuffer;
std::vector<VulkanglTFModel::Vertex> vertexBuffer;
if (fileLoaded) {
if (fileLoaded)
{
glTFModel.loadImages(glTFInput);
glTFModel.loadMaterials(glTFInput);
glTFModel.loadTextures(glTFInput);
const tinygltf::Scene& scene = glTFInput.scenes[0];
for (size_t i = 0; i < scene.nodes.size(); i++) {
const tinygltf::Scene &scene = glTFInput.scenes[0];
for (size_t i = 0; i < scene.nodes.size(); i++)
{
const tinygltf::Node node = glTFInput.nodes[scene.nodes[i]];
glTFModel.loadNode(node, glTFInput, nullptr, scene.nodes[i], indexBuffer, vertexBuffer);
}
glTFModel.loadSkins(glTFInput);
glTFModel.loadAnimations(glTFInput);
// Calculate initial pose
for (auto node : glTFModel.nodes) {
for (auto node : glTFModel.nodes)
{
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);
return;
}
@ -688,7 +771,8 @@ void VulkanExample::loadglTFFile(std::string filename)
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
glTFModel.indices.count = static_cast<uint32_t>(indexBuffer.size());
struct StagingBuffer {
struct StagingBuffer
{
VkBuffer buffer;
VkDeviceMemory memory;
} vertexStaging, indexStaging;
@ -781,8 +865,7 @@ void VulkanExample::setupDescriptors()
std::array<VkDescriptorSetLayout, 3> setLayouts = {
descriptorSetLayouts.matrices,
descriptorSetLayouts.jointMatrices,
descriptorSetLayouts.textures
};
descriptorSetLayouts.textures};
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
@ -799,7 +882,8 @@ void VulkanExample::setupDescriptors()
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
// 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);
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &skin.descriptorSet));
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
for (auto& image : glTFModel.images) {
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);
@ -824,20 +909,20 @@ void VulkanExample::preparePipelines()
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL);
VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0);
const std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
const std::vector<VkDynamicState> dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast<uint32_t>(dynamicStateEnables.size()), 0);
// Vertex input bindings and attributes
const std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
vks::initializers::vertexInputBindingDescription(0, sizeof(VulkanglTFModel::Vertex), VK_VERTEX_INPUT_RATE_VERTEX),
};
const std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
{ 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) },
{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) },
{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();
@ -848,8 +933,7 @@ void VulkanExample::preparePipelines()
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {
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);
pipelineCI.pVertexInputState = &vertexInputStateCI;
@ -867,7 +951,8 @@ void VulkanExample::preparePipelines()
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.solid));
// Wire frame rendering pipeline
if (deviceFeatures.fillModeNonSolid) {
if (deviceFeatures.fillModeNonSolid)
{
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_LINE;
rasterizationStateCI.lineWidth = 1.0f;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.wireframe));
@ -907,19 +992,23 @@ void VulkanExample::prepare()
void VulkanExample::render()
{
renderFrame();
if (camera.updated) {
if (camera.updated)
{
updateUniformBuffers();
}
// POI: Advance animation
if (!paused) {
if (!paused)
{
glTFModel.updateAnimation(frameTimer);
}
}
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay)
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay *overlay)
{
if (overlay->header("Settings")) {
if (overlay->checkBox("Wireframe", &wireframe)) {
if (overlay->header("Settings"))
{
if (overlay->checkBox("Wireframe", &wireframe))
{
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/
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <vector>
#define GLM_FORCE_RADIANS
@ -31,13 +31,13 @@
#define STB_IMAGE_IMPLEMENTATION
#define TINYGLTF_NO_STB_IMAGE_WRITE
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#define TINYGLTF_ANDROID_LOAD_FROM_ASSETS
# define TINYGLTF_ANDROID_LOAD_FROM_ASSETS
#endif
#include "tiny_gltf.h"
#include <vulkan/vulkan.h>
#include "vulkanexamplebase.h"
#include "VulkanTexture.hpp"
#include "vulkanexamplebase.h"
#include <vulkan/vulkan.h>
#define ENABLE_VALIDATION false
@ -45,20 +45,22 @@
// This class is heavily simplified (compared to glTF's feature set) but retains the basic glTF structure
class VulkanglTFModel
{
public:
vks::VulkanDevice* vulkanDevice;
public:
vks::VulkanDevice *vulkanDevice;
VkQueue copyQueue;
/*
Base glTF structures, see gltfscene sample for details
*/
struct Vertices {
struct Vertices
{
VkBuffer buffer;
VkDeviceMemory memory;
} vertices;
struct Indices {
struct Indices
{
int count;
VkBuffer buffer;
VkDeviceMemory memory;
@ -66,54 +68,56 @@ public:
struct Node;
struct Material {
struct Material
{
glm::vec4 baseColorFactor = glm::vec4(1.0f);
uint32_t baseColorTextureIndex;
};
struct Image {
struct Image
{
vks::Texture2D texture;
VkDescriptorSet descriptorSet;
};
struct Texture {
struct Texture
{
int32_t imageIndex;
};
struct Primitive {
struct Primitive
{
uint32_t firstIndex;
uint32_t indexCount;
int32_t materialIndex;
};
struct Mesh {
struct Mesh
{
std::vector<Primitive> primitives;
};
struct Node {
Node* parent;
struct Node
{
Node * parent;
uint32_t index;
std::vector<Node*> children;
std::vector<Node *> children;
Mesh mesh;
// Matrix components are stored separately as they are affected by animations
glm::vec3 translation{};
glm::vec3 scale{ 1.0f };
glm::vec3 scale{1.0f};
glm::quat rotation{};
// Index of the skin for this node
int32_t skin = -1;
glm::mat4 matrix;
// Gets the current local matrix based on translation, rotation and scale, which can all be affected by animations
glm::mat4 getLocalMatrix();
};
struct Vertex {
struct Vertex
{
glm::vec3 pos;
glm::vec3 normal;
glm::vec2 uv;
glm::vec3 color;
// Contains indices of the joints that effect this vertex
glm::vec4 jointIndices;
// Contains the weights that define how strongly this vertex is affected by above joints
glm::vec4 jointWeights;
};
@ -121,12 +125,12 @@ public:
Skin structure
*/
struct Skin {
struct Skin
{
std::string name;
Node* skeletonRoot = nullptr;
Node * skeletonRoot = nullptr;
std::vector<glm::mat4> inverseBindMatrices;
std::vector<Node*> joints;
// The joint matrices for this skin are stored in an shader storage buffer
std::vector<Node *> joints;
vks::Buffer ssbo;
VkDescriptorSet descriptorSet;
};
@ -135,19 +139,22 @@ public:
Animation related structures
*/
struct AnimationSampler {
struct AnimationSampler
{
std::string interpolation;
std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4;
};
struct AnimationChannel {
struct AnimationChannel
{
std::string path;
Node* node;
Node * node;
uint32_t samplerIndex;
};
struct Animation {
struct Animation
{
std::string name;
std::vector<AnimationSampler> samplers;
std::vector<AnimationChannel> channels;
@ -159,23 +166,23 @@ public:
std::vector<Image> images;
std::vector<Texture> textures;
std::vector<Material> materials;
std::vector<Node*> nodes;
std::vector<Node *> nodes;
std::vector<Skin> skins;
std::vector<Animation> animations;
uint32_t activeAnimation = 0;
~VulkanglTFModel();
void loadImages(tinygltf::Model& input);
void loadTextures(tinygltf::Model& input);
void loadMaterials(tinygltf::Model& input);
Node* findNode(Node* parent, uint32_t index);
Node* nodeFromIndex(uint32_t index);
void loadSkins(tinygltf::Model& input);
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 updateJoints(VulkanglTFModel::Node* node);
void loadImages(tinygltf::Model &input);
void loadTextures(tinygltf::Model &input);
void loadMaterials(tinygltf::Model &input);
Node * findNode(Node *parent, uint32_t index);
Node * nodeFromIndex(uint32_t index);
void loadSkins(tinygltf::Model &input);
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 updateJoints(VulkanglTFModel::Node *node);
void updateAnimation(float deltaTime);
void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node);
void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout);
@ -183,12 +190,14 @@ public:
class VulkanExample : public VulkanExampleBase
{
public:
public:
bool wireframe = false;
struct ShaderData {
struct ShaderData
{
vks::Buffer buffer;
struct Values {
struct Values
{
glm::mat4 projection;
glm::mat4 model;
glm::vec4 lightPos = glm::vec4(5.0f, 5.0f, 5.0f, 1.0f);
@ -196,12 +205,14 @@ public:
} shaderData;
VkPipelineLayout pipelineLayout;
struct Pipelines {
struct Pipelines
{
VkPipeline solid;
VkPipeline wireframe = VK_NULL_HANDLE;
} pipelines;
struct DescriptorSetLayouts {
struct DescriptorSetLayouts
{
VkDescriptorSetLayout matrices;
VkDescriptorSetLayout textures;
VkDescriptorSetLayout jointMatrices;
@ -222,5 +233,5 @@ public:
void updateUniformBuffers();
void prepare();
virtual void render();
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay);
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay);
};