2种着色模型x3种基础光照模型;遵循能量守恒的Blinn-Phong

铁名_IronName Lv4

2种着色模型 x 3种基础光照模型

Gouraud 着色模型,Phong 着色模型;
Lambert 光照模型,Phong 光照模型,Blinn-Phong 光照模型;
只写了 base 部分,如下:

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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
Shader "Test/Multi-Base Shaders" {
Properties {
[KeywordEnum(Phong, Gouraud)] _ShadingType ("Shading Type", Float) = 0
[KeywordEnum(Lambert, Phong, BlinnPhong)] _LightModel ("Light Model", Float) = 0
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_BumpMap ("Normal Map", 2D) = "bump" {}
_Specular ("Specular Color", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}

Pass {
Tags { "LightMode"="ForwardBase" }

CGPROGRAM

#pragma multi_compile _SHADINGTYPE_PHONG _SHADINGTYPE_GOURAUD
#pragma multi_compile _LIGHTMODEL_LAMBERT _LIGHTMODEL_PHONG _LIGHTMODEL_BLINNPHONG
#pragma multi_compile_fwdbase

#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"

fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
fixed4 _Specular;
float _Gloss;

struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0;
};

struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 TtoW0 : TEXCOORD1;
float4 TtoW1 : TEXCOORD2;
float4 TtoW2 : TEXCOORD3;
SHADOW_COORDS(4)
float3 color : COLOR;
};

v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);

o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

TANGENT_SPACE_ROTATION;

float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);

#if defined(_SHADINGTYPE_PHONG)

fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;

o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

#elif defined(_SHADINGTYPE_GOURAUD)
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos));

// 环境光
fixed3 albedo = tex2Dlod(_MainTex, float4(v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw, 0, 0)).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

// 漫反射基础(所有光照模型都需要)
fixed NdotL = max(0, dot(worldNormal, worldLightDir));
fixed3 diffuse = _LightColor0.rgb * albedo * NdotL;

// 根据光照模型添加高光
fixed3 specular = 0;
#if defined(_LIGHTMODEL_PHONG)
fixed3 reflDir = reflect(-worldLightDir, worldNormal);
specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldViewDir, reflDir)), _Gloss);
#elif defined(_LIGHTMODEL_BLINNPHONG)
fixed3 halfDir = normalize(worldLightDir + worldViewDir);
specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
#endif
// 组合颜色(此处忽略衰减和阴影)
o.color = fixed4(ambient + diffuse + specular, 1.0);
#endif

TRANSFER_SHADOW(o);
return o;
}

fixed4 frag(v2f i) : SV_Target {
fixed4 final_col = fixed4(1.0,1.0,1.0,1.0);

float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
UNITY_LIGHT_ATTENUATION(atten, i, worldPos);

#if defined(_SHADINGTYPE_PHONG)
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));

fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color.rgb;

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(bump, lightDir));


final_col = fixed4(ambient + diffuse*atten, 1.0);//Lambert 光照模型只有环境光和漫反射项

#if defined(_LIGHTMODEL_BLINNPHONG)
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);

final_col = fixed4(ambient + (diffuse + specular) * atten, 1.0);

#elif defined(_LIGHTMODEL_PHONG)
fixed3 reflDir = reflect(-lightDir, bump);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(viewDir, reflDir)), _Gloss);

final_col = fixed4(ambient + (diffuse + specular) * atten, 1.0);
#endif

#elif defined(_SHADINGTYPE_GOURAUD)
final_col = fixed4(i.color*atten,1.0);
#endif

return final_col;
}

ENDCG
}

Pass {
Tags { "LightMode"="ForwardAdd" }

Blend One One

CGPROGRAM

#pragma multi_compile_fwdadd _LIGHTINGMODEL_LAMBERT _LIGHTINGMODEL_PHONG _LIGHTINGMODEL_BLINNPHONG

// #pragma multi_compile_fwdadd_fullshadows

#pragma vertex vert
#pragma fragment frag

#include "Lighting.cginc"
#include "AutoLight.cginc"

fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
fixed4 _Specular;
float _Gloss;

struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0;
};

struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 TtoW0 : TEXCOORD1;
float4 TtoW1 : TEXCOORD2;
float4 TtoW2 : TEXCOORD3;
SHADOW_COORDS(4)
};

v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);

o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;

o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

TRANSFER_SHADOW(o);

return o;
}

fixed4 frag(v2f i) : SV_Target {
float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));

fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color.rgb;

fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(bump, lightDir));

fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);

UNITY_LIGHT_ATTENUATION(atten, i, worldPos);

return fixed4((diffuse + specular) * atten, 1.0);
}

ENDCG
}
}
FallBack "Specular"
}

加了点能量守恒、环境光照的 Blinn-Phong

累了,以后再搞吧。

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
Pass { 
Tags { "LightMode"="ForwardBase" }

CGPROGRAM
#pragma multi_compile_fwdbase

#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"

fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
fixed4 _Specular;
float _Gloss;
float _Metalness;
samplerCUBE _EnvCube;

struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0;
};

struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 TtoW0 : TEXCOORD1;
float4 TtoW1 : TEXCOORD2;
float4 TtoW2 : TEXCOORD3;
SHADOW_COORDS(4)
};

v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);

o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

TANGENT_SPACE_ROTATION;

float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);

fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;

o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

TRANSFER_SHADOW(o);
return o;
}

fixed4 frag(v2f i) : SV_Target {
//---数据准备---//
float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
UNITY_LIGHT_ATTENUATION(atten, i, worldPos);

fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
fixed3 halfDir = normalize(lightDir + viewDir);

fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color.rgb;

float NdotL = max(0, dot(bump, lightDir));
float NdotH = max(0, dot(bump, halfDir));
float specTerm = pow(NdotH, _Gloss); // 高光分布项

//---材质颜色分配(基于金属度)---//
fixed3 diffColor = lerp(albedo, 0, _Metalness); // 金属无漫反射
fixed3 specColor = lerp(0.04, albedo, _Metalness); // 非金属高光基值0.04
// specColor = lerp(diffColor * specColor, specColor, _Gloss/255);
fixed3 total = diffColor + specColor;
diffColor = diffColor / total;
specColor/= total;
// 直接光照(使用 _LightColor0 作为光源颜色,并乘以衰减)
float3 directLight = _LightColor0.rgb * atten * (diffColor * NdotL + specColor * specTerm);

//---环境光照(基于图像的光照 IBL,简化版)---//
float3 ambientLight = UNITY_LIGHTMODEL_AMBIENT.xyz;

// 环境漫反射
float3 envDiffuse = texCUBE(_EnvCube, bump).rgb;
// 环境镜面反射
float3 reflDir = reflect(-viewDir, bump);
float3 envSpecular = texCUBE(_EnvCube, reflDir).rgb;
// envDiffuse.rgb = lerp(envDiffuse * diffColor.rgb, envDiffuse, _Gloss/255);


// 按金属度混合环境光,并乘以环境光强度
float3 indirectLight = ambientLight * (
(1 - _Metalness) * envDiffuse * albedo + // 非金属:环境漫反射为主
_Metalness * envSpecular // 金属:环境镜面反射为主
);

// 能量钳位
indirectLight = saturate(indirectLight);

return fixed4(directLight + indirectLight, 1.0);
}
ENDCG
}
  • 标题: 2种着色模型x3种基础光照模型;遵循能量守恒的Blinn-Phong
  • 作者: 铁名_IronName
  • 创建于 : 2026-02-17 19:14:28
  • 更新于 : 2026-02-23 17:38:07
  • 链接: https://blog.ironname.top/2026/基础光照模型;PB-Blinn-Phong/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
2种着色模型x3种基础光照模型;遵循能量守恒的Blinn-Phong