原神角色渲染02
身體頭發(fā)陰影
接下來開始搞身體頭發(fā)的陰影,首先,所有ramp圖的wrap mode改為clamp。防止像這個(gè)大佬一樣出現(xiàn)黑線。

然后是ramp圖采樣,首先v方向我們都用半蘭伯特采樣。但是我們觀察ramp圖可以發(fā)現(xiàn),這些ramp圖的明暗交界線是位于很靠右的位置的。這里這個(gè)大佬是通過把Lambert01范圍壓縮,來解決這個(gè)問題(https://zhuanlan.zhihu.com/p/435005339)。

不過我是用另一個(gè)辦法,直接把蘭伯特乘以2,其實(shí)這樣的方法和上面大佬的方法原理一樣,只不過我的少了clamp這個(gè)步驟,在亮部實(shí)際上取到了1到2的值。不過因?yàn)槲抑皩?duì)ramp圖的循環(huán)模式設(shè)置為了clamp鉗制,所以沒什么問題。
這里十分值得一提的是,https://www.bilibili.com/video/BV1h14y177bp,在這個(gè)視頻里,用的半蘭伯特是加了平方的,我試了之后確實(shí)加平方效果更好,暗部更暗亮部更亮了。(這其實(shí)就是power的作用)但是作者說,半蘭伯特不加平方的,面試全不給過,把我嚇到了。我特地去網(wǎng)上搜了一圈,絕大部分資料是直接*0.5+0.5,沒有平方,如果搞這么嚴(yán),感覺有點(diǎn)絕。

然后是u方向的選擇,這個(gè)我研究了半天,很多人是直接手動(dòng)設(shè)置要取哪一行的ramp圖的坐標(biāo)。但是我看了上面那個(gè)大佬,他是直接把lightmap的a通道做v方向的采樣。我便效仿了,但是效果很不對(duì)。而且我看到也有人說這樣不對(duì)之后還是逐行取讀。

后面我找到了原因,首先這個(gè)透明度的值是不能直接用作采樣的v坐標(biāo)的,否則就會(huì)像下圖那樣采樣到不正確的邊緣。而且透明度有三層值,對(duì)應(yīng)的ramp也有三條(冷暖各三條),說明是對(duì)應(yīng)得上的。頭發(fā)那邊也是同理。

唉,從寫上面那一段話到寫這一段話,哥們經(jīng)歷了諸多探索。起初我的想法是,對(duì)lightmap.a做一些運(yùn)算,把它的位置映射到ramp圖對(duì)應(yīng)的v值上。如下圖。但是做好之后,我發(fā)現(xiàn)我的效果不太對(duì)勁。

首先是顏色太淡了,我人力對(duì)比了下ramp圖原圖和引擎的效果,感覺這個(gè)顏色就是十分不對(duì)的,結(jié)果找了半天,把sRGB勾上后,就正常了些。但是很明顯的又能發(fā)現(xiàn),頭發(fā)ramp圖采樣暗部竟然有個(gè)亮線。

我又研究了半天,發(fā)現(xiàn)ramp圖的采樣也不對(duì)勁。ramp圖原圖是只有十行的,理論上來說,只有v值在一個(gè)ramp的v坐標(biāo)區(qū)間內(nèi),比如0.81-0.89,那么ramp顏色是不會(huì)改變的。但是我經(jīng)過多次測(cè)試后發(fā)現(xiàn),提莫的會(huì)改變,而且上面那個(gè)亮線就是在某一個(gè)值的時(shí)候出現(xiàn)的。然后我又經(jīng)過多次嘗試之后,發(fā)現(xiàn)把圖像壓縮關(guān)了就沒有那個(gè)亮線了。

但但但但是,還是有問題,就是上面我說那個(gè)v值在區(qū)間內(nèi)改變,ramp值也會(huì)變的問題。然后我突然發(fā)現(xiàn),tnnd怎么這個(gè)圖變成256*16了。在外面看明明高度是10的。

然后我去搜了一下,哦原來圖片導(dǎo)入unity中尺寸會(huì)變成2的N次方,為的是規(guī)范化格式,不浪費(fèi)空間。就好像磁盤那個(gè)簇,如果一個(gè)簇512k,那么放一個(gè)513k的文件就要兩個(gè)簇,極大的浪費(fèi)了空間,那么我們把513k壓縮到512k,就規(guī)范了格式,不浪費(fèi)空間了。大概就這個(gè)意思。然后這個(gè)ramp圖被調(diào)整到16行后,進(jìn)行了插值計(jì)算。計(jì)算方式如下圖。所以最終,這個(gè)ramp圖被模糊了。也就是我們從材質(zhì)面板看到的樣子。
https://blog.csdn.net/linxinfa/article/details/108827197


到這里所以謎團(tuán)似乎解開了,我想著的是:好吧,你模糊就模糊吧,好在還是有一條能用的ramp。結(jié)果我又發(fā)現(xiàn),這肚子的顏色不太對(duì)啊結(jié)果發(fā)現(xiàn),lightmap的a通道里面,皮膚是1,然而ramp圖里面,皮膚是在中間的。好吧,這下我那個(gè)方法別用了。

于是,我自己把ramp圖改了過來,這下又用回我之前的辦法了。

最終效果也還不錯(cuò)

然后,如何利用lightmap的g通道的陰影蒙版又是一個(gè)問題。g通道內(nèi),黑色是死陰影,永遠(yuǎn)是暗面,灰色是受光照影響的部分,白色是永遠(yuǎn)是亮面。我嘗試了幾個(gè)方法之后,最后還是使用了兩層lerp,第一步,把亮面和暗面混合起來。其實(shí)在這些混合的時(shí)候會(huì)有一些問題,如果直接用lightmap.g混合,中間0.5部分的顏色就是亮暗混合,很怪異。所以我們要讓lightmap.g變成非0即1。所以進(jìn)行了乘2然后clmap的操作,把0.5和1全部劃分為亮部。因?yàn)楹罄m(xù)混合ramp陰影的時(shí)候可以再覆蓋0.5部分,所以這樣操作沒問題。
然后第二層lerp,就是在前面的finalcol的基礎(chǔ)上加上ramp陰影,也就是說,我需要把lightmap.g劃分為兩部分,0,1值是一部分,這部分顏色不用動(dòng),0.5值是一部分,這部分變?yōu)槭褂胷amp陰影。所以我使用了-0.5取絕對(duì)值然后乘2的操作,成功把原來三個(gè)區(qū)域劃分為01區(qū)域。然后再lerp就好了


值得一提的是,我當(dāng)時(shí)發(fā)現(xiàn)ramp陰影和死陰影顏色不一樣,看上去有點(diǎn)突兀,然后我研究了半天怎么讓它們?nèi)诤希Y(jié)果效果都不理想,最后去官方看了一眼,發(fā)現(xiàn)原來官方也沒有解決這個(gè)問題。(要不是我迪希雅歪了,到現(xiàn)在還沒有,至于找個(gè)參考都這么費(fèi)勁嗎QAQ)


那么總之,陰影的效果暫且就先這樣了。其實(shí)后面有挺多步驟我都是自己弄明白原理后自己想的辦法。因?yàn)槲腋杏X網(wǎng)上這么多還原原神渲染的資料,各個(gè)都有些差別,等于說沒個(gè)標(biāo)準(zhǔn)答案。既然明白了基本用法,那就按自己想法來吧,可能效果還差一些,看到最后再看吧,如果效果差很多的話,我再去尋找優(yōu)化的資料。參考大佬的經(jīng)驗(yàn)。
下面還差多少呢?描邊,高光,邊緣光。
法線
本來想著法線不多順便搞的,結(jié)果也花了一番功夫,歸根結(jié)底還是對(duì)urpshader不熟悉的緣故。之后好好學(xué)一下這邊的基礎(chǔ)吧。
其實(shí)也是和之前差不多,多加一個(gè)法線貼圖的采樣,然后輸入結(jié)構(gòu)加入切線信息,輸出結(jié)構(gòu)存在紋理里面(其實(shí)這個(gè)還有點(diǎn)模糊,我暫且理解為紋理)。

下面在頂點(diǎn)著色器里面獲取切線和副切線。這里和CG差別好像挺大的,反正我看網(wǎng)上也有人用以前的方法,但是我用了之后,信息是錯(cuò)誤的。后面終于找到一個(gè)簡(jiǎn)單省事的代碼,而且獲取來的信息是準(zhǔn)確的,以后在URP里面就這樣獲取切線副切線了。

之后就是老三樣,采樣解碼,構(gòu)建TBN,轉(zhuǎn)換。不過好像也有一個(gè)專門函數(shù)用來轉(zhuǎn)換,但是既然這樣行那就先這樣吧。

