(二)Unity顶点/片元着色器基础

1.前言

本文主要讲解以下Unity shader的一些基础内容,以无光照shader为例进行说明,后续进行详细分析与说明。此Shader可以直接复制到Unity中使用(unity2018/2018亲测可用),建议边使用边看如下分析。Shader如下所示:

Shader "LL/Unlit/UnlitShader_basicDismiss"
{
	Properties
	{
		_MainTex("Main Texture",2D)="white"{} _DissolveTex("Dissolve Texture",2D)="white"{} _DissolveCutoff("Dissolve Cutoff",Range(0,1))=1 _Dismiss("Model Dismiss",Range(-1,1))=0 } SubShader { pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float _DissolveCutoff; float _Dismiss; sampler2D _MainTex; sampler2D _DissolveTex; struct a2v { float4 vertex:POSITION; float2 uv:TEXCOORD0; float3 normal:NORMAL; }; struct v2f { float2 uv:TEXCOORD0; float4 vertex:SV_POSITION; }; v2f vert(a2v v) { v2f f; f.uv=v.uv; v.vertex.xyz=v.vertex.xyz+v.normal*_Dismiss; f.vertex=mul(UNITY_MATRIX_MVP,v.vertex); //f.vertex=UnityObjectToClipPos(v.vertex); return f; } float4 frag(v2f f):SV_TARGET { float4 mainTexColor=tex2D(_MainTex,f.uv); float4 dissolveTexColor=tex2D(_DissolveTex,f.uv); clip(dissolveTexColor.rgb-_DissolveCutoff); return mainTexColor; } ENDCG } } } 

2.Shader名称

名称如下所示,此shader名称为UnlitShader_basicDismiss,通过路径LL/Unlit/即可找到。

Shader "LL/Unlit/UnlitShader_basicDismiss"
{
}

3.属性

属性为暴露在Inspector面板中的参数,可以人为更改的,基本格式为:属性名称(“显示名称”,变量类型)= 默认值,如下所示。
属性基本格式以_MainTex("Main Texture",2D)="white"{}为例进行解释:_MainTex为变量名称,括号内双引号内第一个值"Main Texture"为面板上显示内容,第二个值2D为此变量所表示的内容,即为2D纹理。“white”{}则为默认值为白色纹理,写法使用双引号加{},但是对于其他变量则不是,比如_DissolveTex为float类型,则值为1,每一个变量后无需加分号。

	Properties
	{
		_MainTex("Main Texture",2D)="white"{} _DissolveTex("Dissolve Texture",2D)="white"{} _DissolveCutoff("Dissolve Cutoff",Range(0,1))=1 _Dismiss("Model Dismiss",Range(-1,1))=0 } 

变量类型以及使用类型如下表所示:

属性类型 例子 说明
Int _Int(“Int”,Int)=2 Int类型,默认值为2
Float _Float(“Float”,Float)=2.0 Float类型,默认值为2
Range _Range(“Range”,Range(0,1))=0.5 Float类型,默认值为0.5,并锁定范围
Color _Color(“Color”,Color)=(1,1,1,1) Color类型,默认值为白色
Vector _Vector(“Vector”,Vector)=(1,1,1,1) Vector类型(四维向量),默认值为白色(1,1,1,1)
2D _MainTex(“Main Texture”,2D)=“white”{} 2D纹理,默认值为白色纹理
Cube _Cube(“SkyBox”,Cube)=“white”{} Cube纹理,默认值为白色纹理
3D _MainTex(“Main Texture”,3D)=“white”{} 3D纹理,默认值为白色纹理

其中:Range类型是一个slider样式,支持滑动修改和手动直接输入,但是在2018以后无slider样式;Vector类型看名称虽然是向量,其实代表的为四维数据,也可以当作位置输入;Cube则表示此纹理为六面体纹理。

4.SubShader

一个unity Shader中可以包含多个SubShader代码块,最少一个,加载时unity选择与目标平台匹配的第一个SubShader运行,如果都不支持,则会使用Fallback语义指定的Shader。一个SubShader中可以包含多个pass。pass中语句定义在 CGPROGRAM ENDCG之间,表示使用CG/HLSL编写的,当然也可以用其他的语言去写。

	SubShader
	{
		pass
		{
		    CGPROGRAM
		    。。。
		    ENDCG
		}
	}

5.定义顶点/片元着色器

通过#pragma vertex定义顶点着色方法vert(此为方法名称,可以随意修改),同时添加实现。同理通过#pragma fragment定义片元着色器frag,并实现改方法。其中#include "UnityCG.cginc"表示引入此文件中定义的方法、变量以及语义块。此文件获取章节会详细讲解。

			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc" float _DissolveCutoff; float _Dismiss; sampler2D _MainTex; sampler2D _DissolveTex; struct a2v { float4 vertex:POSITION; float2 uv:TEXCOORD0; float3 normal:NORMAL; }; struct v2f { float2 uv:TEXCOORD0; float4 vertex:SV_POSITION; }; v2f vert(a2v v) { v2f f; f.uv=v.uv; v.vertex.xyz=v.vertex.xyz+v.normal*_Dismiss; f.vertex=mul(UNITY_MATRIX_MVP,v.vertex); //f.vertex=UnityObjectToClipPos(v.vertex); return f; } float4 frag(v2f f):SV_TARGET { float4 mainTexColor=tex2D(_MainTex,f.uv); float4 dissolveTexColor=tex2D(_DissolveTex,f.uv); clip(dissolveTexColor.rgb-_DissolveCutoff); return mainTexColor; } 

5.1 变量引用

在上述代码中,定义了两个float以及sampler2D格式变量,这两个变量与属性模块中变量同名,这样变可获取到属性面板变量的值。

5.2 自定义变量

在上述代码中定义了两个struct类型a2v与v2f。其中struct中定义变量时格式为:变量类型+变量名称+变量语义,如下所示:

float4 vertex:POSITION;

float4表示变量vertex是一个四维向量或者数组。但是它代表的含义是由变量语义POSITION定义的,表示此变量为顶点坐标。所以变量normal则为此顶点处的法线,uv则为此处的纹理坐标。同理v2f中SV_POSITION则为裁剪空间下的坐标。在vert方法中返回值为v2f类型,则此时vertex表示的裁剪空间下的顶点坐标;而在frag中作为入口参数,vertex则表示片元的坐标位置,同理其uv也为片元的uv坐标。具体可参考上一篇中顶点/片元着色器部分。

变量类型如下表所示

类型 释义
float 最高位数数据变量
half 中间位数数据变量
fixed 最低位数精度数据变量(由于颜色值为0-1,所以颜色可用fixed4类型)

变量类型+数字n表示一个n维变量,每一维度的数值为相应的类型,如fixed4,表示4维变量,每一维度类型为fixed。

5.3 顶点着色器vert

vert方法最基本的任务是将顶点坐标转换到裁剪空间下(即GPU调用此vert方法对每一个顶点进行处理),所以其入口参数至少包含一个语义为POSITION的顶点坐标,输出值包含语义为SV_POSITION变量,最基本的vert方法如下所示,可根据需要传入其他变量,比如本例还传入了uv和法线。以如下为例通过UnityCG.cginc中的UnityObjectToClipPos方法将顶点坐标转化到裁剪空间中。也可以通过mul(UNITY_MATRIX_MVP,v.vertex)方法实现,即通过MVP矩阵直接成以坐标变量。其实UnityObjectToClipPos就是用的mvp矩阵直接计算。

			float4 vert(float4 vertex:POSITION):SV_POSITION { return UnityObjectToClipPos(vertex); } 

本例中在计算裁剪空间下顶点坐标之前对顶点坐标做了处理,即在其法线方向移动_Dismiss距离,如果其值为0,则不移动。

5.4 片元着色器frag

片元着色器最根本的所用是产生一个像素的颜色,所以可以不用入口参数,直接返回一个颜色值,如下所示:

            float4 frag():SV_TARGET
			{ return fixed4(0.5,1,0,1); } 

本例中相对复杂一些,即根据uv值,通过tex2D(_MainTex,f.uv)方法,对主纹理进行采样,获取相应的颜色值进行返回,并根据_DissolveTex纹理,做了像素的舍弃clip(dissolveTexColor.rgb-_DissolveCutoff);即当clip的值小于0时discard掉此值,即frag在此位置不会返回颜色值,此时对应的位置就不会显示任何颜色,因为颜色rgb分量值范围为0-1,所以对应的_DissolveCutoff值也为0-1。

6.结语

通过一个基本的Shader将shader的基本语法解释清楚了,后续会不断拓展。

猜你喜欢

转载自www.cnblogs.com/llstart-new0201/p/11953025.html
今日推荐