游戲shader(6):利用法線貼圖實(shí)現(xiàn)動(dòng)態(tài)2D光照效果

本文講解2D游戲中汤锨,如何利用法線貼圖來實(shí)現(xiàn)有材質(zhì)特性光绕、全角度、且受時(shí)間影響的接近真實(shí)的光照效果漫试。

本文鏈接 游戲shader(6):利用法線貼圖實(shí)現(xiàn)動(dòng)態(tài)2D光照效果

一极谊、制作背景

? ? 2D游戲中,場(chǎng)景中有多個(gè)火把安岂、蠟燭轻猖、燈光等貼圖,讓場(chǎng)景非常真實(shí)絢麗域那。但遺憾的是咙边,周圍的物體和經(jīng)過的游戲角色,并不受這些光的影響次员。

? ? 我們要做的就是讓周圍的物體和經(jīng)過的游戲角色败许,實(shí)時(shí)地受到這些燈光的影響,實(shí)現(xiàn)仿3D效果淑蔚,增強(qiáng)2D游戲的體驗(yàn)和真實(shí)性市殷。

二、效果動(dòng)態(tài)圖對(duì)比

? ? 以下展示了不受光照影響和受光照影響的效果對(duì)比圖刹衫。很明顯醋寝,對(duì)旁邊的火把光作出反饋時(shí),角色更加真實(shí)带迟。


圖1 角色不受火光影響


圖1 角色受火光影響

三音羞、實(shí)現(xiàn)原理

? ? 實(shí)現(xiàn)基本原理是,我們將環(huán)境光源的坐標(biāo)仓犬、顏色嗅绰、強(qiáng)度實(shí)時(shí)傳入角色的片元shader,據(jù)此重新計(jì)算角色的顏色搀继。

? ? 那么如何確定角色身上哪些像素接受光照窘面、哪些不接受、又接受多少呢叽躯?這個(gè)就要用到法線貼圖了民镜。在法線貼圖上,每個(gè)紋理像素的RGB不再代表顏色分量险毁,而是代表角色身上每個(gè)像素的法向量信息制圈。關(guān)于法線貼圖定義請(qǐng)自行查閱相關(guān)資料们童。

? ? 步驟如下:

? ? 1、定義光照影響因子鲸鹦。這里用光源坐標(biāo)慧库、顏色、強(qiáng)度馋嗜、時(shí)間變量幾個(gè)uniform變量齐板。

? ? 2、準(zhǔn)備法線貼圖葛菇。一種方法是自定義每個(gè)像素的法向量信息甘磨,最后導(dǎo)出貼圖。一種是利用法線貼圖生成工具眯停,這里推薦一個(gè)在線法線貼圖生成工具? https://cpetry.github.io/NormalMap-Online/? 济舆,上傳貼圖,調(diào)整參數(shù)莺债,并生成和下載的法線貼圖滋觉。這里用的是在線生成。

? ? 3齐邦、將法線貼圖紋理椎侠,作為shader的uniform參數(shù)傳入供采樣。

圖3? 在線生成法線貼圖

四措拇、關(guān)鍵實(shí)現(xiàn)和代碼

? ? 一些算法做簡(jiǎn)化處理我纪。思想粗略描述如下:

1、強(qiáng)度距離衰減因子 = 光照強(qiáng)度 × ((感光距離最大值常量 - 角色紋理像素到光源的距離 )/ 感光距離最大值常量);

2丐吓、法向量2D平面分量 = vec2(法線貼圖顏色.R宣羊,法線貼圖顏色.B)* 2.0; // 2d游戲中忽略Z分量

3汰蜘、光照反饋強(qiáng)度因子 = 點(diǎn)積(光源到角色像素的向量仇冯, 法向量2D平面分量)

4、時(shí)間因子族操。動(dòng)態(tài)變化以實(shí)現(xiàn)強(qiáng)弱閃爍效果苛坚。更真實(shí)地,應(yīng)該以光源實(shí)際強(qiáng)度的值為準(zhǔn)色难,在CPU去計(jì)算泼舱。這里簡(jiǎn)便起見,用時(shí)間因子模擬

4枷莉、角色像素最終顏色RGB = 角色紋理原始顏色 × (1-光照原始透明度) + 光照原始顏色RGB × 強(qiáng)度距離衰減因子 × 光照反饋強(qiáng)度因子 × 時(shí)間影響因子 ×〗筷肌(光照原始透明度)

以上混合透明度可以根據(jù)自己想要的效果自定義即可。

shader代碼如下:

u_timeValue // 傳入的時(shí)間值笤妙,數(shù)值自定義冒掌,可每幀隨機(jī)變化噪裕,來模擬閃爍效果 。更真實(shí)地股毫,應(yīng)該以光源實(shí)際強(qiáng)度的值為準(zhǔn)膳音,在CPU去計(jì)算。這里簡(jiǎn)便起見铃诬,用時(shí)間因子模擬祭陷。

vec4 normalColor = texture2D(u_normalTexture, uvn); // 該片元坐標(biāo)在法線貼圖上的采樣顏色

vec2 lightPos = u_lightPos; // 光源的位置

vec4 lightColor = u_lightColor; // 光的原始顏色

float lightRadius = u_lightRadius; // 光能照到的最大半徑

float px = u_nodePos.x + (uvx -u_nodeAnchor.x) * u_nodeWidth; // 計(jì)算角色身上某像素的x位置

float py = u_nodePos.y + (u_nodeAnchor.y - uvy) * u_nodeHeight; // 計(jì)算角色身上某像素的y位置

vec2 vecLight = vec2(px - lightPos.x, py - lightPos.y); // 光源到角色身上某像素的向量

vec2 vecLightN = normalize(vecLight); // 光源到角色身上某像素向量的法向量

float dis = length(vecLight); // 光源到角色身上某像素的距離

vec2 normalVec = vec2(normalColor.r - 0.5, normalColor.g - 0.5) * 2.0; // 法線貼圖坐標(biāo)空間轉(zhuǎn)到顏色空間(-1~1轉(zhuǎn)0~1)

if (u_nodeScaleX == -1.0) { // 可能的x翻轉(zhuǎn)

? ? normalVec.r = -normalVec.r;

}

if (u_texture_flipY > 0.0) { // 可能的y翻轉(zhuǎn)

? ? normalVec.g = -normalVec.g;

float strength2 = max(dot(vecLightN, normalVec), 0.0);  // 關(guān)鍵點(diǎn):法向量和vecLightN 向量做點(diǎn)積運(yùn)算,得到反饋強(qiáng)度值

float strength = smoothstep(0.0, 1.0, 1.0 - dis/lightRadius); // 計(jì)算距離衰減因子趣席,這里采用平滑插值函數(shù)

float time = u_timeValue / timeRatio; // 時(shí)間影響因子

float timeYu = time - float(int(time));// 計(jì)算要用到的時(shí)間余數(shù)

timeYu = timeYu * 0.5 + 0.5 * timeRatio;// 時(shí)間轉(zhuǎn)換到0~timeRatio范圍

float strength3 = timeYu / timeRatio; // 時(shí)間因子轉(zhuǎn)換”尽0~1

strength3 = strength3 * 0.5 + 0.5; // 時(shí)間因子轉(zhuǎn)換 0.5~1 防止閃爍過于強(qiáng)烈很突兀

vec3 mixColor = color.rgb + lightColor.rgb * strength * strength2 * strength3 * lightColor.a; // 最終顏色混合公式.混合方式和參數(shù)可以自定義 這里采用顏色直接相加

color = vec4(mixColor, color.a); // 角色像素最終顏色

本文鏈接 游戲shader(6):利用法線貼圖實(shí)現(xiàn)動(dòng)態(tài)2D光照效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宣肚,一起剝皮案震驚了整個(gè)濱河市想罕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钉寝,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闸迷,死亡現(xiàn)場(chǎng)離奇詭異嵌纲,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)腥沽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門逮走,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人今阳,你說我怎么就攤上這事师溅。” “怎么了盾舌?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵墓臭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我妖谴,道長(zhǎng)窿锉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任膝舅,我火速辦了婚禮嗡载,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仍稀。我一直安慰自己洼滚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布技潘。 她就那樣靜靜地躺著遥巴,像睡著了一般千康。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挪哄,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天吧秕,我揣著相機(jī)與錄音,去河邊找鬼迹炼。 笑死砸彬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斯入。 我是一名探鬼主播砂碉,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼刻两!你這毒婦竟也來了增蹭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤磅摹,失蹤者是張志新(化名)和其女友劉穎滋迈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體户誓,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饼灿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帝美。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碍彭。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖悼潭,靈堂內(nèi)的尸體忽然破棺而出庇忌,到底是詐尸還是另有隱情,我是刑警寧澤舰褪,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布皆疹,位于F島的核電站,受9級(jí)特大地震影響占拍,放射性物質(zhì)發(fā)生泄漏墙基。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一刷喜、第九天 我趴在偏房一處隱蔽的房頂上張望残制。 院中可真熱鬧,春花似錦掖疮、人聲如沸初茶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恼布。三九已至螺戳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間折汞,已是汗流浹背倔幼。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爽待,地道東北人损同。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鸟款,于是被迫代替她去往敵國(guó)和親膏燃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容