Unity Shader URP 学习 基础光照
首先是几种常见的基础光照模型的简单说明
关于Lambert(兰伯特)光照模型
简介
用于模拟漫反射的光照模型,相关的维基百科
光照公式
Diffuse = max(0,dot(nDir, LightDir))
关于HalfLambert(半兰伯特)光照模型
简介
Half Lambert光照模型是Valve公司在制作”半条命“游戏时发明的,用来给在比较暗的区域显示物体。总体来说,该光照模型提高了物体表面的漫反射光.下图是Alyx对于Lambert和Half Lambert的对比示意图
光照公式
Diffuse = dot(nDir, LightDir)*0.5+0.5
关于Phong(冯氏)光照模型
简介
冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射 (Diffuse)和镜面(Specular)光照
- 环境光照(Ambient Lighting):物体几乎永远不会是完全黑暗的。所以环境光照一般是个常量
- 漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响,物体的某一部分越是正对着光源,它就会越亮。
- 镜面光照(Specular Lighting):模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。
光照公式
最终片段颜色:环境颜色+漫反射颜色+镜面反射颜色
环境颜色 = 光源的环境光颜色 × 物体的环境材质颜色
漫反射颜色 = 光源的漫反射光颜色 × 物体的漫反射材质颜色 × 漫反射因子
镜面反射颜色 = 光源的镜面光颜色 × 物体的镜面材质颜色 × 镜面反射因子
镜面反射最终颜色 = 直射光颜色 * 反射光颜色 * pow(max(0, dot(反射光方向, 视野方向)), 光泽度(gloss)) + 漫反射颜色 + 环境光颜色
关于BlinnPhong光照模型
简介
BlinnPhong光照模型是一种改良的高光模型,采用了半角向量(half-angle vector),和Phong的对比如下图:z
参考:
光照公式
最终颜色 = 直射光颜色 * 反射光颜色 * pow(max(0, dot(法线方向, 视野与光线中间向量)), 光泽度(gloss)) + 漫反射颜色 + 环境光颜色
关于Fresnel Reflection/Term
简介
菲涅尔反射描述的是以不同的视角观察物体得到的反射光比例不同的现象
参考:
光照公式
Fresnel = pow((1-dot(法线方向, 视方向)),系数);
关于URP
简介
URP是一种SRP(可编程渲染管线),全称为Universal Render Pipeline。具体请看官方关于URP的文档
URP下的基础光照模型Shader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184Shader "Costom/StandardBlinnPhong"
{
Properties{
[MainColor]_DiffuseColor("Diffuse", Color) = (1, 1, 1, 1)
[MainTexture]_MainTex("Main Tex", 2D) = "white"{}
[Normal]_NormalMap("Normal Map",2D) = "bump"{}
_NormalScale("NormalScale",Range(0,1)) = 0
[Toggle] _UseCubMap("Use Cub Map", Int) = 0
_CubMap("Env Map",CUBE) = ""{}
_Metallic("Metallic",Range(0,1)) = 0
_Smoothness("Smoothness",Range(0,1)) = 0
_Fresnel("Fresnel",Range(0,100)) = 4
}
SubShader
{
Tags{"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
HLSLINCLUDE
struct a2v
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 posWS : TEXCOORD1;
float3 nDirWS : TEXCOORD2;
float3 tDirWS : TEXCOORD3;
float3 bDirWS : TEXCOORD4;
float4 shadowCoord : TEXCOORD5;
};
CBUFFER_START(UnityPerMaterial)
float4 _DiffuseColor;
real4 _MainTex_ST;
real _NormalScale;
float _Metallic;
float _Smoothness;
float _Fresnel;
CBUFFER_END
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);
TEXTURECUBE(_CubMap);
SAMPLER(sampler_CubMap);
ENDHLSL
Pass
{
Tags{"LightMode" = "UniversalForward"}
HLSLPROGRAM
v2f vert(a2v i)
{
v2f o;
o.posWS = TransformObjectToWorld(i.vertex.xyz);
o.pos = TransformWorldToHClip(o.posWS);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
o.nDirWS = TransformObjectToWorldNormal(i.normal);
o.tDirWS = normalize(TransformObjectToWorldDir(i.tangent.xyz));
o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS)*i.tangent.w);
o.shadowCoord = TransformWorldToShadowCoord(o.posWS);
return o;
}
half4 frag(v2f i) : SV_Target
{
float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS);
float3 nDirWS = normalize(i.nDirWS);
float4 normalMap = SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap,i.uv);
float3 normal = UnpackNormal(normalMap);
normal.z = sqrt(1.0 - saturate(dot(normal.xy,normal.xy)));
normal = TransformTangentToWorld(normal,TBN);
normal = normalize(normal);
nDirWS = lerp(nDirWS,normal,_NormalScale);
Light mainLight = GetMainLight(TransformWorldToShadowCoord(i.posWS));
Light mainLight = GetMainLight();
real4 lightColor = real4(mainLight.color, 1);
float3 lightDir = mainLight.direction;
half shadow = mainLight.shadowAttenuation;
half3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
float3 refWS = normalize(reflect(-vDirWS,nDirWS));
float nDotL = dot(nDirWS, lightDir);
float nDotV = dot(nDirWS, vDirWS);
float lambert = max(0.0,nDotL);
float fresnel = pow((1-nDotV),_Fresnel);
float3 halfVec = normalize(lightDir+vDirWS);
float blinnPhong = saturate(dot(nDirWS, halfVec));
float3 reflectDir = normalize(reflect(-lightDir,nDirWS));
float phong = max(0.0,dot(reflectDir,vDirWS));
half4 ambientLight = half4(SampleSH(nDirWS),1);
ambientLight = SAMPLE_TEXTURECUBE_LOD(_CubMap,sampler_CubMap,refWS,(255-_Smoothness*255)*8/255);
_DiffuseColor = pow(max(0.02,_DiffuseColor),1.1);
half4 mainColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
float4 ambient = ambientLight*_DiffuseColor*_Metallic;
float4 diffuse = ((lightColor*lambert*shadow+half4(SampleSH(nDirWS),1))*mainColor*_DiffuseColor)*(1-(_Metallic+_Smoothness)*0.5);
float4 specular = lightColor*lerp(smoothstep(0,0.9,pow(blinnPhong,_Smoothness*255)),float4(0,0,0,0),(1-_Smoothness))*shadow;
specular = lerp(specular,_DiffuseColor*specular,_Metallic)+fresnel*ambientLight*_Smoothness;
float4 result= (ambient+diffuse+specular);
return result;
}
ENDHLSL
}
pass
{
Tags
{
"LightMode"="ShadowCaster"
}
HLSLPROGRAM
v2f vertshadow(a2v i)
{
v2f o;
Light MainLight=GetMainLight();
float3 posWS=TransformObjectToWorld(i.vertex.xyz);
float3 nDirWS=TransformObjectToWorldNormal(i.normal.xyz);
o.pos=TransformWorldToHClip(ApplyShadowBias(posWS,nDirWS,MainLight.direction));
o.pos.z=min(o.pos.z,o.pos.w*UNITY_NEAR_CLIP_VALUE);
o.pos.z=max(o.pos.z,o.pos.w*UNITY_NEAR_CLIP_VALUE);
return o;
}
half4 fragshadow(v2f i):SV_TARGET{
return 0;
}
ENDHLSL
}
}
}
关于本文
本文作者 Master Gong Sheng, 许可由 CC BY-NC 4.0.