• (二)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的基本语法解释清楚了,后续会不断拓展。推荐学习的地方:添加几个连接:[完整代码版](https://blog.csdn.net/l773575310/article/month/2017/11)和[原文版](https://blog.csdn.net/e295166319/category_9271086.html)

  • 相关阅读:
    ls: cannot open directory .: Permission denied
    postman报错:Could not get any response
    IO流的继承关系
    吸顶效果
    linux报错:ls command not found
    内存寻址能力与CPU的位宽有关系吗?
    CPU与内存
    SQL语言的分类
    32位CPU和64位CPU 区别
    linux添加环境变量
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/11953025.html
Copyright © 2020-2023  润新知