今天我们来讲下Shader中 贴图的使用,通过“texture samplers”,可以快速的获取到贴图信息。
开始本教程前,你需要了解Shader中Properties的使用,我们还是基于之前教程的Shader 进行更改,所以如果你不是很清楚,请先参看本系列教程之前的内容。

Sampler 声明
我们通过声明sampler2d类型的变量来向shader添加贴图信息,然后我们在Properties代码块中添加对应的变量,当没有任何贴图的时候,我们默认为白色。
Shader "Tutorial/03_Properties"{
Properties{
_Color("Color", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
}
// ...
//texture
sampler2D _MainTex;
//tint of the texture
fixed4 _Color;
Texture 坐标
接下来我们在Input结构体中添加UV坐标信息。UV坐标决定了贴图的哪个部分显示在Mesh网格的哪个地方。它们已经在我们的模型数据里面了,所以我们无需代码创建uv坐标,直接使用就行了。声明一个float2类型数据,并将属性设定为TEXCOORD0。在vertex shader部分,我们从appdata中读取uv信息,并且赋值给v2f,这样后面的frag shader中可以使用uv信息。我们将uv信息设为颜色的 r 和 g。
CGPROGRAM
//include useful shader functions
#include "UnityCG.cginc"
//define vertex and fragment shader
#pragma vertex vert
#pragma fragment frag
//texture
sampler2D _MainTex;
//tint of the texture
fixed4 _Color;
//the object data that's put into the vertex shader
struct appdata{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//the data that's used to generate fragments and can be read by the fragment shader
struct v2f{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
//the vertex shader
v2f vert(appdata v){
v2f o;
//convert the vertex positions from object space to clip space so they can be rendered
o.position = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
//the fragment shader
fixed4 frag(v2f i) : SV_TARGET{
return fixed4(i.uv.x, i.uv.y, 0, 1);
}
ENDCG

这里我们能看到左下角的uv坐标为(0,0)黑色,右上角为(1,1)黄色。接下来我们使用uv坐标信息,从贴图中读取信息,通过tex2D函数来实现,第一个参数为sampler 第二个参数为uv坐标。然后我们在Inspector中选择一个贴图,来查看效果。
//the fragment shader
fixed4 frag(v2f i) : SV_TARGET{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}

Tiling
现在Inpspector中Texture的旁边你能看到"tiling"和"offset",但是改变它们的值发现没有任何作用。我们可以通过下面的操作让它们能够移动和缩放网格上的贴图。添加一个float4类型的变量TextureName_ST,TextureName对应的是Properties中的贴图属性名,比如这里我们命名为_MainTex_ST。其中ST代表缩放和移动,分别对应float4 的 前两个值x&y和后两个值z&w。我们可以直接通过Unity提供的 TRANSFORM_TEX命令来使用这些值。
初始的uv坐标和贴图的名字作为传入的参数,然后在vertex Shader中来使用它,将input中的uv坐标拷贝到v2f结构体中。现在再到Inspector中试试,已经可以起作用了。
//the vertex shader
v2f vert(appdata v){
v2f o;
//convert the vertex positions from object space to clip space so they can be rendered
o.position = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

Tint
最后,我们添加代码来支持改变贴图的色调。我们使用Color变量作为色调改变的变量,所以我们把它重命名为Tint。然后在fragment Shader中我们将贴图的颜色乘上Tint的值,这意味着Tint为白色时,没有任何作用,当Tint为红色[1,0,0,1] 时,将只有贴图的红色部分起作用。
// ...
//show values to edit in inspector
Properties{
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
}
// ...
//the fragment shader
fixed4 frag(v2f i) : SV_TARGET{
fixed4 col = tex2D(_MainTex, i.uv);
col *= _Color;
return col;
}
// ...

Shader "Tutorial/004_Textures"{
//show values to edit in inspector
Properties{
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
}
SubShader{
//the material is completely non-transparent and is rendered at the same time as the other opaque geometry
Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
Pass{
CGPROGRAM
//include useful shader functions
#include "UnityCG.cginc"
//define vertex and fragment shader
#pragma vertex vert
#pragma fragment frag
//texture and transforms of the texture
sampler2D _MainTex;
float4 _MainTex_ST;
//tint of the texture
fixed4 _Color;
//the object data that's put into the vertex shader
struct appdata{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//the data that's used to generate fragments and can be read by the fragment shader
struct v2f{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
//the vertex shader
v2f vert(appdata v){
v2f o;
//convert the vertex positions from object space to clip space so they can be rendered
o.position = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
//the fragment shader
fixed4 frag(v2f i) : SV_TARGET{
fixed4 col = tex2D(_MainTex, i.uv);
col *= _Color;
return col;
}
ENDCG
}
}
}
至此,我们的Shader和Unity提供的无光照Shader的功能已经基本上一样了,而且理解了每一行Shader代码的作用。Unity中的无光照Shader可以通过New->Shader->Unlit来创建。
网友评论