一 .基础纹理应用
纹理的最初目的就是使用一张图片来控制模型的外观。使用纹理映射技术,我们可以吧一张图“黏”在模型表面,逐纹素(texel)(名字是为了和逐像素进行区分)地控制模型的颜色。
结合之前的光照模型的单张纹理应用:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom/Edu/SingleTexture" {
Properties
{
_MainTex("MainTex",2D)= "white"{}
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8,256)) = 40
_Color("ColorTint",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Diffuse;
fixed4 _Specular;
fixed4 _Color;
float _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
float2 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(viewDir + worldLightDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal,halfDir)),_Gloss);
return fixed4( diffuse + ambient + specular , 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
TRASFORM_TEX实在UnityCG.cginc中定义的:
//Transform 2D UV by scale/bias property
#define TRANSFORM_TEX(tex,name)(tex.xy * name##_ST.xy + name##_ST.zw)
它接受两个参数
第一个参数是顶点的纹理坐标
第二个参数是纹理的名称
看一下效果:
二.纹理采样区间设置
下面为了阐释纹理的属性,编写一个更为纯粹的纹理属性应用shader
Shader "Custom/Edu/SimpleTextureProperties" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
struct a2v
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 color = tex2D(_MainTex,i.uv);
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
利用这个shader在场景中创建一个Quad。
此时我们对纹理使用的Wrap Mode的是Repeat——重复纹理采样。
这种模式下,如果纹理的坐标超过了1,那么整数部分将会被舍弃,而直接使用小数部分进行采用。
下面我们来看另外一种模式
当使用Clamp模式时,超过的部分将会截取到边界值,从而形成一个条形结构。
三.3种滤波模式
纹理导入面板中的下一个属性是FilterMode属性,它决定了当纹理由于变换而产生拉伸是将会使用哪种滤波模式。
Point模式使用了最近邻滤波,在放大或缩小时,它的采样像素数目通常只有一个,因此图像看起来有种像素风格的效果。
Bilinear滤波采用了线性滤波,对于每个目标像素,它会找4个邻近的像素,然后对他们进行线性插值混合后得到最终的像素,因此图像看起来像被模糊了。
Trilinear滤波几乎和Bilinear是一样的,知识Trilinear还会在多级渐远纹理(mipmapping)之间进行混合。
四.纹理的最大尺寸和纹理模式
【我只安装了安卓build的模块】
Unity允许我们为不同目标平选择不同的纹理尺寸和压缩格式。
如果导入的纹理超过了MaxTextureSize中的设置,那么Unity会把这个纹理所防伪这个最大分辨率。
导入的纹理的长宽大小应该是2的整数次幂。
如果使用了非2的整数次幂大小(Non Power of Two,NPOT)的纹理,那么这些纹理往往会占用更多的内存空间,而且GPU的读取该纹理的速度也会下降。甚至有一些平台不支持NPOY纹理。
对于一些不需要使用很高精度的纹理(例如漫反射颜色的纹理),我们应该尽量使用压缩格式!