学习教程(七) 第一篇了解了OpenGL中是如何模拟光照的,后面三篇中简单学习了 Ambient Light(环境光照)、Diffuse Lighting(漫反射光照)、Specular Lighting(镜面高光) 。然后我们可以做一些简单的光照效果,比如不同的高光效果: 文章转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
但是这个东西是学习的一个例子,和自然世界中的光照效果相比,还是有很大的差距的。即使上面的图中看起来是光照在一块方砖上的效果,但是和真正的砖也是有差别的。
文章转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
比如一辆跑车,车身上抛光打蜡,很容易就反光发亮,但是轮胎是不容易发亮的。
所以我们要给不同的物体 ,赋予不同的效果,通过使用三种光照元素定义一个材质颜色,为每个元素指定一个颜色,来对物体的颜色输出进行精密控制。
在Fragment Shader 中,我们定义一个 Struct Material (GLProgram_Cube.h Line:102)
struct Material //替换顶点色 { vec3 ambient; vec3 diffuse; vec3 specular; float shininess; }; uniform Material m_material;
ambient 描述环境光照下这个物体反射的是什么颜色,通常和物体颜色相同。
diffuse 描述漫反射光照下物体的颜色,漫反射颜色被设置为和环境光一样,设置为物体的颜色。
specular 描述的是物体受到的镜面光照的影响的颜色。
shininess 影响镜面高光的散射半径。
通过调整不同的光照颜色向量,我们就能模拟不同的材质。
下面来实现这样一个简单的材质系统。
我们已经在 Fragment Shader 中添加了一个 uniform 材质结构体,然后就要修改 Fragment Shader 的代码。(GLProgram_Cube.h Line 90)
void main() { vec3 ambient=m_material.ambient*m_lightcolor;//环境光; 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_material.diffuse) * m_lightcolor; //漫反射光 vec3 cameraDir=normalize(m_camerapos-out_fragpos); //计算顶点片段指向观察者的向量 vec3 reflectDir=reflect(-lightdir,normal); //计算光的反射 R reflect第一个参数是光源指向片段的向量,所以这里使用 -lightdir float spec=pow(max(dot(cameraDir,reflectDir),0.0),m_material.shininess); //计算镜面亮度,32是高光的发光值 Shininess,发光值越高,反射光越强,散射越小,高光点越集中。 vec3 specular=(spec * m_material.specular) * m_lightcolor; vec3 result=ambient +diffuse+specular; //(环境光+漫反射光) * 物体本身的颜色 gl_FragColor=vec4(result,1.0); }
设置三种光照颜色 (MyApp.h Line 95)文章转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
//传入Material glUniform3f(m_programCube.m_matAmbient, 1.0f, 0.5f, 0.31f); //环境光颜色 glUniform3f(m_programCube.m_matDiffuse, 1.0f, 0.5f, 0.31f); //漫反射颜色 glUniform3f(m_programCube.m_matSpecular, 0.5f, 0.5f, 0.5f); //高光颜色 glUniform1f(m_programCube.m_matShininess, 32.0f); //聚光值
运行程序,得到下面的结果
文章转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
看起来是没什么问题,物体是亮着的,说明 Ambient Lighting 生效。背面比正面暗,说明 Diffuse Lighting 生效。也看到了白色的高光,说明 Specular Lighting生效。
但是对比之前的效果,这个图太亮了。
从代码逻辑上来说,缺少了 光照强度控制。
于是我们再定义一个 Struct Light (GLProgram_Cube.h Line 111)
struct Light //替换光的RGB分量强度 { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform Light m_light;
例如我们设置 Ambient Lighting 值小一点,环境光的影响就少一点,就不那么亮。(MyApp.h Line 101)
//传入light; glUniform3f(m_programCube.m_lightpos, 1.0f, 0.0f, 5.0f);//传入灯光的位置 glUniform3f(m_programCube.m_lightAmbient, 0.2f, 0.2f, 0.2f); glUniform3f(m_programCube.m_lightDiffuse, 0.5f, 0.5f, 0.5f); glUniform3f(m_programCube.m_lightSpecular, 1.0f, 1.0f, 1.0f);
文章转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
如果调整一下 Material 中 Ambient Lighting 分量的值,设置为 (MyApp.h Line 96)
glUniform3f(m_programCube.m_matAmbient, 1.0f, 0.0f, 0.0f);
glUniform3f(m_programCube.m_lightAmbient, 1.0f, 1.0f, 1.0f);
现在可以很方便的调整 Material 效果了,而且能精确的模拟自然效果,因为 三种光照都是可控的。
文章转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
示例工程下载:
http://pan.baidu.com/s/1dDQb69b