diff --git a/base/VulkanglTFModel.hpp b/base/VulkanglTFModel.hpp index 73ab2497..0f9235a5 100644 --- a/base/VulkanglTFModel.hpp +++ b/base/VulkanglTFModel.hpp @@ -332,6 +332,8 @@ namespace vkglTF struct Primitive { uint32_t firstIndex; uint32_t indexCount; + uint32_t firstVertex; + uint32_t vertexCount; Material &material; struct Dimensions { @@ -503,6 +505,44 @@ namespace vkglTF float end = std::numeric_limits::min(); }; + /* + glTF default vertex layout with easy Vulkan mapping functions + */ + enum class VertexComponent { Position, Normal, UV, Color, Joint0, Weight0 }; + + struct Vertex { + glm::vec3 pos; + glm::vec3 normal; + glm::vec2 uv; + glm::vec4 color; + glm::vec4 joint0; + glm::vec4 weight0; + static VkVertexInputBindingDescription inputBindingDescription(uint32_t binding) { + return VkVertexInputBindingDescription({ binding, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX }); + } + static VkVertexInputAttributeDescription 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::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) }); + } + } + }; + + typedef enum FileLoadingFlags { + None = 0, + PreTransformVertices = 1, + }; + /* glTF model loading and rendering class */ @@ -512,14 +552,6 @@ namespace vkglTF VkDescriptorPool descriptorPool; VkDescriptorSetLayout descriptorSetLayout; - struct Vertex { - glm::vec3 pos; - glm::vec3 normal; - glm::vec2 uv; - glm::vec4 joint0; - glm::vec4 weight0; - }; - struct Vertices { VkBuffer buffer; VkDeviceMemory memory; @@ -619,6 +651,7 @@ namespace vkglTF uint32_t indexStart = static_cast(indexBuffer.size()); uint32_t vertexStart = static_cast(vertexBuffer.size()); uint32_t indexCount = 0; + uint32_t vertexCount = 0; glm::vec3 posMin{}; glm::vec3 posMax{}; bool hasSkin = false; @@ -627,6 +660,8 @@ namespace vkglTF const float *bufferPos = nullptr; const float *bufferNormals = nullptr; const float *bufferTexCoords = nullptr; + const float* bufferColors = nullptr; + uint32_t numColorComponents; const uint16_t *bufferJoints = nullptr; const float *bufferWeights = nullptr; @@ -650,6 +685,13 @@ namespace vkglTF const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView]; bufferTexCoords = reinterpret_cast(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); } + if (primitive.attributes.find("COLOR_0") != primitive.attributes.end()) { + const tinygltf::Accessor& colorAccessor = model.accessors[primitive.attributes.find("COLOR_0")->second]; + const tinygltf::BufferView& colorView = model.bufferViews[colorAccessor.bufferView]; + // Color buffer are either of type vec3 or vec4 + numColorComponents = colorAccessor.type == TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3 ? 3 : 4; + bufferColors = reinterpret_cast(&(model.buffers[colorView.buffer].data[colorAccessor.byteOffset + colorView.byteOffset])); + } // Skinning // Joints @@ -667,12 +709,24 @@ namespace vkglTF hasSkin = (bufferJoints && bufferWeights); + vertexCount = static_cast(posAccessor.count); + for (size_t v = 0; v < posAccessor.count; v++) { Vertex vert{}; vert.pos = glm::vec4(glm::make_vec3(&bufferPos[v * 3]), 1.0f); vert.normal = glm::normalize(glm::vec3(bufferNormals ? glm::make_vec3(&bufferNormals[v * 3]) : glm::vec3(0.0f))); vert.uv = bufferTexCoords ? glm::make_vec2(&bufferTexCoords[v * 2]) : glm::vec3(0.0f); - + if (bufferColors) { + switch (numColorComponents) { + case 3: + vert.color = glm::vec4(glm::make_vec3(&bufferColors[v * 3]), 1.0f); + case 4: + vert.color = glm::make_vec4(&bufferColors[v * 4]); + } + } + else { + vert.color = glm::vec4(1.0f); + } vert.joint0 = hasSkin ? glm::vec4(glm::make_vec4(&bufferJoints[v * 4])) : glm::vec4(0.0f); vert.weight0 = hasSkin ? glm::make_vec4(&bufferWeights[v * 4]) : glm::vec4(0.0f); vertexBuffer.push_back(vert); @@ -717,6 +771,8 @@ namespace vkglTF } } Primitive *newPrimitive = new Primitive(indexStart, indexCount, materials[primitive.material]); + newPrimitive->firstVertex = vertexStart; + newPrimitive->vertexCount = vertexCount; newPrimitive->setDimensions(posMin, posMax); newMesh->primitives.push_back(newPrimitive); } @@ -929,7 +985,7 @@ namespace vkglTF } } - void loadFromFile(std::string filename, vks::VulkanDevice *device, VkQueue transferQueue, float scale = 1.0f) + void loadFromFile(std::string filename, vks::VulkanDevice *device, VkQueue transferQueue, uint32_t fileLoadingFlags = vkglTF::FileLoadingFlags::None, float scale = 1.0f) { tinygltf::Model gltfModel; tinygltf::TinyGLTF gltfContext; @@ -984,6 +1040,20 @@ namespace vkglTF return; } + // Pre-transform all vertices by the node matrix hierarchy if requested + if (fileLoadingFlags & FileLoadingFlags::PreTransformVertices) { + for (Node* node : linearNodes) { + const glm::mat4 localMatrix = node->getMatrix(); + if (node->mesh) { + for (Primitive* primitive : node->mesh->primitives) { + for (uint32_t i = 0; i < primitive->vertexCount; i++) { + vertexBuffer[primitive->firstVertex + i].pos = glm::vec3(localMatrix * glm::vec4(vertexBuffer[primitive->firstVertex + i].pos, 1.0f)); + } + } + } + } + } + for (auto extension : gltfModel.extensionsUsed) { if (extension == "KHR_materials_pbrSpecularGlossiness") { std::cout << "Required extension: " << extension; diff --git a/examples/conditionalrender/conditionalrender.cpp b/examples/conditionalrender/conditionalrender.cpp index 061d224e..20112e23 100644 --- a/examples/conditionalrender/conditionalrender.cpp +++ b/examples/conditionalrender/conditionalrender.cpp @@ -221,17 +221,15 @@ public: VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast(dynamicStateEnables.size()), 0); // Vertex bindings and attributes - const std::vector vertexInputBindings = { - vks::initializers::vertexInputBindingDescription(0, sizeof(vkglTF::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX), - }; + VkVertexInputBindingDescription vertexInputBinding = vkglTF::Vertex::inputBindingDescription(0); const std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position - vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal - vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // Location 2: UV + vkglTF::Vertex::inputAttributeDescription(0, 0, vkglTF::VertexComponent::Position), + vkglTF::Vertex::inputAttributeDescription(0, 1, vkglTF::VertexComponent::Normal), + vkglTF::Vertex::inputAttributeDescription(0, 2, vkglTF::VertexComponent::UV) }; VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertexInputState.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); - vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexBindingDescriptionCount = 1; + vertexInputState.pVertexBindingDescriptions = &vertexInputBinding; vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();