diff --git a/destrum/assets_src/flight-helmet/FlightHelmet.bin b/destrum/assets_src/flight-helmet/FlightHelmet.bin new file mode 100644 index 0000000..3a878be Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet.bin differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet.gltf b/destrum/assets_src/flight-helmet/FlightHelmet.gltf new file mode 100644 index 0000000..03b53b4 --- /dev/null +++ b/destrum/assets_src/flight-helmet/FlightHelmet.gltf @@ -0,0 +1,712 @@ +{ + "asset": { + "version": "2.0", + "generator": "babylon.js glTF exporter for Maya 2018 v20200228.3 (with minor hand modifications)" + }, + "extensionsUsed": [ + "KHR_materials_transmission" + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0, + 1, + 2, + 3, + 4, + 5 + ] + } + ], + "nodes": [ + { + "mesh": 0, + "name": "Hose_low" + }, + { + "mesh": 1, + "name": "RubberWood_low" + }, + { + "mesh": 2, + "name": "GlassPlastic_low" + }, + { + "mesh": 3, + "name": "MetalParts_low" + }, + { + "mesh": 4, + "name": "LeatherParts_low" + }, + { + "mesh": 5, + "name": "Lenses_low" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "POSITION": 1, + "TANGENT": 2, + "NORMAL": 3, + "TEXCOORD_0": 4 + }, + "indices": 0, + "material": 0 + } + ], + "name": "Hose_low" + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 6, + "TANGENT": 7, + "NORMAL": 8, + "TEXCOORD_0": 9 + }, + "indices": 5, + "material": 1 + } + ], + "name": "RubberWood_low" + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 11, + "TANGENT": 12, + "NORMAL": 13, + "TEXCOORD_0": 14 + }, + "indices": 10, + "material": 2 + } + ], + "name": "GlassPlastic_low" + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 16, + "TANGENT": 17, + "NORMAL": 18, + "TEXCOORD_0": 19 + }, + "indices": 15, + "material": 3 + } + ], + "name": "MetalParts_low" + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 21, + "TANGENT": 22, + "NORMAL": 23, + "TEXCOORD_0": 24 + }, + "indices": 20, + "material": 4 + } + ], + "name": "LeatherParts_low" + }, + { + "primitives": [ + { + "attributes": { + "POSITION": 26, + "TANGENT": 27, + "NORMAL": 28, + "TEXCOORD_0": 29 + }, + "indices": 25, + "material": 5 + } + ], + "name": "Lenses_low" + } + ], + "accessors": [ + { + "bufferView": 0, + "componentType": 5123, + "count": 59040, + "type": "SCALAR", + "name": "accessorIndices" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 10472, + "max": [ + 0.10810829, + 0.356580257, + 0.190409869 + ], + "min": [ + -0.07221258, + 0.104120225, + -0.088394776 + ], + "type": "VEC3", + "name": "accessorPositions" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 10472, + "type": "VEC4", + "name": "accessorTangents" + }, + { + "bufferView": 1, + "byteOffset": 125664, + "componentType": 5126, + "count": 10472, + "type": "VEC3", + "name": "accessorNormals" + }, + { + "bufferView": 3, + "componentType": 5126, + "count": 10472, + "type": "VEC2", + "name": "accessorUVs" + }, + { + "bufferView": 0, + "byteOffset": 118080, + "componentType": 5123, + "count": 72534, + "type": "SCALAR", + "name": "accessorIndices" + }, + { + "bufferView": 1, + "byteOffset": 251328, + "componentType": 5126, + "count": 13638, + "max": [ + 0.162940636, + 0.7025226, + 0.200029165 + ], + "min": [ + -0.158857465, + -2.14242937E-05, + -0.171545789 + ], + "type": "VEC3", + "name": "accessorPositions" + }, + { + "bufferView": 2, + "byteOffset": 167552, + "componentType": 5126, + "count": 13638, + "type": "VEC4", + "name": "accessorTangents" + }, + { + "bufferView": 1, + "byteOffset": 414984, + "componentType": 5126, + "count": 13638, + "type": "VEC3", + "name": "accessorNormals" + }, + { + "bufferView": 3, + "byteOffset": 83776, + "componentType": 5126, + "count": 13638, + "type": "VEC2", + "name": "accessorUVs" + }, + { + "bufferView": 0, + "byteOffset": 263148, + "componentType": 5123, + "count": 24408, + "type": "SCALAR", + "name": "accessorIndices" + }, + { + "bufferView": 1, + "byteOffset": 578640, + "componentType": 5126, + "count": 4676, + "max": [ + 0.140494063, + 0.61828655, + 0.147373646 + ], + "min": [ + -0.140846014, + 0.440957, + -0.107818365 + ], + "type": "VEC3", + "name": "accessorPositions" + }, + { + "bufferView": 2, + "byteOffset": 385760, + "componentType": 5126, + "count": 4676, + "type": "VEC4", + "name": "accessorTangents" + }, + { + "bufferView": 1, + "byteOffset": 634752, + "componentType": 5126, + "count": 4676, + "type": "VEC3", + "name": "accessorNormals" + }, + { + "bufferView": 3, + "byteOffset": 192880, + "componentType": 5126, + "count": 4676, + "type": "VEC2", + "name": "accessorUVs" + }, + { + "bufferView": 0, + "byteOffset": 311964, + "componentType": 5123, + "count": 60288, + "type": "SCALAR", + "name": "accessorIndices" + }, + { + "bufferView": 1, + "byteOffset": 690864, + "componentType": 5126, + "count": 13636, + "max": [ + 0.132708371, + 0.6024364, + 0.199477077 + ], + "min": [ + -0.203642711, + 0.02116075, + -0.147512689 + ], + "type": "VEC3", + "name": "accessorPositions" + }, + { + "bufferView": 2, + "byteOffset": 460576, + "componentType": 5126, + "count": 13636, + "type": "VEC4", + "name": "accessorTangents" + }, + { + "bufferView": 1, + "byteOffset": 854496, + "componentType": 5126, + "count": 13636, + "type": "VEC3", + "name": "accessorNormals" + }, + { + "bufferView": 3, + "byteOffset": 230288, + "componentType": 5126, + "count": 13636, + "type": "VEC2", + "name": "accessorUVs" + }, + { + "bufferView": 0, + "byteOffset": 432540, + "componentType": 5123, + "count": 65688, + "type": "SCALAR", + "name": "accessorIndices" + }, + { + "bufferView": 1, + "byteOffset": 1018128, + "componentType": 5126, + "count": 12534, + "max": [ + 0.124933377, + 0.716000438, + 0.129168555 + ], + "min": [ + -0.125863016, + 0.2958266, + -0.1541516 + ], + "type": "VEC3", + "name": "accessorPositions" + }, + { + "bufferView": 2, + "byteOffset": 678752, + "componentType": 5126, + "count": 12534, + "type": "VEC4", + "name": "accessorTangents" + }, + { + "bufferView": 1, + "byteOffset": 1168536, + "componentType": 5126, + "count": 12534, + "type": "VEC3", + "name": "accessorNormals" + }, + { + "bufferView": 3, + "byteOffset": 339376, + "componentType": 5126, + "count": 12534, + "type": "VEC2", + "name": "accessorUVs" + }, + { + "bufferView": 0, + "byteOffset": 563916, + "componentType": 5123, + "count": 2208, + "type": "SCALAR", + "name": "accessorIndices" + }, + { + "bufferView": 1, + "byteOffset": 1318944, + "componentType": 5126, + "count": 436, + "max": [ + 0.101920746, + 0.5936986, + 0.152926728 + ], + "min": [ + -0.101920947, + 0.5300429, + 0.090174824 + ], + "type": "VEC3", + "name": "accessorPositions" + }, + { + "bufferView": 2, + "byteOffset": 879296, + "componentType": 5126, + "count": 436, + "type": "VEC4", + "name": "accessorTangents" + }, + { + "bufferView": 1, + "byteOffset": 1324176, + "componentType": 5126, + "count": 436, + "type": "VEC3", + "name": "accessorNormals" + }, + { + "bufferView": 3, + "byteOffset": 439648, + "componentType": 5126, + "count": 436, + "type": "VEC2", + "name": "accessorUVs" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteLength": 568332, + "name": "bufferViewScalar" + }, + { + "buffer": 0, + "byteOffset": 568332, + "byteLength": 1329408, + "byteStride": 12, + "name": "bufferViewFloatVec3" + }, + { + "buffer": 0, + "byteOffset": 1897740, + "byteLength": 886272, + "byteStride": 16, + "name": "bufferViewFloatVec4" + }, + { + "buffer": 0, + "byteOffset": 2784012, + "byteLength": 443136, + "byteStride": 8, + "name": "bufferViewFloatVec2" + } + ], + "buffers": [ + { + "uri": "FlightHelmet.bin", + "byteLength": 3227148 + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 2 + }, + "metallicRoughnessTexture": { + "index": 1 + } + }, + "normalTexture": { + "index": 0 + }, + "occlusionTexture": { + "index": 1 + }, + "doubleSided": true, + "name": "HoseMat" + }, + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 2 + }, + "metallicRoughnessTexture": { + "index": 1 + } + }, + "normalTexture": { + "index": 0 + }, + "occlusionTexture": { + "index": 1 + }, + "name": "RubberWoodMat" + }, + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 5 + }, + "metallicRoughnessTexture": { + "index": 4 + } + }, + "normalTexture": { + "index": 3 + }, + "occlusionTexture": { + "index": 4 + }, + "name": "GlassPlasticMat" + }, + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 8 + }, + "metallicRoughnessTexture": { + "index": 7 + } + }, + "normalTexture": { + "index": 6 + }, + "occlusionTexture": { + "index": 7 + }, + "name": "MetalPartsMat" + }, + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 11 + }, + "metallicRoughnessTexture": { + "index": 10 + } + }, + "normalTexture": { + "index": 9 + }, + "occlusionTexture": { + "index": 10 + }, + "name": "LeatherPartsMat" + }, + { + "extensions": { + "KHR_materials_transmission": { + "transmissionFactor": 1 + } + }, + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 14 + }, + "metallicRoughnessTexture": { + "index": 13 + } + }, + "normalTexture": { + "index": 12 + }, + "occlusionTexture": { + "index": 13 + }, + "name": "LensesMat" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0, + "name": "FlightHelmet_Materials_RubberWoodMat_Normal.png" + }, + { + "sampler": 0, + "source": 1, + "name": "FlightHelmet_Materials_RubberWoodMat_OcclusionRoughMetal.png" + }, + { + "sampler": 0, + "source": 2, + "name": "FlightHelmet_Materials_RubberWoodMat_BaseColor.png" + }, + { + "sampler": 0, + "source": 3, + "name": "FlightHelmet_Materials_GlassPlasticMat_Normal.png" + }, + { + "sampler": 0, + "source": 4, + "name": "FlightHelmet_Materials_GlassPlasticMat_OcclusionRoughMetal.png" + }, + { + "sampler": 0, + "source": 5, + "name": "FlightHelmet_Materials_GlassPlasticMat_BaseColor.png" + }, + { + "sampler": 0, + "source": 6, + "name": "FlightHelmet_Materials_MetalPartsMat_Normal.png" + }, + { + "sampler": 0, + "source": 7, + "name": "FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png" + }, + { + "sampler": 0, + "source": 8, + "name": "FlightHelmet_Materials_MetalPartsMat_BaseColor.png" + }, + { + "sampler": 0, + "source": 9, + "name": "FlightHelmet_Materials_LeatherPartsMat_Normal.png" + }, + { + "sampler": 0, + "source": 10, + "name": "FlightHelmet_Materials_LeatherPartsMat_OcclusionRoughMetal.png" + }, + { + "sampler": 0, + "source": 11, + "name": "FlightHelmet_Materials_LeatherPartsMat_BaseColor.png" + }, + { + "sampler": 0, + "source": 12, + "name": "FlightHelmet_Materials_LensesMat_Normal.png" + }, + { + "sampler": 0, + "source": 13, + "name": "FlightHelmet_Materials_LensesMat_OcclusionRoughMetal.png" + }, + { + "sampler": 0, + "source": 14, + "name": "FlightHelmet_Materials_LensesMat_BaseColor.png" + } + ], + "images": [ + { + "uri": "FlightHelmet_Materials_RubberWoodMat_Normal.png" + }, + { + "uri": "FlightHelmet_Materials_RubberWoodMat_OcclusionRoughMetal.png" + }, + { + "uri": "FlightHelmet_Materials_RubberWoodMat_BaseColor.png" + }, + { + "uri": "FlightHelmet_Materials_GlassPlasticMat_Normal.png" + }, + { + "uri": "FlightHelmet_Materials_GlassPlasticMat_OcclusionRoughMetal.png" + }, + { + "uri": "FlightHelmet_Materials_GlassPlasticMat_BaseColor.png" + }, + { + "uri": "FlightHelmet_Materials_MetalPartsMat_Normal.png" + }, + { + "uri": "FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png" + }, + { + "uri": "FlightHelmet_Materials_MetalPartsMat_BaseColor.png" + }, + { + "uri": "FlightHelmet_Materials_LeatherPartsMat_Normal.png" + }, + { + "uri": "FlightHelmet_Materials_LeatherPartsMat_OcclusionRoughMetal.png" + }, + { + "uri": "FlightHelmet_Materials_LeatherPartsMat_BaseColor.png" + }, + { + "uri": "FlightHelmet_Materials_LensesMat_Normal.png" + }, + { + "uri": "FlightHelmet_Materials_LensesMat_OcclusionRoughMetal.png" + }, + { + "uri": "FlightHelmet_Materials_LensesMat_BaseColor.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9987 + } + ] +} diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_BaseColor.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_BaseColor.png new file mode 100644 index 0000000..6d8e33b Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_BaseColor.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_Normal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_Normal.png new file mode 100644 index 0000000..25aa956 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_Normal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_OcclusionRoughMetal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_OcclusionRoughMetal.png new file mode 100644 index 0000000..01ff83e Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_GlassPlasticMat_OcclusionRoughMetal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_BaseColor.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_BaseColor.png new file mode 100644 index 0000000..693a01d Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_BaseColor.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_Normal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_Normal.png new file mode 100644 index 0000000..5d2d37b Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_Normal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_OcclusionRoughMetal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_OcclusionRoughMetal.png new file mode 100644 index 0000000..72ea477 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LeatherPartsMat_OcclusionRoughMetal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_BaseColor.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_BaseColor.png new file mode 100644 index 0000000..d2dd787 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_BaseColor.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_Normal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_Normal.png new file mode 100644 index 0000000..3989a09 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_Normal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_OcclusionRoughMetal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_OcclusionRoughMetal.png new file mode 100644 index 0000000..372a426 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_LensesMat_OcclusionRoughMetal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_BaseColor.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_BaseColor.png new file mode 100644 index 0000000..908a88b Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_BaseColor.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_Normal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_Normal.png new file mode 100644 index 0000000..191ef7e Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_Normal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png new file mode 100644 index 0000000..95075d8 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_BaseColor.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_BaseColor.png new file mode 100644 index 0000000..02dff40 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_BaseColor.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_Normal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_Normal.png new file mode 100644 index 0000000..c3e6f79 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_Normal.png differ diff --git a/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_OcclusionRoughMetal.png b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_OcclusionRoughMetal.png new file mode 100644 index 0000000..6ce3f64 Binary files /dev/null and b/destrum/assets_src/flight-helmet/FlightHelmet_Materials_RubberWoodMat_OcclusionRoughMetal.png differ diff --git a/destrum/assets_src/shaders/lighting.glsl b/destrum/assets_src/shaders/lighting.glsl index 6b5f95e..a8b8666 100644 --- a/destrum/assets_src/shaders/lighting.glsl +++ b/destrum/assets_src/shaders/lighting.glsl @@ -83,6 +83,18 @@ vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v, return (diffuse + specular) * light.color * light.intensity * attenuation * NoL * occlusion; } +// Analytic approximation of the split sum environment BRDF (Karis, "Physically Based Shading on Mobile"). +// Used to light the flat ambient term with the same specular response as the lights. +vec3 envBRDFApprox(vec3 f0, float roughness, float NoV) +{ + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; + vec2 ab = vec2(-1.04, 1.04) * a004 + r.zw; + return f0 * ab.x + ab.y; +} + // blue -> green -> red, used to visualise how many lights a tile has vec3 lightHeatmapColor(uint lightCount) { diff --git a/destrum/assets_src/shaders/materials.glsl b/destrum/assets_src/shaders/materials.glsl index 8ad827f..ba65334 100644 --- a/destrum/assets_src/shaders/materials.glsl +++ b/destrum/assets_src/shaders/materials.glsl @@ -3,14 +3,19 @@ #extension GL_EXT_buffer_reference : require +// Must match MaterialData in Material.h struct MaterialData { vec4 baseColor; - vec4 metallicRoughnessEmissive; + vec4 emissiveColor; + vec4 metallicRoughnessNormalOcclusion; uint textureFilteringMode; uint diffuseTex; uint normalTex; - uint metallicRoughnessTex; + uint metallicTex; + uint roughnessTex; + uint occlusionTex; uint emissiveTex; + uint _pad0; }; layout (buffer_reference, std430) readonly buffer MaterialsBuffer { diff --git a/destrum/assets_src/shaders/mesh.frag b/destrum/assets_src/shaders/mesh.frag index c971066..0f683f0 100644 --- a/destrum/assets_src/shaders/mesh.frag +++ b/destrum/assets_src/shaders/mesh.frag @@ -12,14 +12,32 @@ layout (location = 0) in vec3 inPos; layout (location = 1) in vec2 inUV; layout (location = 2) in vec3 inNormal; layout (location = 3) in vec4 inTangent; -layout (location = 4) in mat3 inTBN; layout (location = 0) out vec4 outFragColor; +vec3 calculateNormal(MaterialData material, uint samplerID) +{ + vec3 n = normalize(inNormal); + + // Meshes without tangents can't use a normal map + if (dot(inTangent.xyz, inTangent.xyz) < 1e-8) { + return n; + } + + // Re-orthogonalize, the interpolated tangent isn't perpendicular to the normal anymore + vec3 t = normalize(inTangent.xyz - n * dot(n, inTangent.xyz)); + vec3 b = cross(n, t) * inTangent.w; + + vec3 tangentNormal = sampleTexture2D(material.normalTex, samplerID, inUV).rgb * 2.0 - 1.0; + tangentNormal.xy *= material.metallicRoughnessNormalOcclusion.z; + + return normalize(mat3(t, b, n) * tangentNormal); +} + void main() { MaterialData material = pcs.sceneData.materials.data[pcs.materialID]; - uint samplerID = pcs.sceneData.materials.data[pcs.materialID].textureFilteringMode; + uint samplerID = material.textureFilteringMode; vec4 diffuse = sampleTexture2D(material.diffuseTex, samplerID, inUV) * material.baseColor; vec3 baseColor = diffuse.rgb; @@ -28,27 +46,18 @@ void main() // discard; // } - vec3 normal = normalize(inNormal); -// if (inTangent != vec4(0.0)) { -// // FIXME: sometimes Blender doesn't export tangents for some objects -// // for some reason. When we will start computing tangents manually, -// // this check can be removed -// normal = sampleTexture2DLinear(material.normalTex, inUV).rgb; -// // normal.y = 1 - normal.y; // flip to make OpenGL normal maps work -// normal = inTBN * normalize(normal * 2.0 - 1.0); -// normal = normalize(normal); -// } + vec3 n = calculateNormal(material, samplerID); - float metallicF = material.metallicRoughnessEmissive.r; - float roughnessF = material.metallicRoughnessEmissive.g; + float metallicF = material.metallicRoughnessNormalOcclusion.x; + float roughnessF = material.metallicRoughnessNormalOcclusion.y; + float occlusionStrength = material.metallicRoughnessNormalOcclusion.w; - vec4 metallicRoughness = sampleTexture2DLinear(material.metallicRoughnessTex, inUV); - - float roughness = roughnessF * metallicRoughness.g; - // roughness *= roughness; // from perceptual to linear + float metallic = metallicF * sampleTexture2D(material.metallicTex, samplerID, inUV).b; + float roughness = roughnessF * sampleTexture2D(material.roughnessTex, samplerID, inUV).g; roughness = max(roughness, 1e-2); // 0.0 roughness leads to NaNs - float metallic = metallicF * metallicRoughness.b; + float occlusion = sampleTexture2D(material.occlusionTex, samplerID, inUV).r; + float ambientOcclusion = mix(1.0, occlusion, occlusionStrength); vec3 dielectricSpecular = vec3(0.04); vec3 black = vec3(0.0); @@ -57,7 +66,6 @@ void main() vec3 cameraPos = pcs.sceneData.cameraPos.xyz; vec3 fragPos = inPos.xyz; - vec3 n = normal; vec3 v = normalize(cameraPos - fragPos); // forward+: only loop over the lights the culling pass put in this pixel's tile @@ -70,26 +78,28 @@ void main() uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i]; Light light = pcs.sceneData.lights.data[lightIndex]; - float occlusion = 1.0; + float shadow = 1.0; if (light.castShadows != 0) { - occlusion = calculateDirectionalShadow( - fragPos, n, + shadow = calculateDirectionalShadow( + fragPos, normalize(inNormal), pcs.sceneData.lightViewProj, pcs.sceneData.shadowMapId, pcs.sceneData.shadowNormalOffset); } fragColor += calculateLight(light, fragPos, n, v, - diffuseColor, roughness, metallic, f0, occlusion); + diffuseColor, roughness, metallic, f0, shadow); } // emissive - float emissiveF = material.metallicRoughnessEmissive.b; - vec3 emissiveColor = emissiveF * sampleTexture2DLinear(material.emissiveTex, inUV).rgb; + vec3 emissiveColor = material.emissiveColor.rgb * sampleTexture2D(material.emissiveTex, samplerID, inUV).rgb; fragColor += emissiveColor; - // ambient - fragColor += baseColor * pcs.sceneData.ambientColor * pcs.sceneData.ambientIntensity; + // ambient, the specular part keeps metals from turning black without lights + float NoV = clamp(dot(n, v), 0.0001, 1.0); + vec3 ambientLight = pcs.sceneData.ambientColor * pcs.sceneData.ambientIntensity; + vec3 ambientSpecular = envBRDFApprox(f0, roughness, NoV); + fragColor += (diffuseColor + ambientSpecular) * ambientLight * ambientOcclusion; if (pcs.sceneData.debugLightHeatmap != 0) { fragColor = mix(fragColor, lightHeatmapColor(tileLightCount), 0.5); @@ -104,7 +114,7 @@ void main() #if 0 // NORMAL DEBUG - fragColor = normal; + fragColor = n; #endif outFragColor = vec4(fragColor, diffuse.a); diff --git a/destrum/assets_src/shaders/mesh.vert b/destrum/assets_src/shaders/mesh.vert index 42d9f80..0a4b25d 100644 --- a/destrum/assets_src/shaders/mesh.vert +++ b/destrum/assets_src/shaders/mesh.vert @@ -8,7 +8,6 @@ layout (location = 0) out vec3 outPos; layout (location = 1) out vec2 outUV; layout (location = 2) out vec3 outNormal; layout (location = 3) out vec4 outTangent; -layout (location = 4) out mat3 outTBN; // The depth pre-pass reuses this shader, positions have to match bit for bit // so the main pass can depth test against it with LESS_OR_EQUAL @@ -29,10 +28,6 @@ void main() // outNormal = (pcs.transform * vec4(v.normal, 0.0)).xyz; outNormal = mat3(transpose(inverse(pcs.transform))) * v.normal; - outTangent = v.tangent; - - vec3 T = normalize(vec3(pcs.transform * v.tangent)); - vec3 N = normalize(outNormal); - vec3 B = cross(N, T) * v.tangent.w; - outTBN = mat3(T, B, N); + // w is the bitangent sign, the fragment shader builds the TBN from the interpolated vectors + outTangent = vec4(mat3(pcs.transform) * v.tangent.xyz, v.tangent.w); } diff --git a/destrum/include/destrum/Assets/ModelFile.h b/destrum/include/destrum/Assets/ModelFile.h index 72a39a2..ae8b4d6 100644 --- a/destrum/include/destrum/Assets/ModelFile.h +++ b/destrum/include/destrum/Assets/ModelFile.h @@ -11,7 +11,7 @@ #include namespace ModelFile { - inline constexpr std::uint32_t Version = 1; + inline constexpr std::uint32_t Version = 2; inline constexpr std::string_view Extension = ".dmodel"; inline constexpr ModelDoc::LoadOptions CookOptions{}; diff --git a/destrum/include/destrum/Graphics/Caches/MaterialCache.h b/destrum/include/destrum/Graphics/Caches/MaterialCache.h index 7ec751d..7f61fff 100644 --- a/destrum/include/destrum/Graphics/Caches/MaterialCache.h +++ b/destrum/include/destrum/Graphics/Caches/MaterialCache.h @@ -50,6 +50,8 @@ public: void updateMaterialGPU(MaterialID id); private: + [[nodiscard]] MaterialData toMaterialData(const Material& material) const; + std::vector materials; std::vector materialKeys; diff --git a/destrum/include/destrum/Graphics/Material.h b/destrum/include/destrum/Graphics/Material.h index 96f6e83..4e28954 100644 --- a/destrum/include/destrum/Graphics/Material.h +++ b/destrum/include/destrum/Graphics/Material.h @@ -5,17 +5,23 @@ #include #include #include +#include +// Must match MaterialData in materials.glsl struct alignas(16) MaterialData { alignas(16) glm::vec4 baseColor; - alignas(16) glm::vec4 metalRoughnessEmissive; + alignas(16) glm::vec4 emissiveColor; + alignas(16) glm::vec4 metallicRoughnessNormalOcclusion; uint32_t textureFilteringMode; uint32_t diffuseTex; uint32_t normalTex; - uint32_t metallicRoughnessTex; + uint32_t metallicTex; + uint32_t roughnessTex; + uint32_t occlusionTex; uint32_t emissiveTex; - uint32_t _pad0, _pad1, _pad2; // explicit to 64 bytes + uint32_t _pad0; }; +static_assert(sizeof(MaterialData) == 80); enum class TextureFilteringMode : std::uint32_t { Nearest, @@ -23,6 +29,9 @@ enum class TextureFilteringMode : std::uint32_t { Anisotropic, }; +// Metallic / roughness workflow, matching glTF: +// metallic is read from the blue channel, roughness from green and occlusion from red, +// so a packed (occlusion)metallicRoughness texture can be used for all three slots. struct Material { [[nodiscard]] static Material SimpleColor( glm::vec3 color, @@ -32,22 +41,32 @@ struct Material { material.baseColor = color; material.metallicFactor = 0.0f; material.roughnessFactor = 1.0f; - material.emissiveFactor = 0.0f; material.name = std::move(materialName); return material; } + [[nodiscard]] bool UsesTexture(ImageID id) const + { + return id != NULL_IMAGE_ID && + (diffuseTexture == id || normalTexture == id || metallicTexture == id || + roughnessTexture == id || occlusionTexture == id || emissiveTexture == id); + } + glm::vec3 baseColor{1.f, 1.f, 1.f}; float metallicFactor{0.f}; float roughnessFactor{0.7f}; - float emissiveFactor{0.f}; + glm::vec3 emissiveColor{0.f}; + float normalScale{1.f}; + float occlusionStrength{1.f}; TextureFilteringMode textureFilteringMode{TextureFilteringMode::Linear}; ImageID diffuseTexture{NULL_IMAGE_ID}; - // ImageId normalMapTexture{NULL_IMAGE_ID}; - // ImageId metallicRoughnessTexture{NULL_IMAGE_ID}; - // ImageId emissiveTexture{NULL_IMAGE_ID}; + ImageID normalTexture{NULL_IMAGE_ID}; + ImageID metallicTexture{NULL_IMAGE_ID}; + ImageID roughnessTexture{NULL_IMAGE_ID}; + ImageID occlusionTexture{NULL_IMAGE_ID}; + ImageID emissiveTexture{NULL_IMAGE_ID}; std::string name; AssetReference assetReference; diff --git a/destrum/include/destrum/Graphics/RenderResources.h b/destrum/include/destrum/Graphics/RenderResources.h index a9c893c..7cdb960 100644 --- a/destrum/include/destrum/Graphics/RenderResources.h +++ b/destrum/include/destrum/Graphics/RenderResources.h @@ -11,6 +11,8 @@ #include #include +namespace ModelDoc { struct MaterialInfo; } + class GfxDevice; class RenderResources { @@ -40,7 +42,7 @@ public: GfxDevice& gfxDevice, const std::filesystem::path& path, VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT, - bool mipMap = false, + bool mipMap = true, TextureIntent intent = TextureIntent::ColorSrgb); ImageID addImageToCache(GPUImage image); @@ -49,6 +51,9 @@ public: // References are keyed as "source#subresource" in the resource caches. void loadModelAsset(GfxDevice& gfxDevice, std::string_view sourceReference); + // Creates a PBR material from an imported model material, loading its texture maps. + MaterialID addModelMaterial(GfxDevice& gfxDevice, const ModelDoc::MaterialInfo& sourceMaterial); + [[nodiscard]] const GPUImage& getImage(ImageID id) const; [[nodiscard]] ImageID getWhiteTextureID() const { return whiteImageId; } diff --git a/destrum/include/destrum/Util/ModelDoc.h b/destrum/include/destrum/Util/ModelDoc.h index a3ac2c9..25dbf92 100644 --- a/destrum/include/destrum/Util/ModelDoc.h +++ b/destrum/include/destrum/Util/ModelDoc.h @@ -369,6 +369,9 @@ static MaterialInfo LoadMaterialInfo(const aiScene* scene, TextureSemantic::Roughness, out.textures); AddMaterialTextureSlots(scene, material, modelDir, aiTextureType_AMBIENT_OCCLUSION, TextureSemantic::AmbientOcclusion, out.textures); + // glTF occlusion maps are imported as lightmaps + AddMaterialTextureSlots(scene, material, modelDir, aiTextureType_LIGHTMAP, + TextureSemantic::AmbientOcclusion, out.textures); AddMaterialTextureSlots(scene, material, modelDir, aiTextureType_EMISSION_COLOR, TextureSemantic::Emissive, out.textures); diff --git a/destrum/src/Graphics/BindlessSetManager.cpp b/destrum/src/Graphics/BindlessSetManager.cpp index 9c33ca5..750cbfa 100644 --- a/destrum/src/Graphics/BindlessSetManager.cpp +++ b/destrum/src/Graphics/BindlessSetManager.cpp @@ -147,6 +147,8 @@ void BindlessSetManager::initDefaultSamplers(VkDevice device, float maxAnisotrop .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .magFilter = VK_FILTER_NEAREST, .minFilter = VK_FILTER_NEAREST, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .maxLod = VK_LOD_CLAMP_NONE, }; VK_CHECK(vkCreateSampler(device, &samplerCreateInfo, nullptr, &nearestSampler)); vkutil::addDebugLabel(device, nearestSampler, "nearest"); @@ -159,6 +161,7 @@ void BindlessSetManager::initDefaultSamplers(VkDevice device, float maxAnisotrop .magFilter = VK_FILTER_LINEAR, .minFilter = VK_FILTER_LINEAR, .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .maxLod = VK_LOD_CLAMP_NONE, }; VK_CHECK(vkCreateSampler(device, &samplerCreateInfo, nullptr, &linearSampler)); vkutil::addDebugLabel(device, linearSampler, "linear"); @@ -173,6 +176,7 @@ void BindlessSetManager::initDefaultSamplers(VkDevice device, float maxAnisotrop .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, .anisotropyEnable = VK_TRUE, .maxAnisotropy = maxAnisotropy, + .maxLod = VK_LOD_CLAMP_NONE, }; VK_CHECK(vkCreateSampler(device, &samplerCreateInfo, nullptr, &anisotropicSampler)); vkutil::addDebugLabel(device, anisotropicSampler, "anisotropic"); diff --git a/destrum/src/Graphics/Caches/MaterialCache.cpp b/destrum/src/Graphics/Caches/MaterialCache.cpp index 6e52ebe..1f845e3 100644 --- a/destrum/src/Graphics/Caches/MaterialCache.cpp +++ b/destrum/src/Graphics/Caches/MaterialCache.cpp @@ -57,11 +57,6 @@ MaterialID MaterialCache::addMaterial(Material material) device->waitIdle(); } - const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) - { - return imageId != NULL_IMAGE_ID ? imageId : placeholder; - }; - MaterialData* data = static_cast(materialDataBuffer.info.pMappedData); const auto id = getFreeMaterialId(); @@ -72,28 +67,7 @@ MaterialID MaterialCache::addMaterial(Material material) throw std::runtime_error("MaterialCache material buffer is not mapped"); } - data[id] = MaterialData{ - .baseColor = glm::vec4(material.baseColor, 1.0f), - - .metalRoughnessEmissive = glm::vec4{ - material.metallicFactor, - material.roughnessFactor, - material.emissiveFactor, - 0.f - }, - - .textureFilteringMode = static_cast(material.textureFilteringMode), - - .diffuseTex = getTextureOrElse( - material.diffuseTexture, - defaultTextures.white), - - .normalTex = defaultTextures.normal, - - .metallicRoughnessTex = defaultTextures.metallicRoughness, - - .emissiveTex = defaultTextures.emissive, - }; + data[id] = toMaterialData(material); device->getMemoryManager().flushAllocation( materialDataBuffer, static_cast(id) * sizeof(MaterialData), @@ -190,6 +164,35 @@ std::optional MaterialCache::findMaterialByName( return fallback; } +MaterialData MaterialCache::toMaterialData(const Material& material) const +{ + const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) + { + return imageId != NULL_IMAGE_ID ? imageId : placeholder; + }; + + return MaterialData{ + .baseColor = glm::vec4(material.baseColor, 1.0f), + .emissiveColor = glm::vec4(material.emissiveColor, 0.0f), + + .metallicRoughnessNormalOcclusion = glm::vec4{ + material.metallicFactor, + material.roughnessFactor, + material.normalScale, + material.occlusionStrength + }, + + .textureFilteringMode = static_cast(material.textureFilteringMode), + .diffuseTex = getTextureOrElse(material.diffuseTexture, defaultTextures.white), + .normalTex = getTextureOrElse(material.normalTexture, defaultTextures.normal), + .metallicTex = getTextureOrElse(material.metallicTexture, defaultTextures.metallicRoughness), + .roughnessTex = getTextureOrElse(material.roughnessTexture, defaultTextures.metallicRoughness), + .occlusionTex = getTextureOrElse(material.occlusionTexture, defaultTextures.white), + .emissiveTex = getTextureOrElse(material.emissiveTexture, defaultTextures.emissive), + ._pad0 = 0, + }; +} + MaterialID MaterialCache::getFreeMaterialId() const { return static_cast(materials.size()); @@ -212,32 +215,10 @@ void MaterialCache::updateMaterialGPU(MaterialID id) assert(id < materials.size()); assert(materialDataBuffer.info.pMappedData && "materialDataBuffer must be mapped"); - const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) - { - return imageId != NULL_IMAGE_ID ? imageId : placeholder; - }; - - Material& material = materials[id]; - MaterialData* data = reinterpret_cast(materialDataBuffer.info.pMappedData); - data[id] = MaterialData{ - .baseColor = glm::vec4(material.baseColor, 1.0f), - - .metalRoughnessEmissive = glm::vec4{ - material.metallicFactor, - material.roughnessFactor, - material.emissiveFactor, - 0.f - }, - - .textureFilteringMode = static_cast(material.textureFilteringMode), - .diffuseTex = getTextureOrElse(material.diffuseTexture, defaultTextures.white), - .normalTex = defaultTextures.normal, - .metallicRoughnessTex = defaultTextures.metallicRoughness, - .emissiveTex = defaultTextures.emissive, - }; + data[id] = toMaterialData(materials[id]); device->getMemoryManager().flushAllocation( materialDataBuffer, static_cast(id) * sizeof(MaterialData), diff --git a/destrum/src/Graphics/Managers/ImageManager.cpp b/destrum/src/Graphics/Managers/ImageManager.cpp index 1d556fc..4987e61 100644 --- a/destrum/src/Graphics/Managers/ImageManager.cpp +++ b/destrum/src/Graphics/Managers/ImageManager.cpp @@ -148,10 +148,11 @@ std::optional ImageManager::loadImageFromFile( VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; if ((formatProperties.optimalTilingFeatures & requiredFeatures) != requiredFeatures) { - spdlog::error( - "Format {} does not support linear mip generation", - static_cast(data.vkFormat)); - return std::nullopt; + spdlog::warn( + "Format {} does not support linear mip generation, loading '{}' without mips", + static_cast(data.vkFormat), + path.string()); + mipMap = false; } } diff --git a/destrum/src/Graphics/RenderResources.cpp b/destrum/src/Graphics/RenderResources.cpp index b876807..5104113 100644 --- a/destrum/src/Graphics/RenderResources.cpp +++ b/destrum/src/Graphics/RenderResources.cpp @@ -9,18 +9,18 @@ #include #include +#include #include namespace { - const ModelDoc::TextureInfo* FindDiffuseTexture( - const ModelDoc::MaterialInfo& material) + // Returns the first loadable texture, trying the semantics in order + const ModelDoc::TextureInfo* FindTexture( + const ModelDoc::MaterialInfo& material, + std::initializer_list semantics) { - for (const auto semantic : std::array{ - ModelDoc::TextureSemantic::BaseColor, - ModelDoc::TextureSemantic::Diffuse, - }) { + for (const auto semantic : semantics) { for (const auto& texture : material.textures) { - if (texture.semantic == semantic) { + if (texture.semantic == semantic && !texture.embedded && !texture.path.empty()) { return &texture; } } @@ -230,32 +230,56 @@ void RenderResources::loadModelAsset( continue; } - Material material = Material::SimpleColor( - glm::vec3{sourceMaterial.baseColor}, - sourceMaterial.name); - material.assetReference = sourceMaterial.assetReference; - material.metallicFactor = sourceMaterial.metallicFactor; - material.roughnessFactor = sourceMaterial.roughnessFactor; - material.emissiveFactor = std::max({ - sourceMaterial.emissiveColor.x, - sourceMaterial.emissiveColor.y, - sourceMaterial.emissiveColor.z, - }); - - if (const auto* texture = FindDiffuseTexture(sourceMaterial); - texture != nullptr && !texture->embedded && !texture->path.empty()) { - material.diffuseTexture = loadImageFromFile( - gfxDevice, - std::filesystem::path{texture->path}, - VK_IMAGE_USAGE_SAMPLED_BIT, - false, - TextureIntent::ColorSrgb); - } - - materials().addMaterial(std::move(material)); + addModelMaterial(gfxDevice, sourceMaterial); } } +MaterialID RenderResources::addModelMaterial( + GfxDevice& gfxDevice, + const ModelDoc::MaterialInfo& sourceMaterial) +{ + using Semantic = ModelDoc::TextureSemantic; + + const auto loadTexture = [&](std::initializer_list semantics, TextureIntent intent) + { + const auto* texture = FindTexture(sourceMaterial, semantics); + if (texture == nullptr) { + return NULL_IMAGE_ID; + } + return loadImageFromFile( + gfxDevice, + std::filesystem::path{texture->path}, + VK_IMAGE_USAGE_SAMPLED_BIT, + true, + intent); + }; + + Material material = Material::SimpleColor( + glm::vec3{sourceMaterial.baseColor}, + sourceMaterial.name); + material.assetReference = sourceMaterial.assetReference; + material.metallicFactor = sourceMaterial.metallicFactor; + material.roughnessFactor = sourceMaterial.roughnessFactor; + material.emissiveColor = sourceMaterial.emissiveColor; + + material.diffuseTexture = loadTexture({Semantic::BaseColor, Semantic::Diffuse}, TextureIntent::ColorSrgb); + material.normalTexture = loadTexture({Semantic::Normal}, TextureIntent::DataLinear); + material.metallicTexture = loadTexture({Semantic::MetallicRoughness, Semantic::Metallic}, TextureIntent::DataLinear); + material.roughnessTexture = loadTexture({Semantic::MetallicRoughness, Semantic::Roughness}, TextureIntent::DataLinear); + material.occlusionTexture = loadTexture({Semantic::AmbientOcclusion}, TextureIntent::DataLinear); + material.emissiveTexture = loadTexture({Semantic::Emissive}, TextureIntent::ColorSrgb); + + // Formats without PBR factors (FBX, OBJ) leave them at 0, which would hide the map completely + if (material.metallicTexture != NULL_IMAGE_ID && material.metallicFactor == 0.0f) { + material.metallicFactor = 1.0f; + } + if (material.emissiveTexture != NULL_IMAGE_ID && material.emissiveColor == glm::vec3{0.0f}) { + material.emissiveColor = glm::vec3{1.0f}; + } + + return materials().addMaterial(std::move(material)); +} + BindlessSetManager& RenderResources::getBindlessSetManager() { return imageCache->bindlessSetManager; } diff --git a/destrum/src/Graphics/ResourcesInspector.cpp b/destrum/src/Graphics/ResourcesInspector.cpp index 7ee29d5..a50f14c 100644 --- a/destrum/src/Graphics/ResourcesInspector.cpp +++ b/destrum/src/Graphics/ResourcesInspector.cpp @@ -223,7 +223,7 @@ void ResourcesInspector::drawImageDetails(ImageID id, const RenderResources& res std::vector users; for (std::size_t materialId = 0; materialId < materials.materials.size(); ++materialId) { - if (materials.materials[materialId].diffuseTexture == id) + if (materials.materials[materialId].UsesTexture(id)) { users.push_back(materialId); } @@ -232,7 +232,7 @@ void ResourcesInspector::drawImageDetails(ImageID id, const RenderResources& res if (!users.empty()) { ImGui::Separator(); - ImGui::Text("Diffuse texture of %zu material(s):", users.size()); + ImGui::Text("Used by %zu material(s):", users.size()); constexpr std::size_t maxListed = 8; for (std::size_t i = 0; i < std::min(users.size(), maxListed); ++i) diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 0000000..0f2d64b --- /dev/null +++ b/imgui.ini @@ -0,0 +1,30 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 +LastUsed=20261013 + +[Window][Test] +Pos=60,60 +Size=94,54 +Collapsed=0 +LastUsed=20261013 + +[Window][Debug] +Pos=60,60 +Size=107,48 +Collapsed=0 +LastUsed=20261013 + +[Window][Physics] +Pos=60,60 +Size=215,201 +Collapsed=0 +LastUsed=20261013 + +[Window][Inspector] +Pos=669,99 +Size=640,520 +Collapsed=0 +LastUsed=20261013 + diff --git a/lightkeeper/src/Lightkeeper.cpp b/lightkeeper/src/Lightkeeper.cpp index 65577e5..21446b9 100644 --- a/lightkeeper/src/Lightkeeper.cpp +++ b/lightkeeper/src/Lightkeeper.cpp @@ -142,6 +142,33 @@ void LightKeeper::customInit() floorRb->SetType(RigidbodyType::Static); scene.GetPhysics().RegisterGameObject(*planeObj); + const auto helmetObj = scene.CreateGameObject("FlightHelmet"); + helmetObj->GetTransform().SetWorldPosition(glm::vec3(2.f, -1.f, 0.f)); + helmetObj->GetTransform().SetWorldScale(glm::vec3(2.f)); + + const auto helmetModel = AssetManager::GetInstance().LoadModel( + "engine://flight-helmet/FlightHelmet.gltf", + staticModelOptions); + ModelDocUtils::LogModelDocSummary(helmetModel, "FlightHelmet.gltf"); + + std::vector helmetMaterialIDs; + for (const auto& material : helmetModel.materials) + { + helmetMaterialIDs.push_back(resources.addModelMaterial(gfxDevice, material)); + } + + for (const auto& primitive : helmetModel.primitives) + { + const auto partObj = scene.CreateGameObject(primitive.nodeName); + partObj->GetTransform().SetParent(&helmetObj->GetTransform(), false); + + const auto partMeshComp = partObj->AddComponent(); + partMeshComp->SetMeshID(resources.meshes().addMesh(gfxDevice, primitive.mesh)); + partMeshComp->SetMaterialID(primitive.materialIndex < helmetMaterialIDs.size() + ? helmetMaterialIDs[primitive.materialIndex] + : resources.materials().getPlaceholderMaterialId()); + } + const auto CharObj = scene.CreateGameObject("Character"); capybara = CharObj; @@ -504,6 +531,9 @@ void LightKeeper::customInit() const auto texPath = AssetFS::GetInstance().GetFullPath("engine://textures/kobe.png"); texID = resources.loadImageFromFile(gfxDevice, texPath); + + + } void LightKeeper::customUpdate(float dt) diff --git a/tests/destrum_tests.cpp b/tests/destrum_tests.cpp index 46d21f3..403c32f 100644 --- a/tests/destrum_tests.cpp +++ b/tests/destrum_tests.cpp @@ -859,7 +859,7 @@ namespace { "simple materials must preserve their color"); check(material.metallicFactor == 0.0f && material.roughnessFactor == 1.0f && - material.emissiveFactor == 0.0f, + material.emissiveColor == glm::vec3{0.0f}, "simple materials must use non-metallic default factors"); check(material.diffuseTexture == NULL_IMAGE_ID, "simple materials must not require a diffuse image");