前言
最近再阅读《GPU 编程与 CG 语言之阳春白雪下里巴人》 就想着用Unity Shader实现其中的代码,文章夹杂了自己的一些理解,我自己也刚入门shader,难免会有很多错误,希望多多指出,一起交流进步。
阅读本文需要有一定的基础 0基础可以先去阅读 零基础入门Unity Shader 系列文章
10.1 Cook-Torrance 光照模型
公式如下:
其中
是漫反射光强,
是镜面反射光强的计算方法
其中 是菲涅尔反射系数 即:
其中
是反射系数,
是指向视点的向量,
半角向量
值用于度量表面的粗糙程度,较大的m 值对应于粗糙平面,较小的
值对应与较光滑的表面;
是顶点法向量N 和半角向量H 的夹角
化简之后得
最后公式如下
Unity shader 代码如下
Shader "Unlit/Cook-Torrance"
{
Properties
{
_Ka ("Ambient Color", Color) = (1, 1, 1, 1)
_Kd ("Diffuse Color", Color) = (1, 1, 1, 1)
_Ks ("Specular Color", Color) = (1, 1, 1, 1)
_F ("Fresnel", Range(0, 1)) = 0.5
_M ("roughness", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
CGINCLUDE
// 重复使用
float pow2(float x){
return x * x;
}
ENDCG
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
float4 _Ka;
float4 _Kd;
float4 _Ks;
float _F;
float _M;
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.normal);
float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos));
float3 V = normalize(UnityWorldSpaceViewDir(i.worldPos));
float3 H = normalize(L + V);
float3 NL = max(dot(N, L), 0);
float3 NV = max(dot(N, V), 0);
float3 NH = dot(N, H);
float3 VH = dot(V, H);
// 环境光
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Ka;
//漫反射
float3 diffuse = _Kd.rgb * _LightColor0.rgb * NL;
// 高光
float3 specular = (0, 0, 0);
float temp = (pow2(NH) - 1)/(pow2(_M) * pow2(NH));
// 粗糙程度
float roughness = (exp(temp))/pow2(_M) * pow(NH, 4.0);
float a = (2 * NH * NV)/VH;
float b = (2 * NH * NL)/VH;
// 几何衰减系数
float geometric = min(a, b);
geometric = min (1, geometric);
// 菲涅尔反射系数
float fresnelCoe = _F + (1 - _F) * pow (1 - VH, 5.0);
float rs = (fresnelCoe * geometric * roughness)/(NV * NL);
specular = rs * _LightColor0.rgb * NL * _Ks;
return float4 (ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
}
效果如下:
10.3 Bank BRDF经验模型
Bank BRDF的镜面反射部分公式为
分别表示镜面反射系数和高光系数;
表示入射光线方向、
表示实现观察方向、
表示该点的切向量。尤其要注意切向量的计算方法,因为一个三维空间点可能存在无数个切向量,通常我采用“顶点的法向量和视线方向做叉积,其结果作为
Unity shader 代码如下
Shader "Unlit/Bank-BRDF"
{
Properties
{
_Ka ("Ambient Color", Color) = (1, 1, 1, 1)
_Kd ("Diffuse Color", Color) = (1, 1, 1, 1)
_Ks ("Specular Color", Color) = (1, 1, 1, 1)
//ns 系数
_Shininess ("Shininess", Range(8, 256)) = 8
}
SubShader
{
Tags { "RenderType"="Opaque" }
CGINCLUDE
// 重复使用
float pow2(float x){
return x * x;
}
ENDCG
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
float4 _Ka;
float4 _Kd;
float4 _Ks;
float _Shininess;
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.normal);
float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos));
float3 V = normalize(UnityWorldSpaceViewDir(i.worldPos));
float3 H = normalize(L + V);
// 切线方向
float3 T = normalize(cross(N, V));
float3 NL = max(dot(N, L), 0);
float3 NV = max(dot(N, V), 0);
float3 NH = dot(N, H);
float3 VH = dot(V, H);
// 环境光
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Ka;
//漫反射
float3 diffuse = _Kd.rgb * _LightColor0.rgb * NL;
// 高光
float3 specular = (0, 0, 0);
float a = dot(L, T);
float b = dot(V, T);
// 计算bank BRDF 系数
float c = sqrt(1 - pow2(a)) * sqrt(1 - pow2(b)) - a * b;
float brdf = _Ks * pow(c, _Shininess);
specular = brdf * _LightColor0.rgb * NL;
return float4 (ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
}
效果如下:
本章节完

京公网安备 11010502036488号