关于 unity shader 的入门知识点网上还是有很多的,那这里进行一下简单的总结,当然只是对语法结构上的总结。
shader,也叫着色器,是GPU渲染管线中的一部分,只是这部分是可编程的,也就是可以通过编程进行控制。
而在unity中进行的shader编写与传统意义上的shader还是有一些不同的,因为unity相当于做了一层封装,我们需要按照unity给定的语法结构进行shader编写,如果直接像是OpenGL或者Direct3D那样编写是行不通的。
当然,这里只对unity shader进行总结,OpenGL与Direct3D可以自行百度。
OK,对于unity shader而言,更准确的说是unityshaderlab,其有两种常用的结构:
- 表面着色器,也就是surface shader,这是unity提出来的一种概念,简化了shader的编写难度,而且提供了大量的内置变量,宏,方法等等,unity建议使用表面着色器来编写和光照有关的shader。
- 顶点片元着色器,也就是vertex and fragment sahder,在OpenGL与Direct3D中也有类似的着色器,基本上没什么区别。顶点片元着色器比着表面着色器更加的自由与强大,当然,对于光照,顶点片元着色器需要自行处理。
可能有的朋友还听说过固定渲染管线shader,这是一种已经被弃用的shader,但是在一些老式的显卡上还是有这样的shader的。这里不做过多的介绍。
那么,我们来看一下关于shader的语法结构:
整个shader,大致可以分为两个部分:
- Properties块,用于定义属性,显示在Inspector面板上。
- SubShader,子着色器,一个shader可以有多个子着色器,当然,重要的是子着色器里面的内容Pass块,一个子着色器可以包含多个Pass块,Pass块中就是shader代码。当有多个Pass块时,除了会根据平台,硬件等因素自动识别第一可以执行的Pass块外,还可以通过代码控制执行具体的Pass块。
OK,下面是Shader的语法:
Shader "name"{
Properties{
....
}
SubShader{
Tags{...}
[CommonState]
Pass{
//也可以有Tags{}
CGPROGRAM
...
ENCG
}
// Fallback "name"
}
}
大致的语法结构就是这样。
解释一下:
- 属性定义:Properties,定义shader的输入,这些输入可以有默认值,且可以在Inspector面板上进行修改调试,还可以通过代码进行修改。
- 子着色器:一个shader可以有多个子着色器,这些子着色器互不干扰,且只有一个会运行,编写多个子着色器的目的是为了解决平台兼容性问题,unity会自己选择兼容终端平台的shader运行。
- Pass:一个Pass就是一次绘制,可以看成一个DC(DrawCall),对于表面着色器而言,只有一个Pass,但是顶点片元着色器可以有多个Pass,多个Pass可以实现一些特殊效果。
而且我们可以在一个shader中使用另一个shader的某一个Pass块,Pass块是可以命名的,使用use "passname"这样的方式可调用,具体方式。 - CG代码:写在CGPROGRAM与ENDCG之间。
- Fallback:回滚,相当于备胎。
关于shader的输入:
属性定义变量:属性定义中的变量是Shader参数的主要设置方式。 它是随材质变化的,每个使用该Shader的材质都可以在Inspector或者脚本中设置这些参数。这些参数除了在Shader的Properties段中定义外,还需要在Cg中声明方可使用。
全局变量:Shader有一组SetGlobalXXX方法,可以对Shader的在Cg中定义而没有在属性中定义的uniform变量进行设置。这个设置是全局的,所有定义了该uniform的Shader都会受到影响。例如我们希望场景随着时间变化而改变颜色,就可以给场景所使用到的Shader设置统一的全局颜色变量,然后在脚本中通过设置该颜色来改变场景的颜色。在角色释放技能时场景变黑也可以使用这个方法。
至于能在shader中定义的属性,有如下几种:
下面介绍一些关于SubShader中的知识点:
- Tags:标签,被用来修饰子着色器,硬件会通过标签来决定什么时候调用该着色器。
比较常见的Tags有:- Queue 渲染队列
从名字就可以看出来,这个是决定渲染顺序的,它定义了一个整数,决定了shader的渲染次序,数字越小就越早被渲染,这也就意味着,越早渲染就会被后渲染的物体给覆盖掉。
unity中预定义的渲染队列有:
- Queue 渲染队列
RenderType
渲染模式,其实它主要是用在处理camera特效上的,ShaderPeplacement是会用到渲染模式的。通常情况下,我们也就会在当渲染透明物体时用 "RenderType"="Transparent",在渲染不透明物体时用"RenderType"="Opaque"。IgnoreProjector
忽略投影,在一些特效上,可能需要忽略投影所造成的效果。
更多关于Tags的内容
- CommonState:渲染状态,SubShader中可以定义一组Render State,基本上就是一些渲染的开关选项,他们对该SubShader的所有的Pass都有效,所以称Common。当然,这些Render State也可以在每个Pass中分别定义。
比较常见的有以下几种:
Cull Back | Front | Off
多边形表面剔除开关。Back表示背面剔除,Front表示正面剔除,Off表示关闭表面剔除即双面渲染。
ZWrite On | Off
控制当前对象的像素是否写入深度缓冲区(depth buffer),默认是开启的。一般来说绘制不透明物体的话ZWrite开启,绘制透明或半透明物体则ZWrite关闭。
ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)
控制如何进行深度测试,默认是LEqual。
Blend Off
关闭混合
Blend SrcFactor DstFactor
最终颜色 = Shader产生的颜色 × SrcFactor + 屏幕上原来的颜色 × DstFactor
Blend SrcAlpha OneMinusSrcAlpha
透明度混合
更多参考在此
OK,第一部分就先介绍到这里。