#pragma once #include "VulkanApp.h" #include #include #include #include #include #include "LineCanvas.h" #include "UtilsAnim.h" #include enum MaterialType : uint32_t { MaterialType_Invalid = 0, MaterialType_Unlit = 0x80, MaterialType_MetallicRoughness = 0x1, MaterialType_SpecularGlossiness = 0x2, MaterialType_Sheen = 0x4, MaterialType_ClearCoat = 0x8, MaterialType_Specular = 0x10, MaterialType_Transmission = 0x20, MaterialType_Volume = 0x40, }; const uint32_t kMaxMaterials = 128; const uint32_t kMaxEnvironments = 4; const uint32_t kMaxLights = 8; using glm::mat4; using glm::quat; using glm::vec2; using glm::vec3; using glm::vec4; inline mat4 aiMatrix4x4ToMat4(const aiMatrix4x4& from) { mat4 to; to[0][0] = (float)from.a1; to[0][1] = (float)from.b1; to[0][2] = (float)from.c1; to[0][3] = (float)from.d1; to[1][0] = (float)from.a2; to[1][1] = (float)from.b2; to[1][2] = (float)from.c2; to[1][3] = (float)from.d2; to[2][0] = (float)from.a3; to[2][1] = (float)from.b3; to[2][2] = (float)from.c3; to[2][3] = (float)from.d3; to[3][0] = (float)from.a4; to[3][1] = (float)from.b4; to[3][2] = (float)from.c4; to[3][3] = (float)from.d4; return to; } inline vec3 aiVector3DToVec3(const aiVector3D& from) { return vec3(from.x, from.y, from.z); } inline glm::quat aiQuaternionToQuat(const aiQuaternion& from) { return glm::quat(from.w, from.x, from.y, from.z); } enum LightType : uint32_t { LightType_Directional = 0, LightType_Point = 1, LightType_Spot = 2, }; struct EnvironmentMapDataGPU { uint32_t envMapTexture = 0; uint32_t envMapTextureSampler = 0; uint32_t envMapTextureIrradiance = 0; uint32_t envMapTextureIrradianceSampler = 0; uint32_t lutBRDFTexture = 0; uint32_t lutBRDFTextureSampler = 0; uint32_t envMapTextureCharlie = 0; uint32_t envMapTextureCharlieSampler = 0; }; struct LightDataGPU { vec3 direction = vec3(0, 0, 1); float range = 10000.0; vec3 color = vec3(1, 1, 1); float intensity = 1.0; vec3 position = vec3(0, 0, -5); float innerConeCos = 0.0; float outerConeCos = 0.78; LightType type = LightType_Directional; int nodeId = ~0; int padding = 0; }; struct GLTFGlobalSamplers { explicit GLTFGlobalSamplers(const std::unique_ptr& ctx) { clamp = ctx->createSampler({ .minFilter = lvk::SamplerFilter::SamplerFilter_Linear, .magFilter = lvk::SamplerFilter::SamplerFilter_Linear, .mipMap = lvk::SamplerMip::SamplerMip_Linear, .wrapU = lvk::SamplerWrap::SamplerWrap_Clamp, .wrapV = lvk::SamplerWrap::SamplerWrap_Clamp, .wrapW = lvk::SamplerWrap::SamplerWrap_Clamp, .debugName = "Clamp Sampler", }); wrap = ctx->createSampler({ .minFilter = lvk::SamplerFilter::SamplerFilter_Linear, .magFilter = lvk::SamplerFilter::SamplerFilter_Linear, .mipMap = lvk::SamplerMip::SamplerMip_Linear, .wrapU = lvk::SamplerWrap::SamplerWrap_Repeat, .wrapV = lvk::SamplerWrap::SamplerWrap_Repeat, .wrapW = lvk::SamplerWrap::SamplerWrap_Repeat, .debugName = "Wrap Sampler", }); mirror = ctx->createSampler({ .minFilter = lvk::SamplerFilter::SamplerFilter_Linear, .magFilter = lvk::SamplerFilter::SamplerFilter_Linear, .mipMap = lvk::SamplerMip::SamplerMip_Linear, .wrapU = lvk::SamplerWrap::SamplerWrap_MirrorRepeat, .wrapV = lvk::SamplerWrap::SamplerWrap_MirrorRepeat, .debugName = "Mirror Sampler", }); } lvk::Holder clamp; lvk::Holder wrap; lvk::Holder mirror; }; struct EnvironmentsPerFrame { EnvironmentMapDataGPU environments[kMaxEnvironments]; }; struct Vertex { vec3 position; vec3 normal; vec4 color; vec2 uv0; vec2 uv1; float padding[2]; }; struct MorphTarget { uint32_t meshId = ~0; std::vector offset; }; static_assert(sizeof(Vertex) == sizeof(uint32_t) * 16); struct GLTFMaterialTextures { // Metallic Roughness / SpecluarGlossiness lvk::Holder baseColorTexture; lvk::Holder surfacePropertiesTexture; // Common properties lvk::Holder normalTexture; lvk::Holder occlusionTexture; lvk::Holder emissiveTexture; // Sheen lvk::Holder sheenColorTexture; lvk::Holder sheenRoughnessTexture; // Clearcoat lvk::Holder clearCoatTexture; lvk::Holder clearCoatRoughnessTexture; lvk::Holder clearCoatNormalTexture; // Specular lvk::Holder specularTexture; lvk::Holder specularColorTexture; // Transmission lvk::Holder transmissionTexture; // Volumen lvk::Holder thicknessTexture; // Iridescence lvk::Holder iridescenceTexture; lvk::Holder iridescenceThicknessTexture; // Anisotropy lvk::Holder anisotropyTexture; lvk::Holder white; bool wasLoaded = false; }; struct EnvironmentMapTextures { explicit EnvironmentMapTextures(const std::unique_ptr& ctx) : EnvironmentMapTextures( ctx, "data/brdfLUT.ktx", "data/piazza_bologni_1k_prefilter.ktx", "data/piazza_bologni_1k_irradiance.ktx", "data/piazza_bologni_1k_charlie.ktx") { } EnvironmentMapTextures( const std::unique_ptr& ctx, const char* brdfLUT, const char* prefilter, const char* irradiance, const char* prefilterCharlie = nullptr) { texBRDF_LUT = loadTexture(ctx, brdfLUT, lvk::TextureType_2D); if (texBRDF_LUT.empty()) { assert(0); exit(255); } envMapTexture = loadTexture(ctx, prefilter, lvk::TextureType_Cube); if (envMapTexture.empty()) { assert(0); exit(255); } envMapTextureIrradiance = loadTexture(ctx, irradiance, lvk::TextureType_Cube); if (envMapTextureIrradiance.empty()) { assert(0); exit(255); } if (prefilterCharlie) { envMapTextureCharlie = loadTexture(ctx, prefilterCharlie, lvk::TextureType_Cube); if (envMapTextureCharlie.empty()) { assert(0); exit(255); } } } lvk::Holder texBRDF_LUT; lvk::Holder envMapTexture; lvk::Holder envMapTextureCharlie; lvk::Holder envMapTextureIrradiance; }; bool assignUVandSampler( const GLTFGlobalSamplers& samplers, const aiMaterial* mtlDescriptor, aiTextureType textureType, uint32_t& uvIndex, uint32_t& textureSampler, int index = 0); struct GLTFMaterialDataGPU { vec4 baseColorFactor = vec4(1.0f, 1.0f, 1.0f, 1.0f); vec4 metallicRoughnessNormalOcclusion = vec4(1.0f, 1.0f, 1.0f, 1.0f); // Packed metallicFactor, roughnessFactor, normalScale, occlusionStrength vec4 specularGlossiness = vec4(1.0f, 1.0f, 1.0f, 1.0f); vec4 sheenFactors = vec4(1.0f, 1.0f, 1.0f, 1.0f); // Sheen vec4 clearcoatTransmissionThickness = vec4(1.0f, 1.0f, 1.0f, 1.0f); // Clearcoat vec4 specularFactors = vec4(1.0f, 1.0f, 1.0f, 1.0f); vec4 attenuation = vec4(1.0f, 1.0f, 1.0f, 1.0f); vec4 emissiveFactorAlphaCutoff = vec4(0.0f, 0.0f, 0.0f, 0.5f); uint32_t occlusionTexture = 0; uint32_t occlusionTextureSampler = 0; uint32_t occlusionTextureUV = 0; uint32_t emissiveTexture = 0; uint32_t emissiveTextureSampler = 0; uint32_t emissiveTextureUV = 0; uint32_t baseColorTexture = 0; uint32_t baseColorTextureSampler = 0; uint32_t baseColorTextureUV = 0; uint32_t surfacePropertiesTexture = 0; uint32_t surfacePropertiesTextureSampler = 0; uint32_t surfacePropertiesTextureUV = 0; uint32_t normalTexture = 0; uint32_t normalTextureSampler = 0; uint32_t normalTextureUV = 0; uint32_t sheenColorTexture = 0; uint32_t sheenColorTextureSampler = 0; uint32_t sheenColorTextureUV = 0; uint32_t sheenRoughnessTexture = 0; uint32_t sheenRoughnessTextureSampler = 0; uint32_t sheenRoughnessTextureUV = 0; uint32_t clearCoatTexture = 0; uint32_t clearCoatTextureSampler = 0; uint32_t clearCoatTextureUV = 0; uint32_t clearCoatRoughnessTexture = 0; uint32_t clearCoatRoughnessTextureSampler = 0; uint32_t clearCoatRoughnessTextureUV = 0; uint32_t clearCoatNormalTexture = 0; uint32_t clearCoatNormalTextureSampler = 0; uint32_t clearCoatNormalTextureUV = 0; uint32_t specularTexture = 0; uint32_t specularTextureSampler = 0; uint32_t specularTextureUV = 0; uint32_t specularColorTexture = 0; uint32_t specularColorTextureSampler = 0; uint32_t specularColorTextureUV = 0; uint32_t transmissionTexture = 0; uint32_t transmissionTextureSampler = 0; uint32_t transmissionTextureUV = 0; uint32_t thicknessTexture = 0; uint32_t thicknessTextureSampler = 0; uint32_t thicknessTextureUV = 0; uint32_t iridescenceTexture = 0; uint32_t iridescenceTextureSampler = 0; uint32_t iridescenceTextureUV = 0; uint32_t iridescenceThicknessTexture = 0; uint32_t iridescenceThicknessTextureSampler = 0; uint32_t iridescenceThicknessTextureUV = 0; uint32_t anisotropyTexture = 0; uint32_t anisotropyTextureSampler = 0; uint32_t anisotropyTextureUV = 0; uint32_t alphaMode = 0; uint32_t materialTypeFlags = 0; float ior = 1.5f; uint32_t padding[2] = { 0, 0 }; enum AlphaMode : uint32_t { AlphaMode_Opaque = 0, AlphaMode_Mask = 1, AlphaMode_Blend = 2, }; }; static_assert(sizeof(GLTFMaterialDataGPU) % 16 == 0); struct GLTFDataHolder { std::vector textures; }; struct MaterialsPerFrame { GLTFMaterialDataGPU materials[kMaxMaterials]; }; using GLTFNodeRef = uint32_t; using GLTFMeshRef = uint32_t; enum SortingType : uint32_t { SortingType_Opaque = 0, SortingType_Transmission = 1, SortingType_Transparent = 2, }; struct GLTFMesh { lvk::Topology primitive; uint32_t vertexOffset; uint32_t vertexCount; uint32_t indexOffset; uint32_t indexCount; uint32_t matIdx; SortingType sortingType; }; struct GLTFNode { std::string name; uint32_t modelMtxId; mat4 transform = mat4(1); std::vector children; std::vector meshes; }; struct GLTFFrameData { mat4 model; mat4 view; mat4 proj; vec4 cameraPos; }; struct GLTFCamera { std::string name; uint32_t nodeIdx = ~0; vec3 pos; vec3 up; vec3 lookAt; float hFOV; float near; float far; float aspect = 1.0f; float orthoWidth; mat4 getProjection(float windowAspect = 1.0f) const { return orthoWidth != 0.0f ? glm::ortho(-windowAspect / orthoWidth, windowAspect / orthoWidth, -1.0f / orthoWidth, 1.0f / orthoWidth, far, near) : glm::perspective(hFOV, windowAspect == 1.0f ? aspect : windowAspect, near, far); } }; struct GLTFTransforms { uint32_t modelMtxId; uint32_t matId; GLTFNodeRef nodeRef; // for CPU only GLTFMeshRef meshRef; // for CPU only uint32_t sortingType; }; // Skeleton, animation, morphing #define MAX_BONES_PER_VERTEX 8 struct VertexBoneData { vec4 position; vec4 normal; uint32_t boneId[MAX_BONES_PER_VERTEX] = { ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u }; float weight[MAX_BONES_PER_VERTEX] = {}; uint32_t meshId = ~0u; }; static_assert(sizeof(VertexBoneData) == sizeof(uint32_t) * 25); struct GLTFBone { uint32_t boneId = ~0u; mat4 transform = mat4(1); }; GLTFMaterialDataGPU setupglTFMaterialData( const std::unique_ptr& ctx, const GLTFGlobalSamplers& samplers, aiMaterial* const& mtlDescriptor, const char* assetFolder, GLTFDataHolder& glTFDataholder, bool& useVolumetric); struct GLTFContext { explicit GLTFContext(VulkanApp& app_) : app(app_) , samplers(app_.ctx_) , envMapTextures(app_.ctx_) { } GLTFDataHolder glTFDataholder; MaterialsPerFrame matPerFrame; GLTFGlobalSamplers samplers; EnvironmentMapTextures envMapTextures; GLTFFrameData frameData; std::vector transforms; std::vector matrices; std::vector nodesStorage; std::vector meshesStorage; std::unordered_map bonesByName; std::vector morphTargets; std::unordered_map meshesRemap; std::vector animations; std::vector opaqueNodes; std::vector transmissionNodes; std::vector transparentNodes; lvk::Holder envBuffer; lvk::Holder lightsBuffer; lvk::Holder perFrameBuffer; lvk::Holder transformBuffer; lvk::Holder matricesBuffer; lvk::Holder morphStatesBuffer; lvk::Holder pipelineSolid; lvk::Holder pipelineTransparent; lvk::Holder pipelineComputeAnimations; lvk::Holder vert; lvk::Holder frag; lvk::Holder animation; lvk::Holder vertexBuffer; lvk::Holder vertexSkinningBuffer; lvk::Holder vertexMorphingBuffer; lvk::Holder indexBuffer; lvk::Holder matBuffer; lvk::Holder offscreenTex[3] = {}; uint32_t currentOffscreenTex = 0; uint32_t maxVertices = 0; std::vector morphStates; std::vector lights; std::vector cameras; GLTFIntrospective inspector; GLTFNodeRef root; VulkanApp& app; LineCanvas3D canvas3d; bool hasBones = false; bool isVolumetricMaterial = false; bool animated = false; bool skinning = false; bool morphing = false; bool doublesided = false; bool enableMorphing = true; bool isScreenCopyRequired() const { return isVolumetricMaterial; } }; void loadGLTF(GLTFContext& context, const char* gltfName, const char* glTFDataPath); void renderGLTF(GLTFContext& context, const mat4& model, const mat4& view, const mat4& proj, bool rebuildRenderList = false); void animateGLTF(GLTFContext& gltf, AnimationState& anim, float dt); void animateBlendingGLTF(GLTFContext& gltf, AnimationState& anim1, AnimationState& anim2, float weight, float dt); MaterialType detectMaterialType(const aiMaterial* mtl); void printPrefix(int ofs); void printMat4(const aiMatrix4x4& m); std::vector camerasGLTF(GLTFContext& context); void updateCamera(GLTFContext& gltf, const mat4& model, mat4& view, mat4& proj, float aspectRatio); std::vector animationsGLTF(GLTFContext& gltf);