unity 實現手機振動 在2D遊戲中實現方向光照

2021-10-13 21:55:34 字數 4115 閱讀 2800

老實講,這個需求是老闆提的。

遊戲嘛,很多東西都可以做,但是做不做往往不是做的人可以決定的。這個效果雖然沒見過有遊戲實現過(一般實現的都是無方向的邊緣光),但是在一些2d動畫裡是有的——比如一款叫輪舞曲duo!的遊戲,在一些過場和戰鬥畫面裡面出現了很正確的光照效果,比如一盞燈從胸口平移過去可以看到非常合理的溝渠明暗變化過程。

剛看到的時候很驚豔,想想也就是明白了。在2d畫面上加乙個法線圖不就好了,變形後的影象,法線雖然會有一定偏移,但大方向是正確的,並不容易暴露。

所以實現這個並沒有什麼難度,難的是製作上的問題。搞來搞去,法線圖最後只給了5種顏色,分別對應中間,左,右,上,下。所以基本上沒法獲得正確的光照效果,只能做到將物體的不同區域做出區分單獨讓光線生效,如果是平行光,各區域之間是完全沒有過渡的,但如果用點光源,倒是可以靠衰減和角度體現出過渡來,勉強說的過去。

實現方式就是將2d物體看作是個佈告板,然後加上法線圖直接用和法線貼圖一樣的方式處理。

但這樣的話,就需要乙個正常的光照系統了。在不用srp的情況下,unity多光源的方式是多pass,顯然沒這必要。頂點光照又不可能用在法線貼圖上。普通的forward shader裡,因為是用於多pass的,能取到光照資料並不完整。不過好在unity還保留了最早的vertex lit用的光照,可以獲得最近8個光源的資料。

unity_lightcolor 燈光顏色

unity_lightposition 燈光位置,用w可以區分平行光和頂點光

unity_lightatten 點光源範圍,衰減引數

unity_spotdirection spot的資料

要注意的是,這些資料都是在檢視空間內的,而且需要把lightmode設定成vertex才會生效。

而利用的方法在unity自己的shader裡已經提供了,照抄就好:

float3 tolight = unity_lightposition[k].xyz - i.viewposition * unity_lightposition[k].w;

float lengthsq = dot(tolight, tolight);

lengthsq = max(lengthsq, 0.000001);

tolight *= rsqrt(lengthsq);

float atten = 1.0 / (1.0 + lengthsq * unity_lightatten[k].z);

//if (false) //spotlight

//float diff = max (0, dot (viewn, tolight));

lightcolor += unity_lightcolor[k].rgb * (diff * atten);

同時處理了點光源和平行光,並用乙個可選分支來支援spot光,不需要支援可以刪掉。

需要說明的是,這段**本身是用在頂點上的,直接移動到frag上是可以,但就需要靠考慮下效能問題。這組光源事先按距離排序過,所以取前幾個就行了,也可以中途用break提前退出(不存在的光源會被填充為0,0,0,0,unity_lightcolor[k].a == 0就表示後面沒資料了),不過我也不清楚用break有沒有提公升,雖然這種用法同warp肯定在同一分支不會有浪費,但畢竟會多乙個break的成本,而且會阻礙迴圈展開。

由於都是用在較小的2d人物上,即使光源多也不需要做精確的光照裁剪,就不用考慮那些麻煩事了,但是大塊物體比如牆體和路面絕對不能這樣用。現階段由於手機上還無法放棄不支援compute shader的裝置,基本沒啥合適的方案,目前的foward+的光照裁剪部分基本無法脫離compute shader(compute buffer也是其中一部分),傳統的tbdr也不清楚和手機的硬體tbr有沒有衝突。srp我沒認真看過,不清楚它的hd管線(傳統tbdr實現)是否能脫離compute shader,但不管怎麼說,那畢竟也是個延遲渲染,很麻煩的。不支援compute buffer恐怕是下乙個阻礙手遊畫面提公升的節點。

扯遠了,反正現在這做法只能處理人物,場景是不能受光照影響的,效能上浪費太多。控制光源上限就能限制成本,一般單物體最多3個光也差不多夠了。

法線資料直接取樣就行了,畢竟是佈告板。

嚴格來講,應該根據uv方向旋轉貼圖,這樣物體旋轉的時候才不會有問題。但是因為當初沒商量好,都是在單個部件模型上繪製的法線方向,然後打圖集的時候部件會被旋轉,而shader取不到這個旋轉資訊,就無法還原。如果法線圖是在打圖集後,根據圖集裡的方向來繪製本來是沒問題的。

不過旋轉不常見,也就無所謂了,應用了旋轉還可能出現預料之外的情況。但完整的方案應該是要旋轉的,需要乘乙個切線空間到檢視空間的矩陣,和普通的法線貼圖一樣。

但依然需要乘乙個物體空間到檢視空間的矩陣。這裡遇到了乙個坑。按說這裡直接用normalize(mul((float3x3)unity_matrix_it_mv, norm))處理方向就好,但實際執行的時候會在特定位置和角度會出現頻閃現象,我查了下unityshader的原始碼,發現它所有轉換角度的地方都是這樣的

inline float3 unityobjecttoviewnormal( in float3 norm )

用了個巨集來區分uniform和非uniform的情況,而且全走的下面那行,雖然我的模型確實是uniform的。下面那行……看上去完全沒有道理,所以我只能認為unity_matrix_mv被做了什麼手腳,先不管它。

替換了之後就正確了。但實際執行的時候,在某些特定機型執行下面那條shader會直接崩掉而且沒有任何反饋,fallback也無法捕獲,表現出來的是整個麵片大幅度隨機擾動(一段寫在frag的**竟然能影響頂點你敢信?)

也沒辦法只能改回上面那行偶爾錯誤的**。

我也不清楚這算是unity還是裝置的錯,但輸入再怎麼錯,裝置也不應該讓frag影響頂點吧?所以以下機型能不能主動去世?

oppo r9s,華為 榮耀暢玩5x(kiw-al10),vivo x9,華為 榮耀暢玩5a(cam-al00),oppo a57,華為 公尺蘭;麥芒5(mla-al10),三星 galaxy a700(sm-a7000),小公尺 -(hm 4x),vivo xplay5a,vivo x6splus d,樂視 樂max 2(x820),努比亞 z11 mini(nx529j),三星 galaxy a7(sm-a7100),三星 galaxy note 4(sm-n9108v),三星 galaxy note 4(sm-n9109w),樂視 樂1 pro(x800),三星 -(sm-g6100),中興 新axon天機(a2017),錘子 smartisan t2(sm801),谷歌 hamu;xt1100,moto nexus 6(nexus 6),三星 galaxy note 4(sm-n9106w),奇酷 q5(1515-a01),vivo pd1516a(xplay5s),努比亞 z17 mini(nx569j),中興 天機7 max(c2017),酷派 鋒尚n1s(5380ca),海信 a1 ivvi i3p-02(i3p-02),oppo r9st,華為 nova(caz-tl10),樂視 樂2(x528)
總得來講,這個效果表現尚可。設計的時候是在夜間低亮度下使用的,但是高亮度下也不是一點效果都沒有,只是效果差很多罷了。光照本來也就是這樣的東西。

實現的時候用的都是unity自己的東西,倒是挺簡單的,不費啥工夫。主要的人力在於畫法線圖那邊的人。但是圖那麼難的都畫了,劃分5個方向的朝面塗色也不算太麻煩吧。

如果量少,繪製更細緻的法線就能獲得更高的品質。不過要這樣做的話,可能3d建模生成法才反而才是效率最高的做法。

厲害的人還可以考慮立繪或者cg繪製法線。講真的,那個效果才是真的牛批。(不要找我要圖,你覺得我能發嗎?)

一句題外話,現在日式**的npr的可參考例子太少了,其實真想做日式**的npr,除了mmd,真有必要翻下日本那邊的**渲染的3d動畫,嗯,我指的就是那種。

遊戲也有,也是那種的。

誰讓日本遊戲業不行了呢,他們也只能做這個了。

unity3d滑鼠2D控制方法

用到了unity3d 非常好的協同機制實現滑鼠 2d統制,onmousedown 事件表示滑鼠已作了射線判斷得到了物件。拖拽時保持z 軸不變,因為螢幕是 xy二維的,空間是三維的。ienumerator onmousedown print drag compeleted 跟隨滑鼠旋轉物體,並判斷手勢...

Unity實現滑鼠點2D轉3D進行旋轉

如下 using unityengine public class gunfollowmouse monobeh iour v程式設計客棧oid update transform.localrotation quaternion.lerp transform.localrotation,quater...

max unity 方向 在2D遊戲中實現方向光照

老實講,這個需求是老闆提的。遊戲嘛,很多東西都可以做,但是做不做往往不是做的人可以決定的。這個效果雖然沒見過有遊戲實現過 一般實現的都是無方向的邊緣光 但是在一些2d動畫裡是有的 比如一款叫輪舞曲duo 的遊戲,在一些過場和戰鬥畫面裡面出現了很正確的光照效果,比如一盞燈從胸口平移過去可以看到非常合理...