reconstruct gltf loader (not complete yet)

pull/2/head
ink-soul 2023-06-03 10:41:05 +08:00
parent e7d9f78252
commit f5096914ae
1 changed files with 458 additions and 95 deletions

View File

@ -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) 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{}; VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
node->matrix = glm::mat4(1.0f); descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
node->parent = parent; descriptorSetAllocInfo.descriptorPool = descriptorPool;
node->index = nodeIndex; 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 // 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) { glm::vec3 translation = glm::vec3(0.0f);
node->matrix = glm::translate(node->matrix, glm::vec3(glm::make_vec3(inputNode.translation.data()))); if (node.translation.size() == 3) {
translation = glm::make_vec3(node.translation.data());
newNode->translation = translation;
} }
if (inputNode.rotation.size() == 4) { glm::mat4 rotation = glm::mat4(1.0f);
glm::quat q = glm::make_quat(inputNode.rotation.data()); if (node.rotation.size() == 4) {
node->matrix *= glm::mat4(q); glm::quat q = glm::make_quat(node.rotation.data());
newNode->rotation = glm::mat4(q);
} }
if (inputNode.scale.size() == 3) { glm::vec3 scale = glm::vec3(1.0f);
node->matrix = glm::scale(node->matrix, glm::vec3(glm::make_vec3(inputNode.scale.data()))); if (node.scale.size() == 3) {
scale = glm::make_vec3(node.scale.data());
newNode->scale = scale;
} }
if (inputNode.matrix.size() == 16) { if (node.matrix.size() == 16) {
node->matrix = glm::make_mat4x4(inputNode.matrix.data()); 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 // Load node's children
if (inputNode.children.size() > 0) { if (node.children.size() > 0) {
for (size_t i = 0; i < inputNode.children.size(); i++) { for (size_t i = 0; i < node.children.size(); i++) {
loadNode(input.nodes[inputNode.children[i]], input, node, inputNode.children[i], indexBuffer, vertexBuffer); 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 // If the node contains mesh data, we load vertices and indices from 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 (node.mesh > -1) {
const tinygltf::Mesh mesh = input.meshes[inputNode.mesh]; 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 // 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& primitive = mesh.primitives[i];
if (primitive.indices < 0)
{
continue;
}
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());
uint32_t indexCount = 0; uint32_t indexCount = 0;
uint32_t vertexCount = 0;
glm::vec3 posMin{};
glm::vec3 posMax{};
bool hasSkin = false;
// Vertices // Vertices
{ {
const float* positionBuffer = nullptr; const float* positionBuffer = nullptr;
const float* normalsBuffer = nullptr; const float* normalsBuffer = nullptr;
const float* texCoordsBuffer = nullptr; const float* texCoordsBuffer = nullptr;
const float* colorBuffer = nullptr;
const float* tangentsBuffer = 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 // Get buffer data for vertex positions
if (glTFPrimitive.attributes.find("POSITION") != glTFPrimitive.attributes.end()) { if (primitive.attributes.find("POSITION") != primitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("POSITION")->second]; const tinygltf::Accessor& positionAccessor = model.accessors[primitive.attributes.find("POSITION")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView& view = model.bufferViews[positionAccessor.bufferView];
positionBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); positionBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[positionAccessor.byteOffset + view.byteOffset]));
vertexCount = accessor.count; 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 // Get buffer data for vertex normals
if (glTFPrimitive.attributes.find("NORMAL") != glTFPrimitive.attributes.end()) { if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("NORMAL")->second]; const tinygltf::Accessor& normalAccessor = model.accessors[primitive.attributes.find("NORMAL")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView& view = model.bufferViews[normalAccessor.bufferView];
normalsBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); normalsBuffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[normalAccessor.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 (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.attributes.find("TEXCOORD_0")->second]; const tinygltf::Accessor& texcoordAccessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second];
const tinygltf::BufferView& view = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView& view = model.bufferViews[texcoordAccessor.bufferView];
texCoordsBuffer = reinterpret_cast<const float*>(&(input.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); 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()) hasSkin = (jointsBuffer && weightsBuffer);
{
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]));
}
// 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++) {
@ -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.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)));
vert.uv = texCoordsBuffer ? glm::make_vec2(&texCoordsBuffer[v * 2]) : 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); if (colorBuffer)
vert.color = glm::vec3(1.0f, 1.0f, nodeIndex);//Temp set index in color attribute {
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); vertexBuffer.push_back(vert);
} }
} }
// Indices // Indices
{ {
const tinygltf::Accessor& accessor = input.accessors[glTFPrimitive.indices]; const tinygltf::Accessor& accessor = model.accessors[primitive.indices];
const tinygltf::BufferView& bufferView = input.bufferViews[accessor.bufferView]; const tinygltf::BufferView& bufferView = model.bufferViews[accessor.bufferView];
const tinygltf::Buffer& buffer = input.buffers[bufferView.buffer]; const tinygltf::Buffer& buffer = model.buffers[bufferView.buffer];
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: {
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++) { for (size_t index = 0; index < accessor.count; index++) {
indexBuffer.push_back(buf[index] + vertexStart); indexBuffer.push_back(buf[index] + vertexStart);
} }
delete[] buf;
break; break;
} }
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: { 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++) { for (size_t index = 0; index < accessor.count; index++) {
indexBuffer.push_back(buf[index] + vertexStart); indexBuffer.push_back(buf[index] + vertexStart);
} }
delete[] buf;
break; break;
} }
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: { 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++) { for (size_t index = 0; index < accessor.count; index++) {
indexBuffer.push_back(buf[index] + vertexStart); indexBuffer.push_back(buf[index] + vertexStart);
} }
delete[] buf;
break; break;
} }
default: default:
@ -733,20 +1094,22 @@ void VulkanglTFModel::loadNode(const tinygltf::Node& inputNode, const tinygltf::
return; return;
} }
} }
Primitive primitive{}; Primitive* newPrimitive = new Primitive(firstIndex, indexCount, primitive.material > -1 ? materials[primitive.material] : materials.back());
primitive.firstIndex = firstIndex; newPrimitive->firstVertex = vertexStart;
primitive.indexCount = indexCount; newPrimitive->vertexCount = vertexCount;
primitive.materialIndex = glTFPrimitive.material; newPrimitive->setDimensions(posMin, posMax);
node->mesh.primitives.push_back(primitive); newMesh->primitives.push_back(newPrimitive);
} }
newNode -> mesh = newMesh;
} }
if (parent) { if (parent) {
parent->children.push_back(node); parent->children.push_back(newNode);
} }
else { else {
nodes.push_back(node); nodes.push_back(newNode);
} }
linearNodes.push_back(newNode);
} }
VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index) VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index)