OpenGLES入门笔记 :OpenGLES光照基础总结1

时间:2022-09-10 17:19:34

背景

最近开始入门OpenGLES,学习光照相关的知识。其中遇到不少问题,走了不少弯路,下面简要总结一下最近的问题以及自己的一些认识,有不正确的地方希望大家指正。

光照的原理

首先说明的一点是这里我们主要讨论OpenGLES2.0下的光照。

学习光照之前,我们已经做过一些场景,虽然这其中并没有涉及到光的概念,但是我们依然能看到带颜色物体,以及各种图片纹理。所以可以确定的是,没有光照我们依然能看到东西,而不是漆黑一片,我们可以直接看到物体本身的颜色以及其纹理。

我们要添加的光照,在我理解就是在物体本身的颜色上进行一些调制,使其看起来给人感觉是有光照射一样。这些调制包括成比例地缩放颜色值,或者在本身颜色值的基础上进行加减

环境光

试想,如果我们要使一个场景整个变暗下来,那么我们必须让场景的颜色值都减小,相反如果需要变亮,那么我们就应该让颜色值增大。我们说的环境光(Ambient)就是起到这种作用。这种光作用在所有物体上,对物体产生的光照作用也是一样的。

方向光与反射

方向光,顾名思义,带方向的平行光。对于空间中的物体,每个面与光的角度不同,在我们看起来亮暗也是不一样的,每个面的反光程度不同,亮暗也有区别。对于方向光(包括其他光)引起的这种效果,我们分别用漫反射(diffuse)镜面反射(diffuse)来表现。

漫反射

对于漫反射,直观上讲,如果一个面不是正对光线,那么我们看起来会稍微暗一些。那么应该暗多少呢,这就要看这个面与光线的夹角了,如果正对光线,那么光就都会投射到这个面上,如果角度比较小,那么这个面上所接受的光就会减少。

OpenGLES入门笔记 :OpenGLES光照基础总结1

如上图所示,平行的光照在一个斜面上,如果∠2为0°,那么这个面都可以接受到所有的光。如果∠2为锐角,则这个面上接受的光只有全部光的一部分。具体算一下就相当于 完全照射的光 x COS∠2。也就相当于斜面总长度与红线长度的比例关系。而COS∠2的值就是单位法向量与单位光向量的点积,着色器代码如下

float diffuse = max(0.0,dot(vDirctionNormal, uLightDirection));

diffuse 就是这个方向的余弦值,这个值与当前颜色值的乘积就是漫反射的亮度值。

镜面反射

搞明白了漫反射,我们再来看一下镜面反射,相比漫反射,镜面反射给我们直观的感受是晃眼的感觉,也就是某个方向看这个表面,超级亮,眼睛越接近这个方向,表现的越亮,越偏离,则会越暗。

OpenGLES入门笔记 :OpenGLES光照基础总结1
这里我们可以通过与计算漫反射同样的方法计算漫反射平面的基本亮度。不同之处在于,根据我们所在的角度不同,得到的反射光强度是不同的。
如图,假设A光为镜面反射光,如果眼睛正好在A的方向上,那么会感觉特别亮。
但是如果此时眼睛在B方向上,那么就会感觉暗很多,所以此处我们需要增加一个衰减值,凡是不在A方向上看的统统衰减,与A偏差越大,光亮衰减越厉害。
以下是着色器代码:

float specular = max(0.0,dot(vDirctionNormal, uHalfVector));
if(diffuse == 0.0) 
    specular = 0.0;
else 
    specular = pow(specular, uShininess);

uHalfVector为观察方向的向量,也就是A方向或B方向这种的。如果specular较小,说明与A方向偏差较大,那么我们给它一个衰减系数uShininess,让它使劲减小。这就体现出了如果不在反射方向上看,镜面反射并不明显,一旦眼睛对准反射方向,立刻会变得很刺眼。

合成光照

最后,需要把这些光合体,用来调制物体获取光照后的颜色

vec3 scatteredLight = uAmbient.rgb + uLightColor * diffuse;
vec3 reflectedLight = uLightColor * specular * uStrength;
vec3 rgb = min(gl_FragColor.rgb * scatteredLight + reflectedLight, vec3(1.0));

这样我们就获得了叠加光照后的最终的颜色。

遇到的一些问题

1.关于GL版本问题
GL1.0使用的是渲染管线,而GL2.0变成了编写着色器。如果在GL1.0中我们可以使能GL_LIGHTING,使能后如果不加入光源整个场景是黑的。我们可以使用系统预定义的几个光源。
如果我们开启了GL2的模式,那么GL_LIGHTING是不生效的,我们需要把光照相关的计算写入着色器中。
2.关于黑色像素较多的纹理图
在为黑色像素较多的图添加环境光时,如果直接使用rgb值乘以环境光参数,我们会发现场景并没有变量,但是对比度似乎有所增加。这是由于黑色图可能有很多像素值是0,这样的话不管乘以什么系数最终结果都是0,此时我们可以在得到纹理图时为整体增加一个小的基数,这样再进行运算就不会发生黑色点不变的问题了。

texture2D(sTexture, vTextureCoord).rgba + vec4(0.02, 0.02, 0.02, 0)), vec4(1.0)