OpenGL ES 光照計算

  • 光照計算在片元着色器執行,計算每一個像素點的顏色

一、光照計算

1、環境光計算

環境光 = 光源的環境光顏色 * 物體的材質顏色

  • 環境光 = 光的顏色 * 材質顏色;
    光是有顏色的,比如紅光、綠光等;
    材質顏色也就是紋理顏色。

2、發射光的計算

發射顏色 = 物體的反射材質顏色

  • 物體本身是有顏色的,比如手電筒,其本身能發光,發出的光的顏色就是發射顏色。

3、漫反射光照計算

  • 光照有陰面和陽面,由法線計算光與物體之間的夾角,這個夾角分爲入射角和反射角

漫反射顏色 = 光源的漫反射顏色 * 物體的漫反射材質顏色 * DiffuseFactor

DiffuseFactor = max(0, dot(N, L));

  • 漫反射因子DiffuseFactor 是光線與頂點法線向量的點積,是光線與法線之間的夾角,其值不能小於0

4、鏡面光計算

鏡面反射顏色 = 光源的鏡面光顏色 * 物體的鏡面材質顏色 * SpecularFactor

SpecularFactor = power(max(0, dot(N, H)), shininess);
H:視線向量E 與光線向量L 的半向量
dot(N, H):H,N的點積幾何意義,平方線與法線夾角的cos值
shininess:高光的反光度

  • 鏡面因子SpecularFactor,shininess反光度越小光照越集中

5、普通光照計算

光照顏色 = (環境顏色 + 漫反射顏色 + 鏡面反射顏色) * 衰減因子

衰減因子 = 1.0 / (距離衰減常量 + 線性衰減常量 * 距離 + 二次衰減常量 * 距離的平方)
距離衰減常量、線性衰減常量和二次衰減常量均爲常量值

tips:環境光、漫反射光和鏡面光的強度都會受距離的增大而衰減,只有發射光和全局環境光的強度不會受影響

6、聚光燈因子

聚光燈夾角cos值 = power(max(0, dot(單位光源位置, 單位光線向量)), 聚光燈指數);

單位光線向量:是從光源指向頂點的單位向量
聚光燈指數:表示聚光燈的亮度程度
公式解讀:單位光源位置 * 單位光線向量 點積 的 聚光燈指數次方

  • 增加過渡計算
    聚光燈因子 = clamp((外環的聚光燈角度cos值 - 當前頂點的聚光燈角度cos值) / (外環的聚光燈角度cos值 - 內環聚光燈的角度cos值), 0.1);

7、光照計算終極公式

光照顏色 = 發射顏色 + 全局環境顏色 + (環境顏色 + 漫反射顏色 + 鏡面顏色) * 聚光燈效果 * 衰減因子

平面光終極公式

  • 平面光也就是平行光,沒有具體的方向

點光源終極公式

  • 比如燈泡光源,點光源是有方向的

二、光照的GLSL實現

1、環境光的GLSL實現

varying vec3 objectColor;
void main() {

    //至少有10%的光照到物體所有面
    float ambientStrength = 0.1;

    //環境光顏色 = 環境光比率 * 環境光顏色
    vec3 ambient = ambientStrength * lightColor;

    //最終顏色 = 環境光顏色 * 物體顏色
    vec3 result = ambient * objectColor;
    //vec3轉化成vec4
    gl_FragColor = vec4(result, 1.0);

}

2、漫反射光的GLSL實現

uniform vec3 lightColor;     //光源顏色
uniform vec3 lightPo;         //光源位置
uniform vec3 objectColor; //物體顏色
uniform vec3 viewPo;        //物體位置
varying vec3 outNormal;  //傳入當前頂點平面的法向量

//確保法線爲單位向量,normalize爲內建函數,把法向量轉換成單位向量
vec3 norm = normalize(outNormal);
//頂點指向光源的單位向量
vec3 lightDir = normalize(lightPo -   FragPo);
//得到兩向量的cos值,小於0則爲0
float diff = max(dot(norm, lightDir), 0.0);
//夾角乘以光照顏色得到漫反射的光源向量
vec3 diffuse = diff * lightColor;

vec3 result = diffuse * objectColor;
gl_FragColor = vec4(result, 1.0);

3、鏡面光的GLSL實現

//鏡面強度
float specularStrength = 0.5;

//頂點指向觀察點的單位向量
vec3 viewDir = normalize(viewPo - FragPo);

//光線在頂點的反射線(傳入光源指向頂點的向量),鏡面光是反方向的光線
vec3 reflectDir = reflect(-lightDir, outNormal);

//夾角cos值,取256次冪,鏡面因子
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 256.0);

vec3 specular = specularStrength * spec * lightColor;

4、衰減因子計算

//距離衰減常量
float constantPara = 1.0;
//線性衰減常量
float linearPara = 0.09;
//二次衰減因子
float quadraticPara = 0.032;
//距離
float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance * LFDistance));

5、聚光燈過渡計算

//一些複雜的計算操作應該讓CPU做以提高效率,不變的量也建議外部傳輸,避免重複計算
//內錐角cos值
float inCutoff = cos(radians(10.0));
//外錐角cos值
float outCutoff = cos(radians(15.0));
//聚光朝向
vec3 spotDir = vec3(-1.2, -1.0, -2.0);

//光源指向物體的向量和聚光朝向的cos值
float theta = dot(lightDir, normalize(-spotDir));
//內外錐角cos差值
float epsilon = inCutoff - outCutoff;

//clamp(a, b, c);若b<a<c則函數返回a,若不是則返回最小b,最大c
/*(theta - outCutoff)/epsilon 若theta的角度小於內錐角則其值>=1,
若theta的角度大於外錐角則其值<=0,這樣光線就在內外錐角之間平滑變化*/
float intensity = clamp((theta - outCutoff) / epsilon, 0.0, 1.0);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章