diff --git a/assets/example_meshes/gltf/SpecularTest/LeftLabels.png b/assets/example_meshes/gltf/SpecularTest/LeftLabels.png new file mode 100644 index 0000000000..250f00bc5e Binary files /dev/null and b/assets/example_meshes/gltf/SpecularTest/LeftLabels.png differ diff --git a/assets/example_meshes/gltf/SpecularTest/SpecularTest.bin b/assets/example_meshes/gltf/SpecularTest/SpecularTest.bin new file mode 100644 index 0000000000..d0c63b464f Binary files /dev/null and b/assets/example_meshes/gltf/SpecularTest/SpecularTest.bin differ diff --git a/assets/example_meshes/gltf/SpecularTest/SpecularTest.gltf b/assets/example_meshes/gltf/SpecularTest/SpecularTest.gltf new file mode 100644 index 0000000000..ed3485191b --- /dev/null +++ b/assets/example_meshes/gltf/SpecularTest/SpecularTest.gltf @@ -0,0 +1,1283 @@ +{ + "asset" : { + "copyright" : "CC-BY 4.0 Copyright 2021 Analytical Graphics, Inc. Model and Textures by Ed Mackey.", + "generator" : "Khronos glTF Blender I/O v1.5.17", + "version" : "2.0" + }, + "extensionsUsed": [ + "KHR_materials_specular" + ], + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0, + 24 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Labels", + "translation" : [ + -0.5034662485122681, + 0, + 0 + ] + }, + { + "mesh" : 1, + "name" : "1.1_specularFactor", + "translation" : [ + -0.4399999976158142, + 0.33000001311302185, + 0 + ] + }, + { + "mesh" : 2, + "name" : "1.2_specularFactor", + "translation" : [ + -0.32999998331069946, + 0.33000001311302185, + 0 + ] + }, + { + "mesh" : 3, + "name" : "1.3_specularFactor", + "translation" : [ + -0.2199999988079071, + 0.33000001311302185, + 0 + ] + }, + { + "mesh" : 4, + "name" : "1.4_specularFactor", + "translation" : [ + -0.10999999940395355, + 0.33000001311302185, + 0 + ] + }, + { + "mesh" : 5, + "name" : "1.5_specularFactor", + "translation" : [ + 0, + 0.33000001311302185, + 0 + ] + }, + { + "mesh" : 6, + "name" : "2_specularTexture", + "translation" : [ + 0, + 0.2199999988079071, + 0 + ] + }, + { + "mesh" : 7, + "name" : "3.1_whiteColorFactor", + "translation" : [ + -0.4399999976158142, + 0.10999999940395355, + 0 + ] + }, + { + "mesh" : 8, + "name" : "3.2_whiteColorFactor", + "translation" : [ + -0.32999998331069946, + 0.10999999940395355, + 0 + ] + }, + { + "mesh" : 9, + "name" : "3.3_whiteColorFactor", + "translation" : [ + -0.2199999988079071, + 0.10999999940395355, + 0 + ] + }, + { + "mesh" : 10, + "name" : "3.4_whiteColorFactor", + "translation" : [ + -0.10999999940395355, + 0.10999999940395355, + 0 + ] + }, + { + "mesh" : 11, + "name" : "3.5_whiteColorFactor", + "translation" : [ + 0, + 0.10999999940395355, + 0 + ] + }, + { + "mesh" : 12, + "name" : "4_whiteColorTexture" + }, + { + "mesh" : 13, + "name" : "5.1_yellowColorFactor", + "translation" : [ + -0.4399999976158142, + -0.10999999940395355, + 0 + ] + }, + { + "mesh" : 14, + "name" : "5.2_yellowColorFactor", + "translation" : [ + -0.32999998331069946, + -0.10999999940395355, + 0 + ] + }, + { + "mesh" : 15, + "name" : "5.3_yellowColorFactor", + "translation" : [ + -0.2199999988079071, + -0.10999999940395355, + 0 + ] + }, + { + "mesh" : 16, + "name" : "5.4_yellowColorFactor", + "translation" : [ + -0.10999999940395355, + -0.10999999940395355, + 0 + ] + }, + { + "mesh" : 17, + "name" : "5.5_yellowColorFactor", + "translation" : [ + 0, + -0.10999999940395355, + 0 + ] + }, + { + "mesh" : 18, + "name" : "6_yellowColorTexture", + "translation" : [ + 0, + -0.2199999988079071, + 0 + ] + }, + { + "mesh" : 19, + "name" : "7.1_HDR_colorFactor", + "translation" : [ + -0.4399999976158142, + -0.33000001311302185, + 0 + ] + }, + { + "mesh" : 20, + "name" : "7.2_HDR_colorFactor", + "translation" : [ + -0.32999998331069946, + -0.33000001311302185, + 0 + ] + }, + { + "mesh" : 21, + "name" : "7.3_HDR_colorFactor", + "translation" : [ + -0.2199999988079071, + -0.33000001311302185, + 0 + ] + }, + { + "mesh" : 22, + "name" : "7.4_HDR_colorFactor", + "translation" : [ + -0.10999999940395355, + -0.33000001311302185, + 0 + ] + }, + { + "mesh" : 23, + "name" : "7.5_HDR_colorFactor", + "translation" : [ + 0, + -0.33000001311302185, + 0 + ] + }, + { + "children" : [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ], + "name" : "SampleRoot", + "translation" : [ + 0.32499998807907104, + 0, + 0 + ] + } + ], + "materials" : [ + { + "name" : "LabelMat", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicFactor" : 0, + "roughnessFactor" : 0.8 + } + }, + { + "name" : "M1.1_specFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularFactor": 0 + } + } + }, + { + "name" : "M1.2_specFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularFactor": 0.051269 + } + } + }, + { + "name" : "M1.3_specFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularFactor": 0.212231 + } + } + }, + { + "name" : "M1.4_specFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularFactor": 0.520996 + } + } + }, + { + "name" : "M1.5_specFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularFactor": 1 + } + } + }, + { + "name" : "M2_SpecTex", + "pbrMetallicRoughness" : { + "baseColorFactor": [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularTexture": { + "index": 1 + } + } + } + }, + { + "name" : "M3.1_whiteFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0, + 0, + 0 + ] + } + } + }, + { + "name" : "M3.2_whiteFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0.051269, + 0.051269, + 0.051269 + ] + } + } + }, + { + "name" : "M3.3_whiteFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0.212231, + 0.212231, + 0.212231 + ] + } + } + }, + { + "name" : "M3.4_whiteFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0.520996, + 0.520996, + 0.520996 + ] + } + } + }, + { + "name" : "M3.5_whiteFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 1, + 1, + 1 + ] + } + } + }, + { + "name" : "M4_whiteTex", + "pbrMetallicRoughness" : { + "baseColorFactor": [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorTexture": { + "index": 2 + } + } + } + }, + { + "name" : "M5.1_yellowFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0, + 0, + 0 + ] + } + } + }, + { + "name" : "M5.2_yellowFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0.051269, + 0.051269, + 0 + ] + } + } + }, + { + "name" : "M5.3_yellowFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0.212231, + 0.212231, + 0 + ] + } + } + }, + { + "name" : "M5.4_yellowFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0.520996, + 0.520996, + 0 + ] + } + } + }, + { + "name" : "M5.5_yellowFac", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 1, + 1, + 0 + ] + } + } + }, + { + "name" : "M6_yellowTex", + "pbrMetallicRoughness" : { + "baseColorFactor": [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorTexture": { + "index" : 3 + } + } + } + }, + { + "name" : "M7.1_HDR", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 0, + 0, + 0 + ] + } + } + }, + { + "name" : "M7.2_HDR", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 1.184, + 1.184, + 1.184 + ] + } + } + }, + { + "name" : "M7.3_HDR", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 5.441, + 5.441, + 5.441 + ] + } + } + }, + { + "name" : "M7.4_HDR", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 13.276, + 13.276, + 13.276 + ] + } + } + }, + { + "name" : "M7.5_HDR", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0, + 0, + 0, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0 + }, + "extensions": { + "KHR_materials_specular": { + "specularColorFactor": [ + 25, + 25, + 25 + ] + } + } + } + ], + "meshes" : [ + { + "name" : "Labels", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "NORMAL" : 1, + "TEXCOORD_0" : 2 + }, + "indices" : 3, + "material" : 0 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 1 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 2 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 3 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 4 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 5 + } + ] + }, + { + "name" : "FiveSamples", + "primitives" : [ + { + "attributes" : { + "POSITION" : 7, + "NORMAL" : 8, + "TEXCOORD_0" : 9 + }, + "indices" : 10, + "material" : 6 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 7 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 8 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 9 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 10 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 11 + } + ] + }, + { + "name" : "FiveSamples", + "primitives" : [ + { + "attributes" : { + "POSITION" : 7, + "NORMAL" : 8, + "TEXCOORD_0" : 9 + }, + "indices" : 10, + "material" : 12 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 13 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 14 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 15 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 16 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 17 + } + ] + }, + { + "name" : "FiveSamples", + "primitives" : [ + { + "attributes" : { + "POSITION" : 7, + "NORMAL" : 8, + "TEXCOORD_0" : 9 + }, + "indices" : 10, + "material" : 18 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 19 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 20 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 21 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 22 + } + ] + }, + { + "name" : "OneSample", + "primitives" : [ + { + "attributes" : { + "POSITION" : 4, + "NORMAL" : 5 + }, + "indices" : 6, + "material" : 23 + } + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 0, + "source" : 1 + }, + { + "sampler" : 0, + "source" : 2 + }, + { + "sampler" : 0, + "source" : 3 + } + ], + "images" : [ + { + "mimeType" : "image/png", + "name" : "LeftLabels", + "uri" : "LeftLabels.png" + }, + { + "mimeType" : "image/png", + "name" : "specularTextureGrid", + "uri" : "specularTextureGrid.png" + }, + { + "mimeType" : "image/png", + "name" : "WhiteGrid", + "uri" : "WhiteGrid.png" + }, + { + "mimeType" : "image/png", + "name" : "YellowGrid", + "uri" : "YellowGrid.png" + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 56, + "max" : [ + 0.3195691704750061, + 0.37506479024887085, + 1.3717179392358503e-08 + ], + "min" : [ + -0.2473800927400589, + -0.37187379598617554, + -0.002000038046389818 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 56, + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 56, + "type" : "VEC2" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 84, + "type" : "SCALAR" + }, + { + "bufferView" : 4, + "componentType" : 5126, + "count" : 642, + "max" : [ + 0.05000000074505806, + 0.05000000074505806, + 0.05000000447034836 + ], + "min" : [ + -0.05000000447034836, + -0.05000000074505806, + -0.05000000447034836 + ], + "type" : "VEC3" + }, + { + "bufferView" : 5, + "componentType" : 5126, + "count" : 642, + "type" : "VEC3" + }, + { + "bufferView" : 6, + "componentType" : 5123, + "count" : 3840, + "type" : "SCALAR" + }, + { + "bufferView" : 7, + "componentType" : 5126, + "count" : 3645, + "max" : [ + 0.05000000074505806, + 0.05000000074505806, + 0.05000000447034836 + ], + "min" : [ + -0.49000000953674316, + -0.05000000074505806, + -0.05000000447034836 + ], + "type" : "VEC3" + }, + { + "bufferView" : 8, + "componentType" : 5126, + "count" : 3645, + "type" : "VEC3" + }, + { + "bufferView" : 9, + "componentType" : 5126, + "count" : 3645, + "type" : "VEC2" + }, + { + "bufferView" : 10, + "componentType" : 5123, + "count" : 19200, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 672, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 672, + "byteOffset" : 672 + }, + { + "buffer" : 0, + "byteLength" : 448, + "byteOffset" : 1344 + }, + { + "buffer" : 0, + "byteLength" : 168, + "byteOffset" : 1792 + }, + { + "buffer" : 0, + "byteLength" : 7704, + "byteOffset" : 1960 + }, + { + "buffer" : 0, + "byteLength" : 7704, + "byteOffset" : 9664 + }, + { + "buffer" : 0, + "byteLength" : 7680, + "byteOffset" : 17368 + }, + { + "buffer" : 0, + "byteLength" : 43740, + "byteOffset" : 25048 + }, + { + "buffer" : 0, + "byteLength" : 43740, + "byteOffset" : 68788 + }, + { + "buffer" : 0, + "byteLength" : 29160, + "byteOffset" : 112528 + }, + { + "buffer" : 0, + "byteLength" : 38400, + "byteOffset" : 141688 + } + ], + "samplers" : [ + { + "magFilter" : 9729, + "minFilter" : 9987 + } + ], + "buffers" : [ + { + "byteLength" : 180088, + "uri" : "SpecularTest.bin" + } + ] +} diff --git a/assets/example_meshes/gltf/SpecularTest/WhiteGrid.png b/assets/example_meshes/gltf/SpecularTest/WhiteGrid.png new file mode 100644 index 0000000000..ba32aa85f7 Binary files /dev/null and b/assets/example_meshes/gltf/SpecularTest/WhiteGrid.png differ diff --git a/assets/example_meshes/gltf/SpecularTest/YellowGrid.png b/assets/example_meshes/gltf/SpecularTest/YellowGrid.png new file mode 100644 index 0000000000..5ed407a719 Binary files /dev/null and b/assets/example_meshes/gltf/SpecularTest/YellowGrid.png differ diff --git a/assets/example_meshes/gltf/SpecularTest/specularTextureGrid.png b/assets/example_meshes/gltf/SpecularTest/specularTextureGrid.png new file mode 100644 index 0000000000..a478e43149 Binary files /dev/null and b/assets/example_meshes/gltf/SpecularTest/specularTextureGrid.png differ diff --git a/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_pisa_angle0_gt.png b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_pisa_angle0_gt.png new file mode 100644 index 0000000000..a5b3a63587 Binary files /dev/null and b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_pisa_angle0_gt.png differ diff --git a/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_pisa_angle1_gt.png b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_pisa_angle1_gt.png new file mode 100644 index 0000000000..6cefac831e Binary files /dev/null and b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_pisa_angle1_gt.png differ diff --git a/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_uffizi_angle0_gt.png b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_uffizi_angle0_gt.png new file mode 100644 index 0000000000..4d456394a3 Binary files /dev/null and b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_uffizi_angle0_gt.png differ diff --git a/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_uffizi_angle1_gt.png b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_uffizi_angle1_gt.png new file mode 100644 index 0000000000..71373c43d0 Binary files /dev/null and b/assets/ground_truth/006-mesh-pbr-headless_SpecularTest_uffizi_angle1_gt.png differ diff --git a/examples/render/950-pbr/main.cpp b/examples/render/950-pbr/main.cpp index 43af858868..bcf21d4428 100644 --- a/examples/render/950-pbr/main.cpp +++ b/examples/render/950-pbr/main.cpp @@ -21,6 +21,7 @@ int main(int argc, char** argv) NORMAL_TENGENT_MIRROR_TEST, COMPARE_AMBIENT_OCCLUSION, DAMAGED_HELMET, + SPECULAR_TEST, COUNT_EXAMPLES }; @@ -29,9 +30,10 @@ int main(int argc, char** argv) "/gltf/MetalRoughSpheres/MetalRoughSpheres.gltf", "/gltf/NormalTangentMirrorTest/NormalTangentMirrorTest.gltf", "/gltf/CompareAmbientOcclusion/CompareAmbientOcclusion.gltf", - "/gltf/DamagedHelmet/DamagedHelmet.gltf"}; + "/gltf/DamagedHelmet/DamagedHelmet.gltf", + "/gltf/SpecularTest/SpecularTest.gltf"}; - uint selectedExample = METAL_ROUGH_SPHERES; + uint selectedExample = SPECULAR_TEST; enum PanoramasExamples { COLOSSEUM_HDR, @@ -73,6 +75,12 @@ int main(int argc, char** argv) else if (type == EMISSIVE) { typeName = "emissive"; } + else if (type == SPECULAR) { + typeName = "specular"; + } + else if (type == SPECULAR_COLOR) { + typeName = "specularColor"; + } std::cout << " " << typeName << "Texture: "; if (!texture.isNull()) { @@ -105,11 +113,16 @@ int main(int argc, char** argv) std::cout << " normalScale: " << mat.normalScale() << std::endl; std::cout << " occlusionStrength: " << mat.occlusionStrength() << std::endl; + std::cout << " specularFactor: " << mat.specular() << std::endl; + std::cout << " specularColorFactor: " << mat.specularColor() + << std::endl; printTextureInfo(mat, BASE_COLOR); printTextureInfo(mat, METALLIC_ROUGHNESS); printTextureInfo(mat, NORMAL); printTextureInfo(mat, OCCLUSION); printTextureInfo(mat, EMISSIVE); + printTextureInfo(mat, SPECULAR); + printTextureInfo(mat, SPECULAR_COLOR); std::cout << " ------------------------" << std::endl; } std::cout << "------------------------" << std::endl; diff --git a/tests/render/006-mesh-pbr-headless/main.cpp b/tests/render/006-mesh-pbr-headless/main.cpp index bcfb2eb1c5..2534ec0583 100644 --- a/tests/render/006-mesh-pbr-headless/main.cpp +++ b/tests/render/006-mesh-pbr-headless/main.cpp @@ -102,7 +102,8 @@ TEST_CASE("PBR Rendering") "DamagedHelmet/DamagedHelmet.gltf", "MetalRoughSpheres/MetalRoughSpheres.gltf", "CompareAmbientOcclusion/CompareAmbientOcclusion.gltf", - "NormalTangentMirrorTest/NormalTangentMirrorTest.gltf"}; + "NormalTangentMirrorTest/NormalTangentMirrorTest.gltf", + "SpecularTest/SpecularTest.gltf"}; std::vector angles = {0.0f, 3.14159265f / 4.0f}; for (const auto& meshName : meshes) { diff --git a/vclib/core/include/vclib/io/mesh/gltf/detail/load_mesh.h b/vclib/core/include/vclib/io/mesh/gltf/detail/load_mesh.h index b9665225df..f37e19c77c 100644 --- a/vclib/core/include/vclib/io/mesh/gltf/detail/load_mesh.h +++ b/vclib/core/include/vclib/io/mesh/gltf/detail/load_mesh.h @@ -48,6 +48,12 @@ int loadGltfPrimitiveMaterial( bool doubleSided; int baseColorTextureId, metallicRoughnessTextureId, normalTextureId, occlusionTextureId, emissiveTextureId; + + double specular = 1.0; + Point3f specularColor = Point3f(1.0, 1.0, 1.0); + int specularTextureId = -1; + int specularColorTextureId = -1; + const tinygltf::Material& mat = model.materials[p.material]; std::string matName = mat.name; @@ -108,6 +114,37 @@ int loadGltfPrimitiveMaterial( // occlusionStrength occlusionStrength = mat.occlusionTexture.strength; + // specular + if(mat.extensions.contains("KHR_materials_specular")) + { + const auto& specularExt = mat.extensions.at("KHR_materials_specular"); + + if(specularExt.Has("specularFactor")) + specular = specularExt + .Get("specularFactor") + .GetNumberAsDouble(); + + if(specularExt.Has("specularColorFactor")) + for(uint i = 0; i < 3; i++) + specularColor[i] = specularExt + .Get("specularColorFactor") + .Get(i) + .GetNumberAsDouble(); + + if(specularExt.Has("specularTexture")) + specularTextureId = specularExt + .Get("specularTexture") + .Get("index") + .GetNumberAsInt(); + + if(specularExt.Has("specularColorTexture")) + specularColorTextureId = specularExt + .Get("specularColorTexture") + .Get("index") + .GetNumberAsInt(); + + } + // function to load a texture in a material auto loadTextureInMaterial = [&](Material& mat, int textureId, @@ -181,6 +218,8 @@ int loadGltfPrimitiveMaterial( mat.doubleSided() = doubleSided; mat.normalScale() = normalScale; mat.occlusionStrength() = occlusionStrength; + mat.specular() = specular; + mat.specularColor() = specularColor; loadTextureInMaterial( mat, baseColorTextureId, Material::TextureType::BASE_COLOR); loadTextureInMaterial( @@ -193,6 +232,10 @@ int loadGltfPrimitiveMaterial( mat, occlusionTextureId, Material::TextureType::OCCLUSION); loadTextureInMaterial( mat, emissiveTextureId, Material::TextureType::EMISSIVE); + loadTextureInMaterial( + mat, specularTextureId, Material::TextureType::SPECULAR); + loadTextureInMaterial( + mat, specularColorTextureId, Material::TextureType::SPECULAR_COLOR); m.pushMaterial(mat); idx = m.materialCount() - 1; // index of the added material if constexpr (HasColor) { diff --git a/vclib/core/include/vclib/space/core/material.h b/vclib/core/include/vclib/space/core/material.h index 1216a966c3..dcf03894a1 100644 --- a/vclib/core/include/vclib/space/core/material.h +++ b/vclib/core/include/vclib/space/core/material.h @@ -53,6 +53,8 @@ class Material OCCLUSION, ///< The ambient occlusion map (R channel). Stored in linear ///< color space. EMISSIVE, ///< The emissive color texture. Stored in sRGB color space. + SPECULAR, + SPECULAR_COLOR, COUNT ///< Utility value to get the number of texture types. }; @@ -63,7 +65,9 @@ class Material "metallicRoughnessTex", "normalTex", "occlusionTex", - "emissiveTex"}; + "emissiveTex", + "specularTex", + "specularColorTex"}; private: inline static const uint N_TEXTURE_TYPE = @@ -93,6 +97,11 @@ class Material bool mDoubleSided = false; + float mSpecular = 1.0f; + + // needs to be HDR + Point3f mSpecularColor = Point3f(1.0, 1.0, 1.0); + public: /** * @brief Default constructor. @@ -238,6 +247,30 @@ class Material */ float& occlusionStrength() { return mOcclusionStrength; } + /** + * @brief Gets the strength of the specular effect. + * @return The specular strength, in the range [0.0, 1.0]. + */ + float specular() const { return mSpecular; } + + /** + * @brief Gets a mutable reference to the specular strength. + * @return A reference to the specular strength. + */ + float& specular() { return mSpecular; } + + /** + * @brief Gets the specular color of the material. + * @return A const reference to the specular color. + */ + const Point3f& specularColor() const { return mSpecularColor; } + + /** + * @brief Gets a mutable reference to the specular color of the material. + * @return A reference to the specular color. + */ + Point3f& specularColor() { return mSpecularColor; } + /** * @brief Gets the texture descriptor for the base color texture. * @return A const reference to the base color texture descriptor. @@ -318,6 +351,8 @@ class Material vcl::serialize(os, mAlphaMode, mAlphaCutoff); vcl::serialize(os, mNormalScale); vcl::serialize(os, mOcclusionStrength); + vcl::serialize(os, mSpecular); + mSpecularColor.serialize(os); vcl::serialize(os, mTextureDescriptors); vcl::serialize(os, mDoubleSided); } @@ -335,6 +370,8 @@ class Material vcl::deserialize(is, mAlphaMode, mAlphaCutoff); vcl::deserialize(is, mNormalScale); vcl::deserialize(is, mOcclusionStrength); + vcl::deserialize(is, mSpecular); + mSpecularColor.deserialize(is); vcl::deserialize(is, mTextureDescriptors); vcl::deserialize(is, mDoubleSided); } @@ -361,10 +398,12 @@ class Material { switch (type) { case TextureType::BASE_COLOR: - case TextureType::EMISSIVE: return Image::ColorSpace::SRGB; + case TextureType::EMISSIVE: + case TextureType::SPECULAR_COLOR: return Image::ColorSpace::SRGB; case TextureType::METALLIC_ROUGHNESS: case TextureType::NORMAL: case TextureType::OCCLUSION: + case TextureType::SPECULAR: default: return Image::ColorSpace::LINEAR; } } diff --git a/vclib/render/include/vclib/bgfx/drawable/drawable_environment.h b/vclib/render/include/vclib/bgfx/drawable/drawable_environment.h index 9d0c0f93b6..dae5e558b2 100644 --- a/vclib/render/include/vclib/bgfx/drawable/drawable_environment.h +++ b/vclib/render/include/vclib/bgfx/drawable/drawable_environment.h @@ -45,7 +45,7 @@ class DrawableEnvironment Uniform("s_specular", bgfx::UniformType::Sampler); // Sampler of mBrdfLuTexture const Uniform mBrdfLutSamplerUniform = - Uniform("s_tex5", bgfx::UniformType::Sampler); + Uniform("s_brdfLut", bgfx::UniformType::Sampler); // The number of mip levels in the specular cubemap, // this value is needed by the shader to correctly sample the specular map. diff --git a/vclib/render/include/vclib/bgfx/drawable/uniforms/drawable_mesh_uniforms.h b/vclib/render/include/vclib/bgfx/drawable/uniforms/drawable_mesh_uniforms.h index 016fb9f293..81facf8b05 100644 --- a/vclib/render/include/vclib/bgfx/drawable/uniforms/drawable_mesh_uniforms.h +++ b/vclib/render/include/vclib/bgfx/drawable/uniforms/drawable_mesh_uniforms.h @@ -28,7 +28,7 @@ class DrawableMeshUniforms // sMeshData[1]: as uint, first chunk primitive id drawn // sMeshData[2]: 8 texture stages with 4 bit each, to specify if texture is // used (value != 15) and which stage is used for each texture (as uint): - // none|none|brdfLut|emissive|occlusion|normal|metallRough|baseColor + // brdfLut|specularColor|specular|emissive|occlusion|normal|metallRough|baseColor inline static std::array sMeshData = {0.0, 0.0, std::bit_cast(0xFFFFFFFF), 0.0}; @@ -46,6 +46,8 @@ class DrawableMeshUniforms NORMAL, OCCLUSION, EMISSIVE, + SPECULAR, + SPECULAR_COLOR, BRDF_LUT, COUNT }; diff --git a/vclib/render/include/vclib/bgfx/drawable/uniforms/material_uniforms.h b/vclib/render/include/vclib/bgfx/drawable/uniforms/material_uniforms.h index 117dfe4ab9..3d3e4e0675 100644 --- a/vclib/render/include/vclib/bgfx/drawable/uniforms/material_uniforms.h +++ b/vclib/render/include/vclib/bgfx/drawable/uniforms/material_uniforms.h @@ -41,6 +41,13 @@ class MaterialUniforms static inline std::array sEmissiveAlphaCutoffPack = {0.0, 0.0, 0.0, 0.5}; + // settings packed in a vec4 + // .x : pbr settings + static inline std::array sSettings = {0.0, 0.0, 0.0, 0.0}; + + // specular color (RGB) and specular (A) + static inline std::array sSpecularPack = {1.0, 1.0, 1.0, 1.0}; + static inline StaticUniform sBaseColorUniform { "u_baseColorFactor", bgfx::UniformType::Vec4}; @@ -50,6 +57,12 @@ class MaterialUniforms static inline StaticUniform sEmissiveAlphaCutoffPackUniform { "u_emissiveAlphaCutoffPack", bgfx::UniformType::Vec4}; + static inline StaticUniform sSettingsUniform { + "u_settings", + bgfx::UniformType::Vec4}; + static inline StaticUniform sSpecularPackUniform { + "u_specularPack", + bgfx::UniformType::Vec4}; public: MaterialUniforms() = delete; @@ -79,6 +92,11 @@ class MaterialUniforms sEmissiveAlphaCutoffPack[0] = m.emissiveColor().redF(); sEmissiveAlphaCutoffPack[1] = m.emissiveColor().greenF(); sEmissiveAlphaCutoffPack[2] = m.emissiveColor().blueF(); + + sSpecularPack[0] = m.specularColor()[0]; + sSpecularPack[1] = m.specularColor()[1]; + sSpecularPack[2] = m.specularColor()[2]; + sSpecularPack[3] = m.specular(); } static void bind() @@ -86,6 +104,8 @@ class MaterialUniforms sBaseColorUniform.bind(sBaseColor.data()); sFactorsPackUniform.bind(sFactorsPack.data()); sEmissiveAlphaCutoffPackUniform.bind(sEmissiveAlphaCutoffPack.data()); + sSettingsUniform.bind(sSettings.data()); + sSpecularPackUniform.bind(sSpecularPack.data()); } }; diff --git a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/material_uniforms.sh b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/material_uniforms.sh index e0e911832c..fb6c333fc5 100644 --- a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/material_uniforms.sh +++ b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/material_uniforms.sh @@ -11,6 +11,8 @@ uniform vec4 u_baseColorFactor; uniform vec4 u_FactorsPack; uniform vec4 u_emissiveAlphaCutoffPack; +uniform vec4 u_settings; +uniform vec4 u_specularPack; #define u_occlusionStrength u_FactorsPack.r #define u_roughnessFactor u_FactorsPack.g @@ -22,4 +24,7 @@ uniform vec4 u_emissiveAlphaCutoffPack; #define isAlphaModeMask() (u_alphaCutoff >= 0.0) +#define u_specularColorFactor u_specularPack.rgb +#define u_specularFactor u_specularPack.a + #endif // VCL_BGFX_DRAWABLE_DRAWABLE_MESH_MATERIAL_UNIFORMS_SH diff --git a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/common.sh b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/common.sh index f8b17e6b20..110f81f845 100644 --- a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/common.sh +++ b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/common.sh @@ -172,9 +172,8 @@ float pbrSpecular( * the amount of light reflected when looking at a surface with a 0 degree angle (right above). * @return The IBL Fresnel term. */ -vec3 iblGgxFresnel(vec2 brdf, float NoV, float roughness, vec3 F0) +vec3 iblGgxFresnel(vec2 brdf, float NoV, float roughness, vec3 F0, float specularWeight) { - float specularWeight = 1.0; // related to some extension, for now use a neutral value // see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results // Roughness dependent fresnel, from Fdez-Aguera vec3 Fr = max(vec3_splat(1.0 - roughness), F0) - F0; @@ -226,12 +225,15 @@ vec4 pbrColorLights( float metallic, float roughness, vec3 emissive, + float specular, + vec3 specularColor, float exposure, int toneMapping) { vec3 finalColor = vec3_splat(0.0); - vec3 f0_dielectric = vec3_splat(0.04); + vec3 f0_dielectric = min(vec3_splat(0.04) * specularColor, vec3_splat(1.0)); vec3 f90 = vec3_splat(1.0); + vec3 f90_dielectric = vec3_splat(specular); // view direction vec3 V = normalize(cameraEyePos - vPos); @@ -255,7 +257,7 @@ vec4 pbrColorLights( // Fresnel factors for both dielectric and metallic surfaces // 0.04 is an approximation of F0 averaged around many dielectric materials - vec3 dielectric_fresnel = F_Schlick(f0_dielectric, f90, abs(VoH)); + vec3 dielectric_fresnel = F_Schlick(f0_dielectric * specular, f90_dielectric, abs(VoH)); // Metals have the surface color as base reflectivity since no light gets absorbed vec3 metal_fresnel = F_Schlick(color.rgb, f90, abs(VoH)); diff --git a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/fs_surface_pbr.sc b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/fs_surface_pbr.sc index a8d627c5d5..1901b4afc6 100644 --- a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/fs_surface_pbr.sc +++ b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/surface_pbr/fs_surface_pbr.sc @@ -134,6 +134,14 @@ void main() vec3 emissiveColor = u_emissiveFactor * emissiveTexture; + float specular = u_specularFactor; + if (useTexture && isSpecularTextureAvailable()) + specular *= specularTex(texcoord).a; + + vec3 specularColor = u_specularColorFactor; + if (useTexture && isSpecularColorTextureAvailable()) + specularColor *= specularColorTex(texcoord).rgb; + if(useImageBasedLighting()) { // view direction @@ -149,8 +157,7 @@ void main() float NoV = clampedDot(normal, V); - vec3 f0_dielectric = vec3_splat(0.04); - vec3 f90 = vec3_splat(1.0); + vec3 f0_dielectric = min(vec3_splat(0.04) * specularColor, vec3_splat(1.0)); // diffuse light vec3 diffuseLight = textureCube(s_irradiance, leftHand(normal)).rgb; @@ -162,8 +169,8 @@ void main() // Fresnel vec2 brdf = brdfLutTex(vec2(NoV, roughness)).rg; - vec3 metalFresnel = iblGgxFresnel(brdf, NoV, roughness, baseColor.rgb); - vec3 dielectricFresnel = iblGgxFresnel(brdf, NoV, roughness, f0_dielectric); + vec3 metalFresnel = iblGgxFresnel(brdf, NoV, roughness, baseColor.rgb, 1.0); + vec3 dielectricFresnel = iblGgxFresnel(brdf, NoV, roughness, f0_dielectric, specular); // occlusion float occlusion = 1.0; @@ -214,6 +221,8 @@ void main() metallic, roughness, emissiveColor, + specular, + specularColor, u_exposure, u_toneMapping ); diff --git a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/texture_uniforms.sh b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/texture_uniforms.sh index 6d86354c9e..c78c6502cf 100644 --- a/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/texture_uniforms.sh +++ b/vclib/render/shaders/vclib/bgfx/drawable/drawable_mesh/texture_uniforms.sh @@ -23,6 +23,8 @@ SAMPLER2D(s_tex2, 2); SAMPLER2D(s_tex3, 3); SAMPLER2D(s_tex4, 4); SAMPLER2D(s_tex5, 5); +SAMPLER2D(s_tex6, 6); +SAMPLER2D(s_tex7, 7); vec4 textureStage(uint stage, vec2 texcoord) { @@ -39,6 +41,10 @@ vec4 textureStage(uint stage, vec2 texcoord) return texture2D(s_tex4, texcoord); case 5u: return texture2D(s_tex5, texcoord); + case 6u: + return texture2D(s_tex6, texcoord); + case 7u: + return texture2D(s_tex7, texcoord); default: // should never happen, return a magenta color to easily spot the error return vec4(1.0, 0.0, 1.0, 1.0); @@ -54,7 +60,9 @@ vec4 textureStage(uint stage, vec2 texcoord) // 2 -> normal // 3 -> occlusion // 4 -> emissive -// 5 -> brdf lut +// 5 -> specular +// 6 -> specular color +// 7 -> brdf lut // // to get the actual stage index: textureStageBitField(u_textureStagesZ, pos) @@ -108,14 +116,34 @@ vec4 emissiveTex(vec2 texcoord) return textureStage(textureStageBitField(u_textureStagesZ, 4), texcoord); } -bool isBrdfLutTextureAvailable() +bool isSpecularTextureAvailable() { return textureStageBitField(u_textureStagesZ, 5) != 0xF; } -vec4 brdfLutTex(vec2 texcoord) +vec4 specularTex(vec2 texcoord) { return textureStage(textureStageBitField(u_textureStagesZ, 5), texcoord); } +bool isSpecularColorTextureAvailable() +{ + return textureStageBitField(u_textureStagesZ, 6) != 0xF; +} + +vec4 specularColorTex(vec2 texcoord) +{ + return textureStage(textureStageBitField(u_textureStagesZ, 6), texcoord); +} + +bool isBrdfLutTextureAvailable() +{ + return textureStageBitField(u_textureStagesZ, 7) != 0xF; +} + +vec4 brdfLutTex(vec2 texcoord) +{ + return textureStage(textureStageBitField(u_textureStagesZ, 7), texcoord); +} + #endif // VCL_BGFX_DRAWABLE_DRAWABLE_MESH_TEXTURE_UNIFORMS_SH