Unity Shader 基础
概述
在unity中我们需要配合使用材质(Material)和shader来达到效果。
- 常见流程:
- 创建Material
- 创建shader,赋值给上面创建的Material
- 把Material赋值给要渲染的对象
- 在Material面板中调整shader的属性,得到满意的效果
- 创建shader:
- Project视图右键
- Create
- Shader
- unity提供的Shader模板:
- Standard Surface Shader–带有标准光照模型的表面着色器模板
- Unlit Shader–不包含光照的基本的顶点/片元着色器
- Image Effect Shader–实现屏幕后处理效果
- Compute Shader–一段运行在 GPU上的程序,利用GPU的并行性进行一些和常规渲染流水线无关的计算
- Ray Tracing Shader–射线追踪的着色器,目前是实验阶段,后续可能会更改或删除
下面是使用Unlit Shader模板创建的一个shader,关于shader的基础结构,用注释标注了一下
// '/'表示路径 位置:Shader->MyShader->TestShader
Shader "MyShader/TestShader"
{
// 材质和shader的桥梁
Properties
{
// _MainTex是shader中使用的名称
// Texture是材质面板上的名称
// 2D是这个属性的类型
// "white" {}是默认值
_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 = UnityObjectToClipPos(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
}
}
}
1. shader命名
Shader “MyShader/TestShader”
在材质面板中的位置
2. Properties
在这个语义块中,我们可以定义一些属性,这些属性可以显示在材质面板中
Properties
{
_Int ("Int", Int) = 2
_Float ("Float", Float) = 1.4
_Range ("Range", Range(0.0,5.0)) = 3.0
_Color ("Color", Color) = (1,0,1,1)
_Vector ("Vector", Vector) = (1,2,3,4)
_Cube ("Cube", Cube) = ""{}
_3D ("3D", 3D) = "Black"{}
_2D ("2D", 2D) = "white" {}
}
3. SubShader
每个shader文件中,可以包含多个SubShader,但最少要有一个。当unity需要加载这个unity shader时,unity会扫描所有的SubShader语义块,然后选择第一个可以在目标平台中运行的SubShader。如果都不支持的话,会返回FallBack语义指定的SubShader。
SubShader
{
// 可选的
Tags { "RenderType"="Opaque" }
// 可选的 [RenderSetup]
Cull Off
pass{
}
//可以有多个pass
}
3.1 Tags
3.2 RenderSetup
常见渲染状态设置:
3.3 Pass语义块
UsePass "MyShader/TestShader/MYPASS"
pass{
Name "TestPass"
Tags {"LightMode" = "ForwardBase"}
Cull Off
}
UsePass 可以使用其他Shader中的Pass
GrabPass负责抓取屏幕,并将结果存储在一张纹理中,用于后处理
pass的标签类型:
3.4 FallBack
FallBack "MyShader/TestShader2"
// 或者
FallBack Off
表示如果上面的shader都执行不了,那么就执行FallBack指定的shader。也可以选择关闭FallBack,代表如果都执行不了,就算了。
4. Unity Shader的形式
Unity Shader的大概格式:
Shader "MyShader/TestShader2"
{
Properties
{
// 需要的各种属性
}
SubShader
{
// 真正意义上的shader
// 表面着色器(Surface Shader)或者
// 定点/片元着色器(Vertex/Fragment Shader)或者
// 固定函数着色器(Fixed Function Shader)
Tags { "RenderType"="Opaque" }
Cull Off
UsePass "MyShader/TestShader/MYPASS"
pass{
Name "TestPass"
Tags {"LightMode" = "ForwardBase"}
Cull Off
}
pass{
}
}
SubShader
{
}
FallBack Off
}
4.1 表面着色器
Unity做了很多工作,需要的代码量较少,渲染代价较大。Unity会将表面着色器转换成对应的顶点/片元着色器。
新建一个表面着色器,内容是这样的:
Shader "Custom/NewSurfaceShader"
{
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;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
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"
}
表面着色器的内容被定义在CGPROGRAM和ENDCG中间,而不是在Pass中,因为我们不需要关注有多少个pass,unity会处理好这些。代码使用CG/HLSL编写的,也就是需要把CG/HLSL嵌套在ShaderLab中。
4.2 顶点/片元着色器
代码如下:
Shader "Unlit/MyShader"
{
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 = UnityObjectToClipPos(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
}
}
}
需要我们自己定义好每个pass,更复杂一些,灵活度也更高。
4.3 固定函数着色
目前应该只有非常旧的设备会使用。
本文来源《unity shader入门精要》冯乐乐著