RGB与RBGE与HDR与tonemapping

1,248 阅读3分钟

Tone mapping进化论 - 知乎 (zhihu.com)

RGB

  • 一个字节=一个byte=8位,历史原因而成功的
  • 8位是指8位二进制,也就是2的八次方,数值都是0-255
  • R,G,B数值都是0-255,都是8个二进制(2八次方)
  • LDRI 几乎都是LDR,不管是我们的jpg、png、tga还是tiff,都是低动态范围,一般是指数值以整型(integer)类型来储存的图片(0-256)
  • image.png
    • 如图RGB 8bit, 1024x1024的RGB图片,就有1024x1024x3byte=3MB
  • ~8_$[CLH{R(H01OI9C{T5.png
    • 如图RGBA8888,1024x768的RGBA FBO,九幽 1024x768x12/1024/2014 = 9MB
  • 记录
    • 2^1 = 2
    • 2^2 = 4
    • 2^3 = 8
    • 2^4 = 16
    • 2^5 = 32
    • 2^6 = 64
    • 2^7 = 128
    • 2^8 = 256
    • 2^9 = 512
    • 2^10 = 1024
    • 2^11 = 2048
    • 2^12 = 4096
    • 2^13 = 8192
    • 2^14 = 16384
    • 2^15 = 32768
    • 2^16 = 65536

HDR(RGBE)

  • HDRI(也就是HDR的image),高动态范围图像,在储存RGB24数据的基础上,还直接储存了Y亮度值,则是指数值以浮点(float)类型来储存的图片(0-1)
  • WebGL中,HDR指的是让我们能用超过1.0的数据表示颜色值。
  • HDR格式是使用RGBE四个8位通道,一共32位通道来储存信息
  • 当一个帧缓冲的颜色缓冲的内部格式被设定成了GL_RGB16F, GL_RGBA16F, GL_RGB32F 或者GL_RGBA32F时,这些帧缓冲被叫做浮点帧缓冲(Floating Point Framebuffer),浮点帧缓冲可以存储超过0.0到1.0范围的浮点值,所以非常适合HDR渲染。
  • HDR是一个非常宽广的概念。即便两个都是HDR的,但它们的范围仍可能不同。因此有人把这个称为Variable Dynamic Range(VDR)
//Webgl2
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);   
//Webgl1 只有RGBA 
gl.bindTexture(gl.TEXTURE_2D, this.screen);
gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, this.width, this.height, 0);
  • 不进行tone mapping

    • image.png
  • 在进行了tone mapping之后,为了针对人对自然亮度的非线性感知以及显示器de-gamma特性,我们会进行gamma校正,最终输出对应颜色到显示器。

  • Tone Mapping是一个损失很小的转换浮点颜色值至我们所需的LDR[0.0, 1.0]范围内的过程。后面会进行Gamma矫正。

    • Reinhard色调映射
      • Reinhard色调映射,它涉及到分散整个HDR颜色值到LDR颜色值上,所有的值都有对应。
      • 这个算法是倾向明亮的区域的,暗的区域会不那么精细也不那么有区分度
      • Reinhard色调映射算法平均地将所有亮度值分散到LDR上。将Reinhard色调映射应用到之前的片段着色器上,并且加上一个Gamma校正过滤:
      • image.png
      • image.png
      void main()
      {             
          const float gamma = 2.2;
          vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
          // Reinhard色调映射
          vec3 mapped = hdrColor / (hdrColor + vec3(1.0));
          // Gamma校正
          mapped = pow(mapped, vec3(1.0 / gamma));
          color = vec4(mapped, 1.0);
      }   
      
    • 曝光(Exposure)参数的使用
      • image.png
    uniform float exposure;
    void main()
    {             
        const float gamma = 2.2;
        vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
        // 曝光色调映射
        vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);
        // Gamma校正 
        mapped = pow(mapped, vec3(1.0 / gamma));
        color = vec4(mapped, 1.0);
    }  
    
    • AECS
    float3 ACESToneMapping(float3 color, float adapted_lum) 
    { 	
           const float A = 2.51f; 	
           const float B = 0.03f; 	
           const float C = 2.43f; 	
           const float D = 0.59f; 	
           const float E = 0.14f;  	
           return (color * (A * color + B)) / (color * (C * color + D) + E); 
    }
    

image.png