一、多级渐远贴图MipMap
选择贴图,可以勾选贴图的多级渐远效果
[IntRange]_MipMap("MipMap",Range(0,12))=0 //多级渐远贴图的LOD调节滑杆
_MipMapTexture("MipMapTexture",2D)="white"{} //定义多级渐远贴图
多级渐远贴图的采样:
float4 Mipmap=tex2Dlod(_MipMapTexture,float4(i.uv.xy,0,_MipMap));
二、立方体纹理 CubeMap
利用立方体纹理制作反射效果:
反射效果的形成:
float3 R=reflect(-V,N);
reflect函数根据入射向量和法向量求反射向量
而向量V是从模型指向摄像机的方向的向量,所以此时的入射向量为-V
_CubeMap("CubeMap",Cube)="white"{}
samplerCUBE _Cubemap; //声明立方体纹理
float4 Cubemap=texCUBE(_CubeMap,R); //立方体纹理的采样
Shader"unity/Texture03"
{Properties{_MipMapTexture("MipMapTexture",2D)="white"{}[IntRange]_MipMap("MipMap",Range(0,12))=0_CubeMap("CubeMap",Cube)="white"{}}SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MipMapTexture;int _MipMap;samplerCUBE _CubeMap;struct appdate {float4 vertex : POSITION;float4 uv : TEXCOORD;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float4 uv : TEXCOORD;float3 worldNormal:TEXCOORD1;float3 worldPos : TEXCOORD2;};v2f vert(appdate v){v2f o;o.pos=UnityObjectToClipPos(v.vertex);o.worldNormal=UnityObjectToWorldNormal(v.normal);o.worldPos=mul(unity_ObjectToWorld,v.vertex);o.uv=v.uv;return o;}float4 frag(v2f i):SV_Target{float4 Mipmap=tex2Dlod(_MipMapTexture,float4(i.uv.xy,0,_MipMap));float3 N=normalize(i.worldNormal);float3 V =normalize(_WorldSpaceCameraPos-i.worldPos);float3 R=reflect(-V,N);float4 Cubemap=texCUBE(_CubeMap,R);return Cubemap;}ENDCG}}}
三、法线纹理
法线贴图中存储的是每个像素点在切线空间下的法线向量信息
所以采样法线贴图后的值为切线空间下的法线值
//采样法线贴图 (采样结果为切线空间下的法线值) UnpackNormal函数通常用于解压纹理中压缩的法线信息,以获取其正确的法线
float3 normalTex=UnpackNormal(tex2D(_NormalTex,i.uv));
但是光照计算所需要的法线值为世界空间下的法线信息,所以就需要将采样后的法线值转换到世界空间下
这时就需要使用到切线空间变换矩阵,将法线信息由切线空间转换到世界空间
其中 切线 tangent 是一个四维的向量
flaot4 tangent ; //tangent.w代表切线的方向,tangent.xyz代表坐标
- 在顶点着色器中将模型顶点的切线由本地空间转换到世界空间
float3 worldTangent=UnityObjectToWorldDir(v.tangent);
- 再计算切线的方向
float tangentSign=v.tangent.w*unity_WorldTransformParams.w;
- 由世界空间法线向量和世界空间切线向量的叉值算法来计算副切线向量
(注意:此时的世界空间法线向量为模型上各像素点的法线向量,而非采样后的法线值)
//副切线由切线向量和法线向量的叉积所得
float3 worldBinormal=cross(worldNormal,worldTangent)*tangentSign;
- 然后构建切线空间变换矩阵
//给切线空间变换矩阵赋值
o.tSpace0=float3(worldTangent.x,worldBinormal.x,worldNormal.x);
o.tSpace1=float3(worldTangent.y,worldBinormal.y,worldNormal.y);
o.tSpace2=float3(worldTangent.z,worldBinormal.z,worldNormal.z);
- 最后在片元着色器中将采样后的法线值和变换矩阵进行点积操作得到世界空间下法线贴图中的法线值
fixed3 worldN=float3(dot(normalTex,i.tSpace0),dot(normalTex,i.tSpace1),dot(normalTex,i.tSpace2));
Shader"unity/Texture02"
{Properties{//定义法线纹理 [Normal]标签的作用是使得该纹理贴图的位置只能装载法线贴图[Normal]_NormalTex("NormalTex",2D)="white"{}}SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _NormalTex;float4 _NormalTex_ST;struct appdate{float4 vertex:POSITION;float2 uv:TEXCOORD;float3 normal:NORMAL;//(tangent四维向量,xyz代表坐标,w代表切线的方向)float4 tangent:TANGENT;};struct v2f{float4 pos:SV_POSITION;float2 uv:TEXCOORD;//定义切线空间变换矩阵float3 tSpace0:TEXCOORD1;float3 tSpace1:TEXCOORD2;float3 tSpace2:TEXCOORD3;};v2f vert(appdate v){v2f o;o.uv=TRANSFORM_TEX(v.uv,_NormalTex);o.pos=UnityObjectToClipPos(v.vertex);//世界空间法线float3 worldNormal=UnityObjectToWorldNormal(v.normal);//将模型顶点的切线由本地空间转换为世界空间float3 worldTangent=UnityObjectToWorldDir(v.tangent);//决定切线的方向float tangentSign=v.tangent.w*unity_WorldTransformParams.w;//副切线由切线向量和法线向量的叉积所得float3 worldBinormal=cross(worldNormal,worldTangent)*tangentSign;//给切线空间变换矩阵赋值o.tSpace0=float3(worldTangent.x,worldBinormal.x,worldNormal.x);o.tSpace1=float3(worldTangent.y,worldBinormal.y,worldNormal.y);o.tSpace2=float3(worldTangent.z,worldBinormal.z,worldNormal.z);return o;}float4 frag(v2f i):SV_TARGET{ //法线纹理的采样(切线空间下的法线值)//采样法线贴图后的值为一个三维向量fixed3 normalTex=UnpackNormal(tex2D(_NormalTex,i.uv));//worldN是基于切线变换矩阵和切线空间下的法线值所计算得到的世界空间下的法线值fixed3 worldN=float3(dot(normalTex,i.tSpace0),dot(normalTex,i.tSpace1),dot(normalTex,i.tSpace2));fixed3 L=normalize(_WorldSpaceLightPos0);//lamber光照模型 max(0,dot(N,L)fixed NdotL=max(0,dot(worldN,L));return NdotL;}ENDCG}}}