真實的光照非常的複雜,所以有關光照的算法和論文也有不少,想要模擬出更真實的光照往往需要很強的實力,很牛的算法以及很高的數學/物理水平,與此相關的技術到現在爲止也只是在發展中(包括目前比較火的“光線追蹤”),當然,還是要從最簡單的入手,儘可能以最低的門檻,做出個大致的樣子來
一、光照模型與光源
之所以說光照比較複雜,主要是在物理和數學專業上的難度,光通常都不是來自於同一光源,而是來自散落於我們周圍的很多光源,即使它們可能並不是那麼顯而易見,光的一個屬性是,它可以向很多方向發散和反彈,又或是多次反射,所以光最後到達的地點可能並不是它所臨近的直射方向;
光能夠像這樣反射(Reflect)到其他表面,一個物體的光照可能受到來自一個非直射的光源影響
一種基礎光照模型:馮氏光照模型(Phong)的主要結構由3個元素組成
- 環境(Ambient)光:即使在黑暗的情況下,世界上也仍然有一些光亮(月亮、一個來自遠處的光),所以物體永遠不會是完全黑暗的,只要你在室外
- 漫反射(Diffuse):模擬一個發光物對物體的方向性影響(Directional Impact),它是馮氏光照模型最顯著的組成部分,面向光源的一面比其他面會更亮
- 鏡面(Specular)光照:模擬有光澤物體上面出現的亮點,鏡面光照的顏色相比於物體的顏色更傾向於光的顏色
幾種常見光源:
- 環境光:一種低強度的光,沒有位置的概念,由光線經過周圍環境表面多次反射後形成的,可以用環境光可以描述一塊區域的亮度,通常是常量(對應光照模型中的環境光)
- 太陽光:定向光源,在無窮遠出發射光線,光線是平行的,強度不會隨着距離衰減(一般場景中只有至多一個)
- 點光源:在有限空間內某個點上發出的光線,光線強度會隨着距離衰減(最常見光源)
- 聚光燈(SpotLight):一種具有錐形效果的光源,該光源擁有產生光的方向和角度,有主照射方向,光線強度會隨着距離,延着中心向外衰減(例如手電筒,舞臺燈)
陰影(Shadow):
- 軟陰影:陰影邊界柔和,漸變,沒有鋸齒,常見而又普通
- 硬陰影:邊界銳利,通常出現在在和物體的交替處或者是光打下來離物體比較近的地方
二、環境光照
考慮環境光的性質,實現環境光照出乎意料的簡單,如下修改物體的片段着色器:我們只需要用光的顏色乘以一個很小的常量環境因子,再乘以物體的顏色就ok了,這也是最基礎的算法
#version 330 core
out vec4 color;
uniform vec3 objectColor;
uniform vec3 lightColor;
in vec2 texIn;
uniform sampler2D texOutA;
void main()
{
float ambientStrength = 0.1f;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
color = vec4(result, 1.0f);
}
爲了能看出效果,把背景換成黑色:
如果你覺得這過於簡單,可以去嘗試學習全局照明(Global Illumination)算法
三、漫反射和鏡面反射
再回到初高中物理,漫反射和鏡面反射的區別可以用一張圖表示:
爲了簡化問題,我們當然不可能去嘗試計算每條光線的反射角和反射結果,我們只需要知道:漫反射是一個“混沌”的過程,也就是說,無論在什麼方向上觀察物體,從物體反射到我們眼中的光線強度和方向(總量)都是大致相似的,我們只需要考慮光與物體之間的關係,而對於鏡面反射,我們就需要考慮到我們的觀察視角,換句話說:
- 對於漫反射:我們簡單考慮入射光與物體表面法向量的夾角,夾角越大則越亮
- 對於鏡面反射:我們簡單考慮反射光與視線方向的夾角,夾角越大則越亮
入射光和反射光關於物體反射點法向量對稱
對於實現可以參考後面的文章
參考文獻:https://learnopengl.com/Lighting/Basic-Lighting