青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

永遠也不完美的程序

不斷學習,不斷實踐,不斷的重構……

常用鏈接

統(tǒng)計

積分與排名

好友鏈接

最新評論

shader復雜與深入:Normal Map(法線貼圖)2


在前文中我盡可能地把我所理解Normal Map原理總結了一下,本續(xù)篇將從實踐部分繼續(xù)開始,各位看官盡情拍磚。——ZwqXin.com
上篇見:[shader復習與深入:Normal Map(法線貼圖)Ⅰ]
1. 怎樣獲得頂點的TBN
其實我覺得這個是實踐部分最麻煩的地方。OpenGL提供了諸如glNormal、normal-vbo之類的接口設置頂點的法線,然后在shader中以gl_Normal等方式取得頂點法線數(shù)據(jù),但是沒有提供切線和副法線的。當然兩者只要其一就足夠了(另一者可通過叉乘和左/右手定則獲得)。因為要把TBN導入shader,干脆就設置attribute變量,記錄每個頂點的切線。切線一般就是相鄰頂點的差向量了(其實這有時候是非常繁重的工作)。
如果是通常的3DS模型的話,頂點法線是共頂點的面的面法線的加權,這樣法線就不一定垂直于某個面,即與切線不垂直。但只要它們還是近似垂直的,上篇提及的Gram-Schmidt 算法應該可以處理。或者在shader中,把法線與切線叉乘出副法線,再用法線與副法線叉乘得新的切線,也能確保兩兩垂直。這樣之前的TBN矩陣的轉(zhuǎn)置矩陣就能直接作為其逆矩陣,完成向量從模型坐標系往切線空間坐標系的變換了。
問題不只這樣。對于一些模型,共享頂點的三角面片面法線差角太大,這時候計算出的該頂點法線和切線就可能帶來麻煩。在橙書(OpenGL Shading Language)中,談及了切線必須是一致的(consistently),面片相鄰的頂點切線不應該差距太大。但若相鄰面片夾角太大,得到的該頂點法線就可能與“共享該頂點的面片”上的其他頂點的法線差異很大,從而切線也會相差很大,直接導致光向量等在這兩頂點的切線空間差異很大,插值的各個針對像素的光向量方向差異很大,與像素法線點乘的cos也會差異得很明顯(而現(xiàn)實中一般的凹凸面漫反射光線不會有太大方向差異)。解決方法是把該出了問題的頂點拆成兩個(原地拷貝,3DS模型就不用了- -),一個面片用一個,其法線只受所屬的面片的面法線決定(這樣最后會形成突出的邊緣,但夾角大的面片之間實際上就應該會是有這樣的效果吧)。
另一個問題,我們向shader傳入頂點法線切線,希望副法線由兩者叉乘得出。但既然叉乘就有個方向問題(結果可以有兩個方向,AXB與BXA是不一樣的,我以前弄shadow volume就曾被它這種特性作弄過)。AXB改成BXA實際上會導致凹凸感反向,原來凹的變凸了,原來凸的變凹了(要仔細比對,不然會有首因效應)。一般就用N X T吧,因為基本上都是這個順序的,結果也符合原Normal Map。
2. GLSL 1.2 Shader實現(xiàn)代碼
沒什么好說的,就是前面算法翻譯成GLSL。
Vertex Shader:
 
// vertex shader
uniform vec3 lightpos; //傳入光源的模型坐標吧
uniform vec4 eyepos;
 
varying vec3 lightdir;
varying vec3 halfvec;
varying vec3 norm;
varying vec3 eyedir;
 
attribute vec3 rm_Tangent;
 
void main(void)
{
   vec4 pos = gl_ModelViewMatrix * gl_Vertex;
   pos = pos / pos.w;
   
//把光源和眼睛從模型空間轉(zhuǎn)換到視圖空間
   vec4 vlightPos = (gl_ModelViewMatrix * vec4(lightpos, 1.0));
   vec4 veyePos   = (gl_ModelViewMatrix * eyepos);
   
   lightdir = normalize(vlightPos.xyz - pos.xyz);
   vec3 eyedir = normalize(veyePos.xyz - pos.xyz);
   
  //模型空間下的TBN
   norm = normalize(gl_NormalMatrix * gl_Normal);
 
   vec3 vtangent  = normalize(gl_NormalMatrix * rm_Tangent);
 
   vec3 vbinormal = cross(norm,vtangent);
   
   //將光源向量和視線向量轉(zhuǎn)換到TBN切線空間
   lightdir.x = dot(vtangent,  lightdir);
   lightdir.y = dot(vbinormal, lightdir); 
   lightdir.z = dot(norm     , lightdir);
   lightdir = normalize(lightdir);
   
   eyedir.x = dot(vtangent,  eyedir);
   eyedir.y = dot(vbinormal, eyedir);
   eyedir.z = dot(norm     , eyedir);
   eyedir = normalize(eyedir);
   
   halfvec = normalize(lightdir + eyedir);
 
   gl_FrontColor = gl_Color;
   
   gl_TexCoord[0] = gl_MultiTexCoord0;
   
   gl_Position = ftransform();
}
// vertex shaderuniform vec3 lightpos; //傳入光源的模型坐標吧uniform vec4 eyepos;varying vec3 lightdir;varying vec3 halfvec;varying vec3 norm;varying vec3 eyedir;attribute vec3 rm_Tangent;void main(void){   vec4 pos = gl_ModelViewMatrix * gl_Vertex;   pos = pos / pos.w;   //把光源和眼睛從模型空間轉(zhuǎn)換到視圖空間   vec4 vlightPos = (gl_ModelViewMatrix * vec4(lightpos, 1.0));   vec4 veyePos   = (gl_ModelViewMatrix * eyepos);      lightdir = normalize(vlightPos.xyz - pos.xyz);   vec3 eyedir = normalize(veyePos.xyz - pos.xyz);     //模型空間下的TBN   norm = normalize(gl_NormalMatrix * gl_Normal);   vec3 vtangent  = normalize(gl_NormalMatrix * rm_Tangent);   vec3 vbinormal = cross(norm,vtangent);      //將光源向量和視線向量轉(zhuǎn)換到TBN切線空間   lightdir.x = dot(vtangent,  lightdir);   lightdir.y = dot(vbinormal, lightdir);    lightdir.z = dot(norm     , lightdir);   lightdir = normalize(lightdir);      eyedir.x = dot(vtangent,  eyedir);   eyedir.y = dot(vbinormal, eyedir);   eyedir.z = dot(norm     , eyedir);   eyedir = normalize(eyedir);      halfvec = normalize(lightdir + eyedir);   gl_FrontColor = gl_Color;      gl_TexCoord[0] = gl_MultiTexCoord0;      gl_Position = ftransform();}
傳入的lightPos,eyePos,gl_Vertex,gl_Normal,rm_Tangent是其模型坐標系下的坐標、向量,乘以ModelView矩陣(法線切線乘以ModelView矩陣的轉(zhuǎn)置逆矩陣)到了視圖空間(vlightPos,veyePos,pos,norm, vtangent);在視圖空間它們已經(jīng)有了“世界”的概念了,因此可以平等地相互影響(在各自封閉的模型空間是享受不了的),可以作各種點乘叉乘加減乘除計算。
注意,lightPos,eyePos雖說是在其各自模型坐標系下定義的,但不對它們弄什么平移旋轉(zhuǎn)縮放操作的話,其模型矩陣就是一單位陣,此時其“世界坐標 == 模型坐標”。所以這時我可以當它是在世界空間定義的坐標(實際上一般我們都會在世界空間定義這兩個點)。(注意,前提是不對它們做模型變換。)
從以上量得到光源向量、視線向量后(它們在視圖空間),N、T叉乘得B(注意它們現(xiàn)在都在視圖空間),通過TBN矩陣逆矩陣把兩向量變換到當前頂點的切線空間,交給光柵去插值。
對以上有不理解的朋友,可能是沒看上篇:[shader復習與深入:Normal Map(法線貼圖)Ⅰ]
fragment shader:
 
//fragment shader
uniform float shiness;
uniform vec4 ambient, diffuse, specular;
 
uniform sampler2D bumptex;
uniform sampler2D basetex;
 
float amb = 0.2;
float diff = 0.2;
float spec = 0.6;
 
varying vec3 lightdir;
varying vec3 halfvec;
varying vec3 norm;
varying vec3 eyedir;
 
void main(void)
{
   vec3 vlightdir = normalize(lightdir);
   vec3 veyedir = normalize(eyedir);
 
   vec3 vnorm =   normalize(norm);
   vec3 vhalfvec =  normalize(halfvec);  
   
   vec4 baseCol = texture2D(basetex, gl_TexCoord[0].xy); 
   
   //Normal Map里的像素normal定義于該像素的切線空間
   vec3 tbnnorm = texture2D(bumptex, gl_TexCoord[0].xy).xyz;
   
   tbnnorm = normalize((tbnnorm  - vec3(0.5))* 2.0); 
   
   float diffusefract =  max( dot(lightdir,tbnnorm) , 0.0); 
   float specularfract = max( dot(vhalfvec,tbnnorm) , 0.0);
   
   if(specularfract > 0.0){
   specularfract = pow(specularfract, shiness);
   }
   
   gl_FragColor = vec4(amb * ambient.xyz * baseCol.xyz
                 + diff * diffuse.xyz * diffusefract * baseCol.xyz
                 + spec * specular.xyz * specularfract ,1.0);
}
//fragment shaderuniform float shiness;uniform vec4 ambient, diffuse, specular;uniform sampler2D bumptex;uniform sampler2D basetex;float amb = 0.2;float diff = 0.2;float spec = 0.6;varying vec3 lightdir;varying vec3 halfvec;varying vec3 norm;varying vec3 eyedir;void main(void){   vec3 vlightdir = normalize(lightdir);   vec3 veyedir = normalize(eyedir);   vec3 vnorm =   normalize(norm);   vec3 vhalfvec =  normalize(halfvec);        vec4 baseCol = texture2D(basetex, gl_TexCoord[0].xy);       //Normal Map里的像素normal定義于該像素的切線空間   vec3 tbnnorm = texture2D(bumptex, gl_TexCoord[0].xy).xyz;      tbnnorm = normalize((tbnnorm  - vec3(0.5))* 2.0);       float diffusefract =  max( dot(lightdir,tbnnorm) , 0.0);    float specularfract = max( dot(vhalfvec,tbnnorm) , 0.0);      if(specularfract > 0.0){   specularfract = pow(specularfract, shiness);   }      gl_FragColor = vec4(amb * ambient.xyz * baseCol.xyz                 + diff * diffuse.xyz * diffusefract * baseCol.xyz                 + spec * specular.xyz * specularfract ,1.0);}
注意把normal map里的normal由(0,1)映射回(-1,1)。baseCol得到的是基底紋理的像素顏色。其余部分就是per pixel lighting的東西了。[Shader快速復習:Per Pixel Lighting(逐像素光照)]

(上為底紋理和法線紋理,下為它們與某破壁模型合作的效果,紋理from planetpixelemporium.com)
 

(我想是游戲最常用的用途:磚墻。我想是最常用的NormalMap,from NEHE)


(自己把墻壁BaseMap放入Photoshop的normalMapFilter里弄的NormalMap,呃.....)

本文來源于ZwqXin http://www.zwqxin.com/ , 轉(zhuǎn)載請注明
原文地址:http://www.zwqxin.com/archives/shaderglsl/review-normal-map-bump-map-2.html


 

posted on 2010-11-29 17:58 狂爛球 閱讀(2399) 評論(0)  編輯 收藏 引用 所屬分類: 圖形編程

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜精品在线| 亚洲激情小视频| 欧美在线不卡| 性欧美videos另类喷潮| 亚洲自拍电影| 99国产一区| 亚洲激情校园春色| 亚洲美女91| 中文欧美在线视频| 久久精品国产综合精品| 欧美亚洲综合在线| 久久综合狠狠综合久久激情| 久久米奇亚洲| 亚洲精品网站在线播放gif| 91久久黄色| 亚洲日本视频| 欧美在线91| 欧美日韩性生活视频| 国产日韩亚洲欧美| 另类av导航| 欧美一级大片在线观看| 欧美一级成年大片在线观看| 亚洲精品日本| 亚洲欧洲另类国产综合| 亚洲视频一区二区在线观看| 日韩视频一区二区在线观看 | 午夜免费电影一区在线观看| 亚洲婷婷综合久久一本伊一区| 午夜电影亚洲| 免费欧美在线视频| 国产免费一区二区三区香蕉精| 国产在线精品二区| 亚洲人成网站999久久久综合| 亚洲国产精品小视频| 一区二区三区蜜桃网| 久久精品视频va| 亚洲大胆av| 亚洲视频一区二区在线观看| 欧美在线免费视频| 欧美电影免费观看大全| 国产三区精品| 一本一本大道香蕉久在线精品| 国产亚洲午夜| 亚洲精品一二| 午夜影视日本亚洲欧洲精品| 亚洲第一天堂无码专区| 翔田千里一区二区| 欧美人与禽性xxxxx杂性| 极品尤物一区二区三区| 欧美在线亚洲| 亚洲一区二区精品在线观看| 欧美激情影院| 91久久国产综合久久蜜月精品| 亚洲综合视频一区| 日韩视频在线观看免费| 欧美大片免费久久精品三p| 国产一区二区精品久久99| 亚洲一二三区视频在线观看| 亚洲高清免费| 美女精品一区| 在线免费日韩片| 久久一综合视频| 亚洲欧美日韩在线不卡| 国产精品久久久久久久久借妻 | 乱码第一页成人| 久久精品导航| 国产精品日韩精品| 亚洲综合精品| 亚洲综合不卡| 国产伦精品一区二区三区免费迷 | 欧美aⅴ一区二区三区视频| 午夜精品在线| 韩国av一区二区三区在线观看| 欧美在线观看一区| 午夜精品久久久久久久99热浪潮 | 美脚丝袜一区二区三区在线观看| 午夜精彩国产免费不卡不顿大片| 国产精品视频精品视频| 性娇小13――14欧美| 亚洲综合日本| 黄色工厂这里只有精品| 欧美国产日韩免费| 欧美日韩一区二区三区在线看| 亚洲一区久久久| 欧美在线不卡| 久久日韩粉嫩一区二区三区| 91久久久久久久久| 一区二区免费在线视频| 国产视频精品免费播放| 免费日本视频一区| 欧美日本一区二区视频在线观看 | 久久九九国产精品| 免费久久99精品国产自在现线 | 久久久欧美精品sm网站| 久久久久久综合网天天| 日韩亚洲精品视频| 亚洲免费网站| 曰韩精品一区二区| 99这里只有精品| 激情一区二区| 亚洲一区中文| 亚洲美女91| 欧美一区深夜视频| 在线一区欧美| 久久久av网站| 欧美一区成人| 欧美国产日韩精品| 久久亚洲综合色一区二区三区| 欧美日韩福利| 欧美成人一区二免费视频软件| 欧美午夜视频在线观看| 欧美国产日本在线| 黄色亚洲精品| 亚洲欧美综合v| 亚洲视频播放| 欧美激情一区二区| 欧美国产在线视频| 正在播放亚洲| 一片黄亚洲嫩模| 亚洲国产精品成人久久综合一区| 亚洲一区www| 一区二区三区四区五区精品| 久久天天躁狠狠躁夜夜爽蜜月| 香蕉亚洲视频| 国产精品美女久久久久aⅴ国产馆| 亚洲第一黄网| 亚洲国产精品va在线看黑人动漫 | 欧美另类视频在线| 欧美搞黄网站| 在线看国产一区| 久久精品视频在线播放| 久久激情婷婷| 国产欧美精品一区二区色综合| 亚洲精品美女在线观看播放| 亚洲国产成人porn| 麻豆精品在线视频| 亚洲二区三区四区| 亚洲精品久久久久久久久久久久久| 欧美尤物一区| 久久最新视频| 亚洲韩日在线| 欧美韩日视频| 一区二区三区高清在线观看| 亚洲一线二线三线久久久| 欧美亚洲成人网| 亚洲欧美激情一区二区| 久久激情久久| 伊人色综合久久天天| 久久久久久伊人| 久久婷婷影院| 亚洲国产一区二区三区a毛片| 免费观看国产成人| 欧美大片91| 一本久道久久综合婷婷鲸鱼| 欧美日韩在线播放| 亚洲桃色在线一区| 久久精品欧洲| 亚洲第一偷拍| 欧美日韩国产成人在线观看| 亚洲精品美女久久7777777| 亚洲在线观看| 国产又爽又黄的激情精品视频 | 在线视频欧美一区| 欧美一级视频精品观看| 国产婷婷97碰碰久久人人蜜臀| 欧美一区二区三区免费视| 久久久国产精品一区二区中文| 伊人色综合久久天天| 欧美激情aⅴ一区二区三区| 中文欧美日韩| 嫩草国产精品入口| 亚洲在线一区二区| 国产一区二区精品久久| 久久午夜精品| 亚洲在线1234| 亚洲第一成人在线| 欧美一区二区福利在线| 在线高清一区| 欧美日韩在线一区| 久久成人av少妇免费| 亚洲欧洲日夜超级视频| 久久精品国产第一区二区三区最新章节 | 亚洲欧美日韩在线观看a三区| 欧美午夜三级| 欧美与欧洲交xxxx免费观看| 欧美国产日韩一区二区三区| 亚洲欧美久久久久一区二区三区| 一区在线免费| 国产裸体写真av一区二区| 欧美巨乳在线| 玖玖国产精品视频| 香蕉久久国产| 亚洲自拍偷拍网址| 一区二区三区日韩| 亚洲欧洲日产国产综合网| 麻豆av一区二区三区久久| 午夜在线精品| 亚洲一区二区三区免费视频| 亚洲日本电影| 亚洲国产另类久久久精品极度|