生活随笔
收集整理的這篇文章主要介紹了
该如何在后期处理中,实现高亮描边的效果?
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
因?yàn)轫?xiàng)目需要實(shí)現(xiàn)高亮描邊的效果,一開(kāi)始先嘗試了《火炬之光》使用的光照的高亮描邊。就是計(jì)算法線和Camera的夾角來(lái)計(jì)算光照,越靠近邊緣的地方法線和Camera夾角越大頂點(diǎn)越亮。但是感覺(jué)效果不好,正好當(dāng)時(shí)《星際2》發(fā)布了,里面的后期處理描邊效果非常好,原理也不復(fù)雜因此也在項(xiàng)目中實(shí)現(xiàn)了一下。
原理很簡(jiǎn)單,在RT上渲染出人物的片,然后通過(guò)高斯模糊進(jìn)行模糊和擴(kuò)散,然后再通過(guò)模板挖空留下邊的效果,最后在和正常渲染結(jié)果的RT疊加。原理如下:
?
《暗黑3》以及《軒轅》的后處理描邊效果:
?
高亮描邊流程:
1.在場(chǎng)景物件的渲染階段,渲染并寫(xiě)入高亮物體的模版值到高亮效果的輸入RT上。。
1)首先在渲染角色前,打開(kāi)后期處理高亮描邊并將高亮物體設(shè)置不渲染,這么做是因?yàn)閷?xiě)模版值時(shí)需要考慮深度,如果被其他人物遮擋的部分則不能寫(xiě)入模版值。
2)然后在角色物體全部渲染完后,添加模版寫(xiě)入屬性(CStencilPropertySwaper)并渲染高亮物體,其中特效和半透明物件不加模版寫(xiě)入屬性不描邊。偽代碼如下:
?
m_pkStencilProperty->SetStencilOn(TRUE);m_pkStencilProperty->SetStencilFunction(TEST_ALWAYS);m_pkStencilProperty->SetStencilPassAction(ACTION_REPLACE);m_pkStencilProperty->SetStencilFailAction(ACTION_KEEP);m_pkStencilProperty->SetStencilPassZFailAction(ACTION_KEEP);m_pkStencilProperty->SetStencilReference(0x1);
復(fù)制代碼
3)最后還原高亮物體的模版屬性。
2.在后期處理階段,拷貝模版緩沖,并完成后期處理描邊,通過(guò)宏DEVIATION可以調(diào)整擴(kuò)散范圍,也就是粗細(xì),越小越細(xì),MULTIPLITER可以調(diào)整模糊程度,越小越不模糊。
1)復(fù)制深度模版緩沖,為了使用抗拒齒渲染場(chǎng)景時(shí)必須使用默認(rèn)RT,所以要拷貝默認(rèn)的模版緩沖。
?
pktDefaultDepthStencilBuffer->Copy(m_pkTargets[RRT_FULL_1]->GetRenderTargetGroup()->GetDepthStencilBuffer(), NULL, NULL, COPY_FILTER_LINEAR);
復(fù)制代碼
2)使用輸入RT的深度模版緩沖繪制描邊色RT,渲染到RRT_FULL_1(正常大小),結(jié)果就是人物形狀的片。偽代碼如下:
?
StencilEnable = true;StencilFunc = equal;StencilRef = 0x1;StencilPass = keep;//-----------------------------------------------------------------------------// Pixel Shader: PS_HighLightObject// Desc: 填充高亮顏色.//-----------------------------------------------------------------------------float4 PS_HighLightObject() : COLOR{? ? return float4(0.7f, 0.7f, 0.5f, 0.0f);}
復(fù)制代碼
3)降采樣,渲染到RRT_DOWN_0,主要是為了優(yōu)化,對(duì)1/4大小RT模糊。偽代碼如下:
?
//-----------------------------------------------------------------------------// Pixel Shader: PS_DownFilter// Desc: Perform a high-pass filter and on the source texture and scale down.//-----------------------------------------------------------------------------float4 PS_DownFilter(in float2 _f2Tex : TEXCOORD0) : COLOR0{? ? float4 f4Color = 0;? ? for (int i = 0; i < 16; i++)??{? ?? ?f4Color += tex2D(g_BaseTexutre, _f2Tex + TexelCoordsDownFilter[i].xy);??}??return f4Color / 16;}
復(fù)制代碼
4)混合采樣16遍第張貼圖(橫向高斯模糊),使用模版測(cè)試渲染到RRT_DOWN_1,結(jié)果就是挖掉人物部分只剩輪廓邊的貼圖。偽代碼如下:
?
//-----------------------------------------------------------------------------// Pixel Shader: Bloom// Desc: Blur the source image along one axis using a gaussian//? ?? ? distribution. Since gaussian blurs are separable, this shader is//? ?? ? called twice; first along the horizontal axis, then along the//? ?? ? vertical axis.//-----------------------------------------------------------------------------float4 Bloom(in float2 kScreenPosition : TEXCOORD0) : COLOR{? ? float4 kSample = 0.0f;? ? float4 kColor = 0.0f;? ?? ?? ? float2 kSamplePosition;? ?? ? // Perform a one-directional gaussian blur? ? for (int iSample = 0; iSample < 15; iSample++)? ? {? ?? ???kSamplePosition = kScreenPosition + gakSampleOffsets[iSample];? ?? ???kColor = tex2D(BasePointClampSampler, kSamplePosition);? ?? ???kSample += gakSampleWeights[iSample] * kColor;? ? }? ?? ? return kSample;}
復(fù)制代碼
5)混合采樣16遍第張貼圖(橫向高斯模糊),二手游戲購(gòu)買(mǎi)平臺(tái)使用模版測(cè)試渲染回RRT_DOWN_0,結(jié)果就是挖掉人物部分只剩輪廓邊的貼圖。
6)升采樣,渲染到RRT_FULL_1,還原正常大小并挖去中間輪廓只剩下邊。偽代碼如下:
StencilEnable = true;StencilFunc = notequal;StencilRef = 0x1;StencilPass = keep;//-----------------------------------------------------------------------------// Pixel Shader: PS_UpFilter// Desc: Perform a high-pass filter and on the source texture and scale down.//-----------------------------------------------------------------------------float4 PS_UpFilter(in float2 _f2Tex : TEXCOORD0) : COLOR{? ? float4 f4Color =??tex2D(g_BaseTexutre, _f2Tex);? ? return f4Color;}
復(fù)制代碼
7)最后采樣第0張貼圖(后期處理的輸入,就是最終渲染結(jié)果)和采樣第1張貼圖(邊),然后混合相加,渲染到最終RenderTarget,就是帶邊的場(chǎng)景了。偽代碼如下:
?
//-----------------------------------------------------------------------------// Pixel Shader: PS_HighLightBlend// Desc: 在最終渲染結(jié)果上添加描邊.//-----------------------------------------------------------------------------float4 PS_HighLightBlend(in float2 _f2Tex : TEXCOORD0) : COLOR{? ? float4 f4Color1 = tex2D(g_BaseTexutre, _f2Tex);? ? float4 f4Color2 = tex2D(g_ShaderTexure, _f2Tex);? ? return f4Color1 + f4Color2;}
復(fù)制代碼
問(wèn)題:
1)雖然功能很快實(shí)現(xiàn)了,但是真正應(yīng)用的時(shí)候還是花了一些時(shí)間優(yōu)化和遇到很多問(wèn)題。
2)開(kāi)啟抗鋸齒之后深度緩沖不能共享導(dǎo)致的問(wèn)題。通過(guò)使用StretchRect來(lái)拷貝DepthStencilBuffer,來(lái)解決開(kāi)了AA之后描邊的問(wèn)題。偽代碼如下:
?
LPDIRECT3DSURFACE9 lpBackSurfaceSx9 = NULL;HRESULT hr = lpDevice9->GetDepthStencilSurface(&lpBackSurfaceSx9);lpDevice9->StretchRect( lpBackSurfaceSx9, NULL, ((NiDX92DBufferData*)m_spDepthStencilBuffer->GetRendererData())->GetSurface(), NULL, D3DTEXF_LINEAR );
復(fù)制代碼
3)實(shí)現(xiàn)了多種顏色描邊,并解決了多種顏色描邊在不同電腦上顯示不連續(xù)等bug。
4)偶現(xiàn)描邊導(dǎo)致屏幕變白的BUG。因?yàn)樵跊](méi)有描邊物體時(shí)跳過(guò)描邊物體渲染流程,但這個(gè)判斷加在了判斷是否打開(kāi)描邊后期處理的流程之前。所以雖然關(guān)閉了描邊物體的渲染流程但是沒(méi)有關(guān)閉描邊的后期處理流程。當(dāng)游戲正好在描邊狀態(tài)時(shí),系統(tǒng)自動(dòng)降低配置關(guān)閉描邊效果后,會(huì)導(dǎo)致后期處理無(wú)限循環(huán)擴(kuò)大,也就是邊界無(wú)限擴(kuò)大。通過(guò)在判斷沒(méi)有描邊物體中斷描邊物體的渲染流程時(shí)同時(shí)也關(guān)閉描邊的后期處理流程解決。
5)描邊閃爍。因?yàn)槭莃eginrendertarget放到了BeginOffscreen之前了,應(yīng)該放在之間。
6)Alphatest的問(wèn)題,這是因?yàn)閤x渲染顏色時(shí)寫(xiě)入模版值的,這個(gè)時(shí)候因?yàn)橐胊lpha做暗邊,所以沒(méi)有考慮alphatest。最終的方案是先話正常物件,再畫(huà)高亮物件同時(shí)寫(xiě)模版值,最后再畫(huà)一遍寫(xiě)顏色值這時(shí)不通過(guò)深度比較而是通過(guò)模版值比較,因?yàn)槎嘀夭蓸拥那闆r下因?yàn)閦精度的問(wèn)題邊會(huì)亂。
7)在設(shè)置模版采樣之后必須要還原渲染狀態(tài)。否則自己寫(xiě)的Shader會(huì)一直開(kāi)啟Stencil。
8)因?yàn)樵赾opy深度模版緩沖之后清空了Zbuf,在有的電腦上會(huì)連Stencil一起清掉。最終解決的辦法是在去掉情況zbuf,在渲染不通描邊物體顏色時(shí)不使用copy不精確的z(多重采樣zcopy會(huì)不精確,關(guān)掉畫(huà)顏色時(shí)ztest和zwrite)而是使用模版比較(模版值沒(méi)有小數(shù)問(wèn)題)。
9)解決了描邊時(shí)設(shè)備丟失崩潰的問(wèn)題。這是因?yàn)樵O(shè)備丟失時(shí)copy深度buff導(dǎo)致,通過(guò)在設(shè)備丟失時(shí)關(guān)閉后期處理,在設(shè)備丟失好以后打開(kāi)后期處理解決。
總結(jié)
以上是生活随笔為你收集整理的该如何在后期处理中,实现高亮描边的效果?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。