feat: add pbr support
|
After Width: | Height: | Size: 3.1 MiB |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 5.2 MiB |
|
After Width: | Height: | Size: 5.4 MiB |
|
After Width: | Height: | Size: 4.2 MiB |
|
After Width: | Height: | Size: 680 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 588 KiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <destrum/Util/ModelDoc.h>
|
||||
|
||||
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{};
|
||||
|
||||
@@ -50,6 +50,8 @@ public:
|
||||
void updateMaterialGPU(MaterialID id);
|
||||
|
||||
private:
|
||||
[[nodiscard]] MaterialData toMaterialData(const Material& material) const;
|
||||
|
||||
std::vector<Material> materials;
|
||||
std::vector<std::string> materialKeys;
|
||||
|
||||
|
||||
@@ -5,17 +5,23 @@
|
||||
#include <utility>
|
||||
#include <glm/glm.hpp>
|
||||
#include <destrum/Assets/AssetReference.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<MaterialData*>(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<std::uint32_t>(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<VkDeviceSize>(id) * sizeof(MaterialData),
|
||||
@@ -190,6 +164,35 @@ std::optional<MaterialID> 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<std::uint32_t>(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<MaterialID>(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<MaterialData*>(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<std::uint32_t>(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<VkDeviceSize>(id) * sizeof(MaterialData),
|
||||
|
||||
@@ -148,10 +148,11 @@ std::optional<GPUImage> 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<int>(data.vkFormat));
|
||||
return std::nullopt;
|
||||
spdlog::warn(
|
||||
"Format {} does not support linear mip generation, loading '{}' without mips",
|
||||
static_cast<int>(data.vkFormat),
|
||||
path.string());
|
||||
mipMap = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
|
||||
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<ModelDoc::TextureSemantic> 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<Semantic> 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;
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ void ResourcesInspector::drawImageDetails(ImageID id, const RenderResources& res
|
||||
std::vector<std::size_t> 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<MaterialID> 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<MeshRendererComponent>();
|
||||
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)
|
||||
|
||||
@@ -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");
|
||||
|
||||