固定功能管线着色器(Fixed Function Shaders)
一般用于不支持高级着色器特性的旧硬件。采用ShaderLab编写
所有硬件平台都可支持,针对硬件能够执行的基本命令的Shader,当然,功能有限,但是,速度最快。
没有Pass通道
示例
Shader "MyShader" {
Properties{ //属性定义
_Color("Main Color", Color) = (1, 1, 1, 0.5)
_SpecColor("Spec Color", Color) = (1, 1, 1, 1)
_Emission("Emmisive Color", Color) = (0, 0, 0, 0)
_Shininess("Shininess", Range(0.01, 1)) = 0.7
_MainTex("Base (RGB)", 2D) = "white" {}
}
SubShader{
Pass{ //Pass定义
Material { //设置光照所需的材质参数
//漫反射 必须依照光照,与灯光配合,将光打到物体表面反射光,我们才能看到物体
Diffuse [_Color] //漫反射命令,要想受光照影响,必须启用光照 Lighting On
Ambient [_Color] //环境光
Shininess [_Shininess] //滑动条高反射系数,配合启用高光的命令 SeparateSpecular On
Specular [_SpecColor] //高光
Emission [_Emission] //自发光
}
Lighting On //开启灯光
SeparateSpecular On //启用高光颜色
SetTexture [_MainTex] { //设置纹理
constantColor [_Color] //设置一个常量
combine texture * primary DOUBLE, texture * constant //混合命令 与材质混合 double 是图片高亮的表现
}
}
}
}
效果如下
表面着色器(Surface Shaders)
在Unity中,用Cg/HLSL语言编写,嵌入ShaderLab中。采用面向组件的方式,只需要写出关键的表面函数,其余部分由Unity自动生成,包括各种光源类型、渲染实时阴影等
编写规则
1.实现代码位置
实现代码要放置在CGPROGRAM...ENDCG代码块中,而不是放在Pass结构中,会自己编译到Pass
2.使用命令来指明这个是个表面着色器
命令为:#pragma surface...
格式为
#pragma surface 表面函数 光照模型 [可选参数]
表面函数:
用来指明哪个Cg函数包含有表面着色器代码
如:void surf(Input IN, inout SurfaceOutput o)
上面函数作用
“表面函数”的作用是接收输入的UV或者附加数据,然后进行处理,最后将结果填充到输出结构体SurfaceOutput中。
输入结构体lnput一般包含着色器所需的纹理坐标,纹理坐标的命名规则为uv加纹理名称(当使用第二张纹理时使用uv2加纹理名称)。另外还可以在输入结构中设置一些附加数据,如下图
SurfaceOutput描述表面的各种参数,结构标准为下
附加数据
SurfaceOutput结构标准
struct SurfaceOutput{
half3 Albedo; //反射光
half3 Normal; //法线
half3 Emission; //自发光
half Specular; //高光
half Gloss; //光泽度
half Alpha; //透明度
}
光照模型:
可以是内置的Lambert和BlinnPhong,或者是自定义的光照模型
例子
Shader "Diffuse Simple" {
SubShader {
Tags { "RenderType" = "Opaque" } //告诉系统要渲染的对象
CGPROGRAM //表面着色器的实现代码
//指明着色器类型,表面函数和光照模型
#pragma surface surf Lambert
struct Input { //输入数据结构体
float4 color : COLOR;
};
void surf (Input IN, inout SurfaceOutput o) { //表面函数
o.Albedo = 1;
}
ENDCG
}
Fallback "Diffuse"
}
效果如下
添加纹理
Shader "Diffuse Texture" {
Properties { //添加纹理
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input { //数据结构体
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
效果如下
添加法线贴图
Shader "Diffuse Bump" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {} //法线贴图属性
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap; //发现贴图
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
Fallback "Diffuse"
}
法线贴图
效果如下
添加立体反光
Shader "WorldRefl" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Cube ("Cubemap", CUBE) = "" {} //立方体贴图属性
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float3 worldRefl; //输入反射参数
};
sampler2D _MainTex;
samplerCUBE _Cube;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
o.Emission = texCUBE (_Cube, IN.worldRefl).rgb; //将反射颜色设置为自发光
}
ENDCG
}
Fallback "Diffuse"
}
效果如下
顶点着色器(Vertex and Fragment Shaders)
运行于具有可编程渲染管线的硬件上,包含:顶点程序(Vertex Programs)和片段程序(Fragment Programs)
使用顶点着色器进行渲染时,图形硬件的固定功能管线将会关闭,用顶点程序替换掉固定功能管线中标准的3D变换、光照等功能,片段程序会替换掉SetTexture命令中的纹理混合模式
也是用Cg/HLSL编程语言来实现
可用于生成动画和沿法线移动顶点等,后面示例
结构
代码用CGPROGRAM ENDCG语言包围起来,放在ShaderLab中Pass命令中
示例
...
Pass {
//通道设置
CGPROGRAM
//本段Cg代码的编译指令
#pragma vertex vert
#pragma fragment frag
//Cg代码
ENDCG
}
编译指令
可用的编译指令
编译目标
对应不同版本的着色器模型。可设置为#pragma target2.0、#pragma target3.0、#pragma target4.0、#pragma target5.0
渲染平台
支持的平台
- d3d9即Direct3D 9。
- d3d11即Direct3D 11。
- opengl即OpenGL。
- gles 即OpenGL ES 2.0。
- gles3即OpenGL ES 3.0。
- metal 即iOS Metal。
- d3d11_9x即Direct3D 11 9.x feature level。
- xbox360即Xbox360。
- xbox one即Xbox One
- ps3即PlayStation3。
- ps4即PlayStation4。
- psp2即PlavStation Vita
例子
下面是顶点片段着色器的例子。在顶点着色器中可以使用顶点Shader程序修改顶点数据。该方法可用于生成动画和沿法线移动顶点等。通过在表面着色器中书写一个顶点程序函数来实现它,需要把appdata_full结构作为参数传递到方法中。
沿着法线方向移动顶点
Shader "Normal Extrusion" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Amount ("Extrusion Amount", Range(-1,1)) = 0.5 //人物变胖大小
}
SubShader {
Tags { "RenderType" = "Opaque" } //渲染类型为不透明
CGPROGRAM
//定义表面和顶点函数
#pragma surface surf Lambert vertex:vert
struct Input {
float2 uv_MainTex; //MainTex的Uv坐标
};
float _Amount;
void vert (inout appdata_full v) { //输入结构作为参数
v.vertex.xyz += v.normal * _Amount; //修改顶点位置
}
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; //输出漫反射颜色
}
ENDCG
}
Fallback "Diffuse"
}
效果如下,原样可参看上面
通过沿法线移动顶点使人物变胖了
根据法线方向设置模型表面颜色
Shader "Display Normals" {
SubShader {
Pass {
CGPROGRAM
//Cg代码块开始
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f { //顶点数据结构体
float4 pos : SV_POSITION;
float3 color : COLOR0;
};
v2f vert (appdata_base v) //顶点程序代码,计算位置和颜色
{
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.color = v.normal * 0.5 + 0.5;
return o;
}
half4 frag (v2f i) : COLOR //片段程序代码,直接把输入的颜色返回,并把透明度设置为1
{
return half4 (i.color, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
效果如下图
根据切线方向设置模型表面颜色
Shader "Tangents" {
SubShader {
Pass {
Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 输入位置和切线数据
struct appdata {
float4 vertex : POSITION;
float4 tangent : TANGENT;
};
struct v2f { //定义顶点数据结构体
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
v2f vert (appdata v) { //顶点程序函数
v2f o;
o.pos = UnityObjectToClipPos( v.vertex ); //计算顶点位置
o.color = v.tangent * 0.5 + 0.5; //计算顶点颜色
return o;
}
fixed4 frag (v2f i) : COLOR0 { return i.color; } //片段程序,直接返回顶点颜色
ENDCG
}
}
}
材质效果图
人物效果图