---------------------------------------------- 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/