在Unity5.2及以上版本中,Unity一共提供了4中UnityShader模板供我们选择,分别是:UnlitShader、SurfaceShader、ImageEffectShader、ComputeShader。
SurfaceShader:会产生一个包含了标准光照模型的表面着色器模板,代码如下:
Shader "Custom/SurfaceShader" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Unlit Shader 会产生一个不包含光照(但包含雾效)的基本顶点/片元着色器,代码如下:
Shader "Unlit/UnlitShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
Image Effect Shader 则为我们实现各种屏幕后处理效果提供了一个模板,代码如下:
Shader "Hidden/ImageEffectShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
// just invert the colors
col = 1 - col;
return col;
}
ENDCG
}
}
}
Compute Shader会产生一张特殊的Shader文件,这类Shader旨在利用GPU的并行性来进行一些与常规渲染流水线无关的计算,
与正常着色器类似,Compute着色器是项目中的资源文件,具有* .compute文件扩展名。 它们是用DirectX 11风格的HLSL语言编写的,用最少量的#pragma编译指令来指示哪些函数要编译为计算着色器内核。
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D Result;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// TODO: insert actual code here!
Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}
单独的Shader无法发挥任何作用,它必须和材质结合起来,才能产生化学反应。Unity Shader本质上也是一个文本文件,也有ImportSetting面板,如图:
单击Show generated code 按钮来打开一个新文件,在该文件里将显示Unity在背后为该表面着色器生产的顶点/片元着色器、这可以方便我们对这些生成的代码进行修改
如图UnityShader是一个固定函数着色器,在FixedFunction的后面也会出现一个ShowGeneratedCode按钮,来让我们查看该固定函数着色器生成的顶点/片元着色器。
CompileAndShowCode 下拉列表可以让开发者检测该UnityShader针对不同图像编程(例如OpenGL、D3D9、D3D11等)最终编译成Shader代码直接单击按钮可以查看生成的底层的汇编指令。我们可以利用这些代码来分析和优化着色器。
Unityshader 中的Properties语义块中包含了一系列属性,这些属性将会出现在材质面板上,Properties语义块支持的属性类型,如下:
下面给出一个展示所有属性类型的例子:
Shader "Custom/ShaderProperties" {
Properties {
_Int("Int",Int)=2
_Float("Float",Float) = 1.5
_Range("Range",Range(0.0,10.0)) = 3.0
_Color ("Color", Color) = (1,1,1,1)
_Vector("Vector",Vector) = (2,3,6,1)
_2D("2D",2D) = ""{}
_Cube("Cube",Cube) = "while"{}
_3D("3D",3D) = "black"{}
}
FallBack "Diffuse"
}
对于Int、Float、Range这些数字类型的属性,其默认值就是一个单独的数字;
对于Color、Vector这类属性,默认值是用圆括号包围的一个四维向量;
对于2D、Cube、3D这种纹理类型,默认值是通过一个字符串后跟一个花括号来指定,其中。字符串要么是空的,要么是内置的纹理名称,如“white”,“black”,“gray”,“bump”
显示结果如图:
每一个shader中可以包含多个SubShader语义块,但最少要有一个。但不是每一个都能用的到,这个可以根据不同的平台编写不同的SubShader,在使用的时候Unity会扫描所有的SubShader语义块,然后选择第一个能够在目标平台上运行的SubShader。如果所有的都不支持,那么Unity会使用FallBack语义指定的UnityShader,SubShade语义如下:
SubShader
{
//可选的
[Tags]
//可选的
[RenderSetup]
Pass
{
}
}
SubShader
{
}
FallBack "Diffuse"
SubShader中定义了一系列Pass,以及可选的状态[RenderSetup]和标签[Tags]设置。每一个Pass定义了一个一次完整的渲染流程,但如果Pass数目过多,就会造成渲染性能的下降,因此,我们应尽量使用最小数目的Pass。
状态和标签同样可以在Pass板块中声明,只不过,在SubShader中设置,会作用于所有的Pass,但是在Pass中设置,只会作用于本Pass板块
常见的渲染状态设置选项,如下图:
SubShader中的标签(Tags)是一个键值对,它的键和值都是字符串类型;
标签的结构如下:
Tags{"Tagname1" = "Value1" "TagName2" = "Value2"}
标签类型如下图:
Pass语义块:
Pass
{
[Name]
[Tags]
[RenderSetup]
//other Code
}
我们可以在Pass 中定义该Pass的名称。如:Name "MyPassName",通过这个名称,我们可以使用ShaderLab的UsePass命令来直接使用其他UnityShader中的Pass ,如:UsePass"MyShader/MYPASSNAME",这样就可以提高代码的复用性。但是注意:
由于Unity内部会把所有的Pass的名称转换成大写字母来表示,因此,在使用UsePass命令时必须使用大写字母
Pass中同样可以设置标签,但它的标签不同于SubShader的标签,这些标签也是用于告诉渲染引擎我们希望怎样来渲染该物体,如下
好了,这一章就写到这,欢迎大家加入QQ群:280993838 或者关注我的公众号: