物有两面,即使前面有一盏灯,也照不透背后。
就如同天使,华丽耀眼的天使之翼,却不能将光芒照射到阴暗的脸庞。只因为光在后面,而我在前面。
从上一节对 Ambient Light 的学习来看,如果天使周围存在着较强的环境光,那我们应该能看清楚天使的脸庞,应为 Ambient Light 照亮了每个方向。
但是天使周围没有 Ambient Light,而是存在着 Diffuse Light,只能照亮 面对光 的那一面的 漫反射光照。
这一节我们来看 Diffuse Lighting 漫反射光照。
Diffuse Light 漫反射光照 只能照亮 面对光 的那一面
就如同上面的天使。
再例如下面的石柱,面向光的一侧被照的发亮,背面就只有环境光,只能看到较暗的表面。
Diffuse Lighting 漫反射光照的数学原理
光照的方向(顶点指向灯泡的向量) 和 表面法线会有一个角度,根据自然现象,这个角度越大,光照越弱,角度越小,光照越强。
在前面Ambient Light 工程的基础上,我们还需要以下变量:
1、法线
2、灯泡位置
在代码中添加以上变量 ,分别为 normal 、lightpos
首先在 Fragment Shader中加入 (GLProgram_Cube.h Line 73)
"uniform vec3 m_lightpos;"
因为我们是在 Fragment Shader中进行 光照 和 法线 向量点乘计算的,所以需要把 顶点位置 从Vertex Shader中传入到 Fragment Shader中。
在Vertex Shader 中增加 varing 变量(GLProgram_Cube.h Line 56)
"varying vec3 out_fragpos;"
因为我们是在世界坐标进行光照计算的,所以需要计算片段的世界坐标,于是要用 顶点位置 乘以 模型矩阵(GLProgram_Cube.h Line 63)
"out_fragpos=vec3(m_model*vec4(m_position,1));"
在Fragment Shader增加 varying 变量 (GLProgram_Cube.h Line 75)
"varying vec3 out_normal;" "varying vec3 out_fragpos;"
" vec3 normal=normalize(out_normal);" //法线向量 A " vec3 lightdir=normalize(m_lightpos-out_fragpos);" //物体指向灯光 向量 B " float cosvalue=max( dot(normal,lightdir),0.0);" //点乘A B 计算角度cos值,角度越大 cos越小,90度的时候法线和光垂直,最小值。 " vec3 diffuse=cosvalue * m_lightcolor;" //漫反射光
//传入法线数据 glVertexAttribPointer(m_programCube.m_normal, 3, GL_FLOAT, false, sizeof(glm::vec3), normal); glUniform3f(m_programCube.m_lightcolor, 1.0f, 1.0f, 1.0f); //传入灯光的位置 glUniform3f(m_programCube.m_lightpos, 3.0f, 1.0f, 0.0f); //传入模型矩阵 glUniformMatrix4fv(m_programCube.m_model, 1, false, &model[0][0]);
再把环境光加上 (GLProgram_Cube.h Line 89)
" vec3 result=(ambient+diffuse) * m_color;" //(环境光+漫反射光) * 物体本身的颜色
看起来不错,差不多就是我们要的。面对灯光的一面被照亮了,背对灯光的一面是灰暗的。
但是如果旋转一下立方体
这就不正常了,立方体上面一块还是灰暗的,亮的那一面还是亮的!!
这就是说旋转立方体居然没有改变物体 光照情况!!
这也是最重要的一点。
法线!!
物体旋转了,但是法线仍然是原来的法线。漫反射光照强度只和法线有关。法线不变,光照当然不变。
我们也要把 法线 转换到世界坐标中参与计算。
法线转换到世界坐标,是通过 叉乘 模型矩阵的逆矩阵的转置矩阵 。( MyApp.h Line 89 )
//传入模型矩阵的逆矩阵的转置,用于计算法线向量的世界坐标; glm::mat4 modelofnormal = glm::transpose( glm::inverse(model)); glUniformMatrix4fv(m_programCube.m_modelofnormal, 1, false, &modelofnormal[0][0]);
" out_normal=mat3( m_modelofnormal) * m_normal ;"
旋转一下也没问题
示例工程下载:
http://pan.baidu.com/s/1kUcGobP