天天看點

NDK OpenGLES3.0 開發(九):光照基礎OpenGLES 基礎光照模型基礎光照模型實作聯系與交流

作者:位元組流動

來源:

https://blog.csdn.net/Kennethdroid/article/details/101220947

OpenGLES 基礎光照模型

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

NDK OpenGLES3.0 開發(九):光照基礎OpenGLES 基礎光照模型基礎光照模型實作聯系與交流

環境光

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

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

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

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

散射光

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

NDK OpenGLES3.0 開發(九):光照基礎OpenGLES 基礎光照模型基礎光照模型實作聯系與交流

散射光最終強度 = 材質反射系數 × 散射光強度 × 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);
}
      

鏡面光

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

NDK OpenGLES3.0 開發(九):光照基礎OpenGLES 基礎光照模型基礎光照模型實作聯系與交流

鏡面光最終強度 = 材質鏡面亮度因子 × 鏡面光強度 × 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);
}      
效果展示

聯系與交流

技術交流、擷取源碼可以掃碼添加我的微信:Byte-Flow

「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。
NDK OpenGLES3.0 開發(九):光照基礎OpenGLES 基礎光照模型基礎光照模型實作聯系與交流

繼續閱讀