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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章