切線空間法線貼圖(tangent space normal mapping)

前言:我又來翻譯了。黑忱。宴抚。

今天的主題是法線貼圖。法線貼圖和 Phong 著色之間的主要區(qū)別是什么甫煞?關(guān)鍵是我們擁有的信息密度菇曲。對(duì)于 Phong 著色,我們使用三角形網(wǎng)格的每個(gè)頂點(diǎn)給出的法向量(并在三角形內(nèi)插入)抚吠,而法線貼圖紋理提供密集信息常潮,大大改善了渲染細(xì)節(jié)。

好吧楷力,我們已經(jīng)在上一課中應(yīng)用了法線貼圖喊式,但是我們使用全局坐標(biāo)系來存儲(chǔ)紋理。今天我們談?wù)摰氖乔芯€空間法線貼圖萧朝。

所以岔留,我們有兩個(gè)紋理,左邊的一個(gè)是在全局框架中給出的(從RGB 到 XYZ 法線的直接轉(zhuǎn)換)检柬,而在 Darboux 框架中是右邊的:

image

為了使用正確的紋理献联,我們繪制每個(gè)像素,我們計(jì)算切線空間何址。在此基礎(chǔ)上里逆,一個(gè)矢量(通常為z)與我們的表面正交,另外兩個(gè)坐標(biāo)軸給出了與當(dāng)前點(diǎn)相切的平面用爪。然后我們從紋理中讀仍骸(擾動(dòng)的)法向量,將其坐標(biāo)從 Darboux 框架轉(zhuǎn)換為全局系統(tǒng)坐標(biāo)偎血,我們已經(jīng)完成了诸衔。通常,法線貼圖提供法向量的小擾動(dòng)颇玷,因此紋理呈主導(dǎo)藍(lán)色署隘。

好吧,為什么這么亂亚隙?為什么不像以前那樣使用全球系統(tǒng)磁餐?想象一下,我們想要為我們的模型制作動(dòng)畫阿弃。例如诊霹,我采取了黑人模型并張開嘴。很明顯渣淳,要修改法向量脾还。

image

左圖給頭部開口,但是沒有改變的(全局框架)正常紋理入愧。仔細(xì)檢查下唇的內(nèi)部鄙漏。光線直接照在他的臉上;當(dāng)嘴巴閉合時(shí)嗤谚,下唇的背面自然不會(huì)被點(diǎn)亮的。現(xiàn)在嘴巴張開怔蚌,但嘴唇?jīng)]有亮起......正確的圖像是用切線空間法線貼圖計(jì)算的巩步。

因此,如果我們有一個(gè)動(dòng)畫模型桦踊,那么為了在全局幀中進(jìn)行正確的法線貼圖椅野,我們需要每幀動(dòng)畫有一個(gè)紋理,而切線空間相應(yīng)地變形為模型籍胯,而且我們只需要一個(gè)紋理竟闪!

(這兩段話完全沒有理解)

這是另一個(gè)例子:

image

這些是暗黑破壞神模型的紋理。請(qǐng)注意杖狼,紋理中只繪制了一只手炼蛤,而尾部只有一側(cè)。畫家對(duì)雙臂和兩側(cè)使用相同的紋理蝶涩,這意味著在全局坐標(biāo)系中我可以為尾部的左側(cè)提供法向矢量鲸湃。要么是正確的,要么不是兩者兼而有之子寓!武器也是如此暗挑。我需要左側(cè)和右側(cè)的不同信息,例如斜友,檢查左側(cè)圖像中的左右顴骨炸裆,自然法線向量指向相反的方向!

讓我們完成動(dòng)機(jī)部分并直接進(jìn)行計(jì)算鲜屏。

(看不懂)

開始烹看,Phong 著色

好的,這是起點(diǎn)洛史。著色器非常簡(jiǎn)單惯殊,它是 Phong 著色。

struct Shader : public IShader {
    mat<2,3,float> varying_uv;  // triangle uv coordinates, written by the vertex shader, read by the fragment shader
    mat<3,3,float> varying_nrm; // normal per vertex to be interpolated by FS

    virtual Vec4f vertex(int iface, int nthvert) {
        varying_uv.set_col(nthvert, model->uv(iface, nthvert));
        varying_nrm.set_col(nthvert, proj<3>((Projection*ModelView).invert_transpose()*embed<4>(model->normal(iface, nthvert), 0.f)));
        Vec4f gl_Vertex = Projection*ModelView*embed<4>(model->vert(iface, nthvert));
        varying_tri.set_col(nthvert, gl_Vertex);
        return gl_Vertex;
    }

    virtual bool fragment(Vec3f bar, TGAColor &color) {
        Vec3f bn = (varying_nrm*bar).normalize();
        Vec2f uv = varying_uv*bar;

        float diff = std::max(0.f, bn*light_dir);
        color = model->diffuse(uv)*diff;
        return false;
    }
};

這是渲染圖像:

image

出于教育和調(diào)試目的也殖,我將去除皮膚紋理并應(yīng)用具有水平紅色和垂直藍(lán)線的常規(guī)網(wǎng)格

image

讓我們記住 Phong 著色的工作原理:

image

對(duì)于三角形的每個(gè)頂點(diǎn)土思,我們有它的坐標(biāo) p,紋理坐標(biāo) uv 和法向量忆嗜。對(duì)于著色當(dāng)前片段己儒,我們的軟件光柵化器為我們提供了片段(alpha,beta捆毫,gamma)的重心坐標(biāo)闪湾。這意味著片段的坐標(biāo)可以獲得為p = alpha p0 + beta p1 + gamma p2。然后我們以相同的方式插入紋理坐標(biāo)和法線向量:

image

請(qǐng)注意绩卤,藍(lán)線和紅線相應(yīng)地是 u 和 v 的等值線途样。因此江醇,對(duì)于我們表面的每個(gè)點(diǎn),我們定義了一個(gè)所謂的 Darboux 框架何暇,其中 x 和 y 軸平行于藍(lán)色和紅色線陶夜,z 軸垂直于表面。這是切線空間法線貼圖所在的框架赖晶。

如何從三個(gè)樣本重建(3D)線性函數(shù)

好的,所以我們的目標(biāo)是為我們繪制的每個(gè)像素計(jì)算三個(gè)向量(切線基礎(chǔ))辐烂。讓我們把它擱置一段時(shí)間遏插,想象一個(gè)線性函數(shù) f,對(duì)于每個(gè)點(diǎn)(x纠修,y胳嘲,z)給出一個(gè)實(shí)數(shù) f(x,y扣草,z)= Ax + By + Cz + D了牛。唯一的問題是我們不知道 A,B辰妙,C 和 D鹰祸,但是我們知道在空間的三個(gè)不同點(diǎn)(p0,p1密浑,p2)有三個(gè)函數(shù)值:

image
image

將 f 想象為傾斜平面的高度圖是很方便的蛙婴。我們?cè)谄矫嫔闲迯?fù)了三個(gè)不同的(非共線)點(diǎn),我們知道這些點(diǎn)中的 f 的值尔破。三角形內(nèi)的紅線表示等高 f0街图,f0 + 1 米,f0 + 2 米等懒构。對(duì)于線性函數(shù)餐济,我們的等值線是平行(直線)線。

事實(shí)上胆剧,我對(duì)方向更感興趣絮姆,正交于等值線。如果我們沿著 iso 移動(dòng)秩霍,高度不會(huì)改變(嗯滚朵,這是一個(gè)iso!)前域。如果我們偏離 iso 一點(diǎn)點(diǎn)辕近,高度開始變化一點(diǎn)點(diǎn)。當(dāng)我們正交于等值線時(shí)匿垄,我們獲得最陡的上升移宅。

讓我們回想一下归粉,函數(shù)最陡峭的上升方向就是它的梯度。對(duì)于線性函數(shù)f(x漏峰,y糠悼,z) = Ax+By+Cz+D,其梯度是常數(shù)向量(A浅乔,B倔喂,C)【肝回想一下席噩,我們不知道(A,B贤壁,C)的值悼枢。我們只知道該函數(shù)的三個(gè)樣本。我們可以重建 A脾拆,B 和 C 嗎馒索?當(dāng)然可以。

所以名船,我們有三個(gè)點(diǎn) p0绰上,p1,p2 和三個(gè)值 f0渠驼,f1渔期,f2。我們需要找到最陡上升的矢量(A渴邦,B疯趟,C)。讓我們考慮另一個(gè)定義為g(p)= f(p)-f(p0)的函數(shù):

image

顯然谋梭,我們只是簡(jiǎn)單地平移了我們的傾斜平面信峻,而沒有改變它的傾斜度,因此 f 和 g 的最陡上升方向是相同的瓮床。

讓我們重寫 g 的定義

image

請(qǐng)注意盹舞,p ^ x中的上標(biāo) x 表示點(diǎn) p 的 x 坐標(biāo)而不是冪。因此隘庄,函數(shù)g 只是向量 (p - p0) 和 (A B C) 之間的點(diǎn)積踢步。我們?nèi)匀徊恢?(A,B丑掺,C)获印!

好的,讓我們回想一下我們所知道的街州。我們知道如果我們從點(diǎn) p0 到點(diǎn) p2兼丰,那么函數(shù) g 將從零到 f2-f0 玻孟。換句話說,矢量 (p2 - p0) 和(ABC) 之間的點(diǎn)積等于 f2 - f0鳍征。 (p1 - p0) 也是如此黍翎。因此,我們正在尋找向量 ABC 艳丛,與法向量 n 正交并且遵守點(diǎn)積的兩個(gè)約束匣掸。

image

讓我們以矩陣形式重寫:

image

因此,我們得到了一個(gè)易于求解的線性矩陣方程 Ax = b:

image

請(qǐng)注意氮双,我使用字母 A 表示兩種不同的東西碰酝,其含義應(yīng)從上下文中清楚。因此眶蕉,我們的 3x3 矩陣 A 乘以未知向量 x = (A, B, C)砰粹,給出向量 b = (f1 - f0, f2 - f0, 0)唧躲。當(dāng)我們將 A 的逆乘以 b 時(shí)造挽,未知向量 x 變?yōu)橐阎?/p>

還要注意,矩陣 A 與函數(shù) f 沒有任何關(guān)系弄痹。它只包含有關(guān)我們?nèi)切蔚囊恍┬畔ⅰ?/p>

讓我們計(jì)算 Darboux 基礎(chǔ)并應(yīng)用法線的擾動(dòng)

因此饭入,Darboux 是向量三元組 (i,j肛真,n)谐丢,其中 n - 是原始法向量,i蚓让,j 可以如下計(jì)算:

image

這是提交乾忱,使用切線空間中的法線貼圖,在這里您可以檢查相對(duì)于起點(diǎn)(Phong 著色)的差異历极。

直截了當(dāng)?shù)膩戆烧粒矣?jì)算矩陣 A。

mat<3,3,float> A;
A[0] = ndc_tri.col(1) - ndc_tri.col(0);
A[1] = ndc_tri.col(2) - ndc_tri.col(0);
A[2] = bn;

然后計(jì)算 Darboux 的兩個(gè)未知向量 (i, j):

一旦我們得到所有切線基礎(chǔ)趟卸,我從紋理中讀取擾動(dòng)法線并應(yīng)用從切線基礎(chǔ)到全局坐標(biāo)的基礎(chǔ)變化蹄葱。回想一下锄列,我已經(jīng)描述了如何改變基礎(chǔ)图云。

這是最后的渲染圖像,與 Phong shading 比較一下吧邻邮!

image

最后實(shí)現(xiàn)渲染器的代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竣况,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子筒严,更是在濱河造成了極大的恐慌帕翻,老刑警劉巖鸠补,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嘀掸,居然都是意外死亡紫岩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隘截,“玉大人榄棵,你說我怎么就攤上這事⊙悖” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵硫兰,是天一觀的道長(zhǎng)诅愚。 經(jīng)常有香客問我,道長(zhǎng)劫映,這世上最難降的妖魔是什么违孝? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮泳赋,結(jié)果婚禮上雌桑,老公的妹妹穿的比我還像新娘。我一直安慰自己祖今,他們只是感情好校坑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著千诬,像睡著了一般耍目。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上徐绑,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天邪驮,我揣著相機(jī)與錄音,去河邊找鬼泵三。 笑死耕捞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的烫幕。 我是一名探鬼主播俺抽,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼较曼!你這毒婦竟也來了磷斧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弛饭,沒想到半個(gè)月后冕末,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侣颂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年档桃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片憔晒。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藻肄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拒担,到底是詐尸還是另有隱情嘹屯,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布从撼,位于F島的核電站州弟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏低零。R本人自食惡果不足惜婆翔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毁兆。 院中可真熱鬧浙滤,春花似錦阴挣、人聲如沸气堕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)茎芭。三九已至,卻和暖如春誓沸,著一層夾襖步出監(jiān)牢的瞬間梅桩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工拜隧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宿百,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓洪添,卻偏偏與公主長(zhǎng)得像垦页,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子干奢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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