GLSL实现HDR Rendering

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的网站上免费下载)


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/a3070173/archive/2008/11/29/3408573.aspx


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值