reconstruct gltf loader (not complete yet)
parent
e7d9f78252
commit
f5096914ae
|
@ -532,46 +532,6 @@ void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
|
|||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
glTF material
|
||||
*/
|
||||
void glTFModel::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
|
||||
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptorSetAllocInfo.descriptorPool = descriptorPool;
|
||||
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
|
||||
descriptorSetAllocInfo.descriptorSetCount = 1;
|
||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device->logicalDevice, &descriptorSetAllocInfo, &descriptorSet));
|
||||
std::vector<VkDescriptorImageInfo> imageDescriptors{};
|
||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets{};
|
||||
if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) {
|
||||
imageDescriptors.push_back(baseColorTexture->descriptor);
|
||||
VkWriteDescriptorSet writeDescriptorSet{};
|
||||
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeDescriptorSet.descriptorCount = 1;
|
||||
writeDescriptorSet.dstSet = descriptorSet;
|
||||
writeDescriptorSet.dstBinding = static_cast<uint32_t>(writeDescriptorSets.size());
|
||||
writeDescriptorSet.pImageInfo = &baseColorTexture->descriptor;
|
||||
writeDescriptorSets.push_back(writeDescriptorSet);
|
||||
}
|
||||
if (normalTexture && descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) {
|
||||
imageDescriptors.push_back(normalTexture->descriptor);
|
||||
VkWriteDescriptorSet writeDescriptorSet{};
|
||||
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeDescriptorSet.descriptorCount = 1;
|
||||
writeDescriptorSet.dstSet = descriptorSet;
|
||||
writeDescriptorSet.dstBinding = static_cast<uint32_t>(writeDescriptorSets.size());
|
||||
writeDescriptorSet.pImageInfo = &normalTexture->descriptor;
|
||||
writeDescriptorSets.push_back(writeDescriptorSet);
|
||||
}
|
||||
vkUpdateDescriptorSets(device->logicalDevice, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void VulkanglTFModel::loadMaterials(tinygltf::Model& input)
|
||||
{
|
||||
|
@ -610,81 +570,459 @@ void VulkanglTFModel::loadMaterials(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)
|
||||
|
||||
/*
|
||||
glTF material
|
||||
*/
|
||||
void glTFModel::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags)
|
||||
{
|
||||
VulkanglTFModel::Node* node = new VulkanglTFModel::Node{};
|
||||
node->matrix = glm::mat4(1.0f);
|
||||
node->parent = parent;
|
||||
node->index = nodeIndex;
|
||||
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
|
||||
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptorSetAllocInfo.descriptorPool = descriptorPool;
|
||||
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
|
||||
descriptorSetAllocInfo.descriptorSetCount = 1;
|
||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device->logicalDevice, &descriptorSetAllocInfo, &descriptorSet));
|
||||
std::vector<VkDescriptorImageInfo> imageDescriptors{};
|
||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets{};
|
||||
if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) {
|
||||
imageDescriptors.push_back(baseColorTexture->descriptor);
|
||||
VkWriteDescriptorSet writeDescriptorSet{};
|
||||
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeDescriptorSet.descriptorCount = 1;
|
||||
writeDescriptorSet.dstSet = descriptorSet;
|
||||
writeDescriptorSet.dstBinding = static_cast<uint32_t>(writeDescriptorSets.size());
|
||||
writeDescriptorSet.pImageInfo = &baseColorTexture->descriptor;
|
||||
writeDescriptorSets.push_back(writeDescriptorSet);
|
||||
}
|
||||
if (normalTexture && descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) {
|
||||
imageDescriptors.push_back(normalTexture->descriptor);
|
||||
VkWriteDescriptorSet writeDescriptorSet{};
|
||||
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeDescriptorSet.descriptorCount = 1;
|
||||
writeDescriptorSet.dstSet = descriptorSet;
|
||||
writeDescriptorSet.dstBinding = static_cast<uint32_t>(writeDescriptorSets.size());
|
||||
writeDescriptorSet.pImageInfo = &normalTexture->descriptor;
|
||||
writeDescriptorSets.push_back(writeDescriptorSet);
|
||||
}
|
||||
vkUpdateDescriptorSets(device->logicalDevice, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
glTF primitive
|
||||
*/
|
||||
void glTFModel::Primitive::setDimensions(glm::vec3 min, glm::vec3 max) {
|
||||
dimensions.min = min;
|
||||
dimensions.max = max;
|
||||
dimensions.size = max - min;
|
||||
dimensions.center = (min + max) / 2.0f;
|
||||
dimensions.radius = glm::distance(min, max) / 2.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
glTF mesh
|
||||
*/
|
||||
glTFModel::Mesh::Mesh(vks::VulkanDevice* device, glm::mat4 matrix) {
|
||||
this->device = device;
|
||||
this->uniformBlock.matrix = matrix;
|
||||
VK_CHECK_RESULT(device->createBuffer(
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
sizeof(uniformBlock),
|
||||
&uniformBuffer.buffer,
|
||||
&uniformBuffer.memory,
|
||||
&uniformBlock));
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, uniformBuffer.memory, 0, sizeof(uniformBlock), 0, &uniformBuffer.mapped));
|
||||
uniformBuffer.descriptor = { uniformBuffer.buffer, 0, sizeof(uniformBlock) };
|
||||
};
|
||||
|
||||
glTFModel::Mesh::~Mesh() {
|
||||
vkDestroyBuffer(device->logicalDevice, uniformBuffer.buffer, nullptr);
|
||||
vkFreeMemory(device->logicalDevice, uniformBuffer.memory, nullptr);
|
||||
for (auto primitive : primitives)
|
||||
{
|
||||
delete primitive;
|
||||
}
|
||||
}
|
||||
/*
|
||||
glTF node
|
||||
*/
|
||||
glm::mat4 glTFModel::Node::localMatrix() {
|
||||
return glm::translate(glm::mat4(1.0f), translation) * glm::mat4(rotation) * glm::scale(glm::mat4(1.0f), scale) * matrix;
|
||||
}
|
||||
|
||||
glm::mat4 glTFModel::Node::getMatrix() {
|
||||
glm::mat4 m = localMatrix();
|
||||
glTFModel::Node* p = parent;
|
||||
while (p) {
|
||||
m = p->localMatrix() * m;
|
||||
p = p->parent;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void glTFModel::Node::update() {
|
||||
if (mesh) {
|
||||
glm::mat4 m = getMatrix();
|
||||
if (skin) {
|
||||
mesh->uniformBlock.matrix = m;
|
||||
// Update join matrices
|
||||
glm::mat4 inverseTransform = glm::inverse(m);
|
||||
for (size_t i = 0; i < skin->joints.size(); i++) {
|
||||
glTFModel::Node* jointNode = skin->joints[i];
|
||||
glm::mat4 jointMat = jointNode->getMatrix() * skin->inverseBindMatrices[i];
|
||||
jointMat = inverseTransform * jointMat;
|
||||
mesh->uniformBlock.jointMatrix[i] = jointMat;
|
||||
}
|
||||
mesh->uniformBlock.jointCount = (float)skin->joints.size();
|
||||
memcpy(mesh->uniformBuffer.mapped, &mesh->uniformBlock, sizeof(mesh->uniformBlock));
|
||||
}
|
||||
else {
|
||||
memcpy(mesh->uniformBuffer.mapped, &m, sizeof(glm::mat4));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& child : children) {
|
||||
child->update();
|
||||
}
|
||||
}
|
||||
|
||||
glTFModel::Node::~Node() {
|
||||
if (mesh) {
|
||||
delete mesh;
|
||||
}
|
||||
for (auto& child : children) {
|
||||
delete child;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
glTF default vertex layout with easy Vulkan mapping functions
|
||||
*/
|
||||
|
||||
VkVertexInputBindingDescription glTFModel::Vertex::vertexInputBindingDescription;
|
||||
std::vector<VkVertexInputAttributeDescription> glTFModel::Vertex::vertexInputAttributeDescriptions;
|
||||
VkPipelineVertexInputStateCreateInfo glTFModel::Vertex::pipelineVertexInputStateCreateInfo;
|
||||
|
||||
VkVertexInputBindingDescription glTFModel::Vertex::inputBindingDescription(uint32_t binding) {
|
||||
return VkVertexInputBindingDescription({ binding, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX });
|
||||
}
|
||||
|
||||
VkVertexInputAttributeDescription glTFModel::Vertex::inputAttributeDescription(uint32_t binding, uint32_t location, VertexComponent component) {
|
||||
switch (component) {
|
||||
case VertexComponent::Position:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos) });
|
||||
case VertexComponent::Normal:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal) });
|
||||
case VertexComponent::UV:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv) });
|
||||
case VertexComponent::Color:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, color) });
|
||||
case VertexComponent::Tangent:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, tangent) });
|
||||
case VertexComponent::Joint0:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, joint0) });
|
||||
case VertexComponent::Weight0:
|
||||
return VkVertexInputAttributeDescription({ location, binding, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, weight0) });
|
||||
default:
|
||||
return VkVertexInputAttributeDescription({});
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<VkVertexInputAttributeDescription> glTFModel::Vertex::inputAttributeDescriptions(uint32_t binding, const std::vector<VertexComponent> components) {
|
||||
std::vector<VkVertexInputAttributeDescription> result;
|
||||
uint32_t location = 0;
|
||||
for (VertexComponent component : components) {
|
||||
result.push_back(Vertex::inputAttributeDescription(binding, location, component));
|
||||
location++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* @brief Returns the default pipeline vertex input state create info structure for the requested vertex components */
|
||||
VkPipelineVertexInputStateCreateInfo* glTFModel::Vertex::getPipelineVertexInputState(const std::vector<VertexComponent> components) {
|
||||
vertexInputBindingDescription = Vertex::inputBindingDescription(0);
|
||||
Vertex::vertexInputAttributeDescriptions = Vertex::inputAttributeDescriptions(0, components);
|
||||
pipelineVertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
pipelineVertexInputStateCreateInfo.vertexBindingDescriptionCount = 1;
|
||||
pipelineVertexInputStateCreateInfo.pVertexBindingDescriptions = &Vertex::vertexInputBindingDescription;
|
||||
pipelineVertexInputStateCreateInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(Vertex::vertexInputAttributeDescriptions.size());
|
||||
pipelineVertexInputStateCreateInfo.pVertexAttributeDescriptions = Vertex::vertexInputAttributeDescriptions.data();
|
||||
return &pipelineVertexInputStateCreateInfo;
|
||||
}
|
||||
|
||||
glTFModel::Texture* glTFModel::Model::getTexture(uint32_t index)
|
||||
{
|
||||
|
||||
if (index < textures.size()) {
|
||||
return &textures[index];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void glTFModel::Model::createEmptyTexture(VkQueue transferQueue)
|
||||
{
|
||||
emptyTexture.device = device;
|
||||
emptyTexture.width = 1;
|
||||
emptyTexture.height = 1;
|
||||
emptyTexture.layerCount = 1;
|
||||
emptyTexture.mipLevels = 1;
|
||||
|
||||
size_t bufferSize = emptyTexture.width * emptyTexture.height * 4;
|
||||
unsigned char* buffer = new unsigned char[bufferSize];
|
||||
memset(buffer, 0, bufferSize);
|
||||
|
||||
VkBuffer stagingBuffer;
|
||||
VkDeviceMemory stagingMemory;
|
||||
VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo();
|
||||
bufferCreateInfo.size = bufferSize;
|
||||
// This buffer is used as a transfer source for the buffer copy
|
||||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
|
||||
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
|
||||
VkMemoryRequirements memReqs;
|
||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
|
||||
// Copy texture data into staging buffer
|
||||
uint8_t* data;
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void**)&data));
|
||||
memcpy(data, buffer, bufferSize);
|
||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
||||
|
||||
VkBufferImageCopy bufferCopyRegion = {};
|
||||
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
bufferCopyRegion.imageSubresource.layerCount = 1;
|
||||
bufferCopyRegion.imageExtent.width = emptyTexture.width;
|
||||
bufferCopyRegion.imageExtent.height = emptyTexture.height;
|
||||
bufferCopyRegion.imageExtent.depth = 1;
|
||||
|
||||
// Create optimal tiled target image
|
||||
VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo();
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imageCreateInfo.mipLevels = 1;
|
||||
imageCreateInfo.arrayLayers = 1;
|
||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageCreateInfo.extent = { emptyTexture.width, emptyTexture.height, 1 };
|
||||
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &emptyTexture.image));
|
||||
|
||||
vkGetImageMemoryRequirements(device->logicalDevice, emptyTexture.image, &memReqs);
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &emptyTexture.deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, emptyTexture.image, emptyTexture.deviceMemory, 0));
|
||||
|
||||
VkImageSubresourceRange subresourceRange{};
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
vks::tools::setImageLayout(copyCmd, emptyTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange);
|
||||
vkCmdCopyBufferToImage(copyCmd, stagingBuffer, emptyTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion);
|
||||
vks::tools::setImageLayout(copyCmd, emptyTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresourceRange);
|
||||
device->flushCommandBuffer(copyCmd, transferQueue);
|
||||
emptyTexture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
// Clean up staging resources
|
||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
||||
|
||||
VkSamplerCreateInfo samplerCreateInfo = vks::initializers::samplerCreateInfo();
|
||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
|
||||
samplerCreateInfo.maxAnisotropy = 1.0f;
|
||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &emptyTexture.sampler));
|
||||
|
||||
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
|
||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
viewCreateInfo.subresourceRange.levelCount = 1;
|
||||
viewCreateInfo.image = emptyTexture.image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &emptyTexture.view));
|
||||
|
||||
emptyTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
emptyTexture.descriptor.imageView = emptyTexture.view;
|
||||
emptyTexture.descriptor.sampler = emptyTexture.sampler;
|
||||
}
|
||||
|
||||
/*
|
||||
glTF model loading and rendering class
|
||||
*/
|
||||
glTFModel::Model::~Model()
|
||||
{
|
||||
vkDestroyBuffer(device->logicalDevice, vertices.buffer, nullptr);
|
||||
vkFreeMemory(device->logicalDevice, vertices.memory, nullptr);
|
||||
vkDestroyBuffer(device->logicalDevice, indices.buffer, nullptr);
|
||||
vkFreeMemory(device->logicalDevice, indices.memory, nullptr);
|
||||
for (auto texture : textures) {
|
||||
texture.destroy();
|
||||
}
|
||||
for (auto node : nodes) {
|
||||
delete node;
|
||||
}
|
||||
for (auto skin : skins) {
|
||||
delete skin;
|
||||
}
|
||||
if (descriptorSetLayoutUbo != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorSetLayout(device->logicalDevice, descriptorSetLayoutUbo, nullptr);
|
||||
descriptorSetLayoutUbo = VK_NULL_HANDLE;
|
||||
}
|
||||
if (descriptorSetLayoutImage != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorSetLayout(device->logicalDevice, descriptorSetLayoutImage, nullptr);
|
||||
descriptorSetLayoutImage = VK_NULL_HANDLE;
|
||||
}
|
||||
vkDestroyDescriptorPool(device->logicalDevice, descriptorPool, nullptr);
|
||||
emptyTexture.destroy();
|
||||
}
|
||||
|
||||
void glTFModel::Model::loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, std::vector<uint32_t>& indexBuffer, std::vector<Vertex>& vertexBuffer, float globalscale)
|
||||
{
|
||||
glTFModel::Node* newNode = new Node{};
|
||||
newNode->index = nodeIndex;
|
||||
newNode->name = node.name;
|
||||
newNode->skinIndex = node.skin;
|
||||
newNode->matrix = glm::mat4(1.0f);
|
||||
newNode->parent = parent;
|
||||
|
||||
|
||||
// Get the local node matrix
|
||||
// It's either made up from translation, rotation, scale or a 4x4 matrix
|
||||
if (inputNode.translation.size() == 3) {
|
||||
node->matrix = glm::translate(node->matrix, glm::vec3(glm::make_vec3(inputNode.translation.data())));
|
||||
glm::vec3 translation = glm::vec3(0.0f);
|
||||
if (node.translation.size() == 3) {
|
||||
translation = glm::make_vec3(node.translation.data());
|
||||
newNode->translation = translation;
|
||||
}
|
||||
if (inputNode.rotation.size() == 4) {
|
||||
glm::quat q = glm::make_quat(inputNode.rotation.data());
|
||||
node->matrix *= glm::mat4(q);
|
||||
glm::mat4 rotation = glm::mat4(1.0f);
|
||||
if (node.rotation.size() == 4) {
|
||||
glm::quat q = glm::make_quat(node.rotation.data());
|
||||
newNode->rotation = glm::mat4(q);
|
||||
}
|
||||
if (inputNode.scale.size() == 3) {
|
||||
node->matrix = glm::scale(node->matrix, glm::vec3(glm::make_vec3(inputNode.scale.data())));
|
||||
glm::vec3 scale = glm::vec3(1.0f);
|
||||
if (node.scale.size() == 3) {
|
||||
scale = glm::make_vec3(node.scale.data());
|
||||
newNode->scale = scale;
|
||||
}
|
||||
if (inputNode.matrix.size() == 16) {
|
||||
node->matrix = glm::make_mat4x4(inputNode.matrix.data());
|
||||
if (node.matrix.size() == 16) {
|
||||
newNode->matrix = glm::make_mat4x4(node.matrix.data());
|
||||
if (globalscale != 1.0f) {
|
||||
//newNode->matrix = glm::scale(newNode->matrix, glm::vec3(globalscale));
|
||||
}
|
||||
};
|
||||
|
||||
// Load node's children
|
||||
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 (node.children.size() > 0) {
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
loadNode(newNode, model.nodes[node.children[i]],node.children[i],model,indexBuffer,vertexBuffer,globalscale);
|
||||
}
|
||||
}
|
||||
|
||||
// If the node contains mesh data, we load vertices and indices from the buffers
|
||||
// In glTF this is done via accessors and buffer views
|
||||
if (inputNode.mesh > -1) {
|
||||
const tinygltf::Mesh mesh = input.meshes[inputNode.mesh];
|
||||
if (node.mesh > -1) {
|
||||
const tinygltf::Mesh mesh = model.meshes[node.mesh];
|
||||
|
||||
Mesh* newMesh = new Mesh(device, newNode->matrix);
|
||||
newMesh->name = mesh.name;
|
||||
// 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];
|
||||
const tinygltf::Primitive& primitive = mesh.primitives[i];
|
||||
if (primitive.indices < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint32_t firstIndex = static_cast<uint32_t>(indexBuffer.size());
|
||||
uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
|
||||
uint32_t indexCount = 0;
|
||||
uint32_t vertexCount = 0;
|
||||
glm::vec3 posMin{};
|
||||
glm::vec3 posMax{};
|
||||
bool hasSkin = false;
|
||||
// Vertices
|
||||
{
|
||||
const float* positionBuffer = nullptr;
|
||||
const float* normalsBuffer = nullptr;
|
||||
const float* texCoordsBuffer = nullptr;
|
||||
const float* colorBuffer = nullptr;
|
||||
const float* tangentsBuffer = nullptr;
|
||||
size_t vertexCount = 0;
|
||||
uint32_t colorComponentsNum;
|
||||
const uint16_t* jointsBuffer = nullptr;
|
||||
const float* weightsBuffer = nullptr;
|
||||
|
||||
|
||||
|
||||
// Get buffer data for vertex positions
|
||||
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;
|
||||
if (primitive.attributes.find("POSITION") != primitive.attributes.end()) {
|
||||
const tinygltf::Accessor& positionAccessor = model.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[positionAccessor.bufferView];
|
||||
positionBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[positionAccessor.byteOffset + view.byteOffset]));
|
||||
posMin = glm::vec3(positionAccessor.minValues[0], positionAccessor.minValues[1], positionAccessor.minValues[2]);
|
||||
posMax = glm::vec3(positionAccessor.maxValues[0], positionAccessor.maxValues[1], positionAccessor.maxValues[2]);
|
||||
vertexCount = static_cast<uint32_t>(positionAccessor.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 (primitive.attributes.find("NORMAL") != primitive.attributes.end()) {
|
||||
const tinygltf::Accessor& normalAccessor = model.accessors[primitive.attributes.find("NORMAL")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[normalAccessor.bufferView];
|
||||
normalsBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[normalAccessor.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 (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) {
|
||||
const tinygltf::Accessor& texcoordAccessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[texcoordAccessor.bufferView];
|
||||
texCoordsBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[texcoordAccessor.byteOffset + view.byteOffset]));
|
||||
}
|
||||
// material tangent
|
||||
if (primitive.attributes.find("TANGENT") != primitive.attributes.end())
|
||||
{
|
||||
const tinygltf::Accessor& tangentAccessor = model.accessors[primitive.attributes.find("TANGENT")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[tangentAccessor.bufferView];
|
||||
tangentsBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[tangentAccessor.byteOffset + view.byteOffset]));
|
||||
}
|
||||
//color
|
||||
if (primitive.attributes.find("COLOR_0") != primitive.attributes.end())
|
||||
{
|
||||
const tinygltf::Accessor& colorAccessor = model.accessors[primitive.attributes.find("COLOR_0")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[colorAccessor.bufferView];
|
||||
colorBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[colorAccessor.byteOffset + view.byteOffset]));
|
||||
}
|
||||
// skin joints
|
||||
if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end())
|
||||
{
|
||||
const tinygltf::Accessor& jointsAccessor = model.accessors[primitive.attributes.find("JOINTS_0")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[jointsAccessor.bufferView];
|
||||
jointsBuffer = reinterpret_cast<const uint16_t*>(&(model.buffers[view.buffer].data[jointsAccessor.byteOffset + view.byteOffset]));
|
||||
}
|
||||
// skin weights
|
||||
if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end())
|
||||
{
|
||||
const tinygltf::Accessor& weightsAccessor = model.accessors[primitive.attributes.find("WEIGHTSS_0")->second];
|
||||
const tinygltf::BufferView& view = model.bufferViews[weightsAccessor.bufferView];
|
||||
weightsBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[weightsAccessor.byteOffset + view.byteOffset]));
|
||||
}
|
||||
|
||||
if (glTFPrimitive.attributes.find("TANGENT") != glTFPrimitive.attributes.end())
|
||||
{
|
||||
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("TANGENT")->second];
|
||||
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView];
|
||||
tangentsBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
||||
}
|
||||
hasSkin = (jointsBuffer && weightsBuffer);
|
||||
|
||||
|
||||
|
||||
// Append data to model's vertex buffer
|
||||
for (size_t v = 0; v < vertexCount; v++) {
|
||||
|
@ -692,40 +1030,63 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
|
|||
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.uv = texCoordsBuffer ? glm::make_vec2(&texCoordsBuffer[v * 2]) : glm::vec3(0.0f);
|
||||
vert.tangent = tangentsBuffer ? glm::normalize(glm::make_vec3(&tangentsBuffer[v * 4])) : glm::vec3(0.0f);
|
||||
vert.color = glm::vec3(1.0f, 1.0f, nodeIndex);//Temp set index in color attribute
|
||||
if (colorBuffer)
|
||||
{
|
||||
switch (colorComponentsNum)
|
||||
{
|
||||
case 3 :
|
||||
vert.color = glm::vec4(glm::make_vec3(&colorBuffer[v * 3]), 1.0f);
|
||||
case 4 :
|
||||
vert.color = glm::make_vec4(&colorBuffer[v * 4]);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vert.color = glm::vec4(1.0f);
|
||||
}
|
||||
vert.tangent = tangentsBuffer ? glm::vec4(glm::make_vec4(&tangentsBuffer[v * 4])) : glm::vec4(0.0f);
|
||||
vert.joint0 = hasSkin ? glm::vec4(glm::make_vec4(&jointsBuffer[v * 4])) : glm::vec4(0.0f);
|
||||
vert.weight0 = hasSkin ? glm::make_vec4(&weightsBuffer[v * 4]) : glm::vec4(0.0f);
|
||||
|
||||
vertexBuffer.push_back(vert);
|
||||
}
|
||||
}
|
||||
// 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 = model.accessors[primitive.indices];
|
||||
const tinygltf::BufferView& bufferView = model.bufferViews[accessor.bufferView];
|
||||
const tinygltf::Buffer& buffer = model.buffers[bufferView.buffer];
|
||||
|
||||
indexCount += static_cast<uint32_t>(accessor.count);
|
||||
|
||||
// glTF supports different component types of indices
|
||||
switch (accessor.componentType) {
|
||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
|
||||
const uint32_t* buf = reinterpret_cast<const uint32_t*>(&buffer.data[accessor.byteOffset + bufferView.byteOffset]);
|
||||
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++) {
|
||||
indexBuffer.push_back(buf[index] + vertexStart);
|
||||
}
|
||||
delete[] buf;
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
|
||||
const uint16_t* buf = reinterpret_cast<const uint16_t*>(&buffer.data[accessor.byteOffset + bufferView.byteOffset]);
|
||||
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++) {
|
||||
indexBuffer.push_back(buf[index] + vertexStart);
|
||||
}
|
||||
delete[] buf;
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
|
||||
const uint8_t* buf = reinterpret_cast<const uint8_t*>(&buffer.data[accessor.byteOffset + bufferView.byteOffset]);
|
||||
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++) {
|
||||
indexBuffer.push_back(buf[index] + vertexStart);
|
||||
}
|
||||
delete[] buf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -733,20 +1094,22 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
|
|||
return;
|
||||
}
|
||||
}
|
||||
Primitive primitive{};
|
||||
primitive.firstIndex = firstIndex;
|
||||
primitive.indexCount = indexCount;
|
||||
primitive.materialIndex = glTFPrimitive.material;
|
||||
node->mesh.primitives.push_back(primitive);
|
||||
Primitive* newPrimitive = new Primitive(firstIndex, indexCount, primitive.material > -1 ? materials[primitive.material] : materials.back());
|
||||
newPrimitive->firstVertex = vertexStart;
|
||||
newPrimitive->vertexCount = vertexCount;
|
||||
newPrimitive->setDimensions(posMin, posMax);
|
||||
newMesh->primitives.push_back(newPrimitive);
|
||||
}
|
||||
newNode -> mesh = newMesh;
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent->children.push_back(node);
|
||||
parent->children.push_back(newNode);
|
||||
}
|
||||
else {
|
||||
nodes.push_back(node);
|
||||
nodes.push_back(newNode);
|
||||
}
|
||||
linearNodes.push_back(newNode);
|
||||
}
|
||||
|
||||
VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index)
|
||||
|
|
Loading…
Reference in New Issue