TA-Shader-文件 【Unity3D Shader编程】之三(上) :子着色器、通道与标签的写法 & 纹理混合
发布于
2015-12-1
7351
47
TA资源类型
TA资源类型: 算法思路 
shader资源类型: shader代码 
适用引擎: unity 
资源介绍: -

您需要 登录 才可以下载或查看,没有账号?注册

x
接上文(点击传送------>:【Unity3D Shader编程】之三(下) :子着色器、通道与标签的写法 & 纹理混合

【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
PS:由于原文较长.特分为上下两篇.[文章所带资源.回复可见.]作者原话(原帖地址见末尾):本文介绍了unity中子着色器、通道和标签相关的详细概念与写法,以及纹理的设置方法,基本的纹理混合写法,写了5个Shader作为本文Shader讲解的实战内容,最后创建了一个梦幻的光之城堡场景进行了Shader的测试。依旧是国际惯例,先上本文配套程序的截图。
按照国际惯例.先来几张运行的美图效果~

136735aa92f15ee818.png



1.jpg
光之城堡

山坡远眺

通向森林的道路

古墓

雾气氤氲的森林

上帝视角

OK,图先就上这么多。文章末尾有更多的运行截图,并提供了原工程的下载和可运行的exe下载回复即可;


一、子着色器(SubShader)相关内容讲解


话不多说,我们接着上篇文章继续讲。
Unity中的每一个着色器都包含一个subshader的列表,当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器。
我们知道,子着色器定义了一个渲染通道的列表,并可选是否为所有通道初始化所需要的通用状态。子着色器的写法如下:
Subshader{ [Tags] [CommonState] Passdef [Passdef ...] }
也就是通过可选标签,通用状态 和 一个Pass 定义的列表构成了子着色器。
当Unity选择用于渲染的子着色器时,它为每一个被定义的通道渲染一次对象(可能会更多,这取决于光线的交互作用)。当对象的每一次渲染都是很费资源之时,我们便使用尽量少的通道来定义一个着色器。当然,有时在一些显示硬件上需要的效果不能通过单次通道来完成。自然就得使用多通道的子着色器了。
另外,通道定义的类型包括a regular Pass, a Use Pass or aGrab Pass。
任何出现在通道定义的状态同时也能整个子着色器块中可见。这将使得所有通道共享状态。


1.1 关于子着色器标签(SubShader Tags)


子着色器使用标签来告诉渲染引擎期望何时和如何渲染对象。其语法如下:
Tags { "TagName1" ="Value1" "TagName2" = "Value2" }
也就是,为标签"TagName1"指定值"Value1"。为标签"TagName2"指定值"Value2"。我们可以设定任意多的标签。
标签是标准的键值对,也就是可以根据一个键值获得对应的一个值的。SubShader 中的标签是用来决定渲染的次序和子着色器中的其他变量的。

1.1.1  决定渲染次序——队列标签(Queue tag)


我们可以使用 Queue 标签来决定对象被渲染的次序。着色器决定它所归属的对象的渲染队列,任何透明渲染器可以通过这个办法保证在所有不透明对象渲染完毕后再进行渲染。


有四种预定义(predefined)的渲染队列,在预定义队列之间还可以定义更多的队列。这四种预定义的标签如下:


后台(Background) - 这个渲染队列在所有队列之前被渲染,被用于渲染天空盒之类的对象。
几何体(Geometry,默认值)- 这个队列被用于大多数对象。 不透明的几何体使用这个队列。
透明(Transparent) - 这个渲染队列在几何体队列之后被渲染,采用由后到前的次序。任何采用alpha混合的对象(也就是不对深度缓冲产生写操作的着色器)应该在这里渲染(如玻璃,粒子效果等)
覆盖(Overlay) - 这个渲染队列被用于实现叠加效果。任何需要最后渲染的对象应该放置在此处。(如镜头光晕等)


一个使用Tags的示例如下:
  1. Shader "Transparent QueueExample"
  2. {
  3.     SubShader  
  4. {
  5. //写上Tags标签  
  6.        Tags {"Queue" = "Transparent" }
  7.               //开始一个通道  
  8.        Pass  
  9. {
  10.            // 写Shader实体内容  
  11.        }
  12.     }
  13. }
点击此处复制文本

1.1.2 自定义中间队列


让我们来举例说明如何在透明队列中渲染对象。一般情况下,几何体渲染队列为了达到最优的性能优化了对象的绘制次序。而其他渲染队列依据举例排序对象,从最远的对象开始渲染到最近的对象。
而对于特殊的需要,可以使用中间队列来满足。在Unity实现中每一个队列都被一个整数的索引值所代表。后台为1000,几何体为2000,透明为3000,叠加层为4000. 着色器可以自定义一个队列,如:
Tags { "Queue" ="Geometry+1" }
因为渲染队列是从小到大来数的,这就会使对象在所有不透明的对象渲染之后但却在所有透明物体前被渲染,该渲染队列的索引值为2001。当我们希望某些对象总是在其他某些对象前被绘制的情况下,这用起来就很方便了。比如,在绝大多数时候,透明的水总是应该在所有不透明的物体之后并在透明对象前被渲染,这就可以通过中间队列来满足渲染需求。


1.1.3 关于忽略投影标签(IgnoreProjector tag)


后面我们会接触到,若设置IgnoreProjector(忽略投影)标签为"True",那么使用这个着色器的对象就不会被投影机制(Projectors)所影响。这对半透明的物体来说是一个福利,因为暂时没有对他们产生投影的比较合适的办法,那么直接忽略掉就行了。




二、 通道(Pass)相关内容讲解

Pass通道块控制被渲染的对象的几何体。其语法定义是这样的:
Pass { [Name and Tags] [RenderSetup][TextureSetup] }
基本通道命令包含一个可选的渲染设置命令的列表,和可选的被使用的纹理的列表。




2.1 通道中的名称与标签(Name and tags )

一个通道能定义它的Name 和任意数量的Tags。通过使用tags来告诉渲染引擎在什么时候该如何渲染他们所期望的效果。语法如下:
Tags { "TagName1" ="Value1" "TagName2" = "Value2" }
指定TagName1 的值为Value1 ,TagName2 的值为 Value2 你可以指定很多自己喜欢的标签,下面会详细来列举。


标签基本上是键-值对的形式。 内部的Pass标签用来控制光照管道(环境光照,顶点光照和像素光照)中pass 的任务和一些其它选项。注意以下的标签必须在pass段内部,而不是在SubShader中被识别。


2.1.1 光照模式标签(LightMode tag)
LightMode 标签定义了Shader的光照模式,具体含义以后会在讲渲染管线时讲到。下面我们先简单了解一下有哪些光照模式可选,以及他们的具体作用:


Always: 总是渲染。没有运用光照。
ForwardBase:用于正向渲染,环境光、方向光和顶点光等
ForwardAdd:用于正向渲染,用于设定附加的像素光,每个光照对应一个pass
PrepassBase:用于延迟光照,渲染法线/镜面光。
PrepassFinal:用于延迟光照,通过结合纹理,光照和自发光渲染最终颜色
Vertex: 用于顶点光照渲染,当物体没有光照映射时,应用所有的顶点光照
VertexLMRGBM:用于顶点光照渲染,当物体有光照映射的时候使用顶点光照渲染。在平台上光照映射是RGBM 编码
VertexLM:用于顶点光照渲染,当物体有光照映射的时候使用顶点光照渲染。在平台上光照映射是double-LDR 编码(移动平台,及老式台式CPU)
ShadowCaster: 使物体投射阴影。
ShadowCollector: 为正向渲染对象的路径,将对象的阴影收集到屏幕空间缓冲区中。


2.1.2 条件选项标签 (RequireOptions tag )


若想要在一些外部条件得到满足时某pass才渲染,就可以通过使用RequireOptions标签,它的值是一个空格分割的字符串,目前由unity3d支持的选项只有一个,就是渲染植被之时:
SoftVegetation: 如果在QualitySettings中开启渲染软植被(Edit->Project Settings->Quality),则该pass可以渲染


2.2 关于渲染设置 (Render Setup )

通道设定显示硬件的各种状态,例如能打开alpha混合,能使用雾,等等。这些命令如下:
Material { Material Block }
定义一个使用顶点光照管线的材质,详情参考上次我们讲的Material
Lighting On | Off
开启或关闭顶点光照。开启灯光之后,顶点光照才会有作用
Cull Back | Front | Off
设置多边形剔除模式,详细内容后面的文章会讲解到。
ZTest (Less | Greater | LEqual | GEqual |Equal | NotEqual | Always)
设置深度测试模式,详细内容后面的文章会讲解到。
ZWrite On | Off
设置深度写模式,详细内容后面的文章会讲解到。
Fog { Fog Block }
设置雾参数,详细内容后面的文章会讲解到。
AlphaTest (Less | Greater | LEqual | GEqual| Equal | NotEqual | Always) CutoffValue
开启alpha测试
Blend SourceBlendMode |DestBlendMode
设置alpha混合模式
Color Color value
设置当顶点光照关闭时所使用的颜色
ColorMask RGB | A | 0 | any combination of R, G, B, A
设置颜色写遮罩。设置为0将关闭所有颜色通道的渲染
Offset OffsetFactor , OffsetUnits
设置深度偏移
SeparateSpecular On | Off
开启或关闭顶点光照相关的平行高光颜色。
ColorMaterial AmbientAndDiffuse | Emission
当计算顶点光照时使用每顶点的颜色

2.3 关于纹理设置(Texture Setup )
在完成渲染设定后,我们可以指定一定数量的纹理和当使用 SetTexture 命令时所采用的混合模式:
SetTexture [texture property]{ [Combineoptions] }
纹理设置,用于配置固定函数多纹理管线,当自定义fragment shaders 被使用时,这个设置也就被忽略掉了。

2.4 一些细节

2.4.1 关于每像素光照(Per-pixel Lighting )
每像素光照管线通过多次通道渲染对象来完成。Unity渲染对象一次来获取阴影色和任何顶点光照。然后再在额外的并行通道中渲染出每像素光照的效果。

2.4.2 关于每顶点光照(Per-vertex Lighting)
每顶点光照是标准的Direct3D/OpenGL光照模式,通过计算每个顶点的光照来完成。Lighting on命令开启光照。而我们知道,光照被材质块,颜色材质和平行高光等命令所影响。

2.5 一些高端特效的通道命令
有时候,我们会写一些特殊的通道,要多次反复利用普通的功能或是实现高端的特效。应对这些情况,Unity中就有一些高级点武器可以选用,这里简单讲一讲吧,现在先稍微有个概念就好。

2.5.1 UsePass——包含已经写好的通道

UsePass 可以包含来自其他着色器的通道,来减少重复的代码。
例如,在许多像素光照着色器中,阴影色或顶点光照通道在在相应的顶点光照着色器中是相同的。UsePass命令只是包含了另一个着色器的给定通道。例如如下的命令可以使用内置的高光着色器中的名叫"Base"的通道:
UsePass "Specular/BASE"
而为了让UsePass能够认识到指定的是谁,必须给希望使用的通道命名,弄个身份证。通道中的Name命令就是这个功能:
Name "MyPassName"

2.5.2 GrabPass——捕获屏幕内容到纹理中

GrabPass 可以捕获物体所在位置的屏幕的内容并写入到一个纹理中,通常在靠后的通道中使用,这个纹理能被用于后续的通道中完成一些高级图像特效。
一个示例如下:

  1. Shader "GrabPassInvert"
  2. {
  3. SubShader  
  4. {
  5.       //在所有不透明几何体之后绘制  
  6.        Tags { "Queue" = "Transparent" }
  7.    
  8.       //捕获对象后的屏幕到_GrabTexture中  
  9.        GrabPass { }
  10.    
  11.        //用前面捕获的纹理渲染对象,并反相它的颜色  
  12.        Pass  
  13. <span style="white-space:pre">  </span>{
  14.            SetTexture [_GrabTexture] { combine one-texture }
  15.        }
  16.     }
  17. }
点击此处复制文本

三、纹理(Texturing)相关内容讲解

纹理在基本的顶点光照计算完成之后被应用,这也就是SetTexture 命令必须放置在通道的末尾的原因了。在着色器中通过SetTexture 命令来完成。
需要注意的是,SetTexture 命令在使用了片段着色器时不会生效;因为在片段着色器下像素操作被完全描述在着色器中。


材质贴图可以用来实现旧式风格的混合器效果。我们可以在一个通道中使用多个SetTexture命令, SetTexture所有纹理都是按代码顺序来添加的,也就是如同Photoshop中的图层操作一样。SetTexture的语法如下:


SetTexture [TexturePropertyName] { TextureBlock }


解释:分配一个纹理,其中TexturePropertyName必须为一个纹理,也就是在shader最开始的Properties中的属性。在TextrueBlock中设置如何应用纹理,即纹理块控制纹理如何被应用。而在纹理块中能执行3种命令:合并操作,矩阵操作、与常量颜色进行混合操作。

3.1 纹理合并命令


combine src1 * src2
将源1和源2的元素相乘。结果会比单独输出任何一个都要暗


combine src1 + src2
将将源1和源2的元素相加。结果会比单独输出任何一个都要亮


combine src1 - src2
源1 减去 源2


combine src1 +- src2
先相加,然后减去0.5(也就是添加了一个符号)


combine src1 lerp (src2) src3
使用源2的透明度通道值在源3和源1中进行差值,注意差值是反向的:当透明度值是1是使用源1,透明度为0时使用源3


combine src1 * src2 + src3
源1和源2的透明度相乘,然后加上源3


combine src1 * src2 +- src3
源1和源2的透明度相乘,然后和源3做符号加


combine src1 * src2 - src3
源1和源2的透明度相乘,然后和源3相减

其中,所有src属性都可以是previous,constant, primary or texture其中的一个。

Previous 是上一次SetTexture的结果
Primary 是来自光照计算的颜色或是当它绑定时的顶点颜色
Texture是在SetTexture中被定义的纹理的颜色
Constant是被ConstantColor定义的颜色


一些小技巧:


1.上述的公式都均能通过关键字 Double 或是 Quad 将最终颜色调高亮度2倍或4倍。
2.所有的src属性,除了差值参数都能被标记一个“-”负号来使最终颜色反相。
3.所有src属性能通过跟随 alpha 标签来表示只取用alpha通道。


3.2 颜色常量命令


ConstantColor color
定义在combine命令中能被使用的常量颜色


3.3 纹理矩阵命令
matrix [MatrixPropertyName]
使用给定矩阵变换纹理坐标


3.4 一些细节
较老的显卡对纹理一般会使用分层的操作方案,而纹理在每一层后被应用一次颜色的修改。对每一个纹理,一般来说纹理都是和上一次操作的结果混合,如图:


需要注意的是,对于“纯正”的“固定功能流水线”设备(比如说OpenGL, OpenGL ES 1.1, Wii),每个SetTexture阶段的值被限制为0到1的范围之间。而其他的设备(如Direct3D, OpenGL ES 2.0)中,这个范围就不一定是固定的。这种情况就可能会影响SetTexture阶段,可能使产生的值高于1.0。


3.4.1 关于分离的透明度和颜色混合(Separate Alpha & Color computation)


在默认情况下,混合公式被同时用于计算纹理的RGB通道和透明度。同时,我们也能指定针对透明度来单独计算,比如这样,将RGB操作和Alpha操作隔开:


SetTexture [_MainTex] { combine previous *texture, previous + texture }


如上所述,我们对RGB的颜色做乘然后对Alpha透明度相加


3.4.2 关于反射高光(Specular highlights)

默认情况下primary颜色是漫反射,阴影色和高光颜色(在光线计算中定义)的加和。如果我们将通道设置中的SeparateSpecular On 写上,高光色便会在混合计算后被加入,而不是之前。PS:Unity内置的顶点着色器就是加上SeparateSpecular On的。


3.4.3 关于显卡的硬件支持情况说明


我们上篇文章中已经讲到过,一些旧的显示卡不能支持某些纹理混合模式,且不同的卡有不同数目的SetTexture阶段可用。所以我们应该为想支持的显卡来分开写SubShader,适应各种情况 。
PS::支持像素着色器1.1版本的显卡(即NVIDIA GeForce 3 或更高, ATI Radeon 8500 或更高, Intel 9xx)支持所有的混合器模式,并且可以拥有至少4级渲染阶段。下表简述了硬件支持情况。


文章所带工程文件及可运行程序资源回复可下载
尊敬的游客,如果您要查看本帖关注 或 回复可见内容请关注回复后刷新页面查看!


原文链接:http://blog.csdn.net/poem_qianmo/article/details/41175585






参与人数 1 元素币 +3
还没有设置签名!您可以在此展示你的链接,或者个人主页!

使用道具 举报 登录

回复 <
Zh_Jason  发表于 2015-12-1 13:19:30  
2#
好资源~!点赞
回复 收起回复
使用道具
zzh  发表于 2016-5-7 15:03:22  
3#
真的挺不错啊
回复 收起回复
使用道具
FAFA123  发表于 2016-5-10 13:36:03  
4#
66666666666666
回复 收起回复
使用道具
1104084633  发表于 2016-6-27 18:34:49  
5#
太厉害了
回复 收起回复
使用道具
reai007@163.com  发表于 2016-8-5 11:29:58  
6#
xiexiedaniufenxiang
回复 收起回复
使用道具
anhdtse02636  发表于 2016-8-10 10:39:01  
7#
好资源~!点赞
回复 收起回复
使用道具
mfkjcfqwe  发表于 2016-8-29 09:25:30  
8#
haodongxi....
回复 收起回复
使用道具
clown2015  发表于 2016-9-20 09:02:09  
9#
为了元素币,拼了!
回复 收起回复
使用道具
sweethart  发表于 2016-11-25 16:10:32  
10#
{:1_145:}
回复 收起回复
使用道具
xingxiujie  发表于 2016-12-18 20:12:56  
11#
感谢分享?????
回复 收起回复
使用道具
zhoulijing  发表于 2017-1-7 13:14:08  
12#
好东西呀
回复 收起回复
使用道具
zhoulijing  发表于 2017-1-8 18:42:07  
13#
kankan
回复 收起回复
使用道具
大芸彩  发表于 2017-8-2 10:49:29  
14#
快到我了
回复 收起回复
使用道具
aldsgogo  发表于 2018-9-14 13:44:34  
15#
【Unity3D Shader编程】之三(上) :子着色器、通道与标签的写法 & 纹理混合
回复 收起回复
使用道具
ZhaoZG  发表于 2018-10-15 10:13:15  
16#
6666666666666666666666
回复 收起回复
使用道具
狂想曲/ka  发表于 2018-10-15 10:57:01  
17#

谢谢楼主分享
回复 收起回复
使用道具
dsglxq  发表于 2018-10-15 14:27:15  
18#
感谢分享!!!
回复 收起回复
使用道具
qq_bluedream_Nn  发表于 2018-10-16 00:49:30  
19#
正好需要 感谢楼主
回复 收起回复
使用道具
g614749432  发表于 2018-10-16 07:17:09  
20#
感谢分享!!!
回复 收起回复
使用道具
123下一页

快来发表你宝贵的意见吧!

成林 实名

通过了实名认证的内容创造者

unity3D

主题
181
精华
28
超神
5
扩散
750
微金
3000
智慧
220
余额
0
在线时间
5805 小时

【绝】结界玄晶 微库VIP 扩散者 紫色药水 学徒法袍 元素铜币 元素银币 元素金币 元素秘币 长剑 绿色药水 长枪 火元素

快速回复 返回顶部 返回列表