#pragma multi_compile_fwdbase
来源:互联网 发布:淘宝朋友代付退款 编辑:程序博客网 时间:2024/05/29 19:17
ForwardBase
- 1
- 1
告诉渲染管线,这个pass作为ForwardBase处理,缺少它将画不出任何东西。
- 1
- 1
unity官方文档,只有multi_compile的说明,对于multi_compile_fwdbase可谓只字未提,网上唯一能搜到的一篇也是一语带过(虽然不甚详细,但是非常感谢作者分享)。后来打开unity shader面板的Variants里看到:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
很多看过unity生成的vertex/fragment代码的同学,会感到很困惑,代码里充斥着各种条件编译代码,然而unity也没有给出文档,到底有哪些keyword?各自的作用是什么?
看到这个就非常清楚了,unity为forwardbase pass定义的keyword都在这里,而multi_compile_fwdbase就是unity专门为forwardbase预定义的multi_compile。
如果再打开unity最终编译成的glsl代码的话,可以看到,unity为每一组keywards都生成了单独的代码。
如果缺少这行代码的话,那么unity默认会编译
- 1
- 1
这一组条件,碰到其他的情况,那么渲染就会出错。
我们看到,上述每一组条件,都是DIRECTIONAL,那么如果场景中没有平行光呢?点光源或者聚光灯还会起作用么?
答案是不会。forwardbase pass只能以逐像素的方式处理平行光,点光源和聚光灯都会被忽略掉,对应的_LightColor0都将是黑色。注意上面黑体的逐像素,因为可能有人会说,我场景里只有一个点光源,可以把场景照亮。是的,但它是以逐顶点的方式照亮的,后面将会细说。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
unity定义了v2f结构,有无lightmap的两个版本。
- 1
- 1
这个定义在AutoLight.cginc中,它定义了光照和阴影坐标。因为forwardbase只支持平行光,因为平行光的特性,受到的光照强度是一样的,所以并不需要光照坐标,如果投射阴影的话,只需要阴影坐标来采样shadow map。(稍后再forwardadd章节中,会详细讨论不同光源的光照计算)
现在只要知道,这个宏的定义类似如下所示。参数3,4就是下个可用的TEXCOORD序号。
- 1
- 1
接下去就是填充v2f结构,计算齐次空间坐标,uv坐标,normal或者lightmap的uv坐标。就如我们平时写vertex/fragment shader那样,就不累述了。
- 1
- 1
这里是计算球谐光照,没有作为像素光照和顶点光照处理的光源,都在这里计算,包括light probe。
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
这里计算顶点光照,unity只能处理4个顶点光源。unity在上层处理掉了很多东西。如果光源影响到该物体,那么光源的属性(位置,原色,衰减)都会被设置,反之则会直接被忽略。具体计算过程在UnityCG.cginc中,如下所示:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
可以看到,顶点光照就是用简单的Lambert光照方程。
- 1
- 2
- 1
- 2
需要注意的是,因为法向量是归一化的,而光源方向未归一化,所以要乘以顶点离光源距离的平方根的倒数,得到光源和法线夹角的余弦。
lightAttenSq这个值也是由unity设定的,平行光恒为1,点光源和聚光灯随着距离增大而递减。
- 1
- 1
这个的定义也是在AutoLight.cginc中,它计算之前定义的光照和阴影坐标的值。
点光源宏的定义如下:
- 1
- 1
实际就是把顶点坐标转换到光源空间中。
- 1
- 1
这个也是定义在AutoLight.cginc中,它就是把之前得到的光照和阴影坐标,采样光照图和shadow map,来得出光源的最终衰减值。
点光源的宏定义如下:
- 1
- 1
那么这里的_LightTexture0又是什么?在哪里设置的?别急,在forwardadd章节会讲到,这里对这个宏定义的作用有个认识就可以了。
- 1
- 1
unity定义的光照方程都在Lighting.cginc这个文件中,需要注意的是,因为forwarbase只支持平行光,而如果光源类型是平行光,那么_WorldSpaceLightPos0这个变量保存的直接是光源方向。所以这里直接作为第二个参数,传入光照方程。当然也可以定义自己的光照方程,具体戳这里。
ForwardAdd
- 1
- 1
同样告诉渲染管线,这个pass作为forwardadd处理。这里处理额外的像素光源。
- 1
- 1
这个也是unity为forwardadd pass定制的multi_compile,打开Viriants看到如下:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
unity会把forwardadd pass分别编译成适用于上述5种不同光源类型的版本。如果缺少这一行代码,那么unity只会编译DIRECTIONAL这一种情况。
- 1
- 1
注意一下add pass有别于base pass的地方,因为之前base写过深度了,所以add就不用再次写深度了,以叠加的方式渲染到缓存,并且不受雾效影响。
整个add pass相较于base pass显得精简很多,它只考虑实时的光照计算,没有顶点光照,SH,lightmap,阴影这一系列东西。但是,它支持点光源,聚光灯以及cookie。接下去分别讲下,不同光源的光照处理(这里不讨论阴影部分的处理)。
平行光
平行光可以说是最简单的,因为它没有衰减。在AutoLight.cginc中找到unity中对平行光光照的定义:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
可以看到,只有对阴影部分处理的代码,光照部分是空的。因此,不考虑阴影的话,平行光的衰减值永远是1。
点光源
在AutoLight.cginc中找到unity中对点光源光照的定义:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
_LightMatrix0是由unity设置的变换矩阵,把世界空间的顶点,变换到光源空间中。而_LightTexture0是一张由unity生成的渐变图,8位的alpha图,如下图所示:
[图-1 点光源的_LightTexture0贴图]
UNITY_ATTEN_CHANNEL 也就是alpha通道。最终用光照坐标来采样_LightTexture0得到光照的衰减值。
聚光灯
同样在AutoLight.cginc中找到对聚光灯的光照定义:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
可以看到,聚光灯相较于点光源,新增了一张光照贴图,用来表示聚光灯的光照范围,如下图所示:
[图-2 聚光灯的_LightTexture0贴图]
[图-3 聚光灯的_LightTextureB0贴图]
这也符合聚光灯的特性,除了距离的衰减之外,投射到平面的光照范围再通过采样[图-2]来确定,哪里应该被照亮。
总结
以上对于由unity把一个最简单的surface shader转换为vertex/fragment shader之后的代码,做了具体的分析。但也并非面面俱到。限于作者的水平,对于SH,为何用dot(LightCoord, LightCoord).xx来作为uv坐标采样[图-1]光照图,用LightCoord.xy / LightCoord.w + 0.5来采样[图-2],也不理解,如果有大牛知道,还望告知,不胜感激。
- #pragma multi_compile_fwdbase
- #pragma
- Pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- #pragma
- 代理模式
- 自定义可折叠LinearLayout
- MapReduce教程:Hadoop
- 计算机网络---数据链路层与物理层
- poj 1062
- #pragma multi_compile_fwdbase
- JVM系列(一):Java类的加载机制
- 弱引用weak_ptr解决shared_ptr的循环引用
- 《LPD》之头文件,库文件,静态库和共享库
- jquery select chosen禁用某一项option
- javascript变量作用域
- HTML和Dreamwaver
- Android App开发基础篇—实现非阻塞Socket通信
- easyUI conbobox 简单使用