76.深度和法线纹理-效果实现-深度纹理实现全局雾效-Unity自带全局雾效
76.1 知识点
主要讲解内容
全局雾效是什么
Unity自带的全局雾效
修改标准漫反射Shader产生雾效
复制Lesson20_标准光照着色器_标准漫反射的shader Lesson20_BumpedDiffuse
Shader "Unlit/Lesson76_BumpedDiffuse"
{
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)// 漫反射颜色
_MainTex("MainTex", 2D) = ""{}// 单张纹理
_BumpMap("BumpMap", 2D) = ""{}// 法线纹理
_BumpScale("BumpScale", Range(0,1)) = 1// 凹凸程度
// _SpecularColor("SpecularColor", Color) = (1,1,1,1)// 高光反射颜色
// _SpecularNum("SpecularNum", Range(0,20)) = 18// 光泽度
}
SubShader
{
// 加入渲染标签Tags { "RenderType"="Opaque" "Queue"="Geometry"}
// 渲染类型设置为不透明的、渲染队列设置为几何队列(不透明的几何体通常使用该队列)
Tags
{
"RenderType"="Opaque" "Queue"="Geometry"
}
//Base Pass
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
//使用阴影宏内置文件
#include "AutoLight.cginc"
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
// float4 _SpecularColor; //高光颜色
// fixed _SpecularNum; //光泽度
struct v2f
{
//裁剪空间下坐标
float4 pos:SV_POSITION;
//纹理uv
//我们可以单独的声明两个float2的成员用于记录 颜色和法线纹理的uv坐标
//float2 uvTex:TEXCOORD0;//颜色纹理
//float2 uvBump:TEXCOORD1;//法线纹理
//也可以直接声明一个float4的成员 xy用于记录颜色纹理的uv,zw用于记录法线纹理的uv
float4 uv:TEXCOORD0; //纹理变量
//顶点相对于世界坐标的位置 主要用于 之后的 视角方向的计算
//float3 worldPos:TEXCOORD1;
//切线 到 世界空间的 变换矩阵
//float3x3 rotation:TEXCOORD2;
//代表我们切线空间到世界空间的 变换矩阵的3行 三个变量的w存世界坐标
float4 TtoW0:TEXCOORD1;
float4 TtoW1:TEXCOORD2;
float4 TtoW2:TEXCOORD3;
//阴影坐标宏
//n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
//比如这里前面有四个
SHADOW_COORDS(4)
};
v2f vert(appdata_full v)
{
v2f v2f;
//把模型空间下的顶点转到裁剪空间下
v2f.pos = UnityObjectToClipPos(v.vertex);
//计算纹理的缩放偏移
v2f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
v2f.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//得到世界空间下的 顶点位置 用于之后在片元函数中计算视角方向(世界空间下的)
//v2f.worldPos = mul(unity_ObjectToWorld, appdata_full.vertex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
//把模型空间下的法线、切线转换到世界空间下
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent);
//计算副切线 计算叉乘结果后 垂直与切线和法线的向量有两条 通过乘以 切线当中的w,就可以确定是哪一条
//cross是叉乘 appdata_full.tangent.w代表叉乘结果方向
float3 worldBinormal = cross(normalize(worldTangent), normalize(worldNormal)) * v.tangent.w;
//这个就是我们 切线空间到世界空间的 转换矩阵
// | | |
// 切线 副切线 法线
// | | |
//v2f.rotation = float3x3( worldTangent.x, worldBinormal.x, worldNormal.x,
// worldTangent.y, worldBinormal.y, worldNormal.y,
// worldTangent.z, worldBinormal.z, worldNormal.z);
v2f.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
v2f.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
v2f.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
//坐标转换宏
TRANSFER_SHADOW(v2f)
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//世界空间下光的方向
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//世界空间下视角方向
// fixed3 viewDir = normalize(UnityWorldSpaceViewDir(v2f.worldPos));
float3 worldPos = float3(v2f.TtoW0.w, v2f.TtoW1.w, v2f.TtoW2.w);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
//纹理采样函数tex2D
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//利用内置的UnpackNormal函数对法线信息进行逆运算以及可能的解压
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//把计算完毕后的切线空间下的法线转换到世界空间下
// float3 worldNormal = mul(v2f.rotation, tangentNormal);
//以下两种写法等价 但是可以一步到位
//float3x3 rotation = float3x3(v2f.TtoW0.xyz, v2f.TtoW1.xyz, v2f.TtoW2.xyz );
//float3 worldNormal = mul(rotation, tangentNormal);
//本质 就是在进行矩阵运算
float3 worldNormal = float3(dot(v2f.TtoW0.xyz, tangentNormal), dot(v2f.TtoW1.xyz, tangentNormal),
dot(v2f.TtoW2.xyz, tangentNormal));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//兰伯特漫反射颜色 = 光的颜色 * 漫反射材质的颜色 * max(0, dot(世界坐标系下的法线, 光的方向))
fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(worldNormal, normalize(lightDir)));
//不使用高光了
// //半角向量 = 视角方向 + 光的方向
// float3 halfA = normalize(normalize(viewDir) + normalize(lightDir));
//
// //高光反射的颜色 = 光的颜色 * 高光反射材质的颜色 * pow(max(0, dot(世界坐标系下的法线, 半角向量)), 光泽度)
// fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(
// max(0, dot(worldNormal, halfA)), _SpecularNum);
//计算光照衰减和阴影衰减的宏
UNITY_LIGHT_ATTENUATION(atten, v2f, worldPos);
// //布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色 + 高光反射的颜色
// fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;
//布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色*衰减值
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor * atten;
return fixed4(color.rgb, 1);
}
ENDCG
}
//Additional Pass
Pass
{
//设置我们的光照模式 ForwardAdd这种向前渲染模式 主要是用来处理 附加光照渲染的
Tags
{
"LightMode"="ForwardAdd"
}
//线性减淡的效果 进行 光照颜色混合
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//这个编译指令让Unity生成多个包括支持和不支持阴影的Shader变体
//从而为额外的逐像素光源计算阴影,并传递给Shader了
#pragma multi_compile_fwdadd_fullshadows
#include "UnityCG.cginc"
#include "Lighting.cginc"
//使用阴影宏内置文件
#include "AutoLight.cginc"
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
// float4 _SpecularColor; //高光颜色
// fixed _SpecularNum; //光泽度
struct v2f
{
//裁剪空间下坐标
float4 pos:SV_POSITION;
//纹理uv
//我们可以单独的声明两个float2的成员用于记录 颜色和法线纹理的uv坐标
//float2 uvTex:TEXCOORD0;//颜色纹理
//float2 uvBump:TEXCOORD1;//法线纹理
//也可以直接声明一个float4的成员 xy用于记录颜色纹理的uv,zw用于记录法线纹理的uv
float4 uv:TEXCOORD0; //纹理变量
//顶点相对于世界坐标的位置 主要用于 之后的 视角方向的计算
//float3 worldPos:TEXCOORD1;
//切线 到 世界空间的 变换矩阵
//float3x3 rotation:TEXCOORD2;
//代表我们切线空间到世界空间的 变换矩阵的3行 三个变量的w存世界坐标
float4 TtoW0:TEXCOORD1;
float4 TtoW1:TEXCOORD2;
float4 TtoW2:TEXCOORD3;
//阴影坐标宏
//n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
//比如这里前面有四个
SHADOW_COORDS(4)
};
v2f vert(appdata_full v)
{
v2f v2f;
//把模型空间下的顶点转到裁剪空间下
v2f.pos = UnityObjectToClipPos(v.vertex);
//计算纹理的缩放偏移
v2f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
v2f.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//得到世界空间下的 顶点位置 用于之后在片元函数中计算视角方向(世界空间下的)
//v2f.worldPos = mul(unity_ObjectToWorld, appdata_full.vertex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
//把模型空间下的法线、切线转换到世界空间下
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent);
//计算副切线 计算叉乘结果后 垂直与切线和法线的向量有两条 通过乘以 切线当中的w,就可以确定是哪一条
//cross是叉乘 appdata_full.tangent.w代表叉乘结果方向
float3 worldBinormal = cross(normalize(worldTangent), normalize(worldNormal)) * v.tangent.w;
//这个就是我们 切线空间到世界空间的 转换矩阵
// | | |
// 切线 副切线 法线
// | | |
//v2f.rotation = float3x3( worldTangent.x, worldBinormal.x, worldNormal.x,
// worldTangent.y, worldBinormal.y, worldNormal.y,
// worldTangent.z, worldBinormal.z, worldNormal.z);
v2f.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
v2f.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
v2f.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
//坐标转换宏
TRANSFER_SHADOW(v2f)
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//世界空间下光的方向
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//世界空间下视角方向
// fixed3 viewDir = normalize(UnityWorldSpaceViewDir(v2f.worldPos));
float3 worldPos = float3(v2f.TtoW0.w, v2f.TtoW1.w, v2f.TtoW2.w);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
//纹理采样函数tex2D
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//利用内置的UnpackNormal函数对法线信息进行逆运算以及可能的解压
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//把计算完毕后的切线空间下的法线转换到世界空间下
// float3 worldNormal = mul(v2f.rotation, tangentNormal);
//以下两种写法等价 但是可以一步到位
//float3x3 rotation = float3x3(v2f.TtoW0.xyz, v2f.TtoW1.xyz, v2f.TtoW2.xyz );
//float3 worldNormal = mul(rotation, tangentNormal);
//本质 就是在进行矩阵运算
float3 worldNormal = float3(dot(v2f.TtoW0.xyz, tangentNormal), dot(v2f.TtoW1.xyz, tangentNormal),
dot(v2f.TtoW2.xyz, tangentNormal));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//兰伯特漫反射颜色 = 光的颜色 * 漫反射材质的颜色 * max(0, dot(世界坐标系下的法线, 光的方向))
fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(worldNormal, normalize(lightDir)));
//不使用高光了
// //半角向量 = 视角方向 + 光的方向
// float3 halfA = normalize(normalize(viewDir) + normalize(lightDir));
//
// //高光反射的颜色 = 光的颜色 * 高光反射材质的颜色 * pow(max(0, dot(世界坐标系下的法线, 半角向量)), 光泽度)
// fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(
// max(0, dot(worldNormal, halfA)), _SpecularNum);
//计算光照衰减和阴影衰减的宏
UNITY_LIGHT_ATTENUATION(atten, v2f, worldPos);
// //布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色 + 高光反射的颜色
// fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;
//布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色*衰减值
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor * atten;
return fixed4(color.rgb, 1);
}
ENDCG
}
}
//Unity自带的漫反射Shader,里面实现了对应投射阴影的Pass
Fallback "Diffuse"
}
应用雾相关到shader,包括编译指令,结构体宏,顶点转换宏,片元应用宏等
Shader "Unlit/Lesson76_BumpedDiffuse"
{
Properties
{
//...
}
SubShader
{
//...
//Base Pass
Pass
{
//...
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 雾的编译指令 make fog work
#pragma multi_compile_fog
// 用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
//...
struct v2f
{
//...
//雾的宏
UNITY_FOG_COORDS(4)
//阴影坐标宏
//n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
//比如这里前面有四个
SHADOW_COORDS(5)
};
v2f vert(appdata_full v)
{
v2f v2f;
//...
//雾顶点转换宏
UNITY_TRANSFER_FOG(v2f,v2f.pos);
//坐标转换宏
TRANSFER_SHADOW(v2f)
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//...
// 片元应用雾的宏 apply fog
UNITY_APPLY_FOG(v2f.fogCoord, color);
return fixed4(color.rgb, 1);
}
ENDCG
}
//Additional Pass
Pass
{
//...
//线性减淡的效果 进行 光照颜色混合
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 雾的编译指令 make fog work
#pragma multi_compile_fog
//...
#include "UnityCG.cginc"
#include "Lighting.cginc"
//...
struct v2f
{
//...
//雾的宏
UNITY_FOG_COORDS(4)
//阴影坐标宏
//n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
//比如这里前面有四个
SHADOW_COORDS(5)
};
v2f vert(appdata_full v)
{
v2f v2f;
//...
//雾顶点转换宏
UNITY_TRANSFER_FOG(v2f,v2f.pos);
//坐标转换宏
TRANSFER_SHADOW(v2f)
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//...
// 片元应用雾的宏 apply fog
UNITY_APPLY_FOG(v2f.fogCoord, color);
return fixed4(color.rgb, 1);
}
ENDCG
}
}
//Unity自带的漫反射Shader,里面实现了对应投射阴影的Pass
Fallback "Diffuse"
}
创建材质赋值shader给场景中的墙和立方体,修改雾最远距离可以明显看到效果
总结
76.2 知识点代码
Lesson76_BumpedDiffuse.shader
Shader "Unlit/Lesson76_BumpedDiffuse"
{
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)// 漫反射颜色
_MainTex("MainTex", 2D) = ""{}// 单张纹理
_BumpMap("BumpMap", 2D) = ""{}// 法线纹理
_BumpScale("BumpScale", Range(0,1)) = 1// 凹凸程度
// _SpecularColor("SpecularColor", Color) = (1,1,1,1)// 高光反射颜色
// _SpecularNum("SpecularNum", Range(0,20)) = 18// 光泽度
}
SubShader
{
// 加入渲染标签Tags { "RenderType"="Opaque" "Queue"="Geometry"}
// 渲染类型设置为不透明的、渲染队列设置为几何队列(不透明的几何体通常使用该队列)
Tags
{
"RenderType"="Opaque" "Queue"="Geometry"
}
//Base Pass
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 雾的编译指令 make fog work
#pragma multi_compile_fog
// 用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
//使用阴影宏内置文件
#include "AutoLight.cginc"
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
// float4 _SpecularColor; //高光颜色
// fixed _SpecularNum; //光泽度
struct v2f
{
//裁剪空间下坐标
float4 pos:SV_POSITION;
//纹理uv
//我们可以单独的声明两个float2的成员用于记录 颜色和法线纹理的uv坐标
//float2 uvTex:TEXCOORD0;//颜色纹理
//float2 uvBump:TEXCOORD1;//法线纹理
//也可以直接声明一个float4的成员 xy用于记录颜色纹理的uv,zw用于记录法线纹理的uv
float4 uv:TEXCOORD0; //纹理变量
//顶点相对于世界坐标的位置 主要用于 之后的 视角方向的计算
//float3 worldPos:TEXCOORD1;
//切线 到 世界空间的 变换矩阵
//float3x3 rotation:TEXCOORD2;
//代表我们切线空间到世界空间的 变换矩阵的3行 三个变量的w存世界坐标
float4 TtoW0:TEXCOORD1;
float4 TtoW1:TEXCOORD2;
float4 TtoW2:TEXCOORD3;
//雾的宏
UNITY_FOG_COORDS(4)
//阴影坐标宏
//n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
//比如这里前面有四个
SHADOW_COORDS(5)
};
v2f vert(appdata_full v)
{
v2f v2f;
//把模型空间下的顶点转到裁剪空间下
v2f.pos = UnityObjectToClipPos(v.vertex);
//计算纹理的缩放偏移
v2f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
v2f.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//得到世界空间下的 顶点位置 用于之后在片元函数中计算视角方向(世界空间下的)
//v2f.worldPos = mul(unity_ObjectToWorld, appdata_full.vertex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
//把模型空间下的法线、切线转换到世界空间下
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent);
//计算副切线 计算叉乘结果后 垂直与切线和法线的向量有两条 通过乘以 切线当中的w,就可以确定是哪一条
//cross是叉乘 appdata_full.tangent.w代表叉乘结果方向
float3 worldBinormal = cross(normalize(worldTangent), normalize(worldNormal)) * v.tangent.w;
//这个就是我们 切线空间到世界空间的 转换矩阵
// | | |
// 切线 副切线 法线
// | | |
//v2f.rotation = float3x3( worldTangent.x, worldBinormal.x, worldNormal.x,
// worldTangent.y, worldBinormal.y, worldNormal.y,
// worldTangent.z, worldBinormal.z, worldNormal.z);
v2f.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
v2f.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
v2f.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
//雾顶点转换宏
UNITY_TRANSFER_FOG(v2f,v2f.pos);
//坐标转换宏
TRANSFER_SHADOW(v2f)
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//世界空间下光的方向
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//世界空间下视角方向
// fixed3 viewDir = normalize(UnityWorldSpaceViewDir(v2f.worldPos));
float3 worldPos = float3(v2f.TtoW0.w, v2f.TtoW1.w, v2f.TtoW2.w);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
//纹理采样函数tex2D
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//利用内置的UnpackNormal函数对法线信息进行逆运算以及可能的解压
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//把计算完毕后的切线空间下的法线转换到世界空间下
// float3 worldNormal = mul(v2f.rotation, tangentNormal);
//以下两种写法等价 但是可以一步到位
//float3x3 rotation = float3x3(v2f.TtoW0.xyz, v2f.TtoW1.xyz, v2f.TtoW2.xyz );
//float3 worldNormal = mul(rotation, tangentNormal);
//本质 就是在进行矩阵运算
float3 worldNormal = float3(dot(v2f.TtoW0.xyz, tangentNormal), dot(v2f.TtoW1.xyz, tangentNormal),
dot(v2f.TtoW2.xyz, tangentNormal));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//兰伯特漫反射颜色 = 光的颜色 * 漫反射材质的颜色 * max(0, dot(世界坐标系下的法线, 光的方向))
fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(worldNormal, normalize(lightDir)));
//不使用高光了
// //半角向量 = 视角方向 + 光的方向
// float3 halfA = normalize(normalize(viewDir) + normalize(lightDir));
//
// //高光反射的颜色 = 光的颜色 * 高光反射材质的颜色 * pow(max(0, dot(世界坐标系下的法线, 半角向量)), 光泽度)
// fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(
// max(0, dot(worldNormal, halfA)), _SpecularNum);
//计算光照衰减和阴影衰减的宏
UNITY_LIGHT_ATTENUATION(atten, v2f, worldPos);
// //布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色 + 高光反射的颜色
// fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;
//布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色*衰减值
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor * atten;
// 片元应用雾的宏 apply fog
UNITY_APPLY_FOG(v2f.fogCoord, color);
return fixed4(color.rgb, 1);
}
ENDCG
}
//Additional Pass
Pass
{
//设置我们的光照模式 ForwardAdd这种向前渲染模式 主要是用来处理 附加光照渲染的
Tags
{
"LightMode"="ForwardAdd"
}
//线性减淡的效果 进行 光照颜色混合
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 雾的编译指令 make fog work
#pragma multi_compile_fog
//这个编译指令让Unity生成多个包括支持和不支持阴影的Shader变体
//从而为额外的逐像素光源计算阴影,并传递给Shader了
#pragma multi_compile_fwdadd_fullshadows
#include "UnityCG.cginc"
#include "Lighting.cginc"
//使用阴影宏内置文件
#include "AutoLight.cginc"
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
// float4 _SpecularColor; //高光颜色
// fixed _SpecularNum; //光泽度
struct v2f
{
//裁剪空间下坐标
float4 pos:SV_POSITION;
//纹理uv
//我们可以单独的声明两个float2的成员用于记录 颜色和法线纹理的uv坐标
//float2 uvTex:TEXCOORD0;//颜色纹理
//float2 uvBump:TEXCOORD1;//法线纹理
//也可以直接声明一个float4的成员 xy用于记录颜色纹理的uv,zw用于记录法线纹理的uv
float4 uv:TEXCOORD0; //纹理变量
//顶点相对于世界坐标的位置 主要用于 之后的 视角方向的计算
//float3 worldPos:TEXCOORD1;
//切线 到 世界空间的 变换矩阵
//float3x3 rotation:TEXCOORD2;
//代表我们切线空间到世界空间的 变换矩阵的3行 三个变量的w存世界坐标
float4 TtoW0:TEXCOORD1;
float4 TtoW1:TEXCOORD2;
float4 TtoW2:TEXCOORD3;
//雾的宏
UNITY_FOG_COORDS(4)
//阴影坐标宏
//n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
//比如这里前面有四个
SHADOW_COORDS(5)
};
v2f vert(appdata_full v)
{
v2f v2f;
//把模型空间下的顶点转到裁剪空间下
v2f.pos = UnityObjectToClipPos(v.vertex);
//计算纹理的缩放偏移
v2f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
v2f.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//得到世界空间下的 顶点位置 用于之后在片元函数中计算视角方向(世界空间下的)
//v2f.worldPos = mul(unity_ObjectToWorld, appdata_full.vertex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
//把模型空间下的法线、切线转换到世界空间下
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent);
//计算副切线 计算叉乘结果后 垂直与切线和法线的向量有两条 通过乘以 切线当中的w,就可以确定是哪一条
//cross是叉乘 appdata_full.tangent.w代表叉乘结果方向
float3 worldBinormal = cross(normalize(worldTangent), normalize(worldNormal)) * v.tangent.w;
//这个就是我们 切线空间到世界空间的 转换矩阵
// | | |
// 切线 副切线 法线
// | | |
//v2f.rotation = float3x3( worldTangent.x, worldBinormal.x, worldNormal.x,
// worldTangent.y, worldBinormal.y, worldNormal.y,
// worldTangent.z, worldBinormal.z, worldNormal.z);
v2f.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
v2f.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
v2f.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
//雾顶点转换宏
UNITY_TRANSFER_FOG(v2f,v2f.pos);
//坐标转换宏
TRANSFER_SHADOW(v2f)
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//世界空间下光的方向
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//世界空间下视角方向
// fixed3 viewDir = normalize(UnityWorldSpaceViewDir(v2f.worldPos));
float3 worldPos = float3(v2f.TtoW0.w, v2f.TtoW1.w, v2f.TtoW2.w);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
//纹理采样函数tex2D
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//利用内置的UnpackNormal函数对法线信息进行逆运算以及可能的解压
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//把计算完毕后的切线空间下的法线转换到世界空间下
// float3 worldNormal = mul(v2f.rotation, tangentNormal);
//以下两种写法等价 但是可以一步到位
//float3x3 rotation = float3x3(v2f.TtoW0.xyz, v2f.TtoW1.xyz, v2f.TtoW2.xyz );
//float3 worldNormal = mul(rotation, tangentNormal);
//本质 就是在进行矩阵运算
float3 worldNormal = float3(dot(v2f.TtoW0.xyz, tangentNormal), dot(v2f.TtoW1.xyz, tangentNormal),
dot(v2f.TtoW2.xyz, tangentNormal));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//兰伯特漫反射颜色 = 光的颜色 * 漫反射材质的颜色 * max(0, dot(世界坐标系下的法线, 光的方向))
fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(worldNormal, normalize(lightDir)));
//不使用高光了
// //半角向量 = 视角方向 + 光的方向
// float3 halfA = normalize(normalize(viewDir) + normalize(lightDir));
//
// //高光反射的颜色 = 光的颜色 * 高光反射材质的颜色 * pow(max(0, dot(世界坐标系下的法线, 半角向量)), 光泽度)
// fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(
// max(0, dot(worldNormal, halfA)), _SpecularNum);
//计算光照衰减和阴影衰减的宏
UNITY_LIGHT_ATTENUATION(atten, v2f, worldPos);
// //布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色 + 高光反射的颜色
// fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;
//布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色*衰减值
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor * atten;
// 片元应用雾的宏 apply fog
UNITY_APPLY_FOG(v2f.fogCoord, color);
return fixed4(color.rgb, 1);
}
ENDCG
}
}
//Unity自带的漫反射Shader,里面实现了对应投射阴影的Pass
Fallback "Diffuse"
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com