在現(xiàn)實世界里席舍,每個物體會對光產(chǎn)生不同的反應(yīng)布轿。比如說鉆石看起來閃閃發(fā)光,塑料看起來就回暗一些。表面比較光滑的反射光的時候會產(chǎn)生亮點汰扭,表面比較粗糙一點的稠肘,反射光會形成一個光斑。
在上一篇文章中东且,我們指定了一個物體和光的顏色启具,以及結(jié)合環(huán)境光和鏡面強(qiáng)度分量,來定義物體的視覺輸出珊泳。當(dāng)描述一個物體的時候鲁冯,我們可以用這三個分量來定義一個材質(zhì)顏色(Material Color):環(huán)境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和鏡面光照(Specular Lighting)色查。通過為每個分量指定一個顏色薯演,我們就能夠?qū)ξ矬w的顏色輸出有著精細(xì)的控制了。現(xiàn)在秧了,我們再添加反光度(Shininess)這個分量到上述的三個顏色中跨扮,這就有我們需要的所有材質(zhì)屬性了:
我們創(chuàng)建一個結(jié)構(gòu)體來表示材質(zhì):
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shineness;
};
ambient 表示在環(huán)境光照下這個物體反射的顏色,通常這個是和物體相同的顏色验毡,diffuse定義了在漫反射光照下物體的顏色(和環(huán)境光照一樣)衡创,specular設(shè)置的是鏡面光照對物體的顏色影響,最后晶通,shineness影響鏡面高光的散射/半徑(這里可以舉個例子解釋:比如光照到比較粗糙的表面璃氢,可能散射的光圈半徑就大一些,照到類似玻璃狮辽,鋼鐵這類物體的表面一也,形成的光斑直徑就很小)。
這四個元素定義了一個物體的材質(zhì)喉脖,通過它們椰苟,我們能模擬出很多現(xiàn)實世界中的材質(zhì)。但是要想模擬出很真實的效果树叽,這些參數(shù)需要很多次實驗才能得到較為準(zhǔn)確的結(jié)果舆蝴。
讓我們接著上一篇的代碼,用材質(zhì)結(jié)構(gòu)體代替物體顏色來模擬物體的效果
頂點著色器如下:
#version 300 es
precision mediump float;
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shineness;
};
uniform vec3 lightColor;
//光源位置
uniform vec3 lightPos;
//觀察點的位置
uniform vec3 viewPos;
//物體材質(zhì)
uniform Material material;
in vec3 Normal;
in vec3 fragPos;
out vec4 gColor;
void main() {
//計算環(huán)境光照
vec3 ambient = lightColor * material.ambient;
//計算漫反射
vec3 norm = normalize(Normal);
vec3 lightDirection = normalize(lightPos - fragPos);
float diffu = dot(norm,lightDirection);
vec3 diffuse = lightColor * (diffu * material.diffuse);
//計算鏡面光照
//觀察向量
vec3 viewDirection = normalize(viewPos - fragPos);
//反射向量
vec3 reflectDirection = reflect(-lightDirection,norm);
float spec = pow(max(dot(viewDirection,reflectDirection), 0.0) , material.shineness);
vec3 specular = lightColor * (spec * material.specular);
//最終顏色(這里指定物體顏色為紅色)
vec3 result = ambient + diffuse + specular;
gColor = vec4(result,1.0);
}
這里我們假定lightColor為(1.0,1.0,1.0),也就是白光
得到的效果如圖:
這里我們看到了效果题诵,大致是對的洁仗,但是會不會很奇怪,為什么這么亮仇轻,在上一篇文章中京痢,我們通過一個環(huán)境光照強(qiáng)度和鏡面光照強(qiáng)度來控制這兩個分量對最終顏色的影響篷店,而這里我們?nèi)サ袅诉@兩個強(qiáng)度祭椰,所以相當(dāng)于環(huán)境光照臭家,漫反射光照和鏡面光照對物體顏色的影響都是以1.0的強(qiáng)度處理的,所以這里特別亮方淤。
這一步的代碼對應(yīng)的是Cube_material-01文件夾
那么接下來我們改進(jìn)這一點钉赁,我們定義一個結(jié)構(gòu)體Light:
struct Light {
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
我們通過改變Light的三個參數(shù) ambient ,diffuse, specular來改變每種光照的強(qiáng)度携茂,
修改后的頂點著色器:
precision mediump float;
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shineness;
};
struct Light {
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform vec3 lightColor;
//光源位置
uniform vec3 lightPos;
//觀察點的位置
uniform vec3 viewPos;
//物體材質(zhì)
uniform Material material;
//光照的屬性
uniform Light light;
in vec3 Normal;
in vec3 fragPos;
out vec4 gColor;
void main() {
//計算環(huán)境光照
vec3 ambient = light.ambient * material.ambient;
//計算漫反射
vec3 norm = normalize(Normal);
vec3 lightDirection = normalize(lightPos - fragPos);
float diffu = dot(norm,lightDirection);
vec3 diffuse = light.diffuse * (diffu * material.diffuse);
//計算鏡面光照
//觀察向量
vec3 viewDirection = normalize(viewPos - fragPos);
//反射向量
vec3 reflectDirection = reflect(-lightDirection,norm);
float spec = pow(max(dot(viewDirection,reflectDirection), 0.0) , material.shineness);
vec3 specular = light.specular * (spec * material.specular);
//最終顏色(這里指定物體顏色為紅色)
vec3 result = ambient + diffuse + specular;
gColor = vec4(result,1.0);
}
注意這幾處的修改:
這里我們設(shè)置的光的顏色還是白色光 vec3(1.0,1.0,1.0);
這里我們傳入Light結(jié)構(gòu)體你踩,對這幾種光照強(qiáng)度進(jìn)行設(shè)置:
glUniform3f(glGetUniformLocation(_esContext.program, "material.ambient"), 1.0, 0.5, 0.31);
glUniform3f(glGetUniformLocation(_esContext.program, "material.diffuse"), 1.0, 0.5, 0.31);
glUniform3f(glGetUniformLocation(_esContext.program, "material.specular"), 0.5, 0.5, 0.5);
glUniform1f(glGetUniformLocation(_esContext.program, "material.shineness"), 32.f);
glUniform3f(glGetUniformLocation(_esContext.program, "light.ambient"), 0.2 ,0.2, 0.2);
glUniform3f(glGetUniformLocation(_esContext.program, "light.diffuse"), 0.5, 0.5, 0.5);
glUniform3f(glGetUniformLocation(_esContext.program, "light.specular"), 1.0, 1.0, 1.0);
效果如圖:
這樣看上去是不是比較接近真實效果了。
這一步對的代碼對應(yīng)Cube_material-02這個文件夾
彩蛋
現(xiàn)實世界中讳苦,環(huán)境光可能不只是單一的顏色带膜,現(xiàn)在我們做一個變動,根據(jù)時間來改變環(huán)境光的顏色鸳谜,看看有什么不一樣的效果膝藕。
代碼如下:
//構(gòu)建一個隨時間改變光照顏色
float r = sin(self.elapsedTime * 1.2);
float g = sin(self.elapsedTime * 1.3);
float b = sin(self.elapsedTime * 1.7);
GLKVector3 lightColor = GLKVector3Make(r, g, b);
GLKVector3 lightAmbient = GLKVector3Make(0.2, 0.2, 0.2);
GLKVector3 lightDiffuse = GLKVector3Make(0.5, 0.5, 0.5);
lightAmbient = GLKVector3Multiply(lightColor, lightAmbient);
lightDiffuse = GLKVector3Multiply(lightColor, lightDiffuse);
glUniform3fv(glGetUniformLocation(_esContext.program, "light.ambient"), 1, lightAmbient.v);
glUniform3fv(glGetUniformLocation(_esContext.program, "light.diffuse"), 1, lightDiffuse.v);
glUniform3f(glGetUniformLocation(_esContext.program, "light.specular"), 1.0, 1.0, 1.0);
我們這里傳入隨時間改變的顏色進(jìn)去,然后乘到環(huán)境光和漫射光的參數(shù)上咐扭。最終效果如下:
這里通過改變環(huán)境光芭挽,影響物體最終的顏色輸出,是不是類似呼吸燈的效果蝗肪?
這一步的代碼對應(yīng)文件夾Cube_material-03袜爪。