Unity光照模型


(1)兰伯特光照模型:

            兰伯特光照模型是目前最简单通用的模拟漫反射的光照模型,定义如下:模型表面的明亮度直接取决于光线向量(light vector)和表面法线(normal)两个向量将夹角的余弦值。光线向量是指这个点到光从哪个方向射入,表面法线则定义了这个表面的朝向。
        如果漫反射光强设置为Diffuse,入射光光强为I,光方向和法线夹角为θ,那么兰伯特光照模型可以用下面的公式表示:        Diffuse = I * cosθ。进一步地,我们可以通过点乘来求得两个方向向量之间的夹角,入射光方向设置为L,法线方向设置为N,如果光方向向量和法线方向向量都为单位向量(这就是为什么我们在写shader的时候需要normalize操作的原因),那么它们之间的夹角余弦值就可以表示为:cosθ = dot(L,N),最终漫反射光强公式,也就是兰伯特光照模型可以表示为:
       Diffuse = I  * dot(L,N)

逐顶点:
逐像素:

        为什么逐像素计算会得到更好的效果,因为我们逐像素取的光照的方向是一致的,法线方向也是通过上一步的vertex shader传递过来的,如果像素和顶点对应了的话,那不是每个像素的计算结果都会一样呢?然而,其实像素和顶点是不对应的,这个就是传说中的渲染流水线了,在顶点阶段计算的结果,并不是直接传递给像素着色器的,而是经过了一系列的插值计算,我们从vertex shader传递过来的法线方向,只代表了这一个顶点的顶点法线方向,而到了pixel阶段,这个像素所对应的法线等参数相当于其周围几个顶点进行插值后的结果。我们用这一个像素点对应的法线方向与光照方向进行计算,就可以获得该像素点在光照条件下的颜色值,而不是先计算好颜色再插值得到结果。

(2)半兰伯特光照模型

        上面的shader计算光照的时候,我们计算法线方向和光方向的点乘值时,得到的结果有可能是负数,而兰伯特光照模型对于该情况的处理是,dot值为负数,说明该点不会受到光的照射,所以对于该光源,该点无光,直接使用max(0,diffuse)来将不应该受光的位置全都置为黑色。
        兰伯特光照出来的时候,貌似还没有这么高科技的技术,所以呢,有人就想到了一个取巧的技术(据说是《半条命》),既保证了兰伯特模型计算出来的光照结果大于0,又整体提升了亮度,使非直接受光面不是单纯的置为黑色。这是一个在图形学领域经常有的变换,区间转化,从(-1,1)转化到(0,1),如果不考虑无意义的负值,也可以说成从(0,1)转化到了(0.5,1)。方法很简单,乘以0.5再加上0.5。这样,原本亮度为1的地方,乘以0.5变成了0.5,加上0.5就又成了1,而原本光照强度为0的地方,就变成了0.5,原本为负数的地方,也能保证为大于0了

(3)Phong光照模型

Phong光照模型中主要的部分就是对高光的计算,首先来看下面这张图片:
        理想情况下,光源射出的光线,通过镜面反射,正好在反射光方向观察,观察者可以接受到的反射光最多,那么观察者与反射方向之间的夹角就决定了能够观察到高光的多少。夹角越大,高光越小,夹角越小,高光越大。而另一个影响高光大小的因素是表面的光滑程度,表面越光滑,高光越强,表面月粗糙,高光越弱。L代表光源方向,N代表顶点法线方向,V代表观察者方向,R代表反射光方向。首先需要计算反射光的方向R,反射光方向R可以通过入射光方向和法向量求出,R + L = 2dot(N,L)N,进而推出R = 2dot(N,L)N - L。关于R计算的推导,可以看下面这张图:
        下面给出冯氏反射模型公式: I(spcular) = I * k * pow(max(0,dot(R,V)), gloss) ,其中I为入射光颜色向量,k为镜面反射系数,gloss为光滑程度。 通过上面的公式,我们可以看出,镜面反射强度跟反射向量与观察向量的余弦值呈指数关系,指数为gloss,该系数反映了物体表面的光滑程度,该值越大,表示物体越光滑,反射光越集中,当偏离反射方向时,光线衰减程度越大,只有当视线方向与反射光方向非常接近时才能看到高光现象,镜面反射光形成的光斑较亮并且较小;该值越小,表示物体越粗糙,反射光越分散,可以观察到光斑的区域越广,光斑大并且强度较弱

(4)Blinn-Phong光照模型


        Blinn-Phong光照引入了一个概念,半角向量,用H表示。半角向量计算简单,通过将光源方向L和视线方向V相加后归一化即可得到半角向量。Phong光照是比较反射方向R和视线方向V之间的夹角,而Blinn-Phong改为比较半角向量H和法线方向N之间的夹角。半角向量的计算复杂程度要比计算反射光线简单得多,所以Blinn-Phong的性能要高得多,效果比Phong光照相差不多,所以OpenGL中固定管线的光照模型就是Blinn-Phong光照模型。BlinnPhong光照模型如下: I(spcular) = I * k * pow(max(0,dot(N,H)), gloss) ,其中I为入射光颜色向量,k为镜面反射系数,gloss为光滑程度。
(5)应用
应用:一张贴图(刀,其余衣服等贴图)实现,刀的部分高光,其余部分漫反射
        拿一把刀来说,刀身是金属,刀柄是木头,那么,只有刀身适合这种类型的shader。可能我们最简单的想法是把刀拆成两个部分,刀身用的是Specular,刀柄用Diffuse;但是这种做法很麻烦,而且一个物体通过了两个drall call才能渲染出来。所以,聪明的前辈们总是能想到好的办法,次时代类型游戏中最简单的一种贴图就诞生了---高光贴图(通道)。

        所谓高光贴图,或者说成高光通道,就是通过在制作贴图时,把图片的高光信息存储在一个灰度图或者直接存储在贴图的通道内,如果不需要Alpha Test的话,可以直接把高光通道放在Diffuse贴图的Alpha通道。而我们在shader中计算时,通过采样,就可以获得这个贴图中每个像素对应的位置是否是有高光的。这样,在Fragment Shader中可以直接通过这个Mask值乘以高光从而通过一个材质渲染出同一个模型上的不同质地。比如在通道内,0表示无高光,1(255)表示高光最强,那么,不需要高光的地方我们就可以在制作这张图的时候给0,需要高光的,刷上颜色,颜色越接近白色,高光越强。知道了原理之后,我们就可以找一个人物模型贴图,然后在PhotoShop中给RGB格式的贴图增加一个通道,作为高光通道,然后把需要高光的部分抠出来,其他部分置为黑色











































猜你喜欢

转载自blog.csdn.net/qq_37089020/article/details/79943226