在unity中我们经常会使用shader,但是从来没有深究过,最近在做项目时遇到相关问题,无从下手,决定系统学习一番,在此前提下把我学习的过程做一个记录。学习过程中参考了浅墨和风宇冲两位高人的博客,本文有不对的地方,还望指正。
按照学习技术的习惯,在第一次接触shader时,我们首先会想这两个个问题,
问题一:什么是shader,它能做什么?
问题二:unity中shader使用的语言是什么?
问题一:shader,也就是着色器,它本质就是一段程序,这段程序的作用是把Mesh(网格)以指定的方式以及指向的贴图或颜色等处理后,然后通过绘制把处理后的图像显示在屏幕上。所以简而言之:
什么是shader,shader就是一段处理颜色,贴图纹理并且进行计算和变换到渲染器的程序。
unity中shader分两类:Surface Shader(表面着色器)和Vertex Shader &Fragment Shader(顶点着色器&片段着色器)以及Fixed Function
Shader(固定功能着色器)下面会讲如何在区分。
shader能做什么呢,比如光影特效,颜色变换等。暂时只想到这些
问题二:unity中的shader使用的是一种shaderLab的语言编写的。它的语法风格类似NVIDIA的CgFX和Direct3D,它具备了显示材质(Material)所需要的一切信息。
下面我们来看一段unity的shader代码。打开unity,Assets->Create->Shader,会在Assets路径下创建了一个shader脚本,可以用文本编辑工具打开,我使用的是一个VS的shader插件,可以显示语法高亮。代码如下:
Shader "Custom/NewShader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
我们先来看看这段代码的结构,它大体分四块Shader “Custom/NewShader” ,Properties和SubShader以及FallBack “Diffuse”。
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:14px;"></span></span>
简单的可以用如下的形式来概括:
Shader "name" { [Properties] SubShaders[Fallback] }
用图来说
Shader “Custom/NewShader” :它定义了我们自定义的这个shader的目录结构,Custom下名字叫做NewShader。目录和它的名字我们可以随意修改 ,并且不必和文件名相同。 “/”用来构建子菜单,作用便于管理,如Custom/canglang/NewShader那么在 Inspector
检视窗口就会显示成这样
Properties:unity圣典的解释是:
Shaders can define a list of parameters to be set by artists in Unity’s material inspector. The Properties block in
the shader file definesthem.我简单理解为属性定义并且属性会将display
name显示在材质检视器中,显示GUI元素,包括纹理,颜色,滑动条,float值等,能够很便利的让我们进行修改
语法结构为:Properties { Property [Property ...] }
定义属性块,其中可包含多个属性,其定义如下:
name ("display
name", type) =Defaultvalue
type的类型有7种:Range(min,max),Color
,2D,Rect,Cube,Float,Vector,每一种的具体含义及定义如下:
name ("display name", Range (min, max)) =number
定义浮点数属性,在检视器中可通过一个标注最大最小值的滑条来修改。
name ("display name", Color) =(number,number,number,number)
定义颜色属性
name ("display name", 2D) = "name" {options }
定义2D纹理属性
name ("display name", Rect) = "name"{ options }
定义长方形(非2次方)纹理属性
name ("display name", Cube) = "name"{ options }
定义立方贴图纹理属性
name ("display name", Float) = number
定义浮点数属性
name ("display name", Vector) =(number,number,number,number)
定义一个四元素的容器(相当于Vector4)属性
例如_MyColor ("My
Color", Color) =(1,1,1,0)为例,
_MyColor ------Internal
name(内部名称)
My
Color-------Inspector title(Inspector窗口显示的名称)
Color-----------Property
type(属性类型)
(1,1,1,0)--------Default
value(默认值)
注意:
1、Properties块内的语法都是单行的。每个属性都是由内部名称开始,后面括号中是显示在检视面板(Inspector)中的名字和该属性的类型。等号后边跟的是默认值。
2、对于Range和Float类型的属性只能是单精度值。
3、对于Color和Vector类型的属性将包含4个由括号围住的数描述。
4、对于纹理(2D, Rect, Cube) 缺省值既可以是一个空字符串也可以是某个内置的缺省纹理:"white",
"black", "gray" or"bump"
SubShader:子着色器,是shader代码的主体,一个shader可以包含一个或多个子着色器,每个子着色器可以包含一个或多个pass,但是在运行时具体能不能执行或者限制性哪个子着色器完全由运行平台决定。因为机子不同,运行的显卡支持环境也不同。所以多个子着色器的作用就在于此,例如对于一个效果,预想想好ABC多套方案,A在牛逼机子上能运行,B在一般机子上能运行,C在烂机子上运行。全都不行了还有FallBack呢。而且在运行时系统也会把子着色器中代码分成多个合适的pass。
具体结构如下:
SubShader
{
pass
{
}
}
FallBack “Diffuse”:回滚,也称备胎,作用是处理所有SubShader都不能运行的情况,以防万一,留个备胎,不然显示不了咋办呢。这里设的备胎是Diffuse(漫反射)。
注意:SubShader在Shader代码中必须有,而properties和fallback是可以不写的
明天继续。。。