HDR&Filmic Tonemapping Operators
来源:互联网 发布:软件测试的含义 编辑:程序博客网 时间:2024/05/16 07:45
博主在unity5上的渲染结果,第一张图片是母校图书馆 ^ _ ^
但是随着游戏业的画面水准开始向电影水准发展,就需要我们有更好的理解HDR,来进一步把游戏像电影画质推进,这也是近几年的GDC和siggraph上都有一线studio在推HDR相关的技术,比如naughty dog10年的filmic tone mapping,11年crytek在siggraph里面提到的physically based hdr等。
- dynamic range:reinhard的<tone mapping>论文中定义:一个场景中最高亮度与最低亮度的比是dynamic range。
- low dynamic range : 之所以出现这种情况是图像存储介质(打印纸,照片,电脑屏幕等)精度有限造成的,导致在range上没法完全记录一个场景的亮度信息,只能记录有限的一部分,比如游戏里常见的在rgba8上渲染,每个channel大于1的部分就被截取到1了。
- high dynamic range : 准确讲是high dynamic range imaging,是指一种图像技术,它能让图像表示一个比原有技术(之前的LowDynamicRange)更大(greater)的dynamic range
- 这样就可以更加准确和真实的描绘一个场景
oneMapping&ExposureAdjustment
- 自动根据亮度矫正明暗:让我们晚上看东西也能比较清楚,一开灯眼睛要矫正一会回来
- 局部适应性:比较经典的图是:
- 曝光率问题---解决:exposure adjustment。和照相时候曝光原理差不多,白天亮曝光就短一些,晚上曝光长一些,编程时候就是计算render target的平均亮度,然后矫正,这样沙漠的白天和丛林的夜晚都可以在游戏中的rgba8上有一个良好的体现。在hable的论文里,这个属于不同的场景之间的处理问题范畴。
- 压缩的过程中不可避免的涉及到重新分配亮度值,怎么做来得到更好的尽可能不失真的画面这个解决方案就是tone mapping
- zone:存储空间的亮度阶这么一个概念,比如print只有11个zone
- middle grey:中间的亮度
- dynamic range:指场景中最高亮度与最低亮度的比值
- 这是一个最学术派的定义,具体上摄像师一般会追求细节还可以明辨的range
- key:描述整个场景亮度的数值
- dodging and burning:把高亮度的东西亮度降低为dodging,把低亮度的部分加亮为burning
Filmic Tonemapping Operators
The most common questions that I get about my GDC talk have to do with the tonemapping operators. In particular, I’ve always found that when I read through presentations for code snippets that I always miss something. Those 2.2s can be tricky! So this post is a quick reference for various operators that I talked about. Also, I copied and pasted this code from my RenderMonkey scene so there may be typos.
All of these examples use this HDR image of Habib’s killer condo. Also, click any image for the high-res version.
First off, there is good old linear. All it does is read the linear data, do an exposure adjustment, and adjust for the monitor’s gamma of 2.2.
1.
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
2.
{
3.
float3 texColor = tex2D(Texture0, texCoord );
4.
texColor *= 16;
// Hardcoded Exposure Adjustment
5.
float3 retColor =
pow
(texColor,1/2.2);
6.
return
float4(retColor,1);
7.
}
Pretty simple. It looks like this. Click for high-res.
Don’t forget the pow(1/2.2). If you forget that step, it looks like this:
1.
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
2.
{
3.
float3 texColor = tex2D(Texture0, texCoord );
4.
texColor *= 16;
// Hardcoded Exposure Adjustment
5.
float3 retColor = texColor;
6.
return
float4(retColor,1);
7.
}
Next up is Reinhard. There are many variations, bu I’ll do the simplest which is 1/(1+x). A common variation is to only do it on luminance. Don’t forget the pow(1/2.2) at the end!
1.
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
2.
{
3.
float3 texColor = tex2D(Texture0, texCoord );
4.
texColor *= 16;
// Hardcoded Exposure Adjustment
5.
texColor = texColor/(1+texColor);
6.
float3 retColor =
pow
(texColor,1/2.2);
7.
return
float4(retColor,1);
8.
}
Here it is with Haarm-Peter Duiker’s curve. This version is very similar to the Cineon node in Digital Fusion. The texture FilmLut refers tothis TGA file. No pow(1/2.2) necessary.
01.
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
02.
{
03.
float3 texColor = tex2D(Texture0, texCoord );
04.
texColor *= 16;
// Hardcoded Exposure Adjustment
05.
06.
float3 ld = 0.002;
07.
float
linReference = 0.18;
08.
float
logReference = 444;
09.
float
logGamma = 0.45;
10.
11.
float3 LogColor;
12.
LogColor.rgb = (
log10
(0.4*texColor.rgb/linReference)/ld*logGamma + logReference)/1023.f;
13.
LogColor.rgb = saturate(LogColor.rgb);
14.
15.
float
FilmLutWidth = 256;
16.
float
Padding = .5/FilmLutWidth;
17.
18.
// apply response lookup and color grading for target display
19.
float3 retColor;
20.
retColor.r = tex2D(FilmLut, float2( lerp(Padding,1-Padding,LogColor.r), .5)).r;
21.
retColor.g = tex2D(FilmLut, float2( lerp(Padding,1-Padding,LogColor.g), .5)).r;
22.
retColor.b = tex2D(FilmLut, float2( lerp(Padding,1-Padding,LogColor.b), .5)).r;
23.
24.
return
float4(retColor,1);
25.
}
Next up is the optimized formula by Jim Hejl and Richard Burgess-Dawson. I completely forgot about Richard in the GDC talk, but he shares the credit with Jim. Sorry Richard!! Note that you don’t need the pow(1/2.2) for this one either.
1.
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
2.
{
3.
float3 texColor = tex2D(Texture0, texCoord );
4.
texColor *= 16;
// Hardcoded Exposure Adjustment
5.
float3 x = max(0,texColor-0.004);
6.
float3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06);
7.
return
float4(retColor,1);
8.
}
Finally for the Uncharted 2 operator made by yours-truly. For this image I changed the defaults slightly for A and B.
Edit: Oops, in the previous version, I had the exposure bias outside the tonemapping function. Now it is fixed, where it is inside the tonemapping function.
01.
float
A = 0.15;
02.
float
B = 0.50;
03.
float
C = 0.10;
04.
float
D = 0.20;
05.
float
E = 0.02;
06.
float
F = 0.30;
07.
float
W = 11.2;
08.
09.
float3 Uncharted2Tonemap(float3 x)
10.
{
11.
return
((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
12.
}
13.
14.
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
15.
{
16.
float3 texColor = tex2D(Texture0, texCoord );
17.
texColor *= 16;
// Hardcoded Exposure Adjustment
18.
19.
float
ExposureBias = 2.0f;
20.
float3 curr = Uncharted2Tonemap(ExposureBias*texColor);
21.
22.
float3 whiteScale = 1.0f/Uncharted2Tonemap(W);
23.
float3 color = curr*whiteScale;
24.
25.
float3 retColor =
pow
(color,1/2.2);
26.
return
float4(retColor,1);
27.
}
Hopefully, that should clear up most of the ambiguity about these operators.
- HDR&Filmic Tonemapping Operators
- HDR&ToneMapping
- HDR与ToneMapping
- HDR (automatic exposure control + Tonemapping + Bloom)
- HDR
- HDR
- HDR
- HDR
- HDR
- hdr
- HDR
- HDR
- Operators
- Operators
- Operators
- Operators
- tonemapping色彩映射特效
- 色调映射 Tonemapping
- IntelliJ Terminal git log 过长问题
- STL的多线程安全问题
- Android多媒体之音频、视频录制MediaRecorder
- boss给的课后作业:敏捷开发
- 【Android】Android清除本地数据缓存代码
- HDR&Filmic Tonemapping Operators
- 驱动学习--SYS属性节点创建
- getContextPath、getServletPath、getRequestURI的区别
- [刷题]Sort Colors II
- 关于phpMail无法发送邮件问题
- .NET基础--if-else与swirch的区别
- 记录一些UIScrollView的代理方法
- 双向链表的实现
- Leetcode: Zigzag Iterator