亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

OpenGL核心技術之法線貼圖

2019-11-06 09:35:01
字體:
來源:轉載
供稿:網友

筆者介紹:姜雪偉,IT公司技術合伙人,IT高級講師,CSDN社區專家,特邀編輯,暢銷書作者;已出版書籍:《手把手教你架構3D游戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。

CSDN視頻網址:http://edu.csdn.net/lecturer/144

游戲畫面中的美術品質對產品來說非常重要,這決定了產品是否能吸引玩家。美術品質的好壞主要體現在材質的渲染上,材質的渲染不僅是美術的事情也是程序的事情,二者要互相配合才能得到想要的效果。本篇博客主要介紹的是材質的法線渲染,本篇博文也適合美術人員學習,當然對于程序更重要,它從法線的原理講起,逐步深入,博文最后會給出源代碼。

游戲場景中會擺滿很多物體,其中每個物體都可能由成百上千平坦的三角形組成。我們以向三角形上附加紋理的方式來增加額外細節,提升真實感,隱藏多邊形幾何體是由無數三角形組成的事實。紋理確有助益,然而當你近看它們時,這個事實便隱藏不住了。現實中的物體表面并非是平坦的,而是表現出無數(凹凸不平的)細節。

例如,磚塊的表面。磚塊的表面非常粗糙,顯然不是完全平坦的:它包含著接縫處水泥凹痕,以及非常多的細小的空洞。如果我們在一個有光的場景中看這樣一個磚塊的表面,問題就出來了。下圖中我們可以看到磚塊紋理應用到了平坦的表面,并被一個點光源照亮。

光照并沒有呈現出任何裂痕和孔洞,完全忽略了磚塊之間凹進去的線條;表面看起來完全就是平的。我們可以使用specular貼圖根據深度或其他細節阻止部分表面被照的更亮,以此部分地解決問題,但這并不是一個好方案。我們需要的是某種可以告知光照系統給所有有關物體表面類似深度這樣的細節的方式。

如果我們以光的視角來看這個問題:是什么使表面被視為完全平坦的表面來照亮?答案會是表面的法線向量。以光照算法的視角考慮的話,只有一件事決定物體的形狀,這就是垂直于它的法線向量。磚塊表面只有一個法線向量,表面完全根據這個法線向量被以一致的方式照亮。如果每個fragment都是用自己的不同的法線會怎樣?這樣我們就可以根據表面細微的細節對法線向量進行改變;這樣就會獲得一種表面看起來要復雜得多的幻覺:

每個fragment使用了自己的法線,我們就可以讓光照相信一個表面由很多微小的(垂直于法線向量的)平面所組成,物體表面的細節將會得到極大提升。這種每個fragment使用各自的法線,替代一個面上所有fragment使用同一個法線的技術叫做法線貼圖(normal mapping)或凹凸貼圖(bump mapping)。應用到磚墻上,效果像這樣:

你可以看到細節獲得了極大提升,開銷卻不大。因為我們只需要改變每個fragment的法線向量,并不需要改變所有光照公式?,F在我們是為每個fragment傳遞一個法線,不再使用插值表面法線。這樣光照使表面擁有了自己的細節。

為使法線貼圖工作,我們需要為每個fragment提供一個法線。像diffuse貼圖和specular貼圖一樣,我們可以使用一個2D紋理來儲存法線數據。2D紋理不僅可以儲存顏色和光照數據,還可以儲存法線向量。這樣我們可以從2D紋理中采樣得到特定紋理的法線向量。

由于法線向量是個幾何工具,而紋理通常只用于儲存顏色信息,用紋理儲存法線向量不是非常直接。如果你想一想,就會知道紋理中的顏色向量用r、g、b元素代表一個3D向量。類似的我們也可以將法線向量的x、y、z元素儲存到紋理中,代替顏色的r、g、b元素。法線向量的范圍在-1到1之間,所以我們先要將其映射到0到1的范圍:

vec3 rgb_normal = normal * 0.5 + 0.5; // 從 [-1,1] 轉換至 [0,1]將法線向量變換為像這樣的RGB顏色元素,我們就能把根據表面的形狀的fragment的法線保存在2D紋理中。在博客文章開頭展示的那個磚塊的例子的法線貼圖如下所示:

這會是一種偏藍色調的紋理(你在網上找到的幾乎所有法線貼圖都是這樣的)。這是因為所有法線的指向都偏向z軸(0, 0, 1)這是一種偏藍的顏色。法線向量從z軸方向也向其他方向輕微偏移,顏色也就發生了輕微變化,這樣看起來便有了一種深度。例如,你可以看到在每個磚塊的頂部,顏色傾向于偏綠,這是因為磚塊的頂部的法線偏向于指向正y軸方向(0, 1, 0),這樣它就是綠色的了。

在一個簡單的朝向正z軸的平面上,我們可以用這個diffuse紋理和這個法線貼圖來渲染前面部分的圖片。要注意的是這個鏈接里的法線貼圖和上面展示的那個不一樣。原因是OpenGL讀取的紋理的y(或V)坐標和紋理通常被創建的方式相反。鏈接里的法線貼圖的y(或綠色)元素是相反的(你可以看到綠色現在在下邊);如果你沒考慮這個,光照就不正確了(使用SOIL載入紋理會上下顛倒,它也會把法線在y方向上顛倒)。加載紋理,把它們綁定到合適的紋理單元,然后使用下面的改變了的像素著色器來渲染一個平面:

uniform sampler2D normalMap;  void main(){               // 從法線貼圖范圍[0,1]獲取法線    normal = texture(normalMap, fs_in.TexCoords).rgb;    // 將法線向量轉換為范圍[-1,1]    normal = normalize(normal * 2.0 - 1.0);       [...]    // 像往常那樣處理光照}

這里我們將被采樣的法線顏色從0到1重新映射回-1到1,便能將RGB顏色重新處理成法線,然后使用采樣出的法線向量應用于光照的計算。在例子中我們使用的是Blinn-Phong著色器。

通過慢慢隨著時間慢慢移動光源,你就能明白法線貼圖是什么意思了。運行這個例子你就能得到本篇博客開始的那個效果:

實現上述效果的源代碼,頂點著色器代碼如下所示:

#version 330 corelayout (location = 0) in vec3 position;layout (location = 1) in vec3 normal;layout (location = 2) in vec2 texCoords;// Declare an interface block; see 'Advanced GLSL' for what these are.out VS_OUT {    vec3 FragPos;    vec3 Normal;    vec2 TexCoords;} vs_out;uniform mat4 PRojection;uniform mat4 view;uniform mat4 model;void main(){    gl_Position = projection * view * model * vec4(position, 1.0f);    vs_out.FragPos = vec3(model * vec4(position, 1.0));    vs_out.TexCoords = texCoords;        mat3 normalMatrix = transpose(inverse(mat3(model)));    vs_out.Normal = normalMatrix * normal;}

片段著色器代碼如下所示:

#version 330 coreout vec4 FragColor;in VS_OUT {    vec3 FragPos;    vec3 Normal;    vec2 TexCoords;} fs_in;uniform sampler2D diffuseMap;uniform sampler2D normalMap;  uniform vec3 lightPos;uniform vec3 viewPos;uniform bool normalMapping;void main(){               vec3 normal = normalize(fs_in.Normal);    if(normalMapping)    {        // Obtain normal from normal map in range [0,1]        normal = texture(normalMap, fs_in.TexCoords).rgb;        // Transform normal vector to range [-1,1]        normal = normalize(normal * 2.0 - 1.0);       }     // Get diffuse color    vec3 color = texture(diffuseMap, fs_in.TexCoords).rgb;    // Ambient    vec3 ambient = 0.1 * color;    // Diffuse    vec3 lightDir = normalize(lightPos - fs_in.FragPos);    float diff = max(dot(lightDir, normal), 0.0);    vec3 diffuse = diff * color;    // Specular    vec3 viewDir = normalize(viewPos - fs_in.FragPos);    vec3 reflectDir = reflect(-lightDir, normal);    vec3 halfwayDir = normalize(lightDir + viewDir);      float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);    vec3 specular = vec3(0.2) * spec;        FragColor = vec4(ambient + diffuse + specular, 1.0f);}	然而有個問題限制了剛才講的那種法線貼圖的使用。我們使用的那個法線貼圖里面的所有法線向量都是指向正z方向的。上面的例子能用,是因為那個平面的表面法線也是指向正z方向的??墒牵绻覀冊诒砻娣ň€指向正y方向的平面上使用同一個法線貼圖會發生什么?

光照看起來完全不對!發生這種情況是平面的表面法線現在指向了y,而采樣得到的法線仍然指向的是z。結果就是光照仍然認為表面法線和之前朝向正z方向時一樣;這樣光照就不對了。下面的圖片展示了這個表面上采樣的法線的近似情況:

你可以看到所有法線都指向z方向,它們本該朝著表面法線指向y方向的。一個可行方案是為每個表面制作一個單獨的法線貼圖。如果是一個立方體的話我們就需要6個法線貼圖,但是如果模型上有無數的朝向不同方向的表面,這就不可行了。

注意事項:實際上對于復雜模型可以把朝向各個方向的法線儲存在同一張貼圖上,你可能看到過不只是藍色的法線貼圖,不過用那樣的法線貼圖有個問題是你必須記住模型的起始朝向,如果模型運動了還要記錄模型的變換,這是非常不方便的;如果把一個diffuse紋理應用在同一個物體的不同表面上,就像立方體那樣的,就需要做6個法線貼圖,這也不可取。

另一個稍微有點難的解決方案是,在一個不同的坐標空間中進行光照,這個坐標空間里,法線貼圖向量總是指向這個坐標空間的正z方向;所有的光照向量都相對與這個正z方向進行變換。這樣我們就能始終使用同樣的法線貼圖,不管朝向問題。這個坐標空間叫做切線空間(tangent space)。

下篇博客介紹切線空間。。。。。。。。。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
奇米成人av国产一区二区三区| 亚洲国产黄色片| 国产精品香蕉av| 激情久久av一区av二区av三区| 中文字幕不卡在线视频极品| 久久精品国产免费观看| 久久精品久久久久久| 欧美一级大片视频| 中文字幕精品一区久久久久| 亚洲美女中文字幕| 中文字幕免费国产精品| 91精品国产精品| 日韩av免费一区| 欧美日韩成人在线视频| 97人人做人人爱| 欧美日韩亚洲视频一区| 久久久久久久香蕉网| 日本久久久久久久久| 欧美大片在线影院| 国产精品久久久久久久久久久久久久| 美乳少妇欧美精品| 国产日韩在线观看av| 国语自产精品视频在线看抢先版图片| 国外视频精品毛片| 亚洲国产精品高清久久久| 亚洲xxxx做受欧美| 欧美午夜无遮挡| 精品福利在线视频| 北条麻妃一区二区在线观看| 欧美日韩国产专区| 久久777国产线看观看精品| 亚洲aⅴ日韩av电影在线观看| 久青草国产97香蕉在线视频| 精品高清一区二区三区| 久久亚洲精品一区| 国产91露脸中文字幕在线| 18一19gay欧美视频网站| 欧美国产视频一区二区| 日韩av男人的天堂| 欧美福利视频在线观看| 在线观看国产精品淫| 91po在线观看91精品国产性色| 精品免费在线观看| 国产精品尤物福利片在线观看| 国产成人短视频| 亚洲精品视频久久| 国产美女久久久| 不卡伊人av在线播放| 日韩欧美在线视频| 欧美在线免费观看| 一区二区三区视频观看| 黑人精品xxx一区| 69久久夜色精品国产69乱青草| 国精产品一区一区三区有限在线| 国产精品丝袜久久久久久高清| 亚洲新声在线观看| 91精品国产高清自在线看超| 8x海外华人永久免费日韩内陆视频| 国产精品国产福利国产秒拍| 亚洲视频日韩精品| 国产精品视频午夜| 日韩中文字幕在线播放| 日韩美女毛茸茸| 45www国产精品网站| 成人写真福利网| 亚洲欧美制服第一页| 国产欧美日韩中文字幕在线| 亚洲精品黄网在线观看| 亚洲va欧美va国产综合久久| 国产精品∨欧美精品v日韩精品| 亚洲人成在线观看网站高清| 国产成人精品在线观看| 色www亚洲国产张柏芝| 日韩精品免费在线视频| 亚洲视频axxx| 久久国产精品电影| 91po在线观看91精品国产性色| 97在线免费视频| 精品久久久久久久久久久| 日韩视频精品在线| 国产精品视频男人的天堂| 欧美在线亚洲在线| 欧美肥老太性生活视频| 国产精品igao视频| 国产一区红桃视频| 亚洲精品电影网在线观看| 欧美人与物videos| 亚洲香蕉在线观看| 欧美午夜精品伦理| 国产成人精品在线播放| 欧美日在线观看| 欧美成在线观看| 91久久国产精品| 久久久精品亚洲| 欧美激情第99页| 欧美日韩不卡合集视频| 亚洲91精品在线观看| 国产成人久久久精品一区| 亚洲视频axxx| 亚洲香蕉av在线一区二区三区| 国产精品r级在线| 一区二区三区视频免费在线观看| 激情懂色av一区av二区av| 欧美极品少妇与黑人| 亚洲第一偷拍网| 国产精品久久久久久久美男| 尤物yw午夜国产精品视频| 欧美在线视频网| 欧美性极品xxxx做受| 国产亚洲精品久久久久动| 精品一区二区三区四区在线| 51色欧美片视频在线观看| 亚洲一区二区久久久| 日韩在线国产精品| 久久影视三级福利片| 在线日韩第一页| 在线看日韩欧美| 国产欧美一区二区三区四区| 日韩一区二区福利| 国产精品视频大全| 欧美性猛交视频| 成人免费淫片aa视频免费| 欧美极度另类性三渗透| 2019中文字幕免费视频| 亚洲国产精品久久久久久| 欧美午夜精品在线| 欧美大片在线看| 中文字幕国产精品久久| 欧美日韩精品二区| 精品二区三区线观看| 亚洲最大成人免费视频| 91国产精品91| 91久久夜色精品国产网站| 国产91精品黑色丝袜高跟鞋| 91中文精品字幕在线视频| 在线观看91久久久久久| 欧美裸体xxxx极品少妇软件| 国产精品va在线播放我和闺蜜| 欧美国产亚洲精品久久久8v| 永久免费精品影视网站| 欧美性猛交xxxx乱大交极品| 97av视频在线| 亚洲精品大尺度| 91在线高清视频| 欧美激情喷水视频| 亚洲欧美变态国产另类| 亚洲精品国偷自产在线99热| 国产视频综合在线| 97热精品视频官网| 91精品免费久久久久久久久| 精品福利一区二区| 国产精品久久久久久久久久99| 中文字幕欧美视频在线| 久久久国产精彩视频美女艺术照福利| 91中文字幕在线| 91精品视频免费| 亚洲综合国产精品| 亚洲精品乱码久久久久久金桔影视| 成人网页在线免费观看| 日韩视频在线观看免费| 久久综合国产精品台湾中文娱乐网| 亚洲国产成人精品一区二区| 久久精品国产一区二区电影| 91禁外国网站|