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)
- 如图RGB 8bit, 1024x1024的RGB图片,就有1024x1024x3byte=3MB
- 如图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
-
在进行了tone mapping之后,为了针对人对自然亮度的非线性感知以及显示器de-gamma特性,我们会进行gamma校正,最终输出对应颜色到显示器。
-
Tone Mapping是一个损失很小的转换浮点颜色值至我们所需的LDR[0.0, 1.0]范围内的过程。后面会进行Gamma矫正。
- Reinhard色调映射
- Reinhard色调映射,它涉及到分散整个HDR颜色值到LDR颜色值上,所有的值都有对应。
- 这个算法是倾向明亮的区域的,暗的区域会不那么精细也不那么有区分度
- Reinhard色调映射算法平均地将所有亮度值分散到LDR上。将Reinhard色调映射应用到之前的片段着色器上,并且加上一个Gamma校正过滤:
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)参数的使用
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); } - Reinhard色调映射