08 - OpenGL ES學(xué)習(xí)之材質(zhì)

在現(xiàn)實世界里,每個物體會對光產(chǎn)生不同的反應(yīng)。比如說鉆石看起來閃閃發(fā)光,塑料看起來就回暗一些。表面比較光滑的反射光的時候會產(chǎn)生亮點,表面比較粗糙一點的,反射光會形成一個光斑。

在上一篇文章中,我們指定了一個物體和光的顏色,以及結(jié)合環(huán)境光和鏡面強度分量,來定義物體的視覺輸出。當描述一個物體的時候,我們可以用這三個分量來定義一個材質(zhì)顏色(Material Color):環(huán)境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和鏡面光照(Specular Lighting)。通過為每個分量指定一個顏色,我們就能夠?qū)ξ矬w的顏色輸出有著精細的控制了?,F(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ù)需要很多次實驗才能得到較為準確的結(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),也就是白光

得到的效果如圖:


IMG_6706.PNG

這里我們看到了效果,大致是對的,但是會不會很奇怪,為什么這么亮,在上一篇文章中,我們通過一個環(huán)境光照強度和鏡面光照強度來控制這兩個分量對最終顏色的影響,而這里我們?nèi)サ袅诉@兩個強度,所以相當于環(huán)境光照,漫反射光照和鏡面光照對物體顏色的影響都是以1.0的強度處理的,所以這里特別亮。

這一步的代碼對應(yīng)的是Cube_material-01文件夾

那么接下來我們改進這一點,我們定義一個結(jié)構(gòu)體Light:

struct Light {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

我們通過改變Light的三個參數(shù) ambient ,diffuse, specular來改變每種光照的強度,

修改后的頂點著色器:

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)體,對這幾種光照強度進行設(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);

我們這里傳入隨時間改變的顏色進去,然后乘到環(huán)境光和漫射光的參數(shù)上。最終效果如下:


RPReplay_Final1638942312.gif

這里通過改變環(huán)境光,影響物體最終的顏色輸出,是不是類似呼吸燈的效果?
這一步的代碼對應(yīng)文件夾Cube_material-03。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容