unity-shader-05
2024年2月25日
摘要:Diffuse / Specular Reflection / Phong / BlinnPhong
Diffuse / Specular Reflection
- 漫反射和镜面反射的区别就在于微表面的粗糙程度。
Specular Reflection 镜面反射
- 有目的,沿反射方向,不均匀的反射;
- 追求漫反射的列子:化妆镜,车漆;
Diffuse Reflection 漫反射
- 漫无目的,四面八方,均匀的反射;
- 追求漫反射的列子:电影荧幕;
各种向量
常用向量:(全要记)
- nDir:法线方向,点乘操作时简称n;
- lDir:光照方向,点乘操作时简称l;
- vDir:观察方向,点乘操作时简称v;
- rDir:光反射方向,点乘操作时简称r;
- hDir:半角方向(Halfway),lDir和vDir的中间角方向,点乘操作时简称h;
所在空间:(暂时只记WS,其余看热闹)
- OS:ObjectSpace 物体空间,本地空间;
- WS:WorldSpace 世界空间;
- VS: ViewSpace 观察空间;
- CS:HomogenousClipSpace 齐次剪裁空间;
- TS:TangentSpace 切线空间;
- TXS:TextureSpace 纹理空间;
例:nDirWS: 世界空间下的法线方向;
漫反射-Diffuse:
- 因其向四面八方均匀散射,所以反射亮度和观察者看的方向无关;
- 实现方式:Lambert(n dot l),显然vDir不参与计算;
镜面反射-Specular:
镜面反射的反射范围是类似一个圆锥范围-只有在圆锥范围内才能观察到镜面反射的反弹光。
- 因其反射有明显方向性,所以观察者的视角决定了反射光线的有无,明暗;
- 实现方式:
- Phong(r dot v),即光反射方向和视角方向越重合,反射越强;
- Blinn-Phong(n dot h),即法线方向和半角方向越重合,反射越强;
Phong
Reflect (反射)
- 输出入射向量 [I] 的反射向量,就像在具有法线 [N] 的表面上反射/反弹一样
Blinn-Phong
相对phong ,blinn-phong的计算更便宜些。对于现在cpu来说,可忽略不计,以美术为目的。
vs写一个Lambert+BlinnPhong的shader
vs Code
blinn phong
Shader "AP1/L05/L05_OldShool_VS" {
// 材质面板参数
Properties {
//暴露参数
_MainCol ("颜色", color) = (1.0, 1.0, 1.0, 1.0)
_SpecularPow ("高光次幂", range(1,50)) = 30
}
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 共享于vert,frag
// attibute 仅用于vert
// varying 用于vert,frag传数据
uniform float3 _MainCol; // RGB够了 float3
uniform float _SpecularPow; // 标量 float
// 输入结构
struct VertexInput {
float4 vertex : POSITION; //将模型的顶点信息输入进来
float3 normal : NORMAL; //将模型的noraml信息输入进来
};
// 输出结构
struct VertexOutput {
float4 posCS : SV_POSITION; //裁剪空间(暂理解为屏幕空间吧)顶点位置- 由模型顶点信息换算而来的顶点屏幕位置
float4 posWS : TEXCOORD0; //世界空间顶点位置
float3 nDirWS : TEXCOORD1; //世界空间法线方向-由模型法线信息换算来的世界空间法线信息
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; // 新建一个输出结构
o.posCS = UnityObjectToClipPos( v.vertex ); // 变换顶点位置 OS>CS -变换顶点信息 并将其塞给输出结构
o.posWS = mul(unity_ObjectToWorld, v.vertex); // 变换顶点位置 OS>WS
o.nDirWS = UnityObjectToWorldNormal(v.normal); // 变换法线方向 OS>WS -变换法线信息 并将其塞给输出结构
return o; // 将输出结构 输出
}
// 输出结构 >>> 像素
float4 frag(VertexOutput i) : COLOR {
//准备所有要用到的向量,不会计算去SF拆
float3 nDir = i.nDirWS;
float3 lDir = _WorldSpaceLightPos0.xyz;
float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 hDir = normalize(vDir + lDir );
//准备所有要用到的中间数据,这里是两个点积结果;
float nDotl = dot(nDir, lDir);
float nDoth = dot(nDir, hDir);
//编写光照模型
float lambert = max(0.0, nDotl);
float blinnPhong = pow(max(0.0,nDoth),_SpecularPow);
float3 finalRGB = _MainCol* lambert+ blinnPhong;
//返回结果
return float4(finalRGB, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
phong
Shader "AP1/L05/L05_Phong_VS" {
// 材质面板参数
Properties {
//暴露参数
_MainCol ("颜色", color) = (1.0, 1.0, 1.0, 1.0)
_MainCol2 ("高光颜色", color) = (1.0, 1.0, 1.0, 1.0)
_SpecularPow ("高光次幂", range(1,50)) = 30
}
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 float3 _MainCol2; // RGB float3
uniform float3 _MainCol; // RGB float3
uniform float _SpecularPow; // 标量 float
// 输入结构
struct VertexInput {
float4 vertex : POSITION; //将模型的顶点信息输入进来
float3 normal : NORMAL; //将模型的noraml信息输入进来
};
// 输出结构
struct VertexOutput {
float4 posCS : SV_POSITION; //裁剪空间(暂理解为屏幕空间吧)顶点位置- 由模型顶点信息换算而来的顶点屏幕位置
float4 posWS : TEXCOORD0; //世界空间顶点位置
float3 nDirWS : TEXCOORD1; //世界空间法线方向-由模型法线信息换算来的世界空间法线信息
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; // 新建一个输出结构
o.posCS = UnityObjectToClipPos( v.vertex ); // 变换顶点位置 OS>CS -变换顶点信息 并将其塞给输出结构
o.posWS = mul(unity_ObjectToWorld, v.vertex); // 变换顶点位置 OS>WS
o.nDirWS = UnityObjectToWorldNormal(v.normal); // 变换法线方向 OS>WS -变换法线信息 并将其塞给输出结构
return o; // 将输出结构 输出
}
// 输出结构 >>> 像素
float4 frag(VertexOutput i) : COLOR {
//准备所有要用到的向量
float3 nDir = i.nDirWS;
float3 lDir = _WorldSpaceLightPos0.xyz;
float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 vRDir = reflect( -vDir, nDir );
//准备所有要用到的中间数据,这里是两个点积结果;
float nDotl = dot(nDir, lDir); //得到lambert
float vRDotl = dot(vRDir, lDir); //得到phong
//编写光照模型
float lambert = max(0.0, nDotl);
float Phong = pow(max(0.0,vRDotl),_SpecularPow);
float3 finalRGB = (_MainCol* lambert) + (Phong * _MainCol2);
//返回结果
return float4(finalRGB, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}