参考:
《Unity Shader入门精要笔记(十二):纹理属性》
一.基本纹理采样
1.UV坐标:将纹理通过“纹理映射坐标”(纹理展开技术)存储在每个顶点上,每个顶点对应着该纹理在2D坐标上的位置,这个坐标即为UV坐标,其中u为横向坐标,v为纵向坐标;
2.纹理可以有多种256x256或者1024x1024,但UV坐标范围通常被归一化为【0,1】
3.纹理坐标的原点位置:
DirectX:左上角
OpenGL&Unity:左下角
二.纹理的属性
Texture Type:
Texture:普通贴图
Normal map:法线贴图
Editor GUI and Legacy GUI:UI贴图
Sprite(2D and UI):精灵
Cursor:鼠标指针
Reflection:反射贴图
Cookie:遮罩贴图
Lightmap:烘焙贴图
Advanced:高级(可自定义一些贴图属性)
Texture 修改Tilling参数
Wrap Mode:
它决定了当纹理坐标超过[0, 1]范围后将如何平铺。有两项,repeat和clamp,repeat顾名思义,表示重复,当纹理坐标超过1时,整数部分被舍弃,直接使用小数部分进行采样,纹理会不断重复;clamp,纹理坐标大于1时会截取到1,小于0时会截取到0。如下图:
两幅图都是平铺属性为(3,3)的效果,上图repeat就不断重复,下图clamp则截取到边界。
注意,如果要这样的效果,不要忘了Shader中使用纹理的属性(例如上一篇的_MainText_ST)对纹理坐标进行变换,也就是需要类似下面的代码:
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
否则面板没有这个重复模式的选项。
还可以调整纹理坐标的偏移量,使纹理不以(0,0)为原点。下图展示了偏移属性为(0.2, 0.6)时分别使用两种Wrap Mode的结果。
Filter Mode:滤波模式
它决定了当纹理由于变换产生拉伸时会采用哪种滤波模式。有3种模式:Point,Bilinear,Trilinear。
a、Point模式:最近点采样,当纹理坐标没有刚好对应Texture上的一个采样点时,它会选择最近的一个采样点作为该坐标的采样值,当纹理没有拉伸变形时,这样还不错,因为速度是最快的,但如果拉伸变形了,会出现马赛克现象。
b、Bilinear模式:双线性过滤,以像素对应的纹理坐标为中心,采样它周围4个texel(纹素)的像素,取平均值作为该坐标采样值。这是Unity默认的模式,过渡效果相对平滑,当然速度会比最近点采样有一定下降。
c、Trilinear模式:三线性过滤,会对像素大小和纹素大小最接近的两层Mipmap level分别进行双线性过滤,再对结果进行线性插值。由于使用了两次双线性过滤,也就是计算2x4=8个像素的值,速度会更加下降,当然滤波效果更好。下图是一张64x64的纹理贴在512x512的平面时用三种过滤的效果图:
多级渐远纹理技术
代码:
Shader "Custom/Texture"
{
Properties
{
_MainTex("MainTex",2D)="white"{}
_Color("MainTex Color",COLOR)=(1,1,1,1)
_Specular("Specular Color",Color)=(1,1,1,1)
_Gloss("Gloss",Range(1,50))=20
}
SubShader
{
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include"Lighting.cginc"
#include"UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST; //纹理的偏移和缩放(Tiling和offset)
fixed4 _Color;
fixed4 _Specular;
half _Gloss;
struct a2v
{
float4 vertex:POSITION; //取得顶点位置
float3 normal:NORMAL;
float2 texcoord:TEXCOORD0; //纹理的顶点坐标(float2)
};
struct v2f
{
float4 svPos:SV_POSITION; //剪裁空间下的顶点坐标
float3 worldNormal:TEXCOORD0;
float4 worldVertex:TEXCOORD1; //世界空间下的顶点坐标
float2 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos=UnityObjectToClipPos(v.vertex);
f.worldNormal=UnityObjectToWorldNormal(v.normal); //法线从模型空间=》世界空间
f.worldVertex=mul(unity_ObjectToWorld,v.vertex); //顶点坐标从模型空间=》世界空间
//对纹理进行偏移和缩放
//第一种:拆开计算
f.uv=v.texcoord * _MainTex_ST.xy - _MainTex_ST .zw;
//第二种(用自带的系统函数)
//f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
return f;
}
fixed4 frag(v2f f):SV_TARGET
{
fixed3 normalDir=normalize(f.worldNormal); //法线向量
fixed3 lightDir=normalize(WorldSpaceLightDir(f.worldVertex)); //光线向量
fixed3 viewDir=normalize(UnityWorldSpaceViewDir(f.worldVertex)); //视野方向
fixed3 halfDir=normalize(lightDir + viewDir); //平分向量
fixed3 texColor=tex2D(_MainTex,f.uv)*_Color; //纹理颜色
fixed3 diffuse=_LightColor0.rgb * texColor.rgb * max(0,dot(lightDir ,normalDir)); //漫反射
fixed3 specular=_LightColor0.rgb * _Specular.rgb * pow ( max(0,dot(normalDir,halfDir) ),_Gloss); //高光反射
//*texColor环境光和纹理融合效果好点
fixed3 tempcolor=diffuse+specular+UNITY_LIGHTMODEL_AMBIENT.rgb*texColor; //UNITY_LIGHTMODEL_AMBIENT.rgb环境光颜色
return fixed4(tempcolor,1);
}
ENDCG
}
}
FallBack"SPECULAR"
}
效果: