【Unity Shader】标准光照模型总结

逐顶点与逐像素光照
逐顶点光照[per-vertex lighting] [vertex shader]
在每一个顶点上计算光照,而后会在渲染图元内部进行线性插值,最后输出成像素颜色,因为顶点数目每每远小于像素数目,所以逐顶点光照的计算量每每要小于逐像素光照。
逐像素光照[per-pixel lighting][fragment shader]
以每一个像素为基础,获得它的法线(能够是对顶点法线插值获得的,也能够是从法线纹理中采样获得的),而后进行光照模型的计算。这种在面片之间对顶点法线进行插值的技术被称为Phong 着色(Phong shading)。.net

左侧逐像素光照,右侧为逐顶点光照。能够看到逐顶点光照的缺点:被光面与向光面交界处有锯齿。code

逐顶点光照与逐像素光照间的区别:
candycat:
1.因为逐顶点光照依赖于线性插值来获得像素光照,所以,当光照模型中有非线性的计算(例如计算高光反射时),逐顶点光照就会出问题。
2.因为逐顶点光照会在渲染图元内部对顶点颜色进行插值,这会致使渲染图元内部的颜色老是暗于顶点处的最高颜色值,这在某些状况下会产生明显的棱角现象。
puppet_master:
为何逐像素计算会获得更好的效果,由于咱们逐像素取的光照的方向是一致的,法线方向也是经过上一步的vertex shader传递过来的,若是像素和顶点对应了的话,那不是每一个像素的计算结果都会同样呢?然而,其实像素和顶点是不对应的,这个就是传说中的渲染流水线了,在顶点阶段计算的结果,并非直接传递给像素着色器的,而是通过了一系列的插值计算,咱们从vertex shader传递过来的法线方向,只表明了这一个顶点的顶点法线方向,而到了pixel阶段,这个像素所对应的法线等参数至关于其周围几个顶点进行插值后的结果。咱们用这一个像素点对应的法线方向与光照方向进行计算,就能够得到该像素点在光照条件下的颜色值,而不是先计算好颜色再插值获得结果。
coffeecato:这也就解释了为何法线在vert不能进行归一化orm

v2f vert(a2v v)
{
    //把法线转化到世界空间
    //o.worldNormal = mul(v.normal, (float3x3)_World2Object);
    o.worldNormal = UnityObjectToWorldNormal(v.normal);
}

fixed4 frag(v2f i) : SV_Target
{
    //归一化法线,即便在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并非vertex shader直接传出的
    fixed3 worldNormal = normalize(i.worldNormal);
}


高光贴图的由来blog

左侧为Blinn-Phong光照模型,能够看出Blinn-Phong光照模型的高光反射部分看起来更大、更亮一些。游戏

puppet_master:
现实世界中漫反射和镜面反射是共存的,拿一把刀来讲,刀身是金属,刀柄是木头,那么,只有刀身适合这种类型的shader。可能咱们最简单的想法是把刀拆成两个部分,刀身用的是Specular,刀柄用Diffuse;可是这种作法很麻烦,并且一个物体经过了两个drall call才能渲染出来。因此,聪明的前辈们老是能想到好的办法,次时代类型游戏中最简单的一种贴图就诞生了---高光贴图(通道)。
所谓高光贴图,或者说成高光通道,就是经过在制做贴图时,把图片的高光信息存储在一个灰度图或者直接存储在贴图的通道内,若是不须要Alpha Test的话,能够直接把高光通道放在Diffuse贴图的Alpha通道。而咱们在shader中计算时,经过采样,就能够得到这个贴图中每一个像素对应的位置是不是有高光的。这样,在Fragment Shader中能够直接经过这个Mask值乘以高光从而经过一个材质渲染出同一个模型上的不一样质地。好比在通道内,0表示无高光,1(255)表示高光最强,那么,不须要高光的地方咱们就能够在制做这张图的时候给0,须要高光的,刷上颜色,颜色越接近白色,高光越强。
candycat:
高光贴图实际上是一种遮罩纹理(mask texture),遮罩容许咱们保护某区域,使他们免于修改或者加强(减弱)。使用遮罩纹理的流程通常是:经过采样获得遮罩纹理的纹素值,而后使用其中某个(或某几个)通道的值来与某种表面属性进行相乘。
 图片

环境光对模型的影响
puppet_master:
可是在实时图形学,咱们大部分状况是经过一个环境光(Ambient Light)统一表明了间接光,这样,即便在没有光的时候,咱们也能够看见物体。
https://blog.csdn.net/puppet_master/article/details/53074789
candycat:
大多数物体是没有自发光特性的,所以在本书绝大部分的shader中都没有计算自发光部分。若是要计算自发光,只需在片元着色器输出最后的颜色以前,把材质的自发光颜色添加到输出颜色上便可。
coffeecato:
frag返回最终颜色时,若是去掉ambient(环境光)关掉灯光模型会变成黑色get

fixed3 color = diffuse + ambient + specular;        // 关闭灯光 模型不会变黑
fixed3 color = diffuse + specular;                  // 关闭灯光 模型会变黑

本文截图的全部代码均可以从参考资中找到,puppet_master是位作图形的同窗,他的文章很适合入门,推荐关注。it

参考资料:入门

《Unity Shader入门精要》ast

Unity Shader-兰伯特光照模型与Diffuse Shader

Unity Shader-Phong光照模型与Specular