从光照开始,我都会把每一次的学习内容都记录下来,不然的话,太久了真的会容易忘记的>_<
Color
这一章简单定义了在OpenGL中颜色是如何mix的,现在有个例子,一个太阳光打在一个红色的物体上,那么我们会看到物体是红色的(废话)。一个物体是红色的,是因为他会吸收除了红色之外的颜色,剩下的光再到我们的眼睛中时就是红色的了。
太阳光vec3(1.0f ,1.0f ,1.0f)*红色物体 vec3(1.0f ,0.0f ,0.0f)=(1.0f , 0.0f, 0.0f )
很合理对吧,
这也就是之后的基础了,一个光打在物体上,反射的颜色是 光颜色和物体颜色的乘。
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 ambientColor;
void main()
{
FragColor = vec4(ambientColor * objectColor, 1.0);
}
这里给了个简单的fragmentshader,里面定义了uniform的物体颜色和光颜色,相乘就行。
glUniform3f(glGetUniformLocation(testShader->ID, "objColor"), 1.0f, 0.5f, 0.31f);
glUniform3f(glGetUniformLocation(testShader->ID, "ambientColor"), 1.0f, 1.0f, 1.0f);
然后在主程序中修改uniform后看看结果
然后把材质也加上
FragColor = vec4(objColor * ambientColor , 1.0f)*mix(texture(ourTexture,TexCoord),texture(ourFace,TexCoord),mixValue);
得到
Basic Lighting
ok,首先最最重要的就是phong模型,这是一种经验模型,但是非常常用而且实用。
phong Model中包含3部分,环境光ambient,漫反射diffuse,高光specular
环境光ambient的处理最简单,直接把ambientColor与objColor相乘就好。
漫反射diffuse 需要两个参数,1.法向量,2.光线的方向,然后将这两个点乘就好,但是需要注意的是点乘之前一定要normalize!!!
那么,点乘得到的是一个标量,用这个标量与光颜色相乘就能得到漫反射颜色。
vec3 lightDir = normalize( lightPos - FragPos );
vec3 diffuse = max(dot(lightDir,Normal),0) * lightColor ;//漫反射量
FragColor = vec4( ambientColor*objColor + diffuse *objColor, 1.0f);
ok,可以注意到的是这里有个max。可以想象一个画面,一束光如果和平面法向量夹角大于90度,那么就代表没有打到这个平面,也就是这个时候光的作用为0.max的目的就是这个,如果两个向量角度大于90度,点乘得到的是负数,那么就消除它。
镜面反射/高光反射 specular
我们经常会看到一个在灯下的物体上有一块圆型的光斑,这个就是高光。那么,我们什么时候,又或者说什么角度可以看到高光。上面这幅图可以告诉我们,当我们人眼与灯的那个夹角的中位线刚刚好就是法向量的时候,我们就能看到高光,偏了就会减弱。(可以自己想象一下)
所以,我们计算高光项就是基于此,一般来说,判断法向量是中位线 会比 判断人眼方向是反射方向 要好判断的多。 (因为 我有 lightDir 和 eyeDir,直接把两个向量相加然后除以2就可以了),之后的偏离多少就交给dot点乘就好了。
这里的代码还是跟着教程来,可以通过reflect()函数得到橘色向量,然后dot就好。
这里可以看到出现了pow(),后面的32表示的是反光度,反光度越高,就代表高光点越集中。
vec3 reflectVec = reflect( -lightDir,Normal);
vec3 cameraDir = normalize(cameraPos - FragPos );
vec3 specular = pow(max(dot(reflectVec,cameraDir),0),32)*lightColor;
一个比较重要的事情
zzai在vertexShader中,我们有两个参数需要传递给fragmentShader,一个是顶点位置,一个是法向量。
顶点位置需要乘上Model变换转变成世界空间中的位置,但是法向量不能直接乘。
只需要进行处理才可以。
这里看到存在求逆的过程,这个过程是在计算机中尽量避免的。所以在后面会通过法线矩阵来实现。
练习
1.尝试使用sin或cos函数让光源在场景中来回移动。观察光照随时间的改变能让你更容易理解冯氏光照模型。
glUniform3f(glGetUniformLocation(testShader->ID, "lightPos"), 20.0f * cos(glfwGetTime()), 10.0f, 20.0f * sin(glfwGetTime()));
把main中的lightPos中x,z改了就行。这样就是一个高度10,半径20的一个轨迹在运动的光。
2.在观察空间(而不是世界空间)中计算冯氏光照
3.尝试实现一个Gouraud着色(而不是冯氏着色)