光照-02.光照基礎(chǔ)

現(xiàn)實世界的光照是極其復(fù)雜的幕庐,而且會受到諸多因素的影響熔吗,這是以目前我們所擁有的處理能力無法模擬的姆钉。因此OpenGL的光照僅僅使用了簡化的模型并基于對現(xiàn)實的估計來進(jìn)行模擬,這樣處理起來會更容易一些听诸,而且看起來也差不多一樣坐求。這些光照模型都是基于我們對光的物理特性的理解。其中一個模型被稱為馮氏光照模型(Phong Lighting Model)晌梨。馮氏光照模型的主要結(jié)構(gòu)由3個元素組成:環(huán)境(Ambient)桥嗤、漫反射(Diffuse)和鏡面(Specular)光照须妻。這些光照元素看起來像下面這樣:

  • 環(huán)境光照(Ambient Lighting):即使在黑暗的情況下,世界上也仍然有一些光亮(月亮泛领、一個來自遠(yuǎn)處的光)荒吏,所以物體永遠(yuǎn)不會是完全黑暗的。我們使用環(huán)境光照來模擬這種情況渊鞋,也就是無論如何永遠(yuǎn)都給物體一些顏色绰更。
  • 漫反射光照(Diffuse Lighting):模擬一個發(fā)光物對物體的方向性影響(Directional Impact)。它是馮氏光照模型最顯著的組成部分锡宋。面向光源的一面比其他面會更亮儡湾。
  • 鏡面光照(Specular Lighting):模擬有光澤物體上面出現(xiàn)的亮點。鏡面光照的顏色执俩,相比于物體的顏色更傾向于光的顏色徐钠。

為了創(chuàng)建有趣的視覺場景堰酿,我們希望模擬至少這三種光照元素抵蚊。我們將以最簡單的一個開始:環(huán)境光照

環(huán)境光照(Ambient Lighting)

光通常都不是來自于同一光源,而是來自散落于我們周圍的很多光源宋税,即使它們可能并不是那么顯而易見。光的一個屬性是讼油,它可以向很多方向發(fā)散和反彈杰赛,所以光最后到達(dá)的地點可能并不是它所臨近的直射方向;光能夠像這樣反射(Reflect)到其他表面矮台,一個物體的光照可能受到來自一個非直射的光源影響乏屯。考慮到這種情況的算法叫做全局照明(Global Illumination)算法瘦赫,但是這種算法既開銷高昂又極其復(fù)雜辰晕。

因為我們不是復(fù)雜和昂貴算法的死忠粉絲,所以我們將會使用一種簡化的全局照明模型确虱,叫做環(huán)境光照含友。如你在前面章節(jié)所見,我們使用一個(數(shù)值)很小的常量(光)顏色添加進(jìn)物體片段(Fragment校辩,指當(dāng)前討論的光線在物體上的照射點)的最終顏色里窘问,這看起來就像即使沒有直射光源也始終存在著一些發(fā)散的光。

把環(huán)境光添加到場景里非常簡單宜咒。我們用光的顏色乘以一個(數(shù)值)很小常量環(huán)境因子惠赫,再乘以物體的顏色,然后使用它作為片段的顏色:

#version 330 core
out vec4 color;

uniform vec3 objectColor;
uniform vec3 lightColor;

void main ()
{
    float ambientStrength = 0.1f;
    vec3 ambient = ambientStrength * lightColor;
    vec3 result = ambient * objectColor;
    color = vec4(result, 1.0f);
}

如果你現(xiàn)在運行你的程序故黑,你會注意到馮氏光照的第一個階段已經(jīng)應(yīng)用到你的物體上了儿咱。這個物體非常暗庭砍,但不是完全的黑暗,因為我們應(yīng)用了環(huán)境光照(注意發(fā)光立方體沒被環(huán)境光照影響是因為我們對它使用了另一個著色器)混埠。它看起來應(yīng)該像這樣:

Image 059.png

漫反射光照(Diffuse Lighting)

環(huán)境光本身不提供最明顯的光照效果逗威,但是漫反射光照會對物體產(chǎn)生顯著的視覺影響。漫反射光使物體上與光線排布越近的片段越能從光源處獲得更多的亮度岔冀。為了更好的理解漫反射光照凯旭,請看下圖:

圖左上方有一個光源,它所發(fā)出的光線落在物體的一個片段上使套。我們需要測量這個光線與它所接觸片段之間的角度罐呼。如果光線垂直于物體表面,這束光對物體的影響會最大化(譯注:更亮)侦高。為了測量光線和片段的角度嫉柴,我們使用一個叫做法向量(Normal Vector)的東西,它是垂直于片段表面的一種向量(這里以黃色箭頭表示)奉呛,我們在后面再講這個東西计螺。兩個向量之間的角度就能夠根據(jù)點乘計算出來。

我們知道兩個單位向量的角度越小瞧壮,它們點乘的結(jié)果越傾向于1登馒。當(dāng)兩個向量的角度是90度的時候,點乘會變?yōu)?咆槽。這同樣適用于θ陈轿,θ越大,光對片段顏色的影響越小秦忿。

注意麦射,我們使用的是單位向量(Unit Vector,長度是1的向量)取得兩個向量夾角的余弦值灯谣,所以我們需要確保所有的向量都被標(biāo)準(zhǔn)化潜秋,否則點乘返回的值就不僅僅是余弦值了。

點乘返回一個標(biāo)量胎许,我們可以用它計算光線對片段顏色的影響峻呛,基于不同片段所朝向光源的方向的不同,這些片段被照亮的情況也不同呐萨。

所以杀饵,我們需要些什么來計算漫反射光照?

  • 法向量:一個垂直于頂點表面的向量谬擦。
  • 定向的光線:作為光的位置和片段的位置之間的向量差的方向向量切距。為了計算這個光線,我們需要光的位置向量和片段的位置向量惨远。

法向量(Normal Vector)

法向量是垂直于頂點表面的(單位)向量谜悟。由于頂點自身并沒有表面(它只是空間中一個獨立的點)话肖,我們利用頂點周圍的頂點計算出這個頂點的表面。我們能夠使用叉乘這個技巧為立方體所有的頂點計算出法線葡幸,但是由于3D立方體不是一個復(fù)雜的形狀最筒,所以我們可以簡單的把法線數(shù)據(jù)手工添加到頂點數(shù)據(jù)中。更新的頂點數(shù)據(jù)數(shù)組可以在這里找到蔚叨。試著去想象一下床蜘,這些法向量真的是垂直于立方體的各個面的表面的(一個立方體由6個面組成)。

因為我們向頂點數(shù)組添加了額外的數(shù)據(jù)蔑水,所以我們應(yīng)該更新光照的頂點著色器:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
...

現(xiàn)在我們已經(jīng)向每個頂點添加了一個法向量邢锯,已經(jīng)更新了頂點著色器,我們還要更新頂點屬性指針(Vertex Attibute Pointer)搀别。*

注意*丹擎,發(fā)光物使用同樣的頂點數(shù)組作為它的頂點數(shù)據(jù),然而發(fā)光物的著色器沒有使用新添加的法向量歇父。我們不會更新發(fā)光物的著色器或者屬性配置蒂培,但是我們必須至少修改一下頂點屬性指針來適應(yīng)新的頂點數(shù)組的大小。

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid * )0);
glEnableVertexAttribArray(0);

我們只想使用每個頂點的前三個浮點數(shù)榜苫,并且我們忽略后三個浮點數(shù)护戳,所以我們只需要把步長參數(shù)改成GLfloat尺寸的6倍就行了

光物著色器頂點數(shù)據(jù)的不完全使用看起來有點低效,但是這些頂點數(shù)據(jù)已經(jīng)從立方體對象載入到GPU的內(nèi)存里了单刁,所以GPU內(nèi)存不需要再儲存新數(shù)據(jù)灸异。相對于重新給發(fā)光物分配VBO,實際上卻是更高效了羔飞。

所有光照的計算需要在片段著色器里進(jìn)行,所以我們需要把法向量由頂點著色器傳遞到片段著色器檐春。我們這么做:

out vec3 Normal;

void main ()
{
    gl_Position = projection * view * model * vec4(position, 1.0);
    Normal = normal;
} 

剩下要做的事情是逻淌,在片段著色器中定義相應(yīng)的輸入值:

in vec3 Normal;

計算漫反射光照

每個頂點現(xiàn)在都有了法向量,但是我們?nèi)匀恍枰獾奈恢孟蛄亢推蔚奈恢孟蛄颗迸S捎诠獾奈恢檬且粋€靜態(tài)變量卡儒,我們可以簡單的在片段著色器中把它聲明為uniform:

uniform vec3 lightPos;

然后再游戲循環(huán)中(外面也可以,因為它不會變)更新uniform俐巴。我們使用在前面教程中聲明的lightPos向量作為光源位置:

        GLint lightPosLoc = glGetUniformLocation (lightingShader.Program, "lightPos");
        glUniform3f (lightPosLoc, lightPos.x, lightPos.y, lightPos.z);      // 向lighting.frag傳入光源位置
    

最后骨望,我們還需要片段的位置(Position)。我們會在世界空間中進(jìn)行所有的光照計算欣舵,因此我們需要一個在世界空間中的頂點位置擎鸠。我們可以通過把頂點位置屬性乘以模型矩陣(Model Matrix,只用模型矩陣不需要用觀察和投影矩陣)來把它變換到世界空間坐標(biāo)。這個在頂點著色器中很容易完成缘圈,所以讓我們就聲明一個輸出(out)變量劣光,然后計算它的世界空間坐標(biāo):

out vec3 FragPos;   // 片段的位置
out vec3 Normal;

void main ()
{
    gl_Position = projection * view * model * vec4(position, 1.0);
    Normal = normal;
    FragPos = vec3(model * vec4(position, 1.0f));       // 通過把頂點位置屬性乘以模型矩陣得到世界空間中的頂點位置袜蚕,即片段的位置
} 

最后,在片段著色器中添加相應(yīng)的輸入變量绢涡。

in vec3 FragPos;

現(xiàn)在牲剃,所有需要的變量都設(shè)置好了,我們可以在片段著色器中開始光照的計算了雄可。

我們需要做的第一件事是計算光源和片段位置之間的方向向量凿傅。我們同樣希望確保所有相關(guān)向量最后都轉(zhuǎn)換為單位向量,所以我們把法線和方向向量這個結(jié)果都進(jìn)行標(biāo)準(zhǔn)化:

vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);

當(dāng)計算光照時我們通常不關(guān)心一個向量的“量”或它的位置数苫,我們只關(guān)心它們的方向狭归。所有的計算都使用單位向量完成,因為這會簡化了大多數(shù)計算(比如點乘)文判。所以當(dāng)進(jìn)行光照計算時过椎,確保你總是對相關(guān)向量進(jìn)行標(biāo)準(zhǔn)化,這樣它們才會保證自身為單位向量戏仓。忘記對向量進(jìn)行標(biāo)準(zhǔn)化是一個十分常見的錯誤疚宇。

下一步,我們對norm和lightDir向量進(jìn)行點乘赏殃,來計算光對當(dāng)前片段的實際的散射影響敷待。結(jié)果值再乘以光的顏色,得到散射因子仁热。兩個向量之間的角度越大榜揖,散射因子就會越小:

    float diff = max(dot(norm, lightDir), 0.0);         // 點乘
    vec3 diffuse = diff * lightColor;

如果兩個向量之間的角度大于90度抗蠢,點乘的結(jié)果就會變成負(fù)數(shù)举哟,這樣會導(dǎo)致散射因子變?yōu)樨?fù)數(shù)。為此迅矛,我們使用max函數(shù)返回兩個參數(shù)之間較大的參數(shù)妨猩,從而保證散射因子不會變成負(fù)數(shù)。負(fù)數(shù)的顏色是沒有實際定義的秽褒,所以最好避免它壶硅,除非你是那種古怪的藝術(shù)家。

既然我們有了一個環(huán)境光照顏色和一個散射光顏色销斟,我們把它們相加庐椒,然后把結(jié)果乘以物體的顏色,來獲得片段最后的輸出顏色蚂踊。

    vec3 result = (ambient + diffuse) * objectColor;
    color = vec4(result, 1.0f);

如果你的應(yīng)用(和著色器)編譯成功了约谈,你可能看到類似的輸出:

你可以看到使用了散射光照,立方體看起來就真的像個立方體了。嘗試在你的腦中想象窗宇,通過移動正方體措伐,法向量和光的方向向量之間的夾角增大,片段變得更暗军俊。

如果你遇到很多困難侥加,可以對比完整的項目代碼

最后一件事

現(xiàn)在我們已經(jīng)把法向量從頂點著色器傳到了片段著色器粪躬〉0埽可是,目前片段著色器里镰官,我們都是在世界空間坐標(biāo)中進(jìn)行計算的提前,所以,我們不是應(yīng)該把法向量轉(zhuǎn)換為世界空間坐標(biāo)嗎泳唠?基本正確狈网,但是這不是簡單地把它乘以一個模型矩陣就能搞定的。

首先笨腥,法向量只是一個方向向量拓哺,不能表達(dá)空間中的特定位置。同時脖母,法向量沒有齊次坐標(biāo)(頂點位置中的w分量)士鸥。這意味著,對于法向量谆级,我們只能對它應(yīng)用縮放(Scale)和旋轉(zhuǎn)(Rotation)變換烤礁。

因此,如果我們打算把法向量乘以一個模型矩陣肥照,我們就要取模型矩陣左上角的3×3矩陣脚仔,其余部分是模型矩陣的平移部分,舍棄之建峭。(注意玻侥,我們也可以把法向量的w分量設(shè)置為0,再乘以4×4矩陣亿蒸;同樣可以移除平移)。

其次掌桩,如果模型矩陣執(zhí)行了不等比縮放边锁,法向量就不再垂直于表面了,頂點就會以這種方式被改變了波岛。因此茅坛,我們不能用這樣的模型矩陣去乘以法向量。下面的圖展示了應(yīng)用了不等比縮放的矩陣對法向量的影響:

無論何時當(dāng)我們提交一個不等比縮放(注意:等比縮放不會破壞法線,因為法線的方向沒被改變贡蓖,而法線的長度很容易通過標(biāo)準(zhǔn)化進(jìn)行修復(fù))曹鸠,法向量就不會再垂直于它們的表面了,這樣光照會被扭曲斥铺。

修復(fù)這個行為的訣竅是使用另一個為法向量專門定制的模型矩陣彻桃。這個矩陣稱之為正規(guī)矩陣(Normal Matrix),它是進(jìn)行了一點線性代數(shù)操作移除了對法向量的錯誤縮放效果晾蜘。如果你想知道這個矩陣是如何計算出來的邻眷,我建議看這個文章

正規(guī)矩陣被定義為“模型矩陣左上角的逆矩陣的轉(zhuǎn)置矩陣”剔交。真拗口肆饶,如果你不明白這是什么意思,別擔(dān)心岖常;我們還沒有討論逆矩陣(Inverse Matrix)和轉(zhuǎn)置矩陣(Transpose Matrix)驯镊。注意,定義正規(guī)矩陣的大多資源就像應(yīng)用到模型觀察矩陣(Model-view Matrix)上的操作一樣竭鞍,但是由于我們只在世界空間工作(而不是在觀察空間)板惑,我們只使用模型矩陣。

在頂點著色器中笼蛛,我們可以使用inverse和transpose函數(shù)自己生成正規(guī)矩陣洒放,inverse和transpose函數(shù)對所有類型矩陣都有效。注意滨砍,我們也要把這個被處理過的矩陣強(qiáng)制轉(zhuǎn)換為3×3矩陣往湿,這是為了保證它失去了平移屬性,之后它才能乘以法向量惋戏。

Normal = mat3(transpose(inverse(model))) * normal;

在環(huán)境光照部分领追,光照表現(xiàn)沒問題,這是因為我們沒有對物體本身執(zhí)行任何縮放操作响逢,因而不是非得使用正規(guī)矩陣不可绒窑,用模型矩陣乘以法線也沒錯√蛲ぃ可是些膨,如果你進(jìn)行了不等比縮放,使用正規(guī)矩陣去乘以法向量就是必不可少的了钦铺。

對于著色器來說订雾,逆矩陣也是一種開銷比較大的操作,因此矛洞,無論何時洼哎,在著色器中只要可能就應(yīng)該盡量避免逆操作,因為它們必須為你場景中的每個頂點進(jìn)行這樣的處理。以學(xué)習(xí)的目的這樣做很好噩峦,但是對于一個對于效率有要求的應(yīng)用來說锭沟,在繪制之前,你最好用CPU計算出正規(guī)矩陣识补,然后通過uniform把值傳遞給著色器(和模型矩陣一樣)族淮。

鏡面光照(Specular Lighting)

和環(huán)境光照一樣,鏡面光照同樣依據(jù)光的方向向量和物體的法向量李请,但是這次它也會依據(jù)觀察方向瞧筛,例如玩家是從什么方向看著這個片段的。鏡面光照根據(jù)光的反射特性导盅。如果我們想象物體表面像一面鏡子一樣较幌,那么,無論我們從哪里去看那個表面所反射的光白翻,鏡面光照都會達(dá)到最大化乍炉。你可以從下面的圖片看到效果:

我們通過反射法向量周圍光的方向計算反射向量。然后我們計算反射向量和視線方向的角度滤馍,如果之間的角度越小岛琼,那么鏡面光的作用就會越大。它的作用效果就是巢株,當(dāng)我們?nèi)タ垂獗晃矬w所反射的那個方向的時候槐瑞,我們會看到一個高光。

觀察向量(the view vector)是鏡面光照的一個附加變量阁苞,我們可以使用觀察者世界空間位置(Viewer’s World Space Position)和片段的位置來計算困檩。之后,我們計算鏡面光亮度那槽,用它乘以光的顏色悼沿,在用它加上作為之前計算的光照顏色。

我們選擇在世界空間(World Space)進(jìn)行光照計算骚灸,但是大多數(shù)人趨向于在觀察空間(View Space)進(jìn)行光照計算糟趾。在觀察空間計算的好處是,觀察者的位置總是(0, 0, 0)甚牲,所以這樣你直接就獲得了觀察者位置义郑。可是丈钙,我發(fā)現(xiàn)出于學(xué)習(xí)的目的魔慷,在世界空間計算光照更符合直覺。如果你仍然希望在視野空間計算光照的話著恩,那就使觀察矩陣應(yīng)用到所有相關(guān)的需要變換的向量(不要忘記,也要改變正規(guī)矩陣)。

為了得到觀察者的世界空間坐標(biāo)喉誊,我們簡單地使用攝像機(jī)對象的位置坐標(biāo)代替(它就是觀察者)邀摆。所以我們把另一個uniform添加到片段著色器,把相應(yīng)的攝像機(jī)位置坐標(biāo)傳給片段著色器:

uniform vec3 viewPos;

GLint viewPosLoc = glGetUniformLocation (lightingShader.Program, "viewPos");
glUniform3f (viewPosLoc, camera.Position.x, camera.Position.y, camera.Position.z);

現(xiàn)在我們已經(jīng)獲得所有需要的變量伍茄,可以計算鏡面光亮度了栋盹。

  • 首先,我們定義一個鏡面強(qiáng)度(Specular Intensity)變量specularStrength敷矫,給鏡面高光一個中等亮度顏色例获,這樣就不會產(chǎn)生過度的影響了。
float specularStrength = 0.5f;

如果我們把它設(shè)置為1.0f曹仗,我們會得到一個對于珊瑚色立方體來說過度明亮的鏡面亮度因子榨汤。下一節(jié)教程,我們會討論所有這些光照亮度的合理設(shè)置怎茫,以及它們是如何影響物體的收壕。

  • 下一步,我們計算視線方向坐標(biāo)轨蛤,和沿法線軸的對應(yīng)的反射坐標(biāo):
vec3 viewDir = normalize(viewPos - FragPos);    // 視線方向坐標(biāo)
vec3 reflectDir = reflect(-lightDir, norm);         // 使用reflect函數(shù)計算反射光坐標(biāo)

需要注意的是我們使用了lightDir向量的相反數(shù)蜜宪。reflect函數(shù)要求的第一個是從光源指向片段位置的向量,但是lightDir當(dāng)前是從片段指向光源的向量(由先前我們計算lightDir向量時祥山,(減數(shù)和被減數(shù))減法的順序決定)圃验。為了保證我們得到正確的reflect坐標(biāo),我們通過lightDir向量的相反數(shù)獲得它的方向的反向缝呕。第二個參數(shù)要求是一個法向量澳窑,所以我們提供的是已標(biāo)準(zhǔn)化的norm向量。

  • 剩下要做的是計算鏡面亮度分量岳颇。下面的代碼完成了這件事
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 speccular = specularStrength * spec * lightColor;

我們先計算視線方向與反射方向的點乘(確保它不是負(fù)值)照捡,然后得到它的32次冪。這個32是高光的發(fā)光值(Shininess)话侧。一個物體的發(fā)光值越高栗精,反射光的能力越強(qiáng),散射得越少瞻鹏,高光點越小悲立。在下面的圖片里,你會看到不同發(fā)光值對視覺(效果)的影響:

我們不希望鏡面成分過于顯眼新博,所以我們把指數(shù)設(shè)置為32薪夕。剩下的最后一件事情是把它添加到環(huán)境光顏色和散射光顏色里,然后再乘以物體顏色:

vec3 result = (ambient + diffuse + specular) * objectColor;
color = vec4(result, 1.0f);

我們現(xiàn)在為馮氏光照計算了全部的光照元素赫悄。根據(jù)你的觀察點原献,你可以看到類似下面的畫面:

你可以在這里找到完整源碼馏慨。

早期的光照著色器,開發(fā)者在頂點著色器中實現(xiàn)馮氏光照姑隅。在頂點著色器中做這件事的優(yōu)勢是写隶,相比片段來說,頂點要少得多讲仰,因此會更高效慕趴,所以(開銷大的)光照計算頻率會更低。然而鄙陡,頂點著色器中的顏色值是只是頂點的顏色值冕房,片段的顏色值是它與周圍的顏色值的插值。結(jié)果就是這種光照看起來不會非常真實趁矾,除非使用了大量頂點耙册。



在頂點著色器中實現(xiàn)的馮氏光照模型叫做Gouraud著色,而不是馮氏著色愈魏。記住由于插值觅玻,這種光照連起來有點遜色。馮氏著色能產(chǎn)生更平滑的光照效果培漏。

現(xiàn)在你可以看到著色器的強(qiáng)大之處了溪厘。只用很少的信息,著色器就能計算出光照如何影響到我們所有物體的片段顏色牌柄。下一個教程畸悬,我們會更深入的研究光照模型,看看我們還能做些什么珊佣。

練習(xí)

  • 目前蹋宦,我們的光源時靜止的,你可以嘗試使用sin和cos函數(shù)讓光源在場景中來回移動咒锻,此時再觀察光照效果能讓你更容易理解馮氏光照模型冷冗。
// Change the light's position values over time (can be done anywhere in the game loop actually, but try to do it at least before using the light source positions)
lightPos.x = 1.0f + sin (glfwGetTime ()) * 2.0f;
lightPos.y = sin (glfwGetTime () / 2.0f) * 1.0f;
  • 嘗試使用不同的環(huán)境光、漫反射光惑艇、鏡面光強(qiáng)度蒿辙,觀察光照效果。改變鏡面光照的shininess因子試試滨巴。試著理解為什么特定的值或有著特定的視覺輸出思灌。

  • 在觀察空間(而不是世界空間)中計算馮氏光照

項目文件。要點在于
使觀察矩陣應(yīng)用到所有相關(guān)的需要變換的向量(不要忘記恭取,也要改變正規(guī)矩陣)泰偿。

  • 嘗試實現(xiàn)一個Gouraud光照來模擬馮氏光照
// Vertex shader:
// ================
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;

out vec3 LightingColor;

uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;


uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
   
   // Gouraud Shading
   // --------------------------
   vec3 Position = vec3(model * vec4(position, 1.0f));
   vec3 Normal = mat3(transpose(inverse(model))) * normal;

   // Ambient
   float ambientStrength = 0.1f;
   vec3 ambient = ambientStrength * lightColor;

   // Diffuse
   vec3 norm = normalize(Normal);
   vec3 lightDir = normalize(lightPos - Position);
   float diff = max(dot(norm, lightDir), 0.0f);
   vec3 diffuse = diff * lightColor;

   // Specular
   float specularStrength = 1.0f;
   vec3 viewDir = normalize(viewPos - Position);
   vec3 reflectDir = reflect(-lightDir, norm);
   float spec = pow(max(dot(viewDir, reflectDir), 0.0f), 256);
   vec3 specular = specularStrength * spec * lightColor;

   LightingColor = ambient + diffuse + specular;
}


// Fragment shader:
// ================
#version 330 core
in vec3 LightingColor;

out vec4 color;

uniform vec3 objectColor;

void main()
{
    color = vec4(LightingColor * objectColor, 1.0f  );
}


/*
So what do we see?You can see (for yourself or in the provided image) the clear distinction of the two triangles at the front of the cube. This 'stripe' is visible because of fragment interpolation. From the example image we can see that the top-right vertex of the cube's front face is lit with specular highlights. Since the top-right vertex of the bottom-right triangle is lit and the other 2 vertices of the triangle are not, the bright values interpolates to the other 2 vertices. The same happens for the upper-left triangle. Since the intermediate fragment colors are not directly from the light source but are the result of interpolation, the lighting is incorrect at the intermediate fragments and the top-left and bottom-right triangle collide in their brightness resulting in a visible stripe between both triangles.
This effect will become more apparent when using more complicated shapes.
*/
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜈垮,隨后出現(xiàn)的幾起案子耗跛,更是在濱河造成了極大的恐慌裕照,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件课兄,死亡現(xiàn)場離奇詭異牍氛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)烟阐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來紊扬,“玉大人蜒茄,你說我怎么就攤上這事〔褪海” “怎么了檀葛?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腹缩。 經(jīng)常有香客問我屿聋,道長,這世上最難降的妖魔是什么藏鹊? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任润讥,我火速辦了婚禮,結(jié)果婚禮上盘寡,老公的妹妹穿的比我還像新娘楚殿。我一直安慰自己,他們只是感情好竿痰,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布脆粥。 她就那樣靜靜地躺著,像睡著了一般影涉。 火紅的嫁衣襯著肌膚如雪变隔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天蟹倾,我揣著相機(jī)與錄音匣缘,去河邊找鬼。 笑死喊式,一個胖子當(dāng)著我的面吹牛孵户,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岔留,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼夏哭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了献联?” 一聲冷哼從身側(cè)響起竖配,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤何址,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后进胯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體用爪,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年胁镐,在試婚紗的時候發(fā)現(xiàn)自己被綠了偎血。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡盯漂,死狀恐怖颇玷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情就缆,我是刑警寧澤帖渠,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站竭宰,受9級特大地震影響空郊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜切揭,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一狞甚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伴箩,春花似錦入愧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至巩步,卻和暖如春旁赊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背椅野。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工终畅, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人竟闪。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓离福,卻偏偏與公主長得像,于是被迫代替她去往敵國和親炼蛤。 傳聞我的和親對象是個殘疾皇子妖爷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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