1. 程式人生 > >零基礎學習OpenGL(一)--光照

零基礎學習OpenGL(一)--光照

       序:今天開始主要寫寫OpenGL,順帶寫寫其他的Unity,C#,Shader,優化等。這個系列參考自https://learnopengl-cn.github.io,作者不詳,系翻譯了經典的OpenGL教程,講的通俗易懂,大家可以參考一下。所以我也不知道該定義我的文章是轉載還是原創還是翻譯,因為文章裡也有加自己的理解,不懂的歡迎大家來探討。

       定義:  OpenGL:是個規範,規範了一個函式的執行和輸出。     

       渲染模式:  早期的OpenGL使用立即渲染模式(固定渲染管線),3.2版本後廢棄之,鼓勵核心模式下開發。

       狀態機:OpenGL其實是個巨大的狀態機,有一系列的上下文描述、更改OpenGL的狀態,然後來渲染。

       著色器:在GPU上為每一個(渲染管線)階段執行各自的小程式。用來在圖形渲染管線中快速處理資料。

       OpenGL著色器用GLSL(OpenGL Shading Language)編寫。渲染流程參考我的那篇:深入理解渲染流水線----學習Shader的基礎(入門必備)

                                                                             顏色

        世界上的顏色很多,任何顏色都可以由紅色,綠色,藍色三個分量組成(RGB),即這三個值可以組合成任意一種顏色。我們看到物體的顏色其實是物體反射的顏色,即不能被物體吸收的顏色。藍色的物體之所以看到是藍色,是因為白色的光照在物體上,藍色以外的都被吸收了,剩下不被吸收的藍色反射到眼中。

        我們看到的顏色就是:光的顏色 * 物體的顏色(所以使用不同顏色的光源會使物體呈現不同顏色,而且這個顏色和光的顏色有點像)

                                                                              光照

        現實中的光照很複雜,影響因素比較多。但是有很多簡化的模型,比如:

        Phong光照模型:環境光 (簡化的全域性照明,永遠會給物體一些顏色);

                                     漫反射(如果光線垂直於物體表面,這束光對物體的影響就最大,引入了垂直於頂點表面的向量--法向量);

                                     鏡面光照。

 

環境光的計算:

           float ambientStrength = 0.1;

            vec3 ambient = ambientStrength * lightColor;

            vec3 result = ambient * objectColor;

            FragColor = vec4(result, 1.0);

漫反射計算(opengl):

           1.將法線和方向向量標準化:

               vec3 norm = normalize(Normal);

               vec3 lightDir = normalize(lightPos - FragPos);

            2.上面兩個向量點乘,結果再乘以光的顏色,就是漫反射和的分量。(法線和方向向量的夾角越大,cos值越小,點積的值也就越小):

                float diff = max(dot(norm, lightDir), 0.0); //使用max是因為當法線和方向向量的夾角大於90度時,點積的結果是負數。

                 vec3 diffuse = diff * lightColor;

      最後將環境光分量+漫反射分量,再乘物體的顏色,搞定:

                 vec3 result = (ambient + diffuse) * objectColor;

                 FragColor = vec4(result, 1.0);

       法線矩陣:片段著色器中的計算都是世界座標下的,我們需要把法向量也轉到世界空間座標系中,使用法線矩陣乘以法向量即可。

鏡面光照的計算:

        鏡面光照除了依賴光的方向向量和物體的法向量,還依賴於觀察方向。反射向量和視線方向的夾角越小,鏡面光的影響就越大。

         float specularStrength = 0.5;

         vec3 viewDir = normalize(viewPos - FragPos);

         vec3 reflectDir = reflect(-lightDir, norm);

         float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); //視線和反射方向點乘,然後取32次冪,32指反光度。反光度越高,散射越少,高光點越小。

          vec3 specular = specularStrength * spec * lightColor;

最終結果:

          vec3 result = (ambient + diffuse + specular) * objectColor;

          FragColor = vec4(result, 1.0);