From ec23aa58095978df40540702a750496172bb32b3 Mon Sep 17 00:00:00 2001 From: Supakorn 'Jamie' Rassameemasmuang Date: Thu, 29 Feb 2024 00:59:16 -0700 Subject: [PATCH] GLSL: Use linear color for blending pixels in transparent rendering. --- base/shaders/blend.glsl | 18 ++++++++++++++++++ base/shaders/fragment.glsl | 11 +++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/base/shaders/blend.glsl b/base/shaders/blend.glsl index e3ff9ecb7..288b37f8b 100644 --- a/base/shaders/blend.glsl +++ b/base/shaders/blend.glsl @@ -58,6 +58,21 @@ vec4 blend(vec4 outColor, vec4 color) return mix(outColor,color,color.a); } +const float gamma=2.2; +const float invGamma=1.0/gamma; + +/** + * @brief Converts linear color (measuring photon count) to srgb (what our brain thinks + * is the brightness + * example linearToPerceptual(vec3(0.5)) is approximately vec3(0.729) + */ +vec3 linearToPerceptual(vec3 inColor) +{ + // an actual 0.5 brightness (half amount of photons) would + // look brighter than what our eyes think is "half" light + return pow(inColor, vec3(invGamma)); +} + void main() { uint pixel=uint(gl_FragCoord.y)*push.constants[1]+uint(gl_FragCoord.x); @@ -159,5 +174,8 @@ void main() } } + vec3 perceptualColor=linearToPerceptual(outColor.rgb); + outColor = vec4(perceptualColor, outColor.a); + COUNT(pixel)=0u; } diff --git a/base/shaders/fragment.glsl b/base/shaders/fragment.glsl index 7ff28b588..d8a2eabda 100644 --- a/base/shaders/fragment.glsl +++ b/base/shaders/fragment.glsl @@ -287,15 +287,18 @@ void main() { // (e.g. our 0.5 is much much brighter than what swap chain/monitor thinks 0.5 is) // need to give the output image the color our brain perceives with the same photon count // as the original pixel - vec3 outColorInPerceptualSpace=linearToPerceptual(outColor.rgb); - outColor=vec4(outColorInPerceptualSpace,outColor.a); + vec4 linearColor=outColor; + + // outColor is our output vector, so save what we have as linear color + vec3 outColorInPerceptualSpace=linearToPerceptual(linearColor.rgb); + outColor=vec4(outColorInPerceptualSpace,linearColor.a); #ifndef WIDTH // TODO DO NOT DO THE DEPTH COMPARISON WHEN NO TRANSPARENT OBJECTS! uint pixel=uint(gl_FragCoord.y)*push.constants[1]+uint(gl_FragCoord.x); #if defined(TRANSPARENT) || (!defined(HAVE_INTERLOCK) && !defined(OPAQUE)) uint element=INDEX(pixel); uint listIndex=atomicAdd(offset[element],-1u)-1u; - fragment[listIndex]=outColor; + fragment[listIndex]=linearColor; depth[listIndex]=gl_FragCoord.z; #ifndef WIREFRAME discard; @@ -306,7 +309,7 @@ void main() { if(opaqueDepth[pixel] == 0.0 || gl_FragCoord.z < opaqueDepth[pixel]) { opaqueDepth[pixel]=gl_FragCoord.z; - opaqueColor[pixel]=outColor; + opaqueColor[pixel]=linearColor; } endInvocationInterlockARB(); #endif