關(guān)于光照模型的總結(jié)嚷兔,我就不一一細(xì)談了,一是自己記不住那么多做入,二呢冒晰,我覺得知識(shí)還是要實(shí)踐為主。所以以下的東西主要針對(duì)編程而言的竟块,不會(huì)涉及很綜合深刻的講解壶运。照例最后可以猛戳下載代碼。
1.漫反射
漫反射光大概就是從光源照射到物體表面浪秘,不考慮人的觀察視角與反射的角度形成的光源強(qiáng)弱差別蒋情,而只考慮光源入射角和頂點(diǎn)法線的夾角埠况,在各個(gè)方向上均等的反射光線的一種光。
假設(shè)Ld表示光源強(qiáng)度棵癣,Kd表示某個(gè)物體的反射系數(shù)辕翰,那么漫反射公式就是
Ia = Ld * Kd * cos(b)
如下圖
漫反射
那么s和n的點(diǎn)乘就表示夾角的cos了(有疑惑的翻翻幾何課本),于是就有公式如下
漫反射公式
有了這個(gè)公式狈谊,我們愉快的開始寫代碼吧喜命!
attribute vec3 vertPosition; // Vertex position
attribute vec3 vertNorm; // Vertex normal
varying vec3 lightIntensity; // Light intensity
uniform vec3 lightPosition; // Light position in eye - coordinate
uniform vec3 Kd; // Reflect of diffuse light
uniform vec3 Ld; // Intensity of light
uniform mat3 normMat; // matrix of normal
uniform mat4 modelview; // matrix of modelview
uniform mat4 projection; // matrix of projection
void main() {
// Convert normal and position to eye coord
vec3 tnorm = normalize(normMat * vertNorm);
vec3 eyecoord = vec3(modelview * vec4(vertPosition, 1.0));
vec3 s = normalize(lightPosition - eyecoord);
// The diffuse shading equation
lightIntensity = Ld * Kd * max(dot(s, tnorm), 0.0);
gl_Position = projection * modelview * vec4(vertPosition, 1.0);
}
接下來,說代碼吧河劝。
前兩行的attribute變量用于定義頂點(diǎn)坐標(biāo)和頂點(diǎn)法線壁榕,也就是我們屆時(shí)要輸入的值。這里一定要注意赎瞎,這個(gè)shader文件里的處理流程是逐頂點(diǎn)的护桦,就是每次處理一個(gè)頂點(diǎn)變換。
然后定義一個(gè)varying輸出變量煎娇,一會(huì)兒在fragment shader中要用到的二庵。
之后是光源坐標(biāo)Position,這里已經(jīng)轉(zhuǎn)換為觀察坐標(biāo)了缓呛,你也可以在shader里面轉(zhuǎn)換催享。然后就是光照強(qiáng)度La,反射系數(shù)Kd哟绊。
接著定義了法線變換矩陣因妙。這個(gè)東西簡(jiǎn)單講一下。
我扣的圖
類似于圖中的法線票髓,在圖被拉伸(還有旋轉(zhuǎn)什么的攀涵,法線要跟著頂點(diǎn)動(dòng)才對(duì))了之后,法線的方向就錯(cuò)了洽沟,因此需要法線矩陣來變換一下以故。法線矩陣的推導(dǎo)公式就不列出來了,線性代數(shù)我還在復(fù)習(xí)裆操,也講不太好怒详,網(wǎng)上有不少資料,能看懂就好了踪区。剛體變換就用觀察矩陣modelview的左上角3x3就可以了昆烁。
然后定義了觀察變換矩陣和投影變換矩陣。
然后缎岗,雞凍人心的時(shí)刻就到了静尼。
首先我們用法線矩陣變換頂點(diǎn)法向量,觀察矩陣變換頂點(diǎn)坐標(biāo)
vec3 tnorm = normalize(normMat * vertNorm);
vec3 eyecoord = vec3(modelview * vec4(vertPosition, 1.0));
然后計(jì)算指向光源坐標(biāo)的向量,并且歸一化
vec3 s = normalize(lightPosition - eyecoord);
接著鼠渺,就要用到我們上面的公式了
lightIntensity = Ld * Kd * max(dot(s, tnorm), 0.0);
這個(gè)lightIntensity一會(huì)兒就是我們計(jì)算出來的頂點(diǎn)顏色蜗元。
接下來,使用gl_Position輸出最終經(jīng)過觀察->投影變換后的頂點(diǎn)坐標(biāo)
gl_Position = projection * modelview * vec4(vertPosition, 1.0);
至此系冗,頂點(diǎn)shader的工作就完成了奕扣。
然后開始處理片段shader了。
上代碼
precision mediump float;
varying vec3 lightIntensity;
void main() {
gl_FragColor = vec4(lightIntensity, 1.0);
}
其中定義的varying vec3 lightIntensity就是我們?cè)趘ertex shader中計(jì)算出來的光照后的頂點(diǎn)顏色值掌敬。最終賦值給gl_FragColor惯豆,就是頂點(diǎn)的最后顏色了。
然后讓程序跑起來奔害,最終結(jié)果如下
渲染結(jié)果
另外代碼中的ToyMater/ToyTest目錄下是測(cè)試用的楷兽,可以很方便的修修改改的來測(cè)試。