summaryrefslogtreecommitdiffstats
path: root/yum_lighting.cginc
blob: dab631a52e8bfb60d25536860c9f89135e686a72 (plain)
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#ifndef __YUM_LIGHTING_INC
#define __YUM_LIGHTING_INC

#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "UnityPBSLighting.cginc"
#include "UnityLightingCommon.cginc"

#include "features.cginc"
#include "LightVolumes.cginc"
#include "poi.cginc"
#include "yum_pbr.cginc"

// fucking kill me
#ifndef __LTCGI_INC
#define __LTCGI_INC

#include "features.cginc"

#if defined(_LTCGI)
struct ltcgi_acc {
  float3 diffuse;
  float3 specular;
};

#include "Third_Party/at.pimaker.ltcgi/Shaders/LTCGI_structs.cginc"

void ltcgi_cb_diffuse(inout ltcgi_acc acc, in ltcgi_output output);
void ltcgi_cb_specular(inout ltcgi_acc acc, in ltcgi_output output);

#define LTCGI_V2_CUSTOM_INPUT ltcgi_acc
#define LTCGI_V2_DIFFUSE_CALLBACK ltcgi_cb_diffuse
#define LTCGI_V2_SPECULAR_CALLBACK ltcgi_cb_specular

#include "Third_Party/at.pimaker.ltcgi/Shaders/LTCGI.cginc"
void ltcgi_cb_diffuse(inout ltcgi_acc acc, in ltcgi_output output) {
	acc.diffuse += output.intensity * output.color * _LTCGI_DiffuseColor;
}
void ltcgi_cb_specular(inout ltcgi_acc acc, in ltcgi_output output) {
	acc.specular += output.intensity * output.color * _LTCGI_SpecularColor;
}
#endif  // _LTCGI

#endif  // __LTCGI_INC

struct YumLighting {
	float3 view_dir;
	float3 dir;
	float3 direct;
	float3 diffuse;
  float diffuse_luminance;
  float3 specular;
	float NoL;
#if defined(_WRAPPED_LIGHTING)
	float NoL_wrapped_s;  // specular
	float NoL_wrapped_d;  // diffuse
#endif
  float attenuation;
  float3 L00;
  float3 L01r;
  float3 L01g;
  float3 L01b;
};

float getShadowAttenuation(v2f i)
{
	float attenuation;
	// This whole block is yoinked from AutoLight.cginc. I needed a way to
	// control shadow strength so I had to duplicate the code.
#if defined(DIRECTIONAL_COOKIE)
	DECLARE_LIGHT_COORD(i, i.worldPos);
	float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
	attenuation = tex2D(_LightTexture0, lightCoord).w;
#elif defined(POINT_COOKIE)
	DECLARE_LIGHT_COORD(i, i.worldPos);
	float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
	attenuation = tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).r *
		texCUBE(_LightTexture0, lightCoord).w;
#elif defined(DIRECTIONAL)
	float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
	attenuation = 1;
#elif defined(SPOT)
	DECLARE_LIGHT_COORD(i, i.worldPos);
	float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
	attenuation = (lightCoord.z > 0) * UnitySpotCookie(lightCoord) *
    UnitySpotAttenuate(lightCoord.xyz);
#elif defined(POINT)
	unityShadowCoord3 lightCoord =
    mul(unity_WorldToLight, unityShadowCoord4(i.worldPos, 1)).xyz;
	float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
	attenuation = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).r;
#else
	float shadow = 1;
	attenuation = 1;
#endif
	attenuation *= lerp(1, shadow, _Shadow_Strength);
	return attenuation;
}

float3 getDirectLightDirection(v2f i) {
#if defined(POINT) || defined(POINT_COOKIE) || defined(SPOT)
	return normalize((_WorldSpaceLightPos0 - i.worldPos).xyz);
#else
	return _WorldSpaceLightPos0;
#endif
}

float GetLodRoughness(float roughness) {
	return roughness * (1.7 - 0.7 * roughness);
}

float3 getIndirectSpecular(v2f i, YumPbr pbr, float3 view_dir, float diffuse_luminance) {
  float roughness = GetLodRoughness(pbr.roughness_perceptual);
	float3 reflect_dir = reflect(-view_dir, pbr.normal);

  UnityGIInput data;
  data.worldPos = i.worldPos;
  data.worldViewDir = view_dir;
  data.probeHDR[0] = unity_SpecCube0_HDR;
  data.probeHDR[1] = unity_SpecCube1_HDR;
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
  data.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
  data.boxMax[0] = unity_SpecCube0_BoxMax;
  data.probePosition[0] = unity_SpecCube0_ProbePosition;
  data.boxMax[1] = unity_SpecCube1_BoxMax;
  data.boxMin[1] = unity_SpecCube1_BoxMin;
  data.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif

  const float3 env_refl = UnityGI_prefilteredRadiance(data, roughness, reflect_dir);

#if defined(_FALLBACK_CUBEMAP)
  // Check if there's no valid scene cubemap
  float3 canned_refl = env_refl;
  if (!SceneHasReflections() || _Fallback_Cubemap_Force) {
    // Set up data for fallback sampling similar to Unity's system
    half3 reflectVector = reflect(-view_dir, pbr.normal);
    
    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
      reflectVector = BoxProjectedCubemapDirection(reflectVector, data.worldPos, /*probe_position=*/0, /*box_min=*/-1, /*box_max=*/1);
    #endif

    half mip = roughness * UNITY_SPECCUBE_LOD_STEPS;
    float4 envSample = UNITY_SAMPLE_TEXCUBE_LOD(_Fallback_Cubemap, reflectVector, mip);
    canned_refl = DecodeHDR(envSample, _Fallback_Cubemap_HDR) * _Fallback_Cubemap_Brightness * diffuse_luminance;
  }
#endif

#if defined(_FALLBACK_CUBEMAP_LIMIT_METALLIC)
  return lerp(env_refl, canned_refl, pbr.metallic);
#elif defined(_FALLBACK_CUBEMAP)
  return canned_refl;
#else
  return env_refl;
#endif
}

float3 yumSH9(float4 n, float3 worldPos, inout YumLighting light) {
#if defined(YUM_SH9_STANDARD)
  // Unity gives us the first three bands (L0-L2) of SH coefficients as follows:
  //   unity_SHA*.w:   L0 coefficients
  //   unity_SHA*.xyz: L1 coefficients
  //   unity_SHB*:     first four of the L2 coefficients
  //   unity_SHC:      last L2 coefficient

  // Parse out coefficients into a simpler but less efficient format.
  float3 L00  = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
  float3 L1_1 = float3(unity_SHAr.x, unity_SHAg.x, unity_SHAb.x);
  float3 L10  = float3(unity_SHAr.y, unity_SHAg.y, unity_SHAb.y);
  float3 L11  = float3(unity_SHAr.z, unity_SHAg.z, unity_SHAb.z);
  float3 L2_2 = float3(unity_SHBr.x, unity_SHBg.x, unity_SHBb.x);
  float3 L2_1 = float3(unity_SHBr.y, unity_SHBg.y, unity_SHBb.y);
  float3 L20  = float3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z);
  float3 L21  = float3(unity_SHBr.w, unity_SHBg.w, unity_SHBb.w);
  float3 L22  = unity_SHC;

  // Equation 13 from "An Efficient Representation for Irradiance Environment
  // Maps" by Ramamoorthi and Hanrahan. Note that the order of some
  // coefficients is different, and normalization constants have been
  // premultiplied by Unity.
  float3 L0 = L00;
  float3 L1 = L1_1 * n.x + L10 * n.y + L11 * n.z;
  float3 L2 =
    L2_2 * n.x * n.y +
    L2_1 * n.y * n.z +
    L20  * n.z * n.z +
    L21 * n.x * n.z +
    L22 * (n.x * n.x - n.y * n.y);

  light.L00 = L00;
  light.L01r = unity_SHAr.xyz;
  light.L01g = unity_SHAg.xyz;
  light.L01b = unity_SHAb.xyz;

  return L0 + L1 + L2;
#elif 1
  // Light volumes. We omit the L01 contribution since flat shading looks
  // better on avatars.
  LightVolumeSH(worldPos, light.L00, light.L01r, light.L01g, light.L01b);
  return LightVolumeEvaluate(n.xyz, light.L00,
      _UdonLightVolumeEnabled ? light.L01r : 0,
      _UdonLightVolumeEnabled ? light.L01g : 0,
      _UdonLightVolumeEnabled ? light.L01b : 0);
#else
  // On non-photorealistic avatars, simply using the diffuse component looks
  // better. *shruge*
  float3 L00  = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);

  light.L00 = L00;
  light.L01r = unity_SHAr.xyz;
  light.L01g = unity_SHAg.xyz;
  light.L01b = unity_SHAb.xyz;

  return L00;
#endif
}

float4 getIndirectDiffuse(v2f i, float4 vertexLightColor,
    inout YumLighting light) {
	float4 diffuse = vertexLightColor;
#if defined(FORWARD_BASE_PASS)
#if defined(LIGHTMAP_ON)
	diffuse.xyz = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uv2));
#else
	diffuse.xyz += max(0, yumSH9(float4(i.normal, 0), i.worldPos, light));
#endif
#endif
	return diffuse;
}

YumLighting GetYumLighting(v2f i, YumPbr pbr) {
	YumLighting light = (YumLighting) 0;

  // normalize has no visibile impact in test scene
  light.view_dir = -normalize(i.eyeVec.xyz);

  light.dir = getDirectLightDirection(i);

	light.direct = _LightColor0.rgb;
	// TODO filament's spherical harmonics look nicer than this.
	// See FilamentLightIndirect.cginc::UnityGI_Irradiance in filamented.
  light.diffuse = getIndirectDiffuse(i, /*vertexLightColor=*/0, light);
#if defined(_MIN_BRIGHTNESS)
  light.diffuse = max(_Min_Brightness, light.diffuse);
#endif

  light.diffuse_luminance = luminance(light.diffuse);
  light.specular = getIndirectSpecular(i, pbr, light.view_dir, light.diffuse_luminance);

#if defined(_LTCGI)
  ltcgi_acc acc = (ltcgi_acc) 0;
  LTCGI_Contribution(
      acc,
      i.worldPos,
      pbr.normal,
      light.view_dir,
      pbr.roughness_perceptual,
      0);
  light.diffuse += acc.diffuse * _LTCGI_Strength;
  light.specular += acc.specular * _LTCGI_Strength;
#endif

#if defined(_QUANTIZE_SPECULAR)
  float specular_luminance = luminance(light.specular);
  light.specular = light.specular * floor(specular_luminance * _Quantize_Specular_Steps) / _Quantize_Specular_Steps;
#endif
#if defined(_QUANTIZE_DIFFUSE)
  light.diffuse = light.diffuse * floor(light.diffuse_luminance * _Quantize_Diffuse_Steps) / _Quantize_Diffuse_Steps;
  light.diffuse_luminance = luminance(light.diffuse);
#endif

#if defined(_BRIGHTNESS_CONTROL)
  light.direct *= _Brightness_Multiplier;
  light.diffuse *= _Brightness_Multiplier;
  light.specular *= _Brightness_Multiplier;
#endif

  light.NoL = dot(pbr.normal, light.dir);
#if defined(_QUANTIZE_NOL)
  light.NoL = floor(light.NoL * _Quantize_NoL_Steps) / _Quantize_NoL_Steps;
#endif
#if defined(_WRAPPED_LIGHTING)
  light.NoL_wrapped_s = saturate(wrapNoL(light.NoL, _Wrap_NoL_Specular_Strength));
  light.NoL_wrapped_d = saturate(wrapNoL(light.NoL, _Wrap_NoL_Diffuse_Strength));
#endif
  light.NoL = saturate(light.NoL);

  light.attenuation = getShadowAttenuation(i);

	return light;
}

#endif  // __YUM_LIGHTING_INC