1.1.在CG中调用属性变量
Shader通过Properties代码块声明开放出来的属性,如果想访问这些属性,需要在CG代码块中再次进行声明,它的语法格式为:
type name; //type为变量的类型,name为属性变量的名称。
提示:
必须在函数调用属性之前对其进行声明,否则编译会失败。
下面是在这一篇中介绍到的属性,在CG中全部在声明一遍,代码块如下:
Shader "Unlit/在CG中调用属性变量" { Properties { //下面是可能会出现的 Properties 的结构 _2D("2D", 2D) = "" {} //2D贴图类型 _Color("Color",Color) = (1,1,1,1) //颜色类型 _Value("Value",Range(0,10)) = 2.5 //范围类型 _Float("Float",Float) = 0 //浮点类型 _Vector("Vector",Vector) = (0,0,0,0) //向量类型 _Cube("Cube",Cube) = "" {} //立方体贴图类型 _3D("3D",3D) = "" {} //3D贴图类型 //_name("display name" , type) = "defaulttexture" //_属性名CG代码块方便调用(“在面板中显示的” , 属性类型) = 初始化默认值 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" //在CG中声明属性变量 sampler2D _2D //2D贴图类型 float4 _Color //颜色类型 float _Value //范围类型 float _Float //浮点类型 float4 _Vector //向量类型 samplerCUBE _Cube //立方体贴图类型 sampler3D _3D //3D贴图类型 void vert() { } void frag() { } ENDCG } } }
下面是开放属性与CG属性变量的对应关系:
语义 | 描述 |
float,Range | 浮点和范围类型的属性,根据精度可以使用float,half或者fixed |
Color,Vector | 颜色和向量类的属性,可以使用float4,half4或fixed4声明,其中颜色使用低精度的fixed4声明可以减少性能消耗 |
2D | 2D纹理贴图属性,使用sampler2D声明 |
cube | 立方体贴图属性,使用samplerCUBE声明 |
3D | 3D纹理贴图属性,使用sampler3D声明 |
1.2.实现更改颜色
先小试一下,其他的大多都差不多,需要多练习就熟悉了。下面对颜色属性,在CG中重新声明属性变量,实现更改颜色功能。
Shader "Unlit/实现更改颜色" { Properties { //开放颜色属性 _Color("Color",Color) = (1,1,1,1) //颜色类型,默认值为(1,1,1,1)=白色 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag float4 _Color; //在CG中以float4类型再次声明 void vert(in float4 vertex : POSITION, out float4 position : SV_POSITION) { position = UnityObjectToClipPos(vertex); } void frag(out float4 color : SV_TARGET) //在第一篇中解释了,为啥片段着色器可以直邮输出? { //调用颜色变量_Color Color = _Color; //在片段着色器中直接使用变量_Color输出颜色,无返回值。 } ENDCG } } }
1.3.实现使用贴图(启用纹理的变量的Tiling和Offset的语法细则)
上面通过声明实现自由更改颜色。接下来实现使用纹理贴图。
在Properties代码块别定义之后,还需要在CG代码块中再次声明。但是与其他属性不同的是,CG还需要额外声明一个变量用于储存贴图的其他信息。如下面的图:
下面是Tiling和Offset属性:
平铺(Tiling)和偏移(Offset)属性,额外声明的变量就是为了储存这些信息。
在CG中,声明一个纹理的变量的Tiling和Offset的语法结构如下:
float4{TextureName}_ST;
其中TextureName是纹理属性的名称
ST:Scale和Transform的首字母,表示UV的缩放和平移。
x和y分量分别为Tiling的X值和Y值
z和w分量分别为Offset的Z值和W值
纹理坐标的计算公式为:
texcoord = uv * {TextureName}. xy + {TextureName}.zw
注意:公式先乘以平铺再加偏移值。初中的加减乘除运算规则是先乘除再加减,这样记住就可以了。有兴趣的可以看一下背后推导的过程,这里不扩充。
直接上代码,注释里会说的很清楚。
Shader "Unlit/实现使用贴图" { Properties { //开放颜色属性 _MainTex("MainTex", 2D) = "white" {} //2D贴图类型 _MainColor("MainColor",Color) = (1,1,1,1) //颜色类型 //Properties开放的名称为_MainTex的纹理属性,默认值为白色。 //当然这里也可以写成这样,比较灵活,他们要声明的属性是一个类型。 //_2D("2D", 2D) = "white" {}//2D贴图类型 //_Color("Color",Color) = (1,1,1,1) //颜色类型 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag//这三行在第一篇里有详细说明。 float4 _MainColor; //在CG中以float4类型再次声明 //声明纹理属性变量以及ST变量 sampler2D _MainTex; float4 _MainColor_ST; void vert(in float4 vertex : POSITION,in float2 uv : TEXCOORD0, out float4 position : SV_POSITION,out float2 texcoord : TEXCOORD0) { //下面这个“UnityObjectToClipPos”是unity5.6以后的写法,unity5.6以前的写法是“UNITY_MATRIX_MVP” position = UnityObjectToClipPos(vertex); //使用公式计算纹理坐标 texcoord = uv * _MainColor_ST.xy + _MainColor_ST.zw; //如果用不到平铺(Tiling)和偏移(Offset)属性效果,那么可以省略对纹理资源ST变量的声明,同时不再计算其纹理坐标。 //则公式可以写成这样: // texcoord = uv; //也就是UV坐标输入到顶点函数之后无需计算平铺和偏移,而是直接输出。 //片段函数void frag()获取到UV坐标之后直接对纹理进行采样。 } //来到了片段着色器 void frag(in float4 position : SV_POSITION,in float2 texcoord : TEXCOORD0, out float4 color : SV_TARGET) { Color = tex2D(_MainTex,texcoord) * _MainColor; } ENDCG } } }
Pass介绍的第三篇了,是时候介绍 具体的 多一点的 结构体,着色器通常需要输入和输出参数,为了使代码编写更加方便,并且看起了整洁,所以有了这样的一个数据类型——结构体。