diff --git a/android/pbribl/build.py b/android/pbribl/build.py index 5e01aeac..d6ea9772 100644 --- a/android/pbribl/build.py +++ b/android/pbribl/build.py @@ -7,48 +7,42 @@ import glob APK_NAME = "vulkanPBRIBL" SHADER_DIR = "pbribl" ASSETS_MODELS = ["cube.obj", "geosphere.obj", "teapot.dae", "torusknot.obj", "venus.fbx"] -ASSETS_TEXTURES = ["hamarikyu_bridge_radiance_cube.ktx", "hamarikyu_bridge_irradiance_cube.ktx"] +ASSETS_TEXTURES = ["hdr/pisa_cube.ktx"] -if subprocess.call("ndk-build", shell=True) == 0: +if subprocess.call("ndk-build", shell=True) == 0: print("Build successful") # Assets - if not os.path.exists("./assets"): - os.makedirs("./assets") + os.makedirs("./assets/shaders/base", exist_ok=True) + os.makedirs("./assets/shaders/%s" % SHADER_DIR, exist_ok=True) + os.makedirs("./assets/textures/hdr", exist_ok=True) + os.makedirs("./assets/models", exist_ok=True) + os.makedirs("./res/drawable", exist_ok=True) - # Shaders + # Shaders # Base - if not os.path.exists("./assets/shaders/base"): - os.makedirs("./assets/shaders/base") for file in glob.glob("../../data/shaders/base/*.spv"): - shutil.copy(file, "./assets/shaders/base") + shutil.copy(file, "./assets/shaders/base") # Sample - if not os.path.exists("./assets/shaders/%s" % SHADER_DIR): - os.makedirs("./assets/shaders/%s" % SHADER_DIR) for file in glob.glob("../../data/shaders/%s/*.spv" %SHADER_DIR): - shutil.copy(file, "./assets/shaders/%s" % SHADER_DIR) + shutil.copy(file, "./assets/shaders/%s" % SHADER_DIR) # Textures - if not os.path.exists("./assets/textures"): - os.makedirs("./assets/textures") for file in ASSETS_TEXTURES: - shutil.copy("../../data/textures/%s" % file, "./assets/textures") + shutil.copy("../../data/textures/%s" % file, "./assets/textures/hdr") # Models - if not os.path.exists("./assets/models"): - os.makedirs("./assets/models") for file in ASSETS_MODELS: shutil.copy("../../data/models/%s" % file, "./assets/models") # Icon - if not os.path.exists("./res/drawable"): - os.makedirs("./res/drawable") - shutil.copy("../../android/images/icon.png", "./res/drawable") + shutil.copy("../../android/images/icon.png", "./res/drawable") if subprocess.call("ant debug -Dout.final.file=%s.apk" % APK_NAME, shell=True) == 0: - if len(sys.argv) > 1: - if sys.argv[1] == "-deploy": + for arg in sys.argv[1:]: + if arg == "-deploy": if subprocess.call("adb install -r %s.apk" % APK_NAME, shell=True) != 0: print("Could not deploy to device!") else: print("Error during build process!") else: print("Error building project!") + \ No newline at end of file diff --git a/data/shaders/pbribl/pbribl.frag b/data/shaders/pbribl/pbribl.frag index 624a88a7..40c3aa19 100644 --- a/data/shaders/pbribl/pbribl.frag +++ b/data/shaders/pbribl/pbribl.frag @@ -1,6 +1,3 @@ -// Phyiscally based rendering using IBL -// Based on http://www.trentreed.net/blog/physically-based-shading-and-image-based-lighting/ - #version 450 layout (location = 0) in vec3 inWorldPos; @@ -14,10 +11,11 @@ layout (binding = 0) uniform UBO { vec3 camPos; } ubo; -layout (binding = 1) uniform UBOShared { +layout (binding = 1) uniform UBOParams { + vec4 lights[4]; float exposure; float gamma; -} uboShared; +} uboParams; layout(push_constant) uniform PushConsts { layout(offset = 12) float roughness; @@ -28,13 +26,17 @@ layout(push_constant) uniform PushConsts { layout(offset = 32) float b; } material; -layout (binding = 2) uniform samplerCube radianceMap; -layout (binding = 3) uniform samplerCube irradianceMap; +layout (binding = 2) uniform samplerCube samplerIrradiance; +layout (binding = 3) uniform sampler2D samplerBRDFLUT; +layout (binding = 4) uniform samplerCube prefilteredMap; layout (location = 0) out vec4 outColor; +#define PI 3.1415926535897932384626433832795 +#define ALBEDO vec3(material.r, material.g, material.b) + // From http://filmicgames.com/archives/75 -vec3 Uncharted2Tonemap( vec3 x ) +vec3 Uncharted2Tonemap(vec3 x) { float A = 0.15; float B = 0.50; @@ -45,48 +47,116 @@ vec3 Uncharted2Tonemap( vec3 x ) return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; } -// Environment BRDF approximation from https://www.unrealengine.com/blog/physically-based-shading-on-mobile -vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) +// Normal Distribution function -------------------------------------- +float D_GGX(float dotNH, float roughness) { - vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022); - vec4 c1 = vec4(1, 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 SpecularColor * AB.x + AB.y; + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); } -void main() +// Geometric Shadowing function -------------------------------------- +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) { + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +// Fresnel function ---------------------------------------------------- +vec3 F_Schlick(float cosTheta, vec3 F0) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} +vec3 F_SchlickR(float cosTheta, vec3 F0, float roughness) +{ + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); +} + +vec3 prefilteredReflection(vec3 R, float roughness) +{ + const float MAX_REFLECTION_LOD = 9.0; // todo: param/const + float lod = roughness * MAX_REFLECTION_LOD; + float lodf = floor(lod); + float lodc = ceil(lod); + vec3 a = textureLod(prefilteredMap, R, lodf).rgb; + vec3 b = textureLod(prefilteredMap, R, lodc).rgb; + return mix(a, b, lod - lodf); +} + +vec3 specularContribution(vec3 L, vec3 V, vec3 N, vec3 F0, float metallic, float roughness) +{ + // Precalculate vectors and dot products + vec3 H = normalize (V + L); + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotNV = clamp(dot(N, V), 0.0, 1.0); + float dotNL = clamp(dot(N, L), 0.0, 1.0); + + // Light color fixed + vec3 lightColor = vec3(1.0); + + vec3 color = vec3(0.0); + + if (dotNL > 0.0) { + // D = Normal distribution (Distribution of the microfacets) + float D = D_GGX(dotNH, roughness); + // G = Geometric shadowing term (Microfacets shadowing) + float G = G_SchlicksmithGGX(dotNL, dotNV, roughness); + // F = Fresnel factor (Reflectance depending on angle of incidence) + vec3 F = F_Schlick(dotNV, F0); + vec3 spec = D * F * G / (4.0 * dotNL * dotNV + 0.001); + vec3 kD = (vec3(1.0) - F) * (1.0 - metallic); + color += (kD * ALBEDO / PI + spec) * dotNL; + } + + return color; +} + +void main() +{ vec3 N = normalize(inNormal); vec3 V = normalize(ubo.camPos - inWorldPos); - vec3 R = reflect(-V, N); + vec3 R = reflect(-V, N); - vec3 baseColor = vec3(material.r, material.g, material.b); - - // Diffuse and specular color from material color and metallic factor - vec3 diffuseColor = baseColor - baseColor * material.metallic; - vec3 specularColor = mix(vec3(material.specular), baseColor, material.metallic); + float metallic = material.metallic; + float roughness = material.roughness; - // Cube map sampling - ivec2 cubedim = textureSize(radianceMap, 0); - int numMipLevels = int(log2(max(cubedim.s, cubedim.y))); - float mipLevel = numMipLevels - 1.0 + log2(material.roughness); - vec3 radianceSample = pow(textureLod(radianceMap, R, mipLevel).rgb, vec3(2.2f)); - vec3 irradianceSample = pow(texture(irradianceMap, N).rgb, vec3(2.2f)); + vec3 F0 = vec3(0.04); + F0 = mix(F0, ALBEDO, metallic); + + vec3 Lo = vec3(0.0); + for(int i = 0; i < uboParams.lights[i].length(); i++) { + vec3 L = normalize(uboParams.lights[i].xyz - inWorldPos); + Lo += specularContribution(L, V, N, F0, metallic, roughness); + } - vec3 reflection = EnvBRDFApprox(specularColor, pow(material.roughness, 1.0f), clamp(dot(N, V), 0.0, 1.0)); - - // Combine specular IBL and BRDF - vec3 diffuse = diffuseColor * irradianceSample; - vec3 specular = radianceSample * reflection; - vec3 color = diffuse + specular; + vec2 brdf = texture(samplerBRDFLUT, vec2(max(dot(N, V), 0.0), roughness)).rg; + vec3 reflection = prefilteredReflection(R, roughness).rgb; + vec3 irradiance = texture(samplerIrradiance, N).rgb; + + // Diffuse based on irradiance + vec3 diffuse = irradiance * ALBEDO; + + vec3 F = F_SchlickR(max(dot(N, V), 0.0), F0, roughness); + + // Specular reflectance + vec3 specular = reflection * (F * brdf.x + brdf.y); + + // Ambient part + vec3 kD = 1.0 - F; + kD *= 1.0 - metallic; + vec3 ambient = (kD * diffuse + specular); + vec3 color = ambient + Lo; + // Tone mapping - color = Uncharted2Tonemap( color * uboShared.exposure ); + color = Uncharted2Tonemap(color * uboParams.exposure); color = color * (1.0f / Uncharted2Tonemap(vec3(11.2f))); // Gamma correction - color = pow(color, vec3(1.0f / uboShared.gamma)); - - outColor = vec4( color, 1.0 ); + color = pow(color, vec3(1.0f / uboParams.gamma)); + + outColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/data/shaders/pbribl/pbribl.frag.spv b/data/shaders/pbribl/pbribl.frag.spv index ce21aca0..28cabcad 100644 Binary files a/data/shaders/pbribl/pbribl.frag.spv and b/data/shaders/pbribl/pbribl.frag.spv differ diff --git a/data/shaders/pbribl/pbribl.vert b/data/shaders/pbribl/pbribl.vert index bc741abd..8516341c 100644 --- a/data/shaders/pbribl/pbribl.vert +++ b/data/shaders/pbribl/pbribl.vert @@ -34,5 +34,6 @@ void main() outWorldPos = locPos + pushConsts.objPos; outNormal = mat3(ubo.model) * inNormal; outUV = inUV; + outUV.t = 1.0 - inUV.t; gl_Position = ubo.projection * ubo.view * vec4(outWorldPos, 1.0); } diff --git a/data/shaders/pbribl/pbribl.vert.spv b/data/shaders/pbribl/pbribl.vert.spv index a9abfe39..9537021a 100644 Binary files a/data/shaders/pbribl/pbribl.vert.spv and b/data/shaders/pbribl/pbribl.vert.spv differ diff --git a/data/shaders/pbribl/skybox.frag b/data/shaders/pbribl/skybox.frag index c7f5834d..e46fdfe0 100644 --- a/data/shaders/pbribl/skybox.frag +++ b/data/shaders/pbribl/skybox.frag @@ -6,10 +6,11 @@ layout (location = 0) in vec3 inUVW; layout (location = 0) out vec4 outColor; -layout (binding = 1) uniform UBOShared { +layout (binding = 1) uniform UBOParams { + vec4 lights[4]; float exposure; float gamma; -} uboShared; +} uboParams; // From http://filmicworlds.com/blog/filmic-tonemapping-operators/ vec3 Uncharted2Tonemap(vec3 color) @@ -26,13 +27,13 @@ vec3 Uncharted2Tonemap(vec3 color) void main() { - vec3 color = pow(texture(samplerEnv, inUVW).rgb, vec3(2.2)); + vec3 color = texture(samplerEnv, inUVW).rgb; - color = Uncharted2Tonemap(color * uboShared.exposure); - color = color * (1.0 / Uncharted2Tonemap(vec3(11.2))); - - // gamma correction - color = pow(color, vec3(1.0 / uboShared.gamma)); + // Tone mapping + color = Uncharted2Tonemap(color * uboParams.exposure); + color = color * (1.0f / Uncharted2Tonemap(vec3(11.2f))); + // Gamma correction + color = pow(color, vec3(1.0f / uboParams.gamma)); outColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/data/shaders/pbribl/skybox.frag.spv b/data/shaders/pbribl/skybox.frag.spv index caeed8df..d5632e9e 100644 Binary files a/data/shaders/pbribl/skybox.frag.spv and b/data/shaders/pbribl/skybox.frag.spv differ diff --git a/data/textures/hamarikyu_bridge_irradiance_cube.ktx b/data/textures/hamarikyu_bridge_irradiance_cube.ktx deleted file mode 100644 index b449886b..00000000 Binary files a/data/textures/hamarikyu_bridge_irradiance_cube.ktx and /dev/null differ diff --git a/data/textures/hamarikyu_bridge_radiance_cube.ktx b/data/textures/hamarikyu_bridge_radiance_cube.ktx deleted file mode 100644 index 27d6b8f7..00000000 Binary files a/data/textures/hamarikyu_bridge_radiance_cube.ktx and /dev/null differ diff --git a/pbribl/pbribl.cpp b/pbribl/pbribl.cpp index 8f37014f..0582a93a 100644 --- a/pbribl/pbribl.cpp +++ b/pbribl/pbribl.cpp @@ -1,15 +1,15 @@ /* * Vulkan Example - Physical based rendering with image based lighting * -* See http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf +* Note: Requires the separate (HDR) asset pack (see data/textures/hdr/README.md) * -* Important note: Work in progress (assets missing, may not work or compile, etc.) -* -* Copyright (C) 2017 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ +// For reference see http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf + #include #include #include @@ -34,13 +34,14 @@ #define GRID_DIM 7 struct Material { - float roughness; - float metallic; - float specular; - float r,g,b; // Color components as single floats because we use push constants + // Set in object rendering loop + float roughness = 0.0f; + float metallic = 0.0f; + float specular = 0.0f; + float r, g, b; std::string name; Material() {}; - Material(std::string n, glm::vec3 c, float r, float m) : name(n), roughness(r), metallic(m), r(c.r), g(c.g), b(c.b) { specular = 0.8f; }; + Material(std::string n, glm::vec3 c) : name(n), r(c.r), g(c.g), b(c.b) { }; }; class VulkanExample : public VulkanExampleBase @@ -84,7 +85,7 @@ public: struct UBOParams { glm::vec4 lights[4]; - float exposure = 10.0f; + float exposure = 2.0f; float gamma = 2.2f; } uboParams; @@ -115,24 +116,25 @@ public: camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); camera.rotationSpeed = 0.25f; - camera.setRotation({ -22.75f, 180.0f, 0.0f }); - camera.setPosition({ 1.2, 5.6, 17.0f }); + camera.setRotation({ -3.75f, 180.0f, 0.0f }); + camera.setPosition({ 0.55f, 0.85f, 12.0f }); // Setup some default materials (source: https://seblagarde.wordpress.com/2011/08/17/feeding-a-physical-based-lighting-mode/) - materials.push_back(Material("Gold", glm::vec3(1.0f, 0.765557f, 0.336057f), 0.1f, 1.0f)); - materials.push_back(Material("Copper", glm::vec3(0.955008f, 0.637427f, 0.538163f), 0.1f, 1.0f)); - materials.push_back(Material("Chromium", glm::vec3(0.549585f, 0.556114f, 0.554256f), 0.1f, 1.0f)); - materials.push_back(Material("Nickel", glm::vec3(0.659777f, 0.608679f, 0.525649f), 0.1f, 1.0f)); - materials.push_back(Material("Titanium", glm::vec3(0.541931f, 0.496791f, 0.449419f), 0.1f, 1.0f)); - materials.push_back(Material("Cobalt", glm::vec3(0.662124f, 0.654864f, 0.633732f), 0.1f, 1.0f)); - materials.push_back(Material("Platinum", glm::vec3(0.672411f, 0.637331f, 0.585456f), 0.1f, 1.0f)); + materials.push_back(Material("Gold", glm::vec3(1.0f, 0.765557f, 0.336057f))); + materials.push_back(Material("Copper", glm::vec3(0.955008f, 0.637427f, 0.538163f))); + materials.push_back(Material("Chromium", glm::vec3(0.549585f, 0.556114f, 0.554256f))); + materials.push_back(Material("Nickel", glm::vec3(0.659777f, 0.608679f, 0.525649f))); + materials.push_back(Material("Titanium", glm::vec3(0.541931f, 0.496791f, 0.449419f))); + materials.push_back(Material("Cobalt", glm::vec3(0.662124f, 0.654864f, 0.633732f))); + materials.push_back(Material("Platinum", glm::vec3(0.672411f, 0.637331f, 0.585456f))); // Testing materials - materials.push_back(Material("White", glm::vec3(1.0f), 0.1f, 1.0f)); - materials.push_back(Material("Red", glm::vec3(1.0f, 0.0f, 0.0f), 0.1f, 1.0f)); - materials.push_back(Material("Blue", glm::vec3(0.0f, 0.0f, 1.0f), 0.1f, 1.0f)); - materials.push_back(Material("Black", glm::vec3(0.0f), 0.1f, 1.0f)); + materials.push_back(Material("White", glm::vec3(1.0f))); + materials.push_back(Material("Dark", glm::vec3(0.1f))); + materials.push_back(Material("Black", glm::vec3(0.0f))); + materials.push_back(Material("Red", glm::vec3(1.0f, 0.0f, 0.0f))); + materials.push_back(Material("Blue", glm::vec3(0.0f, 0.0f, 1.0f))); - materialIndex = 7; + materialIndex = 9; } ~VulkanExample() @@ -385,13 +387,13 @@ public: pipelineCreateInfo.pVertexInputState = &vertexInputState; // Skybox pipeline (background cube) - shaderStages[0] = loadShader(getAssetPath() + "shaders/pbribl/skybox.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/pbribl/skybox.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(ASSET_PATH "shaders/pbribl/skybox.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(ASSET_PATH "shaders/pbribl/skybox.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.skybox)); // PBR pipeline - shaderStages[0] = loadShader(getAssetPath() + "shaders/pbribl/pbribl.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/pbribl/pbribl.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(ASSET_PATH "shaders/pbribl/pbribl.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(ASSET_PATH "shaders/pbribl/pbribl.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); // Enable depth test and write depthStencilState.depthWriteEnable = VK_TRUE; depthStencilState.depthTestEnable = VK_TRUE; @@ -560,8 +562,8 @@ public: pipelineCI.pVertexInputState = &emptyInputState; // Look-up-table (from BRDF) pipeline - shaderStages[0] = loadShader(getAssetPath() + "shaders/pbribl/genbrdflut.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/pbribl/genbrdflut.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(ASSET_PATH "shaders/pbribl/genbrdflut.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(ASSET_PATH "shaders/pbribl/genbrdflut.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VkPipeline pipeline; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); @@ -799,8 +801,8 @@ public: struct PushBlock { glm::mat4 mvp; // Sampling deltas - float deltaPhi = (2.0f * M_PI) / 180.0f; - float deltaTheta = (0.5f * M_PI) / 64.0f; + float deltaPhi = (2.0f * float(M_PI)) / 180.0f; + float deltaTheta = (0.5f * float(M_PI)) / 64.0f; } pushBlock; VkPipelineLayout pipelinelayout; @@ -847,8 +849,8 @@ public: pipelineCI.pVertexInputState = &vertexInputState; pipelineCI.renderPass = renderpass; - shaderStages[0] = loadShader(getAssetPath() + "shaders/pbribl/filtercube.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/pbribl/irradiancecube.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(ASSET_PATH "shaders/pbribl/filtercube.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(ASSET_PATH "shaders/pbribl/irradiancecube.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VkPipeline pipeline; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); @@ -1244,8 +1246,8 @@ public: pipelineCI.pVertexInputState = &vertexInputState; pipelineCI.renderPass = renderpass; - shaderStages[0] = loadShader(getAssetPath() + "shaders/pbribl/filtercube.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/pbribl/prefilterenvmap.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(ASSET_PATH "shaders/pbribl/filtercube.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(ASSET_PATH "shaders/pbribl/prefilterenvmap.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VkPipeline pipeline; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); @@ -1573,9 +1575,7 @@ public: textOverlay->addText("\"Button X\" to toggle object", 5.0f, 100.0f, VulkanTextOverlay::alignLeft); #else textOverlay->addText("Material: " + materials[materialIndex].name + " (+/-)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); - //textOverlay->addText("Exposure = " + std::to_string(uboParams.exposure) + " (F3/F4)", 5.0f, 100.0f, VulkanTextOverlay::alignLeft); - //textOverlay->addText("\"F2\" to toggle skybox", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); - //textOverlay->addText("\"space\" to toggle object", 5.0f, 100.0f, VulkanTextOverlay::alignLeft); + textOverlay->addText("Exposure: " + std::to_string(uboParams.exposure) + " (F3/F4)", 5.0f, 100.0f, VulkanTextOverlay::alignLeft); #endif } };