Shader(着色器)其实就是一小段程序,它负责将输入的网格或者贴图颜色等信息,进行组合或者变换换之后将其输出。之后再将写好的shader赋予材质,之后就可以由渲染器进行渲染。
Shader大体上可以分为两类:表面着色器(Surface Shader)和片段着色器(Fragment Shader)。这里主要介绍表面着色器。
我们先来看一段shader程序
Shader "Custom/Demo" { //shader的分类和命名
Properties{ //shader的一些属性
_MainTex("Texture",2D)="white"{}
_BumpMap("Bump Map",2D)="bump"{}
_RimColor("Rim Color",Color)=(0.26,0.19,0.16,0.0)
_RimPower("Rim Power",Range(1,10))=5.0
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
CGPROGRAM //CG语言开始
#pragma surface surf Lambert //声明光照模式
#pragma target 3.0
sampler2D _MainTex;
sampler2D _BumpMap;
float4 _RimColor;
float _RimPower;
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
float3 viewDir;
};
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
//从凹凸纹理获取法线值
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
half rim = 1.0 - saturate(dot(normalize(IN.viewDir),o.Normal));
o.Emission = _RimColor.rgb*pow(rim,_RimPower);
}
ENDCG //CG语言结束
}
FallBack "Diffuse"
}
我们先来分析Properties(属性):
属性的语法定义是这样的
_Name("Display Name", type) = defaultValue[{options}]
_Name:属性的变量名,之后代码调用需要这个命名
Display Name:在unity编辑器里面显示的名字
type:type大概有下面几个种类
Color - 一种颜色,由RGBA四个量来定义;
2D - 一张2的阶数大小的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,***终被显示出来;
Rect - 一个非2阶数大小的贴图;
Cube - 即Cube map texture,简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒)
Range(min, max) - 一个介于***小值和***大值之间的浮点数,一般用来当作调整Shader某些特性的参数
Float - 任意一个浮点数;
Vector - 一个四维数;
defaultValue: 定义了这个属性的默认值,通过输入一个符合格式的默认值来指定对应属性的初始值
Color - 以0~1定义的rgba颜色,比如(1,1,1,1);
2D/Rect/Cube - 对于贴图来说,默认值可以为一个代表默认tint颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个
Float,Range - 某个指定的浮点数
Vector - 一个4维数,写为 (x,y,z,w)
***于***后一个{options}只对贴图有关,这个以后再说
所以上面那个shader在编辑器里面看来是这样的
Subshader 子着色器
这个暂时不详细介绍
CG语言声明接口
请允许我把它叫做一个接口,上面我们在CG语言里面再次声明了两个变量,这里很多人就很奇怪,明明在属性里面已经声明过了,为什么还要再次声明一遍。这里的sampler 2D就相当于是一个接口,我们可以通过sampler2D来得到一张图的像素与坐标之间的对应关系。这样就可以的在CG语言里面对其进行运算。(注意:这里的命名要和属性里面的命名包保持一致)
sampler2D _MainTex;
sampler2D _BumpMap;
Input
Input就是表面的意思,输入。这是一个结构体,相信大家也不会陌生。也就是定义了要向输出函数里面输入什么东西。
void surf (Input IN, inout SurfaceOutput o)
surf函数,也就是我们的输出函数。它的两有参数,***个是Input,在计算输出时Shader会多次调用surf函数,每次给入一个贴图上的点坐标,来计算输出。第二个参数是SurfaceOutput,SurfaceOutput是预定义的输出结构,surf函数的目标就是根据输入把这个输出结构填上。
SurfaceOutput结构体的定义如下:
struct SurfaceOutput{
half3 Albedo; //颜色
half3 Emission //发散颜色
half3 Normal //法向值
half Specular //镜面高光
half Gloss //发光强度
half Alpha //透明度
}
在上面的例子中,我们设置了它的颜色,法线还有发散颜色。
FallBack "Diffuse"
很多人认为,***后的FallBack"Diffuse"只是一个备胎,但其实并不是这样。我只能引用官方一句话:A fallback statement has the same effect as if all subshaders from the other shader would be inserted into its place.
发表评论
发表评论: