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