关于纹理贴图介绍
纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比。
编写shader映射纹理
将纹理的颜色取代漫反射的颜色
Shader "AladdinShader/11 Single Texture Shader"
{
Properties
{
_MainTex("Main Tex", 2D) = "white"{}
_Color("Color", Color) = (1,1,1,1)
_Specular("Specular Color", Color)=(1,1,1,1)
_Gloss("Gloss",Range(10,200))=20
}
SubShader {
Pass{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
fixed4 _Color;
fixed4 _Specular;
half _Gloss;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
fixed3 worldNormal:TEXCOORD0;
float4 worldVertex:TEXCOORD1;
float4 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldNormal = UnityObjectToWorldNormal(v.normal);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
f.uv = v.texcoord;
return f;
}
fixed4 frag(v2f f):SV_Target{
fixed3 normalDir = normalize(f.worldNormal);
fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));
fixed3 texColor = tex2D(_MainTex, f.uv.xy) * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(normalDir, lightDir), 0);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss);
fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rbg * texColor;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Specular"
}
我们找一个纹理贴图

然后将贴图赋值给_MainTex属性,调整一下高光颜色和整体贴图颜色属性并且查看效果
第一组效果:


第二组效果:


给纹理添加偏移和缩放
将一个贴图拖到模型上会自动创建跟名字一样的材质,Shader中创建一个2D属性会发现在Inspector面板上会有一个Tiling和Offset两个属性,Tiling是缩放属性,Offset是偏移属性。
将上面的例子修改一下Shader,支持纹理的旋转和缩放:
Shader "AladdinShader/11 Single Texture Shader"
{
Properties
{
_MainTex("Main Tex", 2D) = "white"{}
_Color("Color", Color) = (1,1,1,1)
_Specular("Specular Color", Color)=(1,1,1,1)
_Gloss("Gloss",Range(10,200))=20
}
SubShader {
Pass{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
fixed4 _Color;
fixed4 _Specular;
float4 _MainTex_ST;
half _Gloss;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
fixed3 worldNormal:TEXCOORD0;
float4 worldVertex:TEXCOORD1;
float2 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldNormal = UnityObjectToWorldNormal(v.normal);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
f.uv = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw;
return f;
}
fixed4 frag(v2f f):SV_Target{
fixed3 normalDir = normalize(f.worldNormal);
fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));
fixed3 texColor = tex2D(_MainTex, f.uv.xy) * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(normalDir, lightDir), 0);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss);
fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rbg * texColor;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Specular"
}
说明:
1.pass中定义的新的变量 float4 _MainTex_ST; 是用来获取贴图的Tiling和Offset的值,因为是一个xyzw的四个值,所以我们用float4来定义,变量名_MainTex_ST是一个固定格式的变量,_MainTex是跟纹理贴图变量保持一致,_ST是缩放Scale和移动Translate的首字母。
2. f.uv = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw; 这句是核心,意思是将纹理*Tiling的缩放系数加上偏移量就得到想要的效果。
效果图:




纹理的属性
Texture Type
- Default 就是默认的贴图/Texture
- Normal map 法线贴图
- Editor GUI and Legacy GUI 编辑器贴图
- Sprite(2D and UI) 就是2D图
- Cursor 就是鼠标贴图
- Cubemap就是用来做环境盒子
- Cookie 就是影子贴图
- Lightmap 就是光照贴图,场景烘焙之后的光照贴图,就不用实时计算光照
Advanced
- Read/Write Enabled 是否可读写
- Generate Mip Maps适配贴图 会计算生成若干个贴图 更大效果更好
Wrap Mode
- Repeat 当超过0-1的范围会周期循环读取贴图
- Clap 当超过0-1的范围会使用边界像素
Filter Mode
滤波模式,当纹理拉伸之后图片显示的模式
* Point(no filter) 像素风格
* Bilinear 二线性
* Triliner 三线行
从上到下一次越来越耗费性能,但效果会越来越好,一般选用中间的格式。Triliner会经过插值计算,效果更好,但计算量也最大,如果选择Point格式,比较适合像素风格,但远处看的话效果还行,近看就会看出像素效果。
关于凹凸映射和法线映射
使用情况:我们在减少模型面的情况下使用凹凸映射会让模型看起来更加精细。会修改模型的法线,让模型看起来凹凸不平。
举例:比如我们生活中常见的石头模型,如果模型本身不是精细,因为精细的模型会显得顶点和面数会比较多,但这时候可以采用法线贴图来实现表面坑洼的效果。
石头原效果图:

使用我们自定义的Shader看到模型本身的棱角效果图会感觉石头模型比较光滑

图二就感觉效果跟图一相差很大,但模型是用的同一个模型,这就体现了法线贴图的重要性。
法线贴图
那么何为发现贴图,看下图:

法线贴图就是将贴图的法线用颜色值表现出来,但法线是-1~1,颜色是0~1是怎么对应上的呢?这里就需要做一个处理:
pixel(像素值) = (normal(法线值) + 1) / 2
经过这样的变化就能存到颜色里面,所以我们拿到一个发现贴图我们需要反向运算才能获得正确的法线值。
normal = pixel * 2 - 1
切线空间
切换空间最重要的用途之一,即法线映射(Normal Mapping)。在这个空间里,我们不需要考虑该模型在场景中可能出现的位置、朝向等众多因素,而专注于模型本身。详细的参见文章:https://www.cnblogs.com/naturelight/articles/5486469.html
我们称tangant轴(T)、bitangent轴(B)及法线轴(N)所组成的坐标系,即切线空间(TBN)。

在立方体中,每个面都有对应的切线空间,每个面由两个三角形组成,该两个三角形中的纹理坐标就基于相应的切线空间。
编写法线贴图Shader
Shader "AladdinShader/13 Rock Normal Map Shader"
{
Properties
{
_MainTex("Main Tex", 2D) = "white"{}
_Color("Color", Color) = (1,1,1,1)
_NormalMap("NormalMap", 2D) = "bump"{}
}
SubShader {
Pass{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
fixed4 _Color;
fixed4 _Specular;
float4 _MainTex_ST;
sampler2D _NormalMap;
float4 _NormalMap_ST;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 tangent:TANGENT;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
float3 lightDir:TEXCOORD0;
float4 worldVertex:TEXCOORD1;
float4 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
f.uv.xy = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw;
f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;
TANGENT_SPACE_ROTATION;
f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
return f;
}
fixed4 frag(v2f f):SV_Target{
fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
fixed3 tangentNormal = UnpackNormal(normalColor);
tangentNormal = normalize(tangentNormal);
fixed3 lightDir = normalize(f.lightDir);
fixed3 texColor = tex2D(_MainTex, f.uv.xy) * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal, lightDir), 0);
fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rbg * texColor;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Specular"
}
效果图:

最左边是插件中的模型效果,最右边是自己实现的模型效果
法线贴图添加凹凸参数
添加凹凸参数属性控制凹凸力度
Shader "AladdinShader/13 Rock Normal Map Shader"
{
Properties
{
_MainTex("Main Tex", 2D) = "white"{}
_Color("Color", Color) = (1,1,1,1)
_NormalMap("NormalMap", 2D) = "bump"{}
_BumpScale("Bump Scale", float) = 1
}
SubShader {
Pass{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
fixed4 _Color;
fixed4 _Specular;
float4 _MainTex_ST;
sampler2D _NormalMap;
float4 _NormalMap_ST;
float _BumpScale;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 tangent:TANGENT;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
float3 lightDir:TEXCOORD0;
float4 worldVertex:TEXCOORD1;
float4 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
f.uv.xy = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw;
f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;
TANGENT_SPACE_ROTATION;
f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
return f;
}
fixed4 frag(v2f f):SV_Target{
fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
fixed3 tangentNormal = UnpackNormal(normalColor);
tangentNormal = normalize(tangentNormal);
tangentNormal.xy = tangentNormal.xy * _BumpScale;
fixed3 lightDir = normalize(f.lightDir);
fixed3 texColor = tex2D(_MainTex, f.uv.xy) * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal, lightDir), 0);
fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rbg * texColor;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Specular"
}
调整凹凸属性:



编写透明Shader
Shader "AladdinShader/14 Rock Alpha Shader"
{
Properties
{
_MainTex("Main Tex", 2D) = "white"{}
_Color("Color", Color) = (1,1,1,1)
_NormalMap("NormalMap", 2D) = "bump"{}
_BumpScale("Bump Scale", float) = 1
_Alpha("Alpha", Range(0,1)) = 1
}
SubShader {
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
fixed4 _Color;
fixed4 _Specular;
float4 _MainTex_ST;
sampler2D _NormalMap;
float4 _NormalMap_ST;
float _BumpScale;
float _Alpha;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 tangent:TANGENT;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
float3 lightDir:TEXCOORD0;
float4 worldVertex:TEXCOORD1;
float4 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
f.uv.xy = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw;
f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;
TANGENT_SPACE_ROTATION;
f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
return f;
}
fixed4 frag(v2f f):SV_Target{
fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
fixed3 tangentNormal = UnpackNormal(normalColor);
tangentNormal = normalize(tangentNormal);
tangentNormal.xy = tangentNormal.xy * _BumpScale;
fixed3 lightDir = normalize(f.lightDir);
fixed4 texColor = tex2D(_MainTex, f.uv.xy) * _Color;
fixed3 diffuse = _LightColor0.rgb * texColor.rgb * max(dot(tangentNormal, lightDir), 0);
fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rbg * texColor;
return fixed4(tempColor,texColor.a);
}
ENDCG
}
}
FallBack "Specular"
}
或者属性面板控制:
Shader "AladdinShader/14 Rock Alpha Shader"
{
Properties
{
_MainTex("Main Tex", 2D) = "white"{}
_Color("Color", Color) = (1,1,1,1)
_NormalMap("NormalMap", 2D) = "bump"{}
_BumpScale("Bump Scale", float) = 1
_Alpha("Alpha", Range(0,1)) = 1
}
SubShader {
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
fixed4 _Color;
fixed4 _Specular;
float4 _MainTex_ST;
sampler2D _NormalMap;
float4 _NormalMap_ST;
float _BumpScale;
float _Alpha;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 tangent:TANGENT;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
float3 lightDir:TEXCOORD0;
float4 worldVertex:TEXCOORD1;
float4 uv:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
f.uv.xy = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw;
f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;
TANGENT_SPACE_ROTATION;
f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
return f;
}
fixed4 frag(v2f f):SV_Target{
fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
fixed3 tangentNormal = UnpackNormal(normalColor);
tangentNormal = normalize(tangentNormal);
tangentNormal.xy = tangentNormal.xy * _BumpScale;
fixed3 lightDir = normalize(f.lightDir);
fixed3 texColor = tex2D(_MainTex, f.uv.xy) * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal, lightDir), 0);
fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rbg * texColor;
return fixed4(tempColor,_Alpha);
}
ENDCG
}
}
FallBack "Specular"
}

跟透明相关的代码块
Tags{“Queue” = “Transparent” “IgnoreProjector” = “True” “RenderType” = “Transparent”}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Shader学习交流群:
316977780