OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照

物有两面,即使前面有一盏灯,也照不透背后。

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第1张图片

就如同天使,华丽耀眼的天使之翼,却不能将光芒照射到阴暗的脸庞。只因为光在后面,而我在前面。


从上一节对 Ambient Light  的学习来看,如果天使周围存在着较强的环境光,那我们应该能看清楚天使的脸庞,应为 Ambient Light 照亮了每个方向。

但是天使周围没有 Ambient Light,而是存在着 Diffuse Light,只能照亮 面对光 的那一面的 漫反射光照。


这一节我们来看 Diffuse Lighting 漫反射光照。

Diffuse Light 漫反射光照 只能照亮 面对光 的那一面

就如同上面的天使。

再例如下面的石柱,面向光的一侧被照的发亮,背面就只有环境光,只能看到较暗的表面。


Diffuse Lighting 漫反射光照的数学原理

光照的方向(顶点指向灯泡的向量) 和 表面法线会有一个角度,根据自然现象,这个角度越大,光照越弱,角度越小,光照越强。

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第2张图片


在前面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;"

然后在 Fragment Shader 片段着色器中,首先计算出 片段位置 指向 灯泡位置的向量A,然后向量A 和 法线向量 N 做点乘运算计算 得到结果 cosvalue 。然后再乘以 lightcolor,就得到了 Diffuse Light 值。(GLProgram_Cube.h Line 80)

"	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;"  //漫反射光

我们要从代码中给 lightpos  和 normal 赋值。(MyApp.h Line 78)

//传入法线数据
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]);

执行上面这些步骤后,运行得到下面的效果

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第3张图片


再把环境光加上 (GLProgram_Cube.h Line 89)

"	vec3 result=(ambient+diffuse) * m_color;" //(环境光+漫反射光) * 物体本身的颜色 

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第4张图片


看起来不错,差不多就是我们要的。面对灯光的一面被照亮了,背对灯光的一面是灰暗的。


但是如果旋转一下立方体

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第5张图片

这就不正常了,立方体上面一块还是灰暗的,亮的那一面还是亮的!!

这就是说旋转立方体居然没有改变物体 光照情况!!


这也是最重要的一点。

法线!!

物体旋转了,但是法线仍然是原来的法线。漫反射光照强度只和法线有关。法线不变,光照当然不变。


我们也要把 法线 转换到世界坐标中参与计算。

法线转换到世界坐标,是通过 叉乘 模型矩阵的逆矩阵的转置矩阵 。( MyApp.h Line 89 )

//传入模型矩阵的逆矩阵的转置,用于计算法线向量的世界坐标;
glm::mat4 modelofnormal = glm::transpose( glm::inverse(model));
glUniformMatrix4fv(m_programCube.m_modelofnormal, 1, false, &modelofnormal[0][0]);

然后 通过强转 3维矩阵 去掉 w 分量。( GLProgram_Cube.h Line 62 )

"	out_normal=mat3( m_modelofnormal) * m_normal ;"

最终效果

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第6张图片

旋转一下也没问题

OpenGL ES 学习教程(七) 物有两面,即使前面有一盏灯,也照不透背后。解析Diffuse Lighting 漫反射光照_第7张图片


示例工程下载:

http://pan.baidu.com/s/1kUcGobP


你可能感兴趣的:(OpenGL,es,光照,漫反射,环境光)