庄懂-BoyanTata的个人空间_哔哩哔哩_Bilibili
答疑
ShaderFeature 用到才会编译分支
MultiCompile 用不用到都会编译分支
![](https://i-blog.csdnimg.cn/blog_migrate/a88643133f67e5a58cc7432373abd361.png)
作业回顾
![](https://i-blog.csdnimg.cn/blog_migrate/683e3025c6523385e568f2e7fb056d18.png)
OldSchool Plus代码
_EnvUpCol 环境天顶颜色
_EnvSideCol 环境水平颜色
_EnvDownCol 环境地表颜色
![](https://i-blog.csdnimg.cn/blog_migrate/6b75d3d0b319b43b1219679dc1a5bdaa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1b2f01baaa986cd5af8261b987d459b9.png)
Shader "AP01/L08/OldSchoolPlus"
{
Properties
{
_BaseCol ("基本色", Color) = (0.5, 0.5, 0.5, 1.0)
_LightCol ("光颜色", Color) = (1.0, 1.0, 1.0, 1.0)
_SpecPow ("高光次幂", Range(1, 90)) = 30
_Occlusion ("AO图", 2D) = "white" {}
_EnvInt ("环境光强度", Range(0, 1)) = 0.2
_EnvUpCol ("环境天顶颜色", Color) = (1.0, 1.0, 1.0, 1.0)
_EnvSideCol ("环境水平颜色", Color) = (0.5, 0.5, 0.5, 1.0)
_EnvDownCol ("环境地表颜色", Color) = (0.0, 0.0, 0.0, 0.0)
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Name "FORWARD"
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 追加投影相关包含文件
#include "AutoLight.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
// 输入参数
uniform float3 _BaseCol;
uniform float3 _LightCol;
uniform float _SpecPow;
uniform sampler2D _Occlusion;
uniform float _EnvInt;
uniform float3 _EnvUpCol;
uniform float3 _EnvSideCol;
uniform float3 _EnvDownCol;
// 输入结构
struct VertexInput
{
float4 vertex : POSITION; // 顶点信息 Get✔
float4 normal : NORMAL; // 法线信息 Get✔
float2 uv0 : TEXCOORD0; // UV信息 Get✔
};
// 输出结构
struct VertexOutput
{
float4 pos : SV_POSITION; // 裁剪空间(暂理解为屏幕空间吧)顶点位置
float2 uv0 : TEXCOORD0; // UV0
float4 posWS : TEXCOORD1; // 世界空间顶点位置
float3 nDirWS : TEXCOORD2; // 世界空间法线方向
LIGHTING_COORDS(3,4) // 投影相关
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v)
{
VertexOutput o = (VertexOutput)0; // 新建输出结构
o.pos = UnityObjectToClipPos( v.vertex ); // 变换顶点位置 OS>CS
o.uv0 = v.uv0; // 传递UV
o.posWS = mul(unity_ObjectToWorld, v.vertex); // 变换顶点位置 OS>WS
o.nDirWS = UnityObjectToWorldNormal(v.normal); // 变换法线方向 OS>WS
TRANSFER_VERTEX_TO_FRAGMENT(o) // 投影相关
return o; // 返回输出结构
}
// 输出结构>>>像素
float4 frag(VertexOutput i) : COLOR
{
// 准备向量
float3 nDir = normalize(i.nDirWS);
float3 lDir = _WorldSpaceLightPos0.xyz;
float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 rDir = reflect(-lDir, nDir);
// 准备点积结果
float ndotl = dot(nDir, lDir);
float vdotr = dot(vDir, rDir);
// 光照模型(直接光照部分)
float shadow = LIGHT_ATTENUATION(i); // 获取投影
float lambert = max(0.0, ndotl);
float phong = pow(max(0.0, vdotr), _SpecPow);
float3 dirLighting = (_BaseCol * lambert + phong) * _LightCol * shadow;
// 光照模型(环境光照部分)
float upMask = max(0.0, nDir.g); // 获取朝上部分遮罩
float downMask = max(0.0, -nDir.g); // 获取朝下部分遮罩
float sideMask = 1.0 - upMask - downMask; // 获取侧面部分遮罩
// 混合环境色
float3 envCol = _EnvUpCol * upMask + _EnvSideCol * sideMask + _EnvDownCol * downMask;
float occlusion = tex2D(_Occlusion, i.uv0); // 采样Occlusion贴图
float3 envLighting = envCol * _EnvInt * occlusion; // 计算环境光照
// 返回结果
float3 finalRGB = dirLighting + envLighting;
return float4(finalRGB, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
作业范例批改
![](https://i-blog.csdnimg.cn/blog_migrate/f93faf2e08c8565b99598943ba93dd6c.png)
法线贴图Normal_连连看部分
不能撇开空间,去谈方向
TBN矩阵的作用
将
切线空间下的法线信息变换到世界空间才能和光向量去点乘
![](https://i-blog.csdnimg.cn/blog_migrate/48ccaf45ba97958d7950fae8b881b032.png)
代码部分
![](https://i-blog.csdnimg.cn/blog_migrate/7a33860c1fe20bd74935e51a53732cf1.png)
Shader "AP01/L08/NormalMap"
{
Properties
{
_NormalMap ("法线贴图", 2D) = "bump" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Name "FORWARD"
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
// 输入参数
uniform sampler2D _NormalMap;
// 输入结构
struct VertexInput
{
float4 vertex : POSITION; // 顶点信息
float2 uv0 : TEXCOORD0; // 需要UV坐标 采样法线贴图
float4 normal : NORMAL; // 法线信息
float4 tangent : TANGENT; // 构建TBN矩阵 需要模型切线信息
};
// 输出结构
struct VertexOutput
{
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0; // UV信息
float3 nDirWS : TEXCOORD1; // 世界空间法线信息
float3 tDirWS : TEXCOORD2; // 世界空间切线信息
float3 bDirWS : TEXCOORD3; // 世界空间切线信息
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v)
{
VertexOutput o = (VertexOutput)0; // 新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex ); // 变换顶点信息 并将其塞给输出结构
o.uv0 = v.uv0; // 传递UV信息
o.nDirWS = UnityObjectToWorldNormal(v.normal); // 世界空间法线信息
o.tDirWS = normalize(mul( unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 世界空间切线信息
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w); // 世界空间切线信息
return o; // 将输出结构 输出
}
// 输出结构>>>像素
float4 frag(VertexOutput i) : COLOR
{
// 获取nDir
float3 nDirTS = UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb; // 采样法线纹理并解码 切线空间nDir
float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS); // 构建TBN矩阵
float3 nDirWS = normalize(mul(nDirTS, TBN)); // 世界空间nDir
// 获取lDir
float3 lDir = _WorldSpaceLightPos0.xyz;
// 一般Lambert
float nDotl = dot(nDirWS, lDir); // nDir点积lDir
float lambert = max(0.0, nDotl); // 截断负值
return float4(lambert, lambert, lambert, 1.0); // 输出最终颜色
}
ENDCG
}
}
FallBack "Diffuse"
}