光照效果

本文最后更新于:2023年3月6日 凌晨

Cel Shading

总 悟空 悟空 悟空

那鲁梅亚 那鲁梅亚

  • 参考资料
    • https://www.cnblogs.com/traceplus/p/4205798.html

PBR Character

整体1 整体2 头发 移动端sss效果 武器

Kajiya-Kay Anisotropic

Kajiya-Kay Anisotropic
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
Shader "KajiyaKayAnisotropic"
{
Properties
{
_ShiftMap("ShiftMap", 2D) = "black" {}
_PrimaryShift("PrimaryShift", float) = 1.0
_SecondaryShift("SecondaryShift", float) = 1.0

_AlbedoMap("AlbedoMap", 2D) = "gray" {}
_SpecMask("SpecMask", 2D) = "white" {}
_SpecularColor1("SpecularColor1", Color) = (1,1,1,1)
_SpecularColor2("SpecularColor2", Color) = (1,1,1,1)
_SpecExp1("SpecExp1", float) = 100.0
_SpecExp2("SpecExp2", float) = 100.0
}
SubShader
{
Pass
{
Tags { "LightMode" = "ForwardBase" }

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};

struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 tangent : TEXCOORD2;
float3 binormal : TEXCOORD3;
float3 worldPos : TEXCOORD4;
};

float4 _LightColor0;

sampler2D _ShiftMap;
float4 _ShiftMap_ST;

float _PrimaryShift;
float _SecondaryShift;

sampler2D _AlbedoMap;
float4 _AlbedoMap_ST;

sampler2D _SpecMask;
float4 _SpecMask_ST;

fixed4 _SpecularColor1;
fixed4 _SpecularColor2;

float _SpecExp1;
float _SpecExp2;

float3 ShiftTangent(float3 T, float3 N, float shift)
{
float3 shiftedT = T + (shift * N);
return normalize(shiftedT);
}

float StrandSpecular(float3 T, float3 V, float L, float exponent)
{
float3 H = normalize(L + V);
float dotTH = dot(T, H);
float sinTH = sqrt(1.0 - dotTH*dotTH);
float dirAtten = smoothstep(-1.0, 0.0, dot(T, H));

return dirAtten * pow(sinTH, exponent);
}

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.normal = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
o.tangent = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz);
o.binormal = normalize(cross(o.normal,o.tangent)) * v.tangent.w;
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}

fixed4 frag (v2f i) : SV_Target
{
half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
half3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);

half3 normal = normalize(i.normal);
half3 tangen = normalize(i.tangent);
half3 binormal = normalize(i.binormal);

half3 shiftDir = binormal;

// diffuse lighting
float3 diffuse = saturate(lerp(0.25, 1.0, dot(normal, lightDir)));

// shift tangents
float shiftTex = tex2D(_ShiftMap, i.uv) - 0.5;

// specular lighting
float3 t1 = ShiftTangent(shiftDir, normal, _PrimaryShift + shiftTex);
float3 specular = _SpecularColor1 * StrandSpecular(t1, viewDir, lightDir, _SpecExp1);

// add second specular term
float3 t2 = ShiftTangent(shiftDir, normal, _SecondaryShift + shiftTex);
float specMask = tex2D(_SpecMask, i.uv);
specular += _SpecularColor2 * specMask * StrandSpecular(t2, viewDir, lightDir, _SpecExp2);

// Final color
fixed4 o;
o.rgb = (diffuse + specular) * tex2D(_AlbedoMap, i.uv) * _LightColor0.xyz;
o.a = 1;
// o.rgb *= ambOcc;
// o.a = tex2D(tAlpha, uv);

return o;
}
ENDCG
}
}
Fallback "Diffuse"
}
  • 参考资料
    • https://www.zhihu.com/question/36946353
    • https://blog.csdn.net/noahzuo/article/details/51162472
    • https://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf

Sub Surface Scattering

Sub Surface Scattering
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
//只实现了背面光线透射效果
Shader "SubSurfaceScattering"
{
Properties
{
_BaseColor("Base Color",Color) = (0,0.352,0.219,1)

_ThicknessMap("Thickness Map",2D) = "black"{}

[Header(BasePass)]
_BasePassDistortion("Bass Pass Distortion", Range(0,1)) = 0.2
_BasePassColor("BasePass Color",Color) = (1,1,1,1)
_BasePassPower("BasePass Power",float) = 1
_BasePassScale("BasePass Scale",float) = 2

[Header(CubeMap)]
_CubeMap ("Cube Map", Cube) = "white" {}
_CubeMapScale("Cube Map Scale",float) = 1.0
_FresnelMin("Fresnel Min",Range(-2,2)) = 0
_FresnelMax("Fresnel Max",Range(-2,2)) = 1
}

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

CGPROGRAM

#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"

float4 _BaseColor;

sampler2D _ThicknessMap;

float4 _BasePassColor;
float _BasePassDistortion;
float _BasePassPower;
float _BasePassScale;

samplerCUBE _CubeMap;
float4 _CubeMap_HDR;
float _CubeMapScale;
float _FresnelMin;
float _FresnelMax;

float4 _LightColor0;

struct appdata {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
};

struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalDir : TEXCOORD2;
};

v2f vert(appdata v)
{
v2f o;
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.normalDir = UnityObjectToWorldNormal(v.normal);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.uv = v.texcoord;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}

float4 frag(v2f i) : COLOR
{
//info
float3 normalDir = normalize(i.normalDir);
float3 viewDir = normalize(_WorldSpaceCameraPos - i.posWorld.xyz);
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

//diffuse
float3 diffuseRes = max(0.0, dot(normalDir, lightDir)) * _BaseColor * _LightColor0.rgb;

//trans light
float3 backLightDir = -normalize(lightDir + normalDir * _BasePassDistortion);
float VdotL = max(0.0, dot(viewDir, backLightDir));
float thickness = 1.0 - tex2D(_ThicknessMap, i.uv).r;
float3 backlightRes = max(0.0, pow(VdotL, _BasePassPower)) * _BasePassScale * thickness * _BasePassColor.xyz * _LightColor0.xyz;

//cubeMap
float3 reflectDir = reflect(-viewDir, normalDir);
float4 cubeMapColor = texCUBE(_CubeMap, reflectDir);
half3 cubeMapColorHDR = DecodeHDR(cubeMapColor, _CubeMap_HDR);
float3 cubeMapRes = cubeMapColorHDR * _CubeMapScale;

float3 final_color = diffuseRes + backlightRes + cubeMapRes;

return float4(final_color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse" //提供LightMode为ShadowCaster的Pass;如果shader中有clip操作,则需要自己提供LightMode为ShadowCaster的Pass
}

Light Probe

Light Probe
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
Shader "LightProbe"
{
Properties
{
}
SubShader
{
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "AutoLight.cginc"
#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 normal_world : TEXCOORD1;
float3 pos_world : TEXCOORD2;
float3 tangent_world : TEXCOORD3;
float3 binormal_world : TEXCOORD4;
};

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal_world = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 normal_dir = normalize(i.normal_world);

half3 env_color = ShadeSH9(float4(normal_dir,1.0));
half3 final_color = env_color;

return float4(final_color,1.0);
}
ENDCG
}
}
}

基于SH实现的漫反射

基于SH实现的漫反射
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
Shader "SH"
{
Properties
{
custom_SHAr("Custom SHAr", Vector) = (0, 0, 0, 0)
custom_SHAg("Custom SHAg", Vector) = (0, 0, 0, 0)
custom_SHAb("Custom SHAb", Vector) = (0, 0, 0, 0)
custom_SHBr("Custom SHBr", Vector) = (0, 0, 0, 0)
custom_SHBg("Custom SHBg", Vector) = (0, 0, 0, 0)
custom_SHBb("Custom SHBb", Vector) = (0, 0, 0, 0)
custom_SHC("Custom SHC", Vector) = (0, 0, 0, 1)
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
};

struct v2f
{
float4 pos : SV_POSITION;
float3 normal_world : TEXCOORD1;
};

half4 custom_SHAr;
half4 custom_SHAg;
half4 custom_SHAb;
half4 custom_SHBr;
half4 custom_SHBg;
half4 custom_SHBb;
half4 custom_SHC;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal_world = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 normal_dir = normalize(i.normal_world);

float4 normalForSH = float4(normal_dir, 1.0);
//SHEvalLinearL0L1
half3 x;
x.r = dot(custom_SHAr, normalForSH);
x.g = dot(custom_SHAg, normalForSH);
x.b = dot(custom_SHAb, normalForSH);

//SHEvalLinearL2
half3 x1, x2;
// 4 of the quadratic (L2) polynomials
half4 vB = normalForSH.xyzz * normalForSH.yzzx;
x1.r = dot(custom_SHBr, vB);
x1.g = dot(custom_SHBg, vB);
x1.b = dot(custom_SHBb, vB);

// Final (5th) quadratic (L2) polynomial
half vC = normalForSH.x*normalForSH.x - normalForSH.y*normalForSH.y;
x2 = custom_SHC.rgb * vC;

float3 sh = max(float3(0.0, 0.0, 0.0), (x + x1 + x2));

half3 env_color = sh;
half3 final_color = env_color;

return float4(final_color,1.0);
}
ENDCG
}
}
}

IBL

采样自CubeMap实现Specular
采样自Reflection Probe实现Specular
采样自CubeMap实现Diffuse
采样自Reflection Probe实现Diffuse
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
Shader "IBL"
{
Properties
{
_CubeMap("Cube Map",Cube) = "white"{}
_IsFromCube("IsFromCube", Int) = 1
_IsSpecular("IsSpecular", Int) = 1
_RoughnessMap("Roughness Map",2D) = "black"{}
_RoughnessContrast("Roughness Contrast",Range(1, 10)) = 1
_RoughnessScale("_Roughness Scale",Float) = 1
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 normal_world : TEXCOORD1;
float3 pos_world : TEXCOORD2;
};

samplerCUBE _CubeMap;
float4 _CubeMap_HDR;
int _IsFromCube;
int _IsSpecular;
float _Roughness;
sampler2D _RoughnessMap;
float4 _RoughnessMap_ST;
float _RoughnessContrast;
float _RoughnessScale;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord * _RoughnessMap_ST.xy + _RoughnessMap_ST.zw;
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
o.normal_world = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 normal_dir = normalize(i.normal_world);

float roughness = tex2D(_RoughnessMap, i.uv);
roughness = saturate(pow(roughness, _RoughnessContrast) * _RoughnessScale);
roughness = roughness * (1.7 - 0.7 * roughness);
float mip_level = roughness * 6.0;

half3 dirOfSample;
if (_IsSpecular == 1)
{
half3 view_dir = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
half3 reflect_dir = reflect(-view_dir, normal_dir);
dirOfSample = reflect_dir;
}
else
{
dirOfSample = normal_dir;
}

half3 env_color;
if (_IsFromCube == 1)
{
half4 colorOfCubemap = texCUBElod(_CubeMap, float4(dirOfSample, mip_level));
env_color = DecodeHDR(colorOfCubemap, _CubeMap_HDR); //需要加上这句代码才能在移动端获得HDR信息
}
else
{
half4 colorOfCubemap = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, dirOfSample, mip_level);
env_color = DecodeHDR(colorOfCubemap, unity_SpecCube0_HDR); //需要加上这句代码才能在移动端获得HDR信息
}

half3 final_color = env_color;
return float4(final_color,1.0);
}
ENDCG
}
}
}

Cube

采样自Cube Map
采样自Reflection Probe
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
Shader "Cube"
{
Properties
{
_CubeMap("Cube Map",Cube) = "white"{}
_IsFromCube("IsFromCube", Int) = 1
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f
{
float4 pos : SV_POSITION;
float3 normal_world : TEXCOORD0;
float3 pos_world : TEXCOORD1;
};

samplerCUBE _CubeMap;
float4 _CubeMap_HDR;
int _IsFromCube;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
o.normal_world = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 normal_dir = normalize(i.normal_world);
half3 view_dir = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
half3 reflect_dir = reflect(-view_dir, normal_dir);

half3 env_hdr_color;
if (_IsFromCube == 1)
{
//采样自CubeMap
half4 colorOfCubemap = texCUBE(_CubeMap, reflect_dir);
env_hdr_color = DecodeHDR(colorOfCubemap, _CubeMap_HDR); //需要加上这句代码才能在移动端获得HDR信息
}
else
{
//采样自Reflection Probe
half4 colorOfReflectionProbe = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, reflect_dir);
env_hdr_color = DecodeHDR(colorOfReflectionProbe, unity_SpecCube0_HDR); //需要加上这句代码才能在移动端获得HDR信息
}

half3 final_color = env_hdr_color;
return float4(final_color,1.0);
}
ENDCG
}
}
}

Forward RenderPath+Diffuse+NormalMap+AOMap+SpecularMap+ParallaxMap+ShadowMap+Ambient

Complete1
Complete2

Cascaded Shadow Map

Cascaded Shadow Map
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
Shader "ShadowMap"
{
Properties
{
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f
{
float4 pos : SV_POSITION;
float3 normal_dir : TEXCOORD0;
SHADOW_COORDS(1)
};

float4 _LightColor0;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal_dir = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
TRANSFER_SHADOW(o)
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 normal_dir = normalize(i.normal_dir);
half3 light_dir = normalize(_WorldSpaceLightPos0.xyz);
half shadow = SHADOW_ATTENUATION(i);
half3 diffuse_color = min(shadow, max(0.0,dot(normal_dir, light_dir))) * _LightColor0.xyz;
return half4(diffuse_color,1.0);
}
ENDCG
}
Pass
{
Tags{"LightMode" = "ForwardAdd"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f
{
float4 pos : SV_POSITION;
float3 normal_dir : TEXCOORD1;
float3 pos_world : TEXCOORD2;
LIGHTING_COORDS(3, 4)
};

float4 _LightColor0;

v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal_dir = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}

half4 frag(v2f i) : SV_Target
{
half atten = LIGHT_ATTENUATION(i);
half3 light_dir_point = normalize(_WorldSpaceLightPos0.xyz - i.pos_world);
half3 light_dir = normalize(_WorldSpaceLightPos0.xyz);
light_dir = lerp(light_dir, light_dir_point, _WorldSpaceLightPos0.w);
half3 normal_dir = normalize(i.normal_dir);
half diff_term = min(atten,max(0.0,dot(normal_dir, light_dir)));
half3 diffuse_color = diff_term * _LightColor0.xyz;

return half4(diffuse_color,1.0);
}
ENDCG
}
}
Fallback "Diffuse" //提供LightMode为ShadowCaster的Pass;如果shader中有clip操作,则需要自己提供LightMode为ShadowCaster的Pass
}

Parallax Map

Parallax Map
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
Shader "ParallaxMap"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ParallaxMap("ParallaxMap",2D) = "black"{}
_Parallax("_Parallax",float) = 2
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"

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

struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 pos_world : TEXCOORD1;
float3 normal_dir : TEXCOORD2;
float3 tangent_dir : TEXCOORD3;
float3 binormal_dir : TEXCOORD4;
};

sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _ParallaxMap;
float _Parallax;
float4 _LightColor0;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

o.normal_dir = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
o.tangent_dir = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz);
o.binormal_dir = normalize(cross(o.normal_dir,o.tangent_dir)) * v.tangent.w;
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 view_dir = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
half3 normal_dir = normalize(i.normal_dir);
half3 tangent_dir = normalize(i.tangent_dir);
half3 binormal_dir = normalize(i.binormal_dir);
float3x3 TBN = float3x3(tangent_dir, binormal_dir, normal_dir);
half3 view_tangentspace = normalize(mul(TBN, view_dir));

//一般不会直接做10次迭代
half2 uv_parallax = i.uv;
for (int j = 0; j < 10; j++)
{
half height = tex2D(_ParallaxMap, uv_parallax);
uv_parallax = uv_parallax - (0.5 - height) * view_tangentspace.xy * _Parallax * 0.01f;
}

half4 base_color = tex2D(_MainTex, uv_parallax);

half3 light_dir = normalize(_WorldSpaceLightPos0.xyz);
half diff_term = max(0.0,dot(normal_dir, light_dir));
half3 diffuse_color = diff_term * _LightColor0.xyz * base_color.xyz;

half3 final_color = diffuse_color;
return half4(final_color,1.0);
}
ENDCG
}
}
}

Specular Map

Specular Map
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
Shader "SpecularMap"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_SpecMask("Spec Mask",2D) = "white"{}
_Shininess("Shininess",Range(0.01,100)) = 1.0
_SpecIntensity("SpecIntensity",Range(0.01,5)) = 1.0
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
};

struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal_dir : TEXCOORD1;
float3 pos_world : TEXCOORD2;
};

sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _SpecMask;
float _Shininess;
float _SpecIntensity;
float4 _LightColor0;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

o.normal_dir = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 view_dir = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
half3 normal_dir = normalize(i.normal_dir);

half4 base_color = tex2D(_MainTex, i.uv);
half4 spec_mask = tex2D(_SpecMask, i.uv);

half3 light_dir = normalize(_WorldSpaceLightPos0.xyz);
half diff_term = max(0.0,dot(normal_dir, light_dir));
half3 diffuse_color = diff_term * _LightColor0.xyz * base_color.xyz;

half3 half_dir = normalize(light_dir + view_dir);
half NdotH = dot(normal_dir, half_dir);
half3 spec_color = pow(max(0.0, NdotH), _Shininess)
* diff_term * _LightColor0.xyz * _SpecIntensity * spec_mask.rgb;

half3 final_color = diffuse_color + spec_color;
return half4(final_color,1.0);
}
ENDCG
}
}
}

AO Map

AO Map
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
Shader "AOMap"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_AOMap("AO Map",2D) = "white"{}
_AOIntensity("AOIntensity", float) = 3
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"

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

struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal_dir : TEXCOORD1;
};

sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _AOMap;
float _AOIntensity;
float4 _LightColor0;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.normal_dir = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
return o;
}

half4 frag (v2f i) : SV_Target
{
half3 normal_dir = normalize(i.normal_dir);

half4 base_color = tex2D(_MainTex, i.uv);

half4 ao_color = pow(tex2D(_AOMap, i.uv), _AOIntensity);

half3 light_dir = normalize(_WorldSpaceLightPos0.xyz);
half3 diffuse_color = max(0.0,dot(normal_dir, light_dir)) * _LightColor0.xyz * base_color.xyz;

half3 final_color = diffuse_color * ao_color; //AO效果应该和最终计算结果混合

return half4(final_color,1.0);
}
ENDCG
}
}
}

Normal Map In Tangent Space

Normal Map In Tangent Space
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
Shader "Normal Map In Tangent Space" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_BumpMap ("Normal Map", 2D) = "bump" {}
_BumpScale ("Bump Scale", Float) = 1.0
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }

CGPROGRAM

#pragma vertex vert
#pragma fragment frag

#include "Lighting.cginc"

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

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

struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 lightDir: TEXCOORD1;
float3 viewDir : TEXCOORD2;
};

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;

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

float3x3 worldToTangent = float3x3(worldTangent, worldBinormal, worldNormal);

o.lightDir = mul(worldToTangent, WorldSpaceLightDir(v.vertex));
o.viewDir = mul(worldToTangent, WorldSpaceViewDir(v.vertex));

return o;
}

fixed4 frag(v2f i) : SV_Target {
fixed3 tangentLightDir = normalize(i.lightDir);
fixed3 tangentViewDir = normalize(i.viewDir);

fixed4 packedNormal = tex2D(_BumpMap, i.uv.zw);
fixed3 tangentNormal;

// 如果法线纹理没有设置为Normal map
// tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;
// tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

// 如果法线纹理设置为Normal map
tangentNormal = UnpackNormal(packedNormal);
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

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

fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));

return fixed4(diffuse, 1.0);
}

ENDCG
}
}
FallBack "Specular"
}
//Unity Shader rumen

Forward RenderPath

兰伯特漫反射+Blin-Phong高光反射+Ambient

4个点光源、1个平行光
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
Shader "Forward Rendering" {
Properties {
_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
_Specular ("Specular", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Tags { "RenderType"="Opaque" }

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

CGPROGRAM

#pragma multi_compile_fwdbase

#pragma vertex vert
#pragma fragment frag

#include "Lighting.cginc"

fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;

struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};

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

o.worldNormal = UnityObjectToWorldNormal(v.normal);

o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

return o;
}

fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));

fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);

fixed atten = 1.0;

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

ENDCG
}

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

Blend One One

CGPROGRAM

#pragma multi_compile_fwdadd

#pragma vertex vert
#pragma fragment frag

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

fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;

struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};

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

o.worldNormal = UnityObjectToWorldNormal(v.normal);

o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

return o;
}

fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
#ifdef USING_DIRECTIONAL_LIGHT
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
#else
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
#endif

fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));

fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);

#ifdef USING_DIRECTIONAL_LIGHT
fixed atten = 1.0;
#else
#if defined (POINT)
float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
#elif defined (SPOT)
float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
#else
fixed atten = 1.0;
#endif
#endif

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

ENDCG
}
}
FallBack "Specular"
}
//Unity Shader rumen

光照效果
https://roudersky.com/posts/f65cb81a.html
作者
Rouder
发布于
2023年1月2日
许可协议