http://blog.csdn.net/a3070173/archive/2008/11/29/3408573.aspx
- HDR - 全称High dynamic rang,是目前流行的3D特效技术.其基本原理是:虽然在计算机图形中可以使用完全的浮点型来表
- 示颜色,但之前由于一直受到硬件的限制,从外部载入的纹理格式大多只能以每种颜色成分用一个字节来表示,也就是0-255,
- 当这个低范围的颜色值转换为浮点型之后就会导致一定量的颜色间隔,而HDR技术通过采用浮点型的外部纹理格式弥补了原来
- 整型纹理格式所导致的颜色间隔,从而增强了计算机图形的颜色表现能力.当然这只是笼统的说法,而且每个人对同一个概念
- 的理解也不尽相同,所以我在本文的最后列出了一些个人认为比较有用的参考资料,这里只简单描述一下我的HDR - OpenGL实
- 现,其实HDR的理念理解了之后就会比较简单,但真要编码实现的话还是有很多东西需要琢磨.
- 下面列出的是主要渲染流程:
- 备注(FBO代表Frame Buffer Object)
- 1.渲染整个场景到FBO1
- 2.下采样FBO1到尺寸为原来1/4的FBO2中
- 3.下采样FBO2到尺寸为原来1/8的FBO3中
- DownSample片元着色器:
- uniform sampler2D g_SceneTexture;
- void main()
- {
- gl_FragColor = texture2D(g_SceneTexture, gl_TexCoord[0].st);
- }
- 4.对经过两次下采样并保存在FBO3中的内容进行高斯过滤,并将处理过后的图像
- 保存在FBO4中(备注:高斯过滤分为横向过滤和纵向过滤两个通道,所以需要一个FBO5进行过渡)
- 高斯过滤片元着色器:
- const int g_iWeightNumber = 17;
- uniform sampler2D g_DecalTexture;
- uniform bool g_bFilterModel;
- uniform float g_aryWeight[g_iWeightNumber]; // Blur权重数组
- uniform vec2 g_aryVerticalOffset[g_iWeightNumber]; // 横向Blur偏移数组
- uniform vec2 g_aryHorizontalOffset[g_iWeightNumber]; // 纵向Blur偏移数组
- void main()
- {
- vec4 vec4Sum = vec4(0.0);
- if (g_bFilterModel)
- {
- // 横向过滤
- for(int i = 0; i < g_iWeightNumber; ++i)
- {
- vec4Sum += texture2D(g_DecalTexture, gl_TexCoord[0].st + g_aryVerticalOffset[i])*g_aryWeight[i];
- }
- }
- else
- {
- // 纵向过滤
- for(int i = 0; i < g_iWeightNumber; ++i)
- {
- vec4Sum += texture2D(g_DecalTexture, gl_TexCoord[0].st + g_aryHorizontalOffset[i])*g_aryWeight[i];
- }
- }
- gl_FragColor = vec4Sum;
- }
- 5.FBO4中的内容与FBO1中的内容进行特效处理和ToneMapping以将高动态范围的颜色值映射对低动态范围以便于显示.
- ToneMapping片元着色器:
- const float g_fGamma = 1.0/2.0;
- uniform float g_fBlurAmount; // 模糊量
- uniform float g_fRadialEffectAmount; // 放射式效果量
- uniform float g_fExposure; // 暴光量
- uniform sampler2D g_SceneTexture;
- uniform sampler2D g_BlurTexture;
- // 计算放射式效果
- vec4 CaculateRadial(vec2 p_vec2TexCoord,int p_iSampleNumber,
- float p_fStartScale = 1.0, float p_fScaleMul = 0.9)
- {
- // 临时变量
- vec4 vec4TempColor = vec4(0.0);
- float fCurrentScale = p_fStartScale;
- vec2 vec2TempTexCoord = vec2(0.0);
- // 遍历采样
- for(int i = 0; i < p_iSampleNumber; ++i)
- {
- vec2TempTexCoord = (p_vec2TexCoord - 0.5)*fCurrentScale + 0.5; // 采样方式
- vec4TempColor += texture2D(g_BlurTexture, vec2TempTexCoord);
- fCurrentScale *= p_fScaleMul;
- }
- vec4TempColor /= float(p_iSampleNumber);
- return vec4TempColor;
- }
- // 计算小插图效果
- float CaculateVignette(vec2 p_vec2Position, float p_fInner, float p_fOuter)
- {
- float L = length(p_vec2Position);
- return ( 1.0 - smoothstep(p_fInner, p_fOuter, L) );
- }
- void main()
- {
- vec4 vec4SceneColor = texture2D(g_SceneTexture, gl_TexCoord[0].st); // 计算原始场景颜色
- vec4 vec4BlurColor = texture2D(g_BlurTexture, gl_TexCoord[0].st); // 计算经Blur后的场景颜色
- vec4 vec4RadialEffectColor = CaculateRadial(gl_TexCoord[0].st, 30, 1.0, 0.95); // 计算放射效果的颜色
- // 混合场景与Blur
- vec4 vec4Temp = lerp(vec4SceneColor, vec4BlurColor, g_fBlurAmount);
- // 添加放射性效果
- vec4Temp += vec4RadialEffectColor*g_fRadialEffectAmount;
- // 进行暴光
- vec4Temp *= g_fExposure;
- // 添加圆形扩散小插图效果使得中间部分较亮而四个边角逐渐变暗
- vec4Temp *= CaculateVignette(gl_TexCoord[0].st*2.0 - 1.0, 0.7, 1.5);
- // 使用Gamma校正规范会低范围光照
- vec4Temp.rgb = pow(vec4Temp.rgb, vec3(g_fGamma));
- // 最终颜色
- gl_FragColor = vec4Temp;
- }
- Demo效果截图:
- exe文件:http://www.fileupyours.com/view/219112/GLSL/HDR%20Rendering.rar
- VC9运行库:http://www.fileupyours.com/view/219112/GLSL/VC9RunningLib.rar
- 参考资料:1.DirectX SDK Sample - HDRLighting(备注:这个可以从DirectX SDK中获得)
- 2.Nvidia SDK 10.5 - HDR(备注:Nvidia SDK可以在Nvidia的网站上免费下载)