NDK OpenGLES3.0 開發(九):光照基礎

該原創文章首發於微信公衆號:字節流動

OpenGLES 基礎光照模型

OpenGLES 目前還無法模擬現實世界的複雜光照效果,爲了在效果要求和實現難度之間做一個平衡,往往採用一些簡化的模型來模擬光照效果。馮氏光照模型(Phong Lighting Model)便是其中常用的一個光照模型,它由三種元素光組成,分別是環境光(Ambient Lighting)、散射光(Diffuse Lighting)及鏡面光(Specular Lighting)。

馮氏光照模型

環境光

環境光表示從四面八方照射到物體上且各個方向都均勻的光,不依賴於光源位置,沒有方向性。

要把環境光照添加到場景裏,只需用光的顏色乘以一個(數值)很小常量環境因子,再乘以物體的顏色,然後使用它作爲片段的顏色:

void main()
{
    float ambientStrength = 0.1f; //常量環境因子
    vec3 ambient = ambientStrength * lightColor; //環境光強度

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

散射光

散射光表示從物體表面向各個方向均勻反射的光。散射光的強度與入射光的強度及入射角密切相關,所以當光源位置發生變化,散射光效果也會發生明顯變化。

散射光

散射光最終強度 = 材質反射係數 × 散射光強度 × max(cos(入射角),0)

其中入射角表示:當前片段光源照射方向與法向量之間的夾角。
實現散射光的片段着色器腳本:

out vec3 fragPos;//當前片段座標
out vec3 normal; //當前片段法向量
uniform vec3 lightPos;//光源位置
void main()
{
    float diffuseStrength = 0.5f; //材質反射係數

	vec3 norm = normalize(normal); // 歸一化
	vec3 lightDir = normalize(lightPos - fragPos);//當前片段光源照射方向向量

    float diff = max(dot(norm, lightDir), 0.0);// dot 表示兩個向量的點乘
    vec3 diffuse = diffuseStrength * diff * lightColor; //散射光最終強度

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

鏡面光

鏡面光是由光滑物體表面反射的方向比較集中的光,鏡面光強度不僅依賴於入射光與法向量的夾角,也依賴於觀察者的位置。

鏡面光

鏡面光最終強度 = 材質鏡面亮度因子 × 鏡面光強度 × max(cos(反射光向量與視線方向向量夾角),0)

修正後的模型也可表示爲:
鏡面光最終強度 = 材質鏡面亮度因子 × 鏡面光強度 × max(cos(半向量與法向量夾角),0)
其中半向量爲鏡面反射光向量與視線方向向量(從片段到觀察者)的半向量。

實現鏡面光的片段着色器腳本:

out vec3 fragPos;//當前片段座標
out vec3 normal; //當前片段法向量
uniform vec3 lightPos;//光源位置
void main()
{
    float specularStrength = 0.5f;

    vec3 norm = normalize(normal); // 歸一化
    vec3 viewDir = normalize(viewPos - FragPos); //視線方向向量 
    vec3 reflectDir = reflect(-lightDir, norm); //鏡面反射光向量

    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); 
    //視線方向向量與鏡面反射光向量點乘的32次冪,這個32是高光的發光值(Shininess)。一個物體的發光值越高,反射光的能力越強,散射得越少,高光點越小。
    vec3 specular = specularStrength * spec * lightColor; //鏡面光最終強度

    vec3 result = specular * objectColor;
    color = vec4(result, 1.0f);
}

基礎光照模型實現

實現基礎光照模型的頂點着色器:

#version 300 es
precision mediump float;
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
layout(location = 2) in vec3 a_normal;
uniform mat4 u_MVPMatrix;
uniform mat4 u_ModelMatrix;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 viewPos;
out vec2 v_texCoord;
out vec3 ambient;
out vec3 diffuse;
out vec3 specular;
void main()
{
gl_Position = u_MVPMatrix * a_position;
vec3 fragPos = vec3(u_ModelMatrix * a_position);

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

// Diffuse
float diffuseStrength = 0.5;
vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0)));
vec3 lightDir = normalize(lightPos - fragPos);
float diff = max(dot(unitNormal, lightDir), 0.0);
diffuse = diffuseStrength * diff * lightColor;

// Specular
float specularStrength = 0.9;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 reflectDir = reflect(-lightDir, unitNormal);
float spec = pow(max(dot(unitNormal, reflectDir), 0.0), 16.0);
specular = specularStrength * spec * lightColor;
v_texCoord = a_texCoord;
}

對應的片段着色器:

#version 300 es
precision mediump float;
in vec2 v_texCoord;
in vec3 ambient;
in vec3 diffuse;
in vec3 specular;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;
void main()
{
vec4 objectColor = texture(s_TextureMap, v_texCoord);
vec3 finalColor = (ambient + diffuse + specular) * vec3(objectColor);
outColor = vec4(finalColor, 1.0);
}

效果圖:
gif

實現代碼路徑:
https://github.com/githubhaohao/NDK_OpenGLES_3_0

聯繫與交流

我的公衆號
我的公衆號
我的微信

我的微信

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