序:今天开始主要写写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);