標籤:style class blog http tar ext
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的網站上免費下載)