故事的开始在上一篇!!!
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声明 |
先小试一下,其他的大多都差不多,需要多练习就熟悉了。下面对颜色属性,在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
}
}
}
上面通过声明实现自由更改颜色。接下来实现使用纹理贴图。
在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介绍的第三篇了,是时候介绍 具体的 多一点的 结构体,着色器通常需要输入和输出参数,为了使代码编写更加方便,并且看起了整洁,所以有了这样的一个数据类型——结构体。