學習OpenGL ES for Android(十二)— 光照貼圖

在之前文章中,我們模擬了物體的獨特的光照特效,但是在一個面上所有點的效果都是一樣的,顯然和現實情況還有差距。在現實世界中,大部分物體的表面都是有不同材質的,對光的反應也不相同。在光照場景中,通常有漫反射鏡面光貼圖(Map)兩種方式,來精確控制物體的漫反射分量和鏡面光分量以模擬現實世界的物體。

漫反射貼圖

現在我們使用紋理來代替前面的純色實現立方體的面,然後顯示光照的效果。我們使用下面這樣一幅圖片來作爲立方體的面,

這樣顯示出來的效果應該類似一個木箱。我們修改上篇的代碼,在材質結構圖中,把diffuse定義爲sampler2D,並去掉ambient,且不再定義物體的顏色,

struct Material {
    sampler2D diffuse;
    vec3 specular;
    float shininess;
};

計算結果時使用紋理的像素顏色(不包括透明度)來計算,

    // 環境光照
    vec3 ambient = light.ambient* texture2D(material.diffuse, TextCoord).rgb;
    // 漫反射光照
    // 歸一化光源線
    vec3 lightDir = normalize(light.position - fragPos);
    float diff = max(dot(norm, lightDir), 0.1);
    vec3 diffuse = diff * light.diffuse * texture2D(material.diffuse, TextCoord).rgb;

    // 鏡面光照
    vec3 viewDir = normalize(-fragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.1), material.shininess);
    vec3 specular = spec * light.specular * material.specular;
    // 結果,使用ambient,diffuse,specular相加則爲結合的效果
    vec3 result = ambient + diffuse + specular;

    gl_FragColor = vec4(result, 1.0);

此時光照的效果圖如下

鏡面光貼圖

這時已經非常接近現實世界的物體光照效果了,但是我們看到箱子每個點的光照效果都相同,但是事實上應該不相同。我們看到箱子的中間部分是木頭,周圍的邊框是鋼鐵,鋼鐵的反射是比木頭的反射大得多的,此時我們需要引入鏡面光貼圖。先看下使用的貼圖圖片,

使用這張圖片的像素點計算時,黑色的部分沒有反光,越是接近白色反光越大(實際上木頭也有反光度的,這裏我們暫時設置爲黑色了,也可以自己把黑色ps爲灰色的測試)。在代碼方面,同樣的我們定義specular爲sampler2D,在計算鏡面光照時使用我們的鏡面貼圖計算,關鍵代碼如下,

struct Material {
    sampler2D diffuse;
    sampler2D specular;
    float shininess;
};
...
void main() {
    // 環境光照
    vec3 ambient = light.ambient* texture2D(material.diffuse, TextCoord).rgb;
    // 漫反射光照
    // 歸一化光源線
    vec3 lightDir = normalize(light.position - fragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * light.diffuse * texture2D(material.diffuse, TextCoord).rgb;

    // 鏡面光照
    vec3 viewDir = normalize(-fragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = spec * light.specular * texture2D(material.specular, TextCoord).rgb;
    // 結果
    vec3 result = ambient + diffuse + specular;

    gl_FragColor = vec4(result, 1.0);
}

此時運行的效果如下,我們看到邊緣的光照比較明顯,中間的光線比較弱 

本章對應文檔https://learnopengl-cn.github.io/02%20Lighting/04%20Lighting%20maps/,源碼地址https://github.com/jklwan/OpenGLProject/blob/master/sample/src/main/java/com/chends/opengl/renderer/light/LightMapsRenderer.java

PS:因爲着色器的代碼比較多,把着色器的代碼放到raw資源文件下了(也可以放在assets下,只是引入方式不同),這裏推薦安裝GLSL的插件GLSL Support。

練習題中改變鏡面光貼圖的圖片,圖片如果是彩色的,箱子被照到也會顯示彩色;添加放射光貼圖,見源碼運行效果。

發佈了52 篇原創文章 · 獲贊 17 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章