DX9 Update中的HDRLighting Sample分析 (2) (轉)

worldblog發表於2007-08-17
DX9 Update中的HDRLighting Sample分析 (2) (轉)[@more@]  DX9 Update中的HDRLighting Sample分析 (2)

 上一篇我們分析到得出了場景的平均亮度值。下面如果我們不打算做Star和Bloom效果的話,我們可以直接使用這個亮度值來進行我們最後的調整,獲得最後的畫面。但是如果HDR缺少了Star和Bloom或類似的效果的話,就如同太陽失去了光芒一樣。不過在進行我們的Star和Bloom效果處理之前還有一個問題需要解決,這個問題和這些效果沒什麼關係。我們知道我們的眼睛當遇到強光的時候,並不是一下子就能適應,而是有個漸進的過程。如果我們的沒有這個處理的話,將會失色很多。也就是說兩個亮度值之間需要有個過渡的變化。我們如何做到這一點呢?

 fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * ( 1 - pow( 0.98f, 30 * g_fElapsedTime ) );

 上面的就是我們計算過渡亮度值的公式,fCurrentLum是我們的目標的亮度值,fAdaptedLum是上一楨的亮度值,我們在每次計算的時候,一般是保持fCurrentLum,上一次計算的fNewAdaptation作為這次計算的fAdaptedLum,這樣我們就能做到逐步的接近我們的最終結果fCurrentLum。而我們把每楨計算得出的fNewAdaptation作為我們調整顏色用的亮度值。

 讓我們來具體的看看程式碼

 if( m_bAdaptationInvalid )
 {
 // Clear the update flag
 m_bAdaptationInvalid = false;

 // Calculate the current luminance adaptation level
 CalculateAdaptation();
 }

 這裡的if( m_bAdaptationInvalid )並不起作用,因為在FrameMove()內都m_bAdaptationInvalid設定成了true.也就是說每楨都CalculateAdaptation();我們來看看著個函式是如何實現上面說得那樣的計算:

 HRESULT CMyD3DApplication::CalculateAdaptation()
 {
 HRESULT hr = S_OK;
 UINT uiPass, uiPasunt;

 // S current & last luminance
 PDIRECT3DTEXTURE9 pTexSwap = m_pTexAdaptedLuminanceLast;
 m_pTexAdaptedLuminanceLast = m_pTexAdaptedLuminanceCur;
 m_pTexAdaptedLuminanceCur = pTexSwap;

 這裡可以看到每楨都了Cur和Last,將上楨的結果作為這一楨的輸入引數

 m_pEffect->SetTechnique("CalculateAdaptedLum");
 m_pEffect->SetFloat("g_fElapsedTime", m_fElapsedTime);
 
 m_pd3dDevice->SetRenderTarget(0, pSurfAdaptedLum);
 m_pd3dDevice->SetTexture(0, m_pTexAdaptedLuminanceLast);
 m_pd3dDevice->SetTexture(1, m_apTexToneMap[0]);
 m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
 m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
 m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
 m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_POINT );

 這裡m_apTexToneMap(0)就是我們的最終的目標亮度值,這裡用到的shader的程式碼如下

 float4 CalculateAdaptedLum(in float2 vScreenPosition : TEXCOORD0) : COLOR
 {
 float fAdaptedLum = tex2D(s0, float2(0.5f, 0.5f));
 float fCurrentLum = tex2D(s1, float2(0.5f, 0.5f));
 
 // The user's adapted luminance level is simulated by closing the gap between
 // adapted luminance and current luminance by 2% every frame, based on a
 // 30 fps rate. This is not an accurate model of human adaptation, which can
 // take longer than half an hour.
 float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * 
 ( 1 - pow( 0.98f, 30 * g_fElapsedTime ) );
 return float4(fNewAdaptation, fNewAdaptation, fNewAdaptation, 1.0f);
 }

 這裡就是使用上面說到的公式來計算我們當前的亮度值

 }

 透過上面的計算,我們在最後使用的亮度值儲存在了m_pTexAdaptedLuminanceCur裡面。

 接下來我們就準備開始獲得Star和Bloom效果了.首先我們需要將場景中特別亮的畫素給提取出來。

 SceneScaled_To_BrightPass();

 這個函式就是獲得我們Star和Bloom所需要的來源貼圖.我們來看看著個函式的內部實現

 HRESULT CMyD3DApplication::SceneScaled_To_BrightPass()
 {
 ....

 m_pEffect->SetTechnique("BrightPasilter");

 m_pd3dDevice->SetRenderTarget( 0, pSurfBrightPass );
 m_pd3dDevice->SetTexture( 0, m_pTexSceneScaled );
 m_pd3dDevice->SetTexture( 1, m_pTexAdaptedLuminanceCur );
 m_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, TRUE );
 m_pd3dDevice->SetScissorRect( &rectDest );
 m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
 m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
 m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_POINT );
 m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_POINT );

 我們使用剛剛計算得出的m_pTexAdaptedLuminanceCur(如果跳過模擬過渡的階段,這裡應該使用m_apTexToneMap(0))和m_pTexSceneScaled作為我們的引數,計算後的只剩下我們需要的亮度資訊儲存pSurfBrightPass,我們來看看這裡用到的shader的操作

 float4 BrightPassFilter(in float2 vScreenPosition : TEXCOORD0) : COLOR
 {
 float4 vSample = tex2D( s0, vScreenPosition );
 float fAdaptedLum = tex2D( s1, float2(0.5f, 0.5f) );

 // Detene what the pixel's value will be after tone-map occurs
 vSample.rgb *= g_fMiddleGray/(fAdaptedLum + 0.001f);

 // Subtract out dark pixels
 vSample.rgb -= BRIGHT_PASS_THRESHOLD;

 // Clamp to 0
 vSample = max(vSample, 0.0f);

 // Map the resulting value into the 0 to 1 range. Higher values for
 // BRIGHT_PASS_OFFSET will isolate lights from illuminated scene 
 // s.
 vSample.rgb /= (BRIGHT_PASS_OFFSET+vSample);
 
 return vSample;
 }

 這裡透過-BRIGHT_PASS_THRESHOLD和Clamp to 0我們就得到了只剩下我們需要的畫素亮度值得Texture了

 }

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-963732/,如需轉載,請註明出處,否則將追究法律責任。

相關文章