英吋 XNA

XNA – BasicEffect的光線

如果有試著用XNA內建的shader(也就是BasicEffect),而且也將方向光(Direct Light)打開的話。
或許你可能會發現某些部分的面,會完全沒受到光,看起來就像一塊瘡疤!
當然,可以用高超的打光技巧掩飾這個問題,可惜我沒有

最近在改寫「KiloWatt Animation」的預設shader,因為它只有單一方向光以及不太適當的fog計算方式。
本來想要找個很棒的shader來用,可惜和HLSL不夠熟,完全不知從何下手…
最後決定把BasicEffect(以下簡稱BE)的寫法移植過來,我比較習慣他的fog,以及有三個方向光。

撞了無數次牆壁後,終於移植完成,成功的將光線和fog放進去。
但是,之前使用BE方向光的問題就同樣地出現了。
經過這次移植,也對HLSL有更進一步的了解,就試著解決這個問題。

先來看看原始的光線會造成的狀況:

左圖和右圖差別在於光線的反射光(SpecularColor)和物件的反射強度(SpecularPower)

右圖可以很明顯地看到"瘡疤",當反射程度越高越容易發現。

 float3 L = -DirLightXDirection;
 float3 H = normalize(E + L);
 float dt = max(0,dot(L,N));
 result.Diffuse += DirLightXDiffuseColor * dt;
 if (dt != 0)
     result.Specular += DirLightXSpecularColor * pow(max(0,dot(H,N)), SpecularPower);

這是BE裡面計算光線的方法「ComputePerPixelLights(…)」裡的光線算法。
我推測這一切的問題來源在於「dt = max(0,dot(L,N));」。
dt影響到後面「result.Diffuse += DirLightXDiffuseColor * dt;」
,它將dot值小於0的一律比照辦理。
所以才會產生交界(以0為界線)的地方會有明顯的區分,而非漸進式的遞減。
至於解法,應該有千百種吧…
我只用一個簡單的想法「背光的就將之變暗就是,但是只會變暗到一定程度」。
這是基於他原本忽略背光的方式而改的,至於變暗的限制,只是單純避免暗過頭,會全黑掉低

 float3 L = -DirLightXDirection;
 float3 H = normalize(E + L);
 float dt = dot(L,N);
 if(dt < 0)
     dt *= 0.1;
 result.Diffuse += DirLightXDiffuseColor * dt;
 if (dt != 0)
     result.Specular += DirLightXSpecularColor * pow(max(0,dot(H,N)), SpecularPower);


這樣就可以避免瘡疤的出現了~很簡單吧!
前面也說過,這只是純粹消除瘡疤。
如果有華麗的解決方法,麻煩偷偷告訴我XDD

–End

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.