#pragma once #include #include #include #include #include #include #include #ifndef GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS #endif #ifndef GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE #endif #include #include #include #ifndef TINYGLTF_NO_STB_IMAGE_WRITE #define TINYGLTF_NO_STB_IMAGE_WRITE #endif // #ifdef VK_USE_PLATFORM_ANDROID_KHR #define TINYGLTF_ANDROID_LOAD_FROM_ASSETS #endif #include "tiny_gltf.h" #include "VulkanDevice.hpp" //#include "VulkanUtils.hpp" #include "vulkan/vulkan.h" #define ENABLE_VALIDATION false #define MAX_NUM_JOINTS 128u // Contains everything required to render a glTF model in Vulkan // This class is heavily simplified (compared to glTF's feature set) but retains the basic glTF structure namespace glTFModel { struct Node; struct BoundingBox { glm::vec3 min; glm::vec3 max; bool valid = false; BoundingBox(); BoundingBox(glm::vec3 min, glm::vec3 max); BoundingBox getAABB(glm::mat4 m); }; struct TextureSampler { VkFilter magFilter; VkFilter minFilter; VkSamplerAddressMode addressModeU; VkSamplerAddressMode addressModeV; VkSamplerAddressMode addressModeW; }; struct Texture { vks::VulkanDevice* device; VkImage image; VkImageLayout imageLayout; VkDeviceMemory deviceMemory; VkImageView view; uint32_t width, height; uint32_t mipLevels; uint32_t layerCount; VkDescriptorImageInfo descriptor; VkSampler sampler; void updateDescriptor(); void destroy(); // Load a texture from a glTF image (stored as vector of chars loaded via stb_image) and generate a full mip chaing for it void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, vks::VulkanDevice* device, VkQueue copyQueue); }; struct Material { enum AlphaMode { ALPHAMODE_OPAQUE, ALPHAMODE_MASK, ALPHAMODE_BLEND }; AlphaMode alphaMode = ALPHAMODE_OPAQUE; float alphaCutoff = 1.0f; float metallicFactor = 1.0f; float roughnessFactor = 1.0f; glm::vec4 baseColorFactor = glm::vec4(1.0f); glm::vec4 emissiveFactor = glm::vec4(1.0f); glTFModel::Texture* baseColorTexture; glTFModel::Texture* metallicRoughnessTexture; glTFModel::Texture* normalTexture; glTFModel::Texture* occlusionTexture; glTFModel::Texture* emissiveTexture; bool doubleSided = false; struct TexCoordSets { uint8_t baseColor = 0; uint8_t metallicRoughness = 0; uint8_t specularGlossiness = 0; uint8_t normal = 0; uint8_t occlusion = 0; uint8_t emissive = 0; } texCoordSets; struct Extension { glTFModel::Texture* specularGlossinessTexture; glTFModel::Texture* diffuseTexture; glm::vec4 diffuseFactor = glm::vec4(1.0f); glm::vec3 specularFactor = glm::vec3(0.0f); } extension; struct PbrWorkflows { bool metallicRoughness = true; bool specularGlossiness = false; } pbrWorkflows; VkDescriptorSet descriptorSet = VK_NULL_HANDLE; }; struct Primitive { uint32_t firstIndex; uint32_t indexCount; uint32_t vertexCount; Material& material; bool hasIndices; BoundingBox bb; Primitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, Material& material); void setBoundingBox(glm::vec3 min, glm::vec3 max); }; struct Mesh { vks::VulkanDevice* device; std::vector primitives; BoundingBox bb; BoundingBox aabb; struct UniformBuffer { VkBuffer buffer; VkDeviceMemory memory; VkDescriptorBufferInfo descriptor; VkDescriptorSet descriptorSet; void* mapped; } uniformBuffer; struct UniformBlock { glm::mat4 matrix; glm::mat4 jointMatrix[128]{}; float jointcount{ 0 }; } uniformBlock; Mesh(vks::VulkanDevice* device, glm::mat4 matrix); ~Mesh(); void setBoundingBox(glm::vec3 min, glm::vec3 max); }; struct Skin { std::string name; Node* skeletonRoot = nullptr; std::vector inverseBindMatrices; std::vector joints; }; struct Node { Node* parent; uint32_t index; std::vector children; glm::mat4 matrix; std::string name; Mesh* mesh; Skin* skin; int32_t skinIndex = -1; glm::vec3 translation{}; glm::vec3 scale{ 1.0f }; glm::quat rotation{}; BoundingBox bvh; BoundingBox aabb; glm::mat4 localMatrix(); glm::mat4 getMatrix(); void update(); ~Node(); }; struct AnimationChannel { enum PathType { TRANSLATION, ROTATION, SCALE }; PathType path; Node* node; uint32_t samplerIndex; }; struct AnimationSampler { enum InterpolationType { LINEAR, STEP, CUBICSPLINE }; InterpolationType interpolation; std::vector inputs; std::vector outputsVec4; }; struct Animation { std::string name; std::vector samplers; std::vector channels; float start = std::numeric_limits::max(); float end = std::numeric_limits::min(); }; struct Model { vks::VulkanDevice* device; struct Vertex { glm::vec3 pos; glm::vec3 normal; glm::vec2 uv0; glm::vec2 uv1; glm::vec4 joint0; glm::vec4 weight0; glm::vec4 color; }; struct Vertices { VkBuffer buffer = VK_NULL_HANDLE; VkDeviceMemory memory; } vertices; struct Indices { VkBuffer buffer = VK_NULL_HANDLE; VkDeviceMemory memory; } indices; glm::mat4 aabb; std::vector nodes; std::vector linearNodes; std::vector skins; std::vector textures; std::vector textureSamplers; std::vector materials; std::vector animations; std::vector extensions; struct Dimensions { glm::vec3 min = glm::vec3(FLT_MAX); glm::vec3 max = glm::vec3(-FLT_MAX); } dimensions; struct LoaderInfo { uint32_t* indexBuffer; Vertex* vertexBuffer; size_t indexPos = 0; size_t vertexPos = 0; }; void destroy(VkDevice device); void loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale); void getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount); void loadSkins(tinygltf::Model& gltfModel); void loadTextures(tinygltf::Model& gltfModel, vks::VulkanDevice* device, VkQueue transferQueue); VkSamplerAddressMode getVkWrapMode(int32_t wrapMode); VkFilter getVkFilterMode(int32_t filterMode); void loadTextureSamplers(tinygltf::Model& gltfModel); void loadMaterials(tinygltf::Model& gltfModel); void loadAnimations(tinygltf::Model& gltfModel); void loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f); void drawNode(Node* node, VkCommandBuffer commandBuffer); void draw(VkCommandBuffer commandBuffer); void calculateBoundingBox(Node* node, Node* parent); void getSceneDimensions(); void updateAnimation(uint32_t index, float time); Node* findNode(Node* parent, uint32_t index); Node* nodeFromIndex(uint32_t index); }; }