plumageRender/base/VulkanglTFModel.h

308 lines
8.4 KiB
C
Raw Normal View History

2023-05-17 14:49:05 +08:00
/*
* Vulkan glTF model and texture loading class based on tinyglTF (https://github.com/syoyo/tinygltf)
*
* Copyright (C) 2018 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <stdlib.h>
#include <string>
#include <fstream>
#include <vector>
#include "vulkan/vulkan.h"
#include "VulkanDevice.h"
#include <ktx.h>
#include <ktxvulkan.h>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#define TINYGLTF_NO_STB_IMAGE_WRITE
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#define TINYGLTF_ANDROID_LOAD_FROM_ASSETS
#endif
#include "tiny_gltf.h"
#if defined(__ANDROID__)
#include <android/asset_manager.h>
#endif
namespace vkglTF
{
enum DescriptorBindingFlags {
ImageBaseColor = 0x00000001,
ImageNormalMap = 0x00000002
};
extern VkDescriptorSetLayout descriptorSetLayoutImage;
extern VkDescriptorSetLayout descriptorSetLayoutUbo;
extern VkMemoryPropertyFlags memoryPropertyFlags;
extern uint32_t descriptorBindingFlags;
struct Node;
/*
glTF texture loading class
*/
struct Texture {
vks::VulkanDevice* device = nullptr;
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();
void fromglTfImage(tinygltf::Image& gltfimage, std::string path, vks::VulkanDevice* device, VkQueue copyQueue);
};
/*
glTF material class
*/
struct Material {
vks::VulkanDevice* device = nullptr;
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);
vkglTF::Texture* baseColorTexture = nullptr;
vkglTF::Texture* metallicRoughnessTexture = nullptr;
vkglTF::Texture* normalTexture = nullptr;
vkglTF::Texture* occlusionTexture = nullptr;
vkglTF::Texture* emissiveTexture = nullptr;
vkglTF::Texture* specularGlossinessTexture;
vkglTF::Texture* diffuseTexture;
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
Material(vks::VulkanDevice* device) : device(device) {};
void createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags);
};
/*
glTF primitive
*/
struct Primitive {
uint32_t firstIndex;
uint32_t indexCount;
uint32_t firstVertex;
uint32_t vertexCount;
Material& material;
struct Dimensions {
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
glm::vec3 size;
glm::vec3 center;
float radius;
} dimensions;
void setDimensions(glm::vec3 min, glm::vec3 max);
Primitive(uint32_t firstIndex, uint32_t indexCount, Material& material) : firstIndex(firstIndex), indexCount(indexCount), material(material) {};
};
/*
glTF mesh
*/
struct Mesh {
vks::VulkanDevice* device;
std::vector<Primitive*> primitives;
std::string name;
struct UniformBuffer {
VkBuffer buffer;
VkDeviceMemory memory;
VkDescriptorBufferInfo descriptor;
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
void* mapped;
} uniformBuffer;
struct UniformBlock {
glm::mat4 matrix;
glm::mat4 jointMatrix[64]{};
float jointcount{ 0 };
} uniformBlock;
Mesh(vks::VulkanDevice* device, glm::mat4 matrix);
~Mesh();
};
/*
glTF skin
*/
struct Skin {
std::string name;
Node* skeletonRoot = nullptr;
std::vector<glm::mat4> inverseBindMatrices;
std::vector<Node*> joints;
};
/*
glTF node
*/
struct Node {
Node* parent;
uint32_t index;
std::vector<Node*> 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{};
glm::mat4 localMatrix();
glm::mat4 getMatrix();
void update();
~Node();
};
/*
glTF animation channel
*/
struct AnimationChannel {
enum PathType { TRANSLATION, ROTATION, SCALE };
PathType path;
Node* node;
uint32_t samplerIndex;
};
/*
glTF animation sampler
*/
struct AnimationSampler {
enum InterpolationType { LINEAR, STEP, CUBICSPLINE };
InterpolationType interpolation;
std::vector<float> inputs;
std::vector<glm::vec4> outputsVec4;
};
/*
glTF animation
*/
struct Animation {
std::string name;
std::vector<AnimationSampler> samplers;
std::vector<AnimationChannel> channels;
float start = std::numeric_limits<float>::max();
float end = std::numeric_limits<float>::min();
};
/*
glTF default vertex layout with easy Vulkan mapping functions
*/
enum class VertexComponent { Position, Normal, UV, Color, Tangent, Joint0, Weight0 };
struct Vertex {
glm::vec3 pos;
glm::vec3 normal;
glm::vec2 uv;
glm::vec4 color;
glm::vec4 joint0;
glm::vec4 weight0;
glm::vec4 tangent;
static VkVertexInputBindingDescription vertexInputBindingDescription;
static std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
static VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo;
static VkVertexInputBindingDescription inputBindingDescription(uint32_t binding);
static VkVertexInputAttributeDescription inputAttributeDescription(uint32_t binding, uint32_t location, VertexComponent component);
static std::vector<VkVertexInputAttributeDescription> inputAttributeDescriptions(uint32_t binding, const std::vector<VertexComponent> components);
/** @brief Returns the default pipeline vertex input state create info structure for the requested vertex components */
static VkPipelineVertexInputStateCreateInfo* getPipelineVertexInputState(const std::vector<VertexComponent> components);
};
enum FileLoadingFlags {
None = 0x00000000,
PreTransformVertices = 0x00000001,
PreMultiplyVertexColors = 0x00000002,
FlipY = 0x00000004,
DontLoadImages = 0x00000008
};
enum RenderFlags {
BindImages = 0x00000001,
RenderOpaqueNodes = 0x00000002,
RenderAlphaMaskedNodes = 0x00000004,
RenderAlphaBlendedNodes = 0x00000008
};
/*
glTF model loading and rendering class
*/
class Model {
private:
vkglTF::Texture* getTexture(uint32_t index);
vkglTF::Texture emptyTexture;
void createEmptyTexture(VkQueue transferQueue);
public:
vks::VulkanDevice* device;
VkDescriptorPool descriptorPool;
struct Vertices {
int count;
VkBuffer buffer;
VkDeviceMemory memory;
} vertices;
struct Indices {
int count;
VkBuffer buffer;
VkDeviceMemory memory;
} indices;
std::vector<Node*> nodes;
std::vector<Node*> linearNodes;
std::vector<Skin*> skins;
std::vector<Texture> textures;
std::vector<Material> materials;
std::vector<Animation> animations;
struct Dimensions {
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
glm::vec3 size;
glm::vec3 center;
float radius;
} dimensions;
bool metallicRoughnessWorkflow = true;
bool buffersBound = false;
std::string path;
Model() {};
~Model();
void loadNode(vkglTF::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, std::vector<uint32_t>& indexBuffer, std::vector<Vertex>& vertexBuffer, float globalscale);
void loadSkins(tinygltf::Model& gltfModel);
void loadImages(tinygltf::Model& gltfModel, vks::VulkanDevice* device, VkQueue transferQueue);
void loadMaterials(tinygltf::Model& gltfModel);
void loadAnimations(tinygltf::Model& gltfModel);
void loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, uint32_t fileLoadingFlags = vkglTF::FileLoadingFlags::None, float scale = 1.0f);
void bindBuffers(VkCommandBuffer commandBuffer);
void drawNode(Node* node, VkCommandBuffer commandBuffer, uint32_t renderFlags = 0, VkPipelineLayout pipelineLayout = VK_NULL_HANDLE, uint32_t bindImageSet = 1);
void draw(VkCommandBuffer commandBuffer, uint32_t renderFlags = 0, VkPipelineLayout pipelineLayout = VK_NULL_HANDLE, uint32_t bindImageSet = 1);
void getNodeDimensions(Node* node, glm::vec3& min, glm::vec3& max);
void getSceneDimensions();
void updateAnimation(uint32_t index, float time);
Node* findNode(Node* parent, uint32_t index);
Node* nodeFromIndex(uint32_t index);
void prepareNodeDescriptor(vkglTF::Node* node, VkDescriptorSetLayout descriptorSetLayout);
};
}