LearnOpenGL


----------------------------------------------
LearnOpenGL
----------------------------------------------
OpenGL基礎知識:
    https://www.opengl.org/:OpenGL官方網站。
    https://www.opengl.org/registry/:包含OpenGL各版本的規范和擴展。
    https://learnopengl-cn.github.io
    https://khronos.org/registry/OpenGL/specs/gl/glspec33.core.pdf
    http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf

版本
    早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管線),這個模式下繪制圖形很方便。OpenGL的大多數功能都被庫隱藏起來,開發者很少能控制OpenGL如何進行計算的自由。而開發者迫切希望能有更多的靈活性。隨着時間推移,規范越來越靈活,開發者對繪圖細節有了更多的掌控。立即渲染模式確實容易使用和理解,但是效率太低。因此從OpenGL3.2開始,規范文檔開始廢棄立即渲染模式,推出核心模式(Core-profile)
    所有OpenGL的更高的版本都是在3.3的基礎上,引入了額外的功能,並沒有改動核心架構。

簡寫
    VAO(Vertex Array Object) : 頂點數組對象:
    VBO(Vertex Buffer Object) : 頂點緩沖對象
    EBO(Element Buffer Object): 索引緩沖對象
    IBO(Index Buffer Object): 
    TBO(Texture Buffer Object):Uniform數據容量是有限的。故可用TBO,把數據裝入一個一維紋理的Buffer中以提供給Shader
    UBO(Uniform buffer object): 可供Shader間共享Uniform 變量 UBO:http://blog.csdn.net/panda1234lee/article/details/71326063
        layout(std140) uniform matVP   
        {   
          mat4 matProj;   
          mat4 matView;   
        };   


OpenGL 坐標系
        y(0,1,0)
        |
        .----x(1,0,0)
       /
      z(0,0,1)
     標准化設備坐標(Normalized Device Coordinates)范圍:[-1, 1]


----------------------------------------------
Shader
----------------------------------------------
渲染管道
    VertexShader      : 頂點着色器,輸入一個頂點,輸出一個頂點
    ShapeAssmbly      : 形狀(圖元)裝配。所有頂點作為輸入,並所有的點裝配成指定圖元的形狀
    GeometryShader    : 幾何着色器。把圖元形式的一系列頂點的集合作為輸入,它可以通過產生新頂點構造出新的(或是其它的)圖元來生成其他形狀
    Rasterization     : 光柵化階段。把圖元映射為最終屏幕上相應的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。並執行裁切(Clipping)
    FragmentShader    : 片段着色器。主要目的是計算一個像素的最終顏色
    TestAndBlending   : Alpha測試和混合階段。判斷這個像素是其它物體的前面還是后面,決定是否應該丟棄

着色器文件類型
    .vert:頂點着色器(Vertex Shader)
    .frag:片段着色器(Fragment Shader)
    .geom:幾何着色器(Geometry Shader)
    .tesc:細分控制着色器(Tessellation Control Shader)
    .tese:細分計算着色器(Tessellation Evaluation Shader)
    .comp:計算着色器(Compute Shader)


Shader 數據類型(http://blog.csdn.net/peeno/article/details/52996589)
    void	跟C語言的void類似,表示空類型。作為函數的返回類型,表示這個函數不返回值。
    bool	布爾類型,可以是true 和false,以及可以產生布爾型的表達式。
    int	整型 代表至少包含16位的有符號的整數。可以是十進制的,十六進制的,八進制的。
    float	浮點型
    bvec2	包含2個布爾成分的向量
    bvec3	包含3個布爾成分的向量
    bvec4	包含4個布爾成分的向量
    ivec2	包含2個整型成分的向量
    ivec3	包含3個整型成分的向量
    ivec4	包含4個整型成分的向量
    mat2 或者 mat2x2	2x2的浮點數矩陣類型
    mat3或者mat3x3	3x3的浮點數矩陣類型
    mat4x4	4x4的浮點矩陣
    mat2x3	2列3行的浮點矩陣(OpenGL的矩陣是列主順序的)
    mat2x4	2列4行的浮點矩陣
    mat3x2	3列2行的浮點矩陣
    mat3x4	3列4行的浮點矩陣
    mat4x2	4列2行的浮點矩陣
    mat4x3	4列3行的浮點矩陣
    sampler1D	用於內建的紋理函數中引用指定的1D紋理的句柄。只可以作為一致變量或者函數參數使用
    sampler2D	二維紋理句柄
    sampler3D	三維紋理句柄
    samplerCube	cube map紋理句柄
    sampler1DShadow	一維深度紋理句柄
    sampler2DShadow	二維深度紋理句柄
    ------------------------------
    vec(x,y,z,w)
    可以使用上面4個字母任意組合來創建一個和原來向量一樣長的(同類型)新向量,只要原來向量有那些分量即可,如
    vec2 someVec;
    vec4 differentVec = someVec.xyxx;
    vec3 anotherVec = differentVec.zyw

內置變量
    頂點着色器可用的內置變量
        gl_Color	vec4	輸入屬性-表示頂點的主顏色
        gl_SecondaryColor	vec4	輸入屬性-表示頂點的輔助顏色
        gl_Normal	vec3	輸入屬性-表示頂點的法線值
        gl_Vertex	vec4	輸入屬性-表示物體空間的頂點位置
        gl_MultiTexCoordn	vec4	輸入屬性-表示頂點的第n個紋理的坐標
        gl_FogCoord	float	輸入屬性-表示頂點的霧坐標
        gl_Position	vec4	輸出屬性-變換后的頂點的位置,用於后面的固定的裁剪等操作。所有的頂點着色器都必須寫這個值。
        gl_ClipVertex	vec4	輸出坐標,用於用戶裁剪平面的裁剪
        gl_PointSize	float	點的大小
        gl_FrontColor	vec4	正面的主顏色的varying輸出
        gl_BackColor	vec4	背面主顏色的varying輸出
        gl_FrontSecondaryColor	vec4	正面的輔助顏色的varying輸出
        gl_BackSecondaryColor	vec4	背面的輔助顏色的varying輸出
        gl_TexCoord[]	vec4	紋理坐標的數組varying輸出
        gl_FogFragCoord	float	霧坐標的varying輸出
    片段着色器可用內置變量
        gl_Color	vec4	包含主顏色的插值只讀輸入
        gl_SecondaryColor	vec4	包含輔助顏色的插值只讀輸入
        gl_TexCoord[]	vec4	包含紋理坐標數組的插值只讀輸入
        gl_FogFragCoord	float	包含霧坐標的插值只讀輸入
        gl_FragCoord	vec4	只讀輸入,窗口的x,y,z和1/w
        gl_FrontFacing	bool	只讀輸入,如果是窗口正面圖元的一部分,則這個值為true
        gl_PointCoord	vec2	點精靈的二維空間坐標范圍在(0.0, 0.0)到(1.0, 1.0)之間,僅用於點圖元和點精靈開啟的情況下。
        gl_FragData[]	vec4	使用glDrawBuffers輸出的數據數組。不能與gl_FragColor結合使用。
        gl_FragColor	vec4	輸出的顏色用於隨后的像素操作
        gl_FragDepth	float	輸出的深度用於隨后的像素操作,如果這個值沒有被寫,則使用固定功能管線的深度值代替
    
內建函數(https://www.khronos.org/registry/OpenGL-Refpages/gl4/)——
    數學函數
    三角函數
    紋理函數
    三維函數
    


基礎Shader示例
    VertexShader
        #version 330 core
        layout (location = 0) in vec3 position;
        void main()
        {
            gl_Position = vec4(position.x, position.y, position.z, 1.0);
        }
    FragmengShader
        #version 330 core
        out vec4 color;
        void main()
        {
            color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
        }
    GeometryShader
        可以修改模型。可以對每個頂點附近的數據進行訪問,然后使用這些數據或生成新的幾何形體。
        如對折線進行besizer插值,變為平滑曲線
        如對三角形進行插值,變為一個曲面
        這個功能原先是一些三維軟件進行后期渲染時的技術,現在被加入顯卡中,可用於實時渲染
        缺點:增加了面片,會降低效率。
        http://blog.csdn.net/panda1234lee/article/details/71248763
        動態生成頂點需要三維知識,慢慢研究吧

參數和傳遞
    變量在shader中傳遞(in out)
        頂點着色器
            layout (location = 0) in vec3 position; // position變量的屬性位置值為0
            out vec4 vertexColor; // 為片段着色器指定一個顏色輸出
            void main()
            {
                gl_Position = vec4(position, 1.0); // 注意我們如何把一個vec3作為vec4的構造器的參數
                vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f); // 把輸出變量設置為暗紅色
            }
        片段着色器
            in vec4 vertexColor; // 從頂點着色器傳來的輸入變量(名稱相同、類型相同)
            out vec4 color; // 片段着色器輸出的變量名可以任意命名,類型必須是vec4
            void main()
            {
                color = vertexColor;
            }
        在GL3.x中,廢棄了attribute關鍵字(以及varying關鍵字),屬性變量統一用in/out作為前置關鍵字
    Uniform變量
        全局只讀變量,由外部傳遞給shader,各個shader中共用
        out vec4 color;
        uniform vec4 ourColor; // 在OpenGL程序代碼中設定這個變量
        void main()
        {
            color = ourColor;
        }
        uniform mat4 viewProjMatrix; //投影+視圖矩陣
        uniform mat4 viewMatrix;        //視圖矩陣
        uniform vec3 lightPosition;     //光源位置
    attribute變量
        只能在vertex shader中使用的變量
        一般用來表示一些頂點的數據,如:頂點坐標,法線,紋理坐標,頂點顏色等。
        attribute vec4 a_position;
        attribute vec2 a_texCoord0;
        一般用函數glBindAttribLocation()來綁定每個attribute變量的位置,然后用函數glVertexAttribPointer()為每個attribute變量賦值。
        所以一些奇怪的各平台都不一致的變量就是這么來的
    varying變量
        是vertex和fragment shader之間做數據傳遞用的。
        一般vertex shader修改varying變量的值,然后fragment shader使用該varying變量的值。
    常用的全局變量
        gl_Position
        gl_FragColor
        gl_VertexID

線段模式/面片填充模式?
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL|GL_LINE);  


----------------------------------------------
紋理 Texture
----------------------------------------------
紋理坐標系
    y(0,1)
    |
    .----x
    (0,0)   (1,0)
    范圍:[0, 1]
    紋理坐標看起來就像這樣:
    GLfloat texCoords[] = {
        0.0f, 0.0f, // 左下角
        1.0f, 0.0f, // 右下角
        0.5f, 1.0f // 上中
    };

多級漸遠紋理(Mipmap)
    距觀察者的距離超過一定的閾值,OpenGL會使用不同的多級漸遠紋理,即最適合物體的距離的那個     

應用紋理示例(片段着色器)
    in vec3 ourColor;
    in vec2 TexCoord;
    out vec4 color;
    uniform sampler2D ourTexture;
    void main()
    {
        color = texture(ourTexture, TexCoord);  // 用紋理
        color = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0f); // 用紋理和色彩混合
        color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2);  // 兩種紋理混合
    }
    
紋理顛倒問題
    OpenGL要求y軸0.0坐標是在圖片的底部的,但是圖片的y軸0.0坐標通常在頂部
    TexCoord = vec2(texCoord.x, 1.0f - texCoord.y);



----------------------------------------------
向量/矩陣/變換/坐標系
https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/
----------------------------------------------
向量(就是n*1矩陣)
    v = (x, y)                   : 一般用於表示方向,原點在(0,0)
    v+w = (v.x+w.x, v.y+w.y)     : 向量相加
    v-w = (v.x-w.x, v.y-w.y)     : 向量相減
    |v| = sqrt(x*2+y*2)          : 向量長度
    n=v/|v|                      : 標准化向量。它的長度是1
    v¯⋅k¯=||v¯||⋅||k¯||⋅cosθ      : 向量點乘,如(0,6, -0.8)⋅(0, 1) = (0.6*0)+(-0.8*1)=-0.8  --> 143.1度
    v¯⋅k¯=1⋅1⋅cosθ=cosθ           : 標准化向量點乘,可用於得到夾角。
    v*k                          : 叉乘只在3D空間中有定義,它需要兩個不平行向量作為輸入,生成一個正交於兩個輸入向量的第三個向量

單位矩陣(IdentityMatrix)
    1  0  0  0
    0  1  0  0
    0  0  1  0
    0  0  0  1
    乘以一個向量完全不變
    
放縮
    Sx 0  0  0
    0  Sy 0  0
    0  0  Sz 0
    0  0  0  1
    
位移
    1  0  0  Tx
    0  1  0  Ty
    0  0  1  Tz
    0  0  0  1

旋轉(沿z軸旋轉)
    cosθ  sinθ  0  0
    −sinθ cosθ  0  0
    0     0     1  0
    0     0     0  1
        
任意角度旋轉(http://v.youku.com/v_show/id_XMTgxNDgzMjUyNA==.html?spm=a2h0j.8191423.module_basic_relation.5~5!2~5~5!3~5!2~1~3~A)
    歐拉角(Euler Angles): 
        偏航角(Yaw):Ry
        俯仰角(Pitch):Rx
        滾轉角(Roll):Rz

坐標系轉換
    https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/
    空間和坐標系
        局部空間(Local Space): 一個物體的初始空間。所有的坐標都是相對於物體的原點的。
        世界空間(World Space): 所有的坐標都相對於全局原點。
        觀察空間(View Space): 所有的坐標都是從攝像機的視角觀察的。
        裁剪空間(Clip Space): 所有的坐標都是從攝像機視角觀察的,但是該空間應用了投影。這個空間應該是一個頂點坐標最終的空間,作為頂點着色器的輸出。OpenGL負責處理剩下的事情(裁剪/透視除法)。
        屏幕空間(Screen Space): 所有的坐標都由屏幕視角來觀察。坐標的范圍是從0到屏幕的寬/高。
    電腦上看到的
        剪裁矩陣 = 投影矩陣 視圖矩陣 模型矩陣 本地矩陣
        Vclip = Mprojection ⋅ Mview ⋅ Mmodel ⋅ Vlocal
    -------------------------------------------
    頂點着色器
        #version 330 core
        layout (location = 0) in vec3 position;
        uniform mat4 model;
        uniform mat4 view;
        uniform mat4 projection;
        void main()
        {
            gl_Position = projection * view * model * vec4(position, 1.0f);  // 矩陣是右邊到左邊乘
        }
        
相機及LookAt矩陣
    攝像機位置   
    目標位置
    世界空間中的上向量
    
    
----------------------------------------------
色彩,材質,貼圖
----------------------------------------------
物體的色彩=光線照到物體表面后,反射的光進入眼睛的色彩,其余的光被物體吸收了。
    物體色彩=光照色彩*反射色彩
    glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
    glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
    glm::vec3 result = lightColor * toyColor; // = (0.0f, 0.5f, 0.0f);


片段着色器
    out vec4 color;
    uniform vec3 objectColor;
    uniform vec3 lightColor;
    void main()
    {
        color = vec4(lightColor * objectColor, 1.0f);
    }


馮氏光照模型材質(Phong Lighting Model)。
    https://learnopengl-cn.github.io/02%20Lighting/02%20Basic%20Lighting/
    馮氏光照模型的主要結構由3個元素組成:
        環境(Ambient):無論如何永遠都給物體一些顏色
        漫反射(Diffuse):模擬一個發光物對物體的方向性影響,面向光源的一面比其他面會更亮
        鏡面高光(Specular):模擬有光澤物體上面出現的亮點。鏡面光照的顏色,相比於物體的顏色更傾向於光的顏色。
    Phong 材質的基本結構
        struct Material
        {
            vec3 ambient;
            vec3 diffuse;
            vec3 specular;
            float shininess;
        };
    常用材質(http://devernay.free.fr/cours/opengl/materials.html)        
    計算示例
        void main()
        {
            // 環境光
            vec3 ambient = lightColor * material.ambient;
        
            // 漫反射光
            vec3 norm = normalize(Normal);
            vec3 lightDir = normalize(lightPos - FragPos);
            float diff = max(dot(norm, lightDir), 0.0);
            vec3 diffuse = lightColor * (diff * material.diffuse);
        
            // 鏡面高光
            vec3 viewDir = normalize(viewPos - FragPos);
            vec3 reflectDir = reflect(-lightDir, norm);  
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
            vec3 specular = lightColor * (spec * material.specular);  
            
            // 最后色彩
            vec3 result = ambient + diffuse + specular;
            color = vec4(result, 1.0f);
        }




漫反射貼圖材質(Diffuse texture)
    struct Material
    {
        sampler2D diffuse;
        vec3 specular;
        float shininess;
    };
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
    vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

漫反射高光貼圖材質    
    struct Material
    {
        sampler2D diffuse;
        sampler2D specular;
        float shininess;
    };
    vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
    vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
    color = vec4(ambient + diffuse + specular, 1.0f);

立方體貼圖(CubeMap)
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/    
    立方體貼圖它包含6個2D紋理
    面片着色器
        in vec3 textureDir; // 用一個三維方向向量來表示立方體貼圖紋理的坐標
        uniform samplerCube cubemap;  // 立方體貼圖紋理采樣器
        void main()
        {
            color = texture(cubemap, textureDir);
        }
    天空盒
        天空盒常用立方體+加立方體貼圖模擬。為什么不用球體?那球要很大很大很大才行
        https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/
        http://www.custommapmakers.org/skyboxes.php

反射(可用於做金屬效果)
    將環境貼圖融合到物體表面
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/
    vertexShader
        #version 330 core
        layout (location = 0) in vec3 position;
        layout (location = 1) in vec3 normal;
        out vec3 Normal;
        out vec3 Position;
        uniform mat4 model;
        uniform mat4 view;
        uniform mat4 projection;
        void main()
        {
            gl_Position = projection * view * model * vec4(position, 1.0f);
            Normal = mat3(transpose(inverse(model))) * normal;
            Position = vec3(model * vec4(position, 1.0f));
        }
    fragmentShader
        #version 330 core
        in vec3 Normal;
        in vec3 Position;
        out vec4 color;
        uniform vec3 cameraPos;
        uniform samplerCube skybox;
        void main()
        {
            vec3 I = normalize(Position - cameraPos);
            vec3 R = reflect(I, normalize(Normal));
            color = texture(skybox, R);
        }

折射(可用於玻璃制物體)
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/
    void main()
    {
        float ratio = 1.00 / 1.52;
        vec3 I = normalize(Position - cameraPos);
        vec3 R = refract(I, normalize(Normal), ratio);
        color = texture(skybox, R);
    }


雙面紋理
    #version 330 core
    out vec4 color;
    in vec2 TexCoords;
    uniform sampler2D frontTexture;
    uniform sampler2D backTexture;
    void main()
    {
        if(gl_FrontFacing)
            color = texture(frontTexture, TexCoords);
        else
            color = texture(backTexture, TexCoords);
    }

法線凹凸貼圖(NormalMapping)
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/04%20Normal%20Mapping/
    每個fragment使用了自己的法線
    法線來源一個法線貼圖圖像文件(大部分為藍綠色)
    法線數據 rgba->xyzw, 故物體正面偏藍,頂部偏綠,右側偏紅
    
視差貼圖(ParallaxMapping)
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/05%20Parallax%20Mapping/        
    每個頂點都根據從高度貼圖采樣出來的高度值進行位移,根據材質的幾何屬性平坦的平面變換成凹凸不平的表面
    視差貼圖嘗試模擬深度,能夠根據你觀察它們的方向使磚塊疊加到其他磚塊上。
    
  
        
----------------------------------------------
光源
請和材質結合在一起看
----------------------------------------------
點光源(向所有方向發射光線,如燈泡)
    定義
        struct PointLight {
            vec3 position;
            vec3 ambient;
            vec3 diffuse;
            vec3 specular;
            float constant;
            float linear;
            float quadratic;  
        };
    照到物體上后顯示的色彩
        vec3 ambient = light.ambient * material.ambient;
        vec3 diffuse = light.diffuse * (diff * material.diffuse);
        vec3 specular = light.specular * (spec * material.specular);
        // 計算定點光在確定位置的光照顏色
        vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
        {
            vec3 lightDir = normalize(light.position - fragPos);
            // 計算漫反射強度
            float diff = max(dot(normal, lightDir), 0.0);
            // 計算鏡面反射
            vec3 reflectDir = reflect(-lightDir, normal);
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
            // 計算衰減
            float distance    = length(light.position - fragPos);
            float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
            // 將各個分量合並
            vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, TexCoords));
            vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, TexCoords));
            vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
            ambient  *= attenuation;
            diffuse  *= attenuation;
            specular *= attenuation;
            return (ambient + diffuse + specular);
        }

方向光(如很遠的太陽光)
    方向光
        struct DirectionLight
        {
            vec3 direction;
            vec3 ambient;
            vec3 diffuse;
            vec3 specular;
            // 二次衰減
            float constant;
            float linear;
            float quadratic;
        };
        float distance = length(light.position - FragPos);
        float attenuation = 1.0f / (light.constant + light.linear*distance +light.quadratic*(distance*distance));
        ambient *= attenuation;
        diffuse *= attenuation;
        specular *= attenuation;
        vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
        {
            vec3 lightDir = normalize(-light.direction);
            // 計算漫反射強度
            float diff = max(dot(normal, lightDir), 0.0);
            // 計算鏡面反射強度
            vec3 reflectDir = reflect(-lightDir, normal);
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
            // 合並各個光照分量
            vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, TexCoords));
            vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, TexCoords));
            vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
            return (ambient + diffuse + specular);
        } 

聚光(如舞台聚光燈)
    https://learnopengl-cn.github.io/02%20Lighting/05%20Light%20casters/
    定義
        struct SpotLight
        {
            vec3 position;
            vec3 direction;
            float cutOff;
            ...
        };
    柔化邊緣
        float theta = dot(lightDir, normalize(-light.direction));
        float epsilon = light.cutOff - light.outerCutOff;
        float intensity = clamp((theta - light.outerCutOff) / epsilon,0.0, 1.0);
        light.diffuse* = intensity;
        specular* = intensity;

環境光
    統一加個參數,增加所有亮度
    更逼真的方案是:環境光遮蔽

環境光遮蔽(Ambient Occlusion)
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/09%20SSAO/
    它的原理是通過將褶皺、孔洞和非常靠近的牆面變暗的方法近似模擬出間接光照,這些區域很大程度上是被周圍的幾何體遮蔽的,光線會很難流失,所以這些地方看起來會更暗一些。
    可以模擬出陰影效果,讓場景更加逼真
    在2007年,Crytek公司發布了一款叫做屏幕空間環境光遮蔽(Screen-Space Ambient Occlusion, SSAO)的技術,並用在了他們的看家作孤島危機上。這一技術使用了屏幕空間場景的深度而不是真實的幾何體數據來確定遮蔽量。
    
  
----------------------------------------------
高級議題
----------------------------------------------
深度測試
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/01%20Depth%20testing/
    
模版測試
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/02%20Stencil%20testing/

半透明和混合
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/03%20Blending/    

面剔除(Face culling)
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/04%20Face%20culling/
    OpenGL允許檢查所有正面朝向(Front facing)觀察者的面,並渲染它們,而丟棄所有背面朝向(Back facing)的面。以增加性能。
    glEnable(GL_CULL_FACE);  // 所有的不是正面朝向的面都會被丟棄。
    glCullFace(GL_BACK);  // 也可以手工指定拋棄的面. 只剔除背面

幀緩沖 FBO
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/05%20Framebuffers/

實例化
    https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/10%20Instancing/
    共用模型,增加性能的方法。常用於渲染大量的同模型的物體,如隕石帶。
    實例渲染通常用來渲染草、草叢、粒子以及像這樣的場景


抗鋸齒
	Anti Aliasing
	https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/11%20Anti%20Aliasing/

陰影貼圖(shadow mapping)
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/03%20Shadows/01%20Shadow%20Mapping/
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/03%20Shadows/02%20Point%20Shadows/
    深度測試+柔化+。。。

HDR(高動態范圍 (High Dynamic Range)
    如多個光源疊加,色彩值會大於1.0,傳統做法是限制在1.0,但這樣會丟失細節
    HDR 高動態范圍的思路是,局部色彩值大於1.0,全屏依據比例調整色彩值到0-1.0間。以保留細節
    允許用更大范圍的顏色值渲染從而獲取大范圍的黑暗與明亮的場景細節,最后將所有HDR值轉換成在[0.0, 1.0]范圍的LDR(Low Dynamic Range,低動態范圍)。轉換HDR值到LDR值得過程叫做色調映射(Tone Mapping)

光暈,泛光(bloom)
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/07%20Bloom/    
    像平時那樣渲染一個有光場景,提取出場景的HDR顏色緩沖以及只有這個場景明亮區域可見的圖片。被提取的帶有亮度的圖片接着被模糊,結果被添加到HDR場景上面
    

延遲着色(Deferred Shading or Rendering)
    https://learnopengl-cn.github.io/05%20Advanced%20Lighting/08%20Deferred%20Shading/
    正向渲染(Forward Rendering): 在場景中我們根據所有光源照亮一個物體,之后再渲染下一個物體,以此類推
    延遲渲染(Deferred Rendering): 優化擁有大量光源的場景。
    原理看不懂。。。。反正用於適合渲染多光源到就是了。
    缺點:大內存開銷,沒有MSAA和混合(仍需要正向渲染的配合)。

基於物理的渲染(PBR Physically Based Rendering)
    https://learnopengl-cn.github.io/07%20PBR/01%20Theory/    
    就是非常逼真的模擬現實
    滿足以下三個條件
        基於微平面(Microfacet)的表面模型。
        能量守恆:出射光線的能量永遠不能超過入射光線的能量(發光面除外)
        應用基於物理的BRDF。
    一個逼真的金屬球體可能用到以下材質
        
        albedo     : 反射率。模擬銹
        normal     : 凹凸法線
        metallic   : 金屬質地
        roughness  : 粗糙質地
        ao         : 環境光遮蔽貼圖
    
----------------------------------------------
后期處理
----------------------------------------------
反色
    void main()
    {
        color = vec4(vec3(1.0 - texture(screenTexture, TexCoords)), 1.0);
    }


灰度
    void main()
    {
        color = texture(screenTexture, TexCoords);
        float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
        color = vec4(average, average, average, 1.0);
    }


銳化
    const float offset = 1.0 / 300;  
    void main()
    {
        vec2 offsets[9] = vec2[](
            vec2(-offset, offset),  // top-left
            vec2(0.0f,    offset),  // top-center
            vec2(offset,  offset),  // top-right
            vec2(-offset, 0.0f),    // center-left
            vec2(0.0f,    0.0f),    // center-center
            vec2(offset,  0.0f),    // center-right
            vec2(-offset, -offset), // bottom-left
            vec2(0.0f,    -offset), // bottom-center
            vec2(offset,  -offset)  // bottom-right
        );
    
        float kernel[9] = float[](
            -1, -1, -1,
            -1,  9, -1,
            -1, -1, -1
        );
    
        vec3 sampleTex[9];
        for(int i = 0; i < 9; i++)
        {
            sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i]));
        }
        vec3 col = vec3(0.0);
        for(int i = 0; i < 9; i++)
            col += sampleTex[i] * kernel[i];
    
        color = vec4(col, 1.0);
    }

模糊
    float kernel[9] = float[](
        1.0 / 16, 2.0 / 16, 1.0 / 16,
        2.0 / 16, 4.0 / 16, 2.0 / 16,
        1.0 / 16, 2.0 / 16, 1.0 / 16  
    );

邊緣檢測
    float kernel[9] = float[](
        1, 1, 1,
        1, -8, 1,
        1, 1, 1
    );
    


    
----------------------------------------------
幾何着色器(更改原有模型,如實現曲面效果/顯示法線)
----------------------------------------------
幾何着色器
    示例(
        #version 330 core
        layout (points) in;
        layout (triangle_strip, max_vertices = 5) out;
        void build_house(vec4 position)
        {
            gl_Position = position + vec4(-0.2f, -0.2f, 0.0f, 0.0f);// 1:左下角
            EmitVertex();
            gl_Position = position + vec4( 0.2f, -0.2f, 0.0f, 0.0f);// 2:右下角
            EmitVertex();
            gl_Position = position + vec4(-0.2f,  0.2f, 0.0f, 0.0f);// 3:左上
            EmitVertex();
            gl_Position = position + vec4( 0.2f,  0.2f, 0.0f, 0.0f);// 4:右上
            EmitVertex();
            gl_Position = position + vec4( 0.0f,  0.4f, 0.0f, 0.0f);// 5:屋頂
            EmitVertex();
            EndPrimitive();
        }
        void main()
        {
            build_house(gl_in[0].gl_Position);
        }

爆破物體
    把每個三角形沿着它們的法線向量移動一小段距離
    geometryShader
        https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/09%20Geometry%20Shader/
        #version 330 core
        layout (triangles) in;
        layout (triangle_strip, max_vertices = 3) out;
        in VS_OUT {
            vec2 texCoords;
        } gs_in[];
        out vec2 TexCoords;
        uniform float time;
        vec4 explode(vec4 position, vec3 normal)
        {
            float magnitude = 2.0f;
            vec3 direction = normal * ((sin(time) + 1.0f) / 2.0f) * magnitude;
            return position + vec4(direction, 0.0f);
        }
        vec3 GetNormal()
        {
           vec3 a = vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position);
           vec3 b = vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position);
           return normalize(cross(a, b));
        }
        void main() 
        {
            vec3 normal = GetNormal();
            gl_Position = explode(gl_in[0].gl_Position, normal);
            TexCoords = gs_in[0].texCoords;
            EmitVertex();
            gl_Position = explode(gl_in[1].gl_Position, normal);
            TexCoords = gs_in[1].texCoords;
            EmitVertex();
            gl_Position = explode(gl_in[2].gl_Position, normal);
            TexCoords = gs_in[2].texCoords;
            EmitVertex();
            EndPrimitive();
        }

顯示每個面的法線
    vertextShader
        #version 330 core
        layout (location = 0) in vec3 position;
        layout (location = 1) in vec3 normal;
        
        out VS_OUT {
            vec3 normal;
        } vs_out;
        
        uniform mat4 projection;
        uniform mat4 view;
        uniform mat4 model;
        
        void main()
        {
            gl_Position = projection * view * model * vec4(position, 1.0f);
            mat3 normalMatrix = mat3(transpose(inverse(view * model)));
            vs_out.normal = normalize(vec3(projection * vec4(normalMatrix * normal, 1.0)));
        }
    geometryShader    
        #version 330 core
        layout (triangles) in;
        layout (line_strip, max_vertices = 6) out;
        in VS_OUT {
            vec3 normal;
        } gs_in[];
        const float MAGNITUDE = 0.4f;
        void GenerateLine(int index)
        {
            gl_Position = gl_in[index].gl_Position;
            EmitVertex();
            gl_Position = gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0f) * MAGNITUDE;
            EmitVertex();
            EndPrimitive();
        }
        void main()
        {
            GenerateLine(0); // First vertex normal
            GenerateLine(1); // Second vertex normal
            GenerateLine(2); // Third vertex normal
        }

----------------------------------------------
調試工具
----------------------------------------------
https://learnopengl-cn.github.io/06%20In%20Practice/01%20Debugging/

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM