yum-archive/2ner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum-archive/2ner

yumbuncha shitttt0a8d744

master
13.7 KiB430 linesraw
1#ifndef __YUM_LIGHTING_INC
2#define __YUM_LIGHTING_INC
3
4#include "UnityCG.cginc"
5#include "AutoLight.cginc"
6#include "UnityPBSLighting.cginc"
7#include "UnityLightingCommon.cginc"
8#include "UnityStandardCoreMinimal.cginc"
9
10#include "features.cginc"
11#include "LightVolumes.cginc"
12#include "poi.cginc"
13#include "yum_pbr.cginc"
14#include "math.cginc"
15
16// fucking kill me
17#ifndef __LTCGI_INC
18#define __LTCGI_INC
19
20#include "features.cginc"
21
22#if defined(_LTCGI)
23struct ltcgi_acc {
24  float3 diffuse;
25  float3 specular;
26};
27
28#include "Third_Party/at.pimaker.ltcgi/Shaders/LTCGI_structs.cginc"
29
30void ltcgi_cb_diffuse(inout ltcgi_acc acc, in ltcgi_output output);
31void ltcgi_cb_specular(inout ltcgi_acc acc, in ltcgi_output output);
32
33#define LTCGI_V2_CUSTOM_INPUT ltcgi_acc
34#define LTCGI_V2_DIFFUSE_CALLBACK ltcgi_cb_diffuse
35#define LTCGI_V2_SPECULAR_CALLBACK ltcgi_cb_specular
36
37#include "Third_Party/at.pimaker.ltcgi/Shaders/LTCGI.cginc"
38void ltcgi_cb_diffuse(inout ltcgi_acc acc, in ltcgi_output output) {
39	acc.diffuse += output.intensity * output.color * _LTCGI_DiffuseColor;
40}
41void ltcgi_cb_specular(inout ltcgi_acc acc, in ltcgi_output output) {
42	acc.specular += output.intensity * output.color * _LTCGI_SpecularColor;
43}
44#endif  // _LTCGI
45
46#endif  // __LTCGI_INC
47
48float3 Shade4PointLightsWrapped(
49    float4 lightPosX, float4 lightPosY, float4 lightPosZ,
50    float3 lightColor0, float3 lightColor1, float3 lightColor2, float3 lightColor3,
51    float4 lightAttenSq,
52    float3 pos, float3 normal, float wrapStrength)
53{
54    // to light vectors
55    float4 toLightX = lightPosX - pos.x;
56    float4 toLightY = lightPosY - pos.y;
57    float4 toLightZ = lightPosZ - pos.z;
58    
59    // squared lengths
60    float4 lengthSq = 0;
61    lengthSq += toLightX * toLightX;
62    lengthSq += toLightY * toLightY;
63    lengthSq += toLightZ * toLightZ;
64    
65    // NdotL
66    float4 ndotl = 0;
67    ndotl += toLightX * normal.x;
68    ndotl += toLightY * normal.y;
69    ndotl += toLightZ * normal.z;
70    
71    // correct NdotL
72    float4 corr = rsqrt(lengthSq);
73    ndotl = ndotl * corr;
74    
75    // Apply wrapped lighting
76    float4 wrappedNdotl;
77    wrappedNdotl.x = saturate(wrapNoL(ndotl.x, wrapStrength));
78    wrappedNdotl.y = saturate(wrapNoL(ndotl.y, wrapStrength));
79    wrappedNdotl.z = saturate(wrapNoL(ndotl.z, wrapStrength));
80    wrappedNdotl.w = saturate(wrapNoL(ndotl.w, wrapStrength));
81    
82    // attenuation
83    float4 atten = 1.0 / (1.0 + lengthSq * lightAttenSq);
84    float4 diff = wrappedNdotl * atten;
85    
86    // final color
87    float3 col = 0;
88    col += lightColor0 * diff.x;
89    col += lightColor1 * diff.y;
90    col += lightColor2 * diff.z;
91    col += lightColor3 * diff.w;
92    
93    return col;
94}
95
96struct YumLighting {
97	float3 view_dir;
98	float3 dir;
99	float3 direct;
100	float3 diffuse;
101  float diffuse_luminance;
102  float3 specular;
103	float NoL;
104#if defined(_WRAPPED_LIGHTING)
105	float NoL_wrapped_s;  // specular
106	float NoL_wrapped_d;  // diffuse
107#endif
108  float attenuation;
109  float3 L00;
110  float3 L01r;
111  float3 L01g;
112  float3 L01b;
113  float occlusion;
114  Light derivedLight;
115};
116
117float getShadowAttenuation(v2f i, f2f f)
118{
119	float attenuation;
120	float shadow;
121	// This whole block is yoinked from AutoLight.cginc. I needed a way to
122	// control shadow strength so I had to duplicate the code.
123#if defined(DIRECTIONAL_COOKIE)
124	DECLARE_LIGHT_COORD(i, f.worldPos);
125	shadow = UNITY_SHADOW_ATTENUATION(i, f.worldPos);
126	attenuation = tex2D(_LightTexture0, lightCoord).w;
127#elif defined(POINT_COOKIE)
128	DECLARE_LIGHT_COORD(i, f.worldPos);
129	shadow = UNITY_SHADOW_ATTENUATION(i, f.worldPos);
130	attenuation = tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).r *
131		texCUBE(_LightTexture0, lightCoord).w;
132#elif defined(DIRECTIONAL)
133	shadow = UNITY_SHADOW_ATTENUATION(i, f.worldPos);
134	attenuation = 1;
135#elif defined(SPOT)
136	DECLARE_LIGHT_COORD(i, f.worldPos);
137	shadow = UNITY_SHADOW_ATTENUATION(i, f.worldPos);
138	attenuation = (lightCoord.z > 0) * UnitySpotCookie(lightCoord) *
139    UnitySpotAttenuate(lightCoord.xyz);
140#elif defined(POINT)
141	unityShadowCoord3 lightCoord =
142    mul(unity_WorldToLight, unityShadowCoord4(f.worldPos, 1)).xyz;
143	shadow = UNITY_SHADOW_ATTENUATION(i, f.worldPos);
144	attenuation = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).r;
145#else
146	shadow = 1;
147	attenuation = 1;
148#endif
149	float realtimeAttenuation = attenuation * lerp(1, shadow, _Shadow_Strength);
150
151	GetBakedAttenuation(realtimeAttenuation, i.uv01.zw, f.worldPos);
152
153	return realtimeAttenuation;
154}
155
156float3 getDirectLightDirection(v2f i, f2f f) {
157#if defined(POINT) || defined(POINT_COOKIE) || defined(SPOT)
158	return normalize((_WorldSpaceLightPos0 - f.worldPos).xyz);
159#else
160	return _WorldSpaceLightPos0;
161#endif
162}
163
164float GetLodRoughness(float roughness) {
165	return roughness * (1.7 - 0.7 * roughness);
166}
167
168float3 getIndirectSpecular(v2f i, f2f f, YumPbr pbr, float3 view_dir, float diffuse_luminance) {
169#if defined(_ANISOTROPY)
170  float3 aniso_tangent = cross(view_dir, pbr.binormal);
171  float3 aniso_normal = -normalize(cross(aniso_tangent, pbr.binormal));
172  float3 refl_normal = normalize(lerp(pbr.normal, aniso_normal, _Anisotropy_Strength));
173  float3 reflect_dir = reflect(-view_dir, refl_normal);
174#else
175  float3 reflect_dir = reflect(-view_dir, pbr.normal);
176#endif
177
178  UnityGIInput data;
179  data.worldPos = f.worldPos;
180  data.worldViewDir = view_dir;
181  data.probeHDR[0] = unity_SpecCube0_HDR;
182  data.probeHDR[1] = unity_SpecCube1_HDR;
183#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
184  data.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
185#endif
186#ifdef UNITY_SPECCUBE_BOX_PROJECTION
187  data.boxMax[0] = unity_SpecCube0_BoxMax;
188  data.probePosition[0] = unity_SpecCube0_ProbePosition;
189  data.boxMax[1] = unity_SpecCube1_BoxMax;
190  data.boxMin[1] = unity_SpecCube1_BoxMin;
191  data.probePosition[1] = unity_SpecCube1_ProbePosition;
192#endif
193
194  // Apply roughness adjustment to match filamented's behavior
195  float3 env_refl = UnityGI_prefilteredRadiance(data, pbr.roughness_perceptual, reflect_dir);
196
197#if defined(_FALLBACK_CUBEMAP)
198  // Check if there's no valid scene cubemap
199  float3 canned_refl = env_refl;
200  if (!SceneHasReflections() || _Fallback_Cubemap_Force) {
201    // Set up data for fallback sampling similar to Unity's system
202    half3 reflectVector = reflect(-view_dir, pbr.normal);
203
204    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
205      reflectVector = BoxProjectedCubemapDirection(reflectVector, data.worldPos, /*probe_position=*/0, /*box_min=*/-1, /*box_max=*/1);
206    #endif
207
208    half mip = pbr.roughness_perceptual * UNITY_SPECCUBE_LOD_STEPS;
209    float4 envSample = UNITY_SAMPLE_TEXCUBE_LOD(_Fallback_Cubemap, reflectVector, mip);
210    canned_refl = DecodeHDR(envSample, _Fallback_Cubemap_HDR) * _Fallback_Cubemap_Brightness * diffuse_luminance;
211  }
212#endif
213
214#if defined(_FALLBACK_CUBEMAP_LIMIT_METALLIC)
215  return lerp(env_refl, canned_refl, pbr.metallic);
216#elif defined(_FALLBACK_CUBEMAP)
217  return canned_refl;
218#else
219  return env_refl;
220#endif
221}
222
223float3 yumSH9(float4 n, float3 worldPos, inout YumLighting light) {
224//#define YUM_SH9_STANDARD
225#if defined(YUM_SH9_STANDARD)
226  // Unity gives us the first three bands (L0-L2) of SH coefficients as follows:
227  //   unity_SHA*.w:   L0 coefficients
228  //   unity_SHA*.xyz: L1 coefficients
229  //   unity_SHB*:     first four of the L2 coefficients
230  //   unity_SHC:      last L2 coefficient
231
232  // Parse out coefficients into a simpler but less efficient format.
233  float3 L00  = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
234  float3 L1_1 = float3(unity_SHAr.x, unity_SHAg.x, unity_SHAb.x);
235  float3 L10  = float3(unity_SHAr.y, unity_SHAg.y, unity_SHAb.y);
236  float3 L11  = float3(unity_SHAr.z, unity_SHAg.z, unity_SHAb.z);
237  float3 L2_2 = float3(unity_SHBr.x, unity_SHBg.x, unity_SHBb.x);
238  float3 L2_1 = float3(unity_SHBr.y, unity_SHBg.y, unity_SHBb.y);
239  float3 L20  = float3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z);
240  float3 L21  = float3(unity_SHBr.w, unity_SHBg.w, unity_SHBb.w);
241  float3 L22  = unity_SHC;
242
243  // Equation 13 from "An Efficient Representation for Irradiance Environment
244  // Maps" by Ramamoorthi and Hanrahan. Note that the order of some
245  // coefficients is different, and normalization constants have been
246  // premultiplied by Unity.
247  float3 L0 = L00;
248  float3 L1 = L1_1 * n.x + L10 * n.y + L11 * n.z;
249  float3 L2 =
250    L2_2 * n.x * n.y +
251    L2_1 * n.y * n.z +
252    L20  * n.z * n.z +
253    L21 * n.x * n.z +
254    L22 * (n.x * n.x - n.y * n.y);
255
256#if defined(_WRAPPED_LIGHTING)
257  float wrap_term = _Wrap_NoL_Diffuse_Strength;
258  // Original coefficients: 1, 2/3, 1/4.
259  // Wrapped coefficients: 1, (2-w)/3, ((1-w)^2)/4.
260
261  // Setting w=0, the l1 band is:
262  //   (2-w)/3 = 2/3
263  //   2-w = 2
264  //   1-w/2 = 1
265  float l1_wrap = 1.0f - wrap_term * 0.75f;
266  L1 *= l1_wrap;
267
268  // The l2 band is:
269  //   ((1-w)^2)/4 = 1/4
270  //   (1-w)^2 = 1
271  float l2_wrap = (1.0f-wrap_term);
272  l2_wrap *= l2_wrap;
273  L2 *= l2_wrap;
274#else
275  float l1_wrap = 1.0f;
276#endif  // _WRAPPED_LIGHTING
277
278  light.L00 = L00;
279  light.L01r = unity_SHAr.xyz * l1_wrap;
280  light.L01g = unity_SHAg.xyz * l1_wrap;
281  light.L01b = unity_SHAb.xyz * l1_wrap;
282
283  return L0 + L1 + L2;
284#else  // !YUM_SH9_STANDARD
285  LightVolumeSH(worldPos, light.L00, light.L01r, light.L01g, light.L01b);
286
287#if defined(_LIGHT_VOLUMES_BRIGHTNESS)
288  [branch]
289  if (_Light_Volumes_Brightness_Enabled_Dynamic) {
290    float3 probe_L00  = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
291    float t = _Light_Volumes_Brightness;
292    light.L00 = lerp(probe_L00, light.L00, t);
293    light.L01r = lerp(unity_SHAr.xyz, light.L01r, t);
294    light.L01g = lerp(unity_SHAg.xyz, light.L01g, t);
295    light.L01b = lerp(unity_SHAb.xyz, light.L01b, t);
296  }
297#endif
298
299  // Hack to get directional information from SH.
300  float3 light_dir = normalize(float3(luminance(light.L01r), luminance(light.L01g), luminance(light.L01b)));
301  light.derivedLight.l = light_dir;
302  light.derivedLight.colorIntensity = float4(light.L00, 1);
303  light.derivedLight.attenuation = 1;
304  light.derivedLight.NoL = saturate(dot(n.xyz, light_dir));
305
306#if defined(_WRAPPED_LIGHTING)
307  float wrap_term = _Wrap_NoL_Diffuse_Strength;
308  // Hack. Not energy preserving but sorta close. I think this looks better at fully flat mode.
309  float l1_wrap = 1.0f - wrap_term * 0.75f;
310  light.L01r *= l1_wrap;
311  light.L01g *= l1_wrap;
312  light.L01b *= l1_wrap;
313#endif  // _WRAPPED_LIGHTING
314
315  return LightVolumeEvaluate(n.xyz, light.L00, light.L01r, light.L01g, light.L01b);
316#endif
317}
318
319float4 getIndirectDiffuse(v2f i,
320    f2f f,
321    float3 normal,
322    float4 vertexLightColor,
323    inout YumLighting light) {
324  float4 diffuse = vertexLightColor;
325#if defined(FORWARD_BASE_PASS)
326  diffuse.xyz += max(0, yumSH9(float4(normal, 0), f.worldPos, light));
327#endif
328
329  return diffuse;
330}
331
332float3 applyQuasiShadows(float3 color, YumLighting light) {
333  float3 result = color;
334#if defined(_QUASI_SHADOWS)
335  float NoL = light.derivedLight.NoL;
336  float threshold = _Quasi_Shadows_0_Threshold;
337  float width = _Quasi_Shadows_0_Width;
338  float3 shadow_color = _Quasi_Shadows_0_Color.rgb;
339  float interp = smoothstep(threshold - width, threshold + width, NoL);
340  result = lerp(color * shadow_color, color, interp);
341#endif
342  return result;
343}
344
345YumLighting GetYumLighting(v2f i, f2f f, YumPbr pbr) {
346	YumLighting light = (YumLighting) 0;
347
348  // normalize has no visibile impact in test scene
349  light.view_dir = -f.viewDir;
350
351  light.dir = getDirectLightDirection(i, f);
352
353	// Use proper light color/intensity separation
354	light.direct = _LightColor0.rgb;
355
356	// Calculate attenuation first, before diffuse lighting
357  light.attenuation = getShadowAttenuation(i, f);
358
359	float3 tangentNormal = mul(f.tbn, pbr.normal);
360	float3x3 tangentToWorld = float3x3(i.tangent.xyz, f.binormal, i.normal);
361
362	// Use Bakery-aware irradiance function
363#if defined(LIGHTMAP_ON)
364	light.diffuse = BakeryGI_Irradiance(
365			pbr.normal,           // worldNormal
366			f.worldPos,           // worldPos
367			float4(i.uv01.zw, 0, 0),               // lightmapUV (xy = uv0, zw = uv1)
368			float3(0,0,0),        // ambient (will be calculated internally)
369			light.attenuation,    // attenuation
370			tangentNormal,        // tangentNormal
371			tangentToWorld,       // tangentToWorld
372			light.occlusion,            // out occlusion
373			light.derivedLight          // out Light
374	);
375#if defined(_GRAYSCALE_LIGHTMAPS)
376  light.diffuse.gb = light.diffuse.r;
377#endif
378#else
379  light.diffuse = getIndirectDiffuse(i, f, pbr.normal, float4(i.vertexLight.xyz, 0), light);
380  light.occlusion = 1;
381#endif
382
383#if defined(_MIN_BRIGHTNESS)
384  light.diffuse = max(_Min_Brightness, light.diffuse);
385#endif
386
387  light.diffuse_luminance = luminance(light.diffuse);
388  light.specular = getIndirectSpecular(i, f, pbr, light.view_dir, light.diffuse_luminance);
389
390#if defined(_LTCGI)
391  ltcgi_acc acc = (ltcgi_acc) 0;
392  LTCGI_Contribution(
393      acc,
394      f.worldPos,
395      pbr.normal,
396      light.view_dir,
397      pbr.roughness_perceptual,
398      0);
399  light.diffuse += acc.diffuse * _LTCGI_Strength;
400  light.specular += acc.specular * _LTCGI_Strength;
401#endif
402
403#if defined(_QUANTIZE_SPECULAR)
404  float specular_luminance = luminance(light.specular);
405  light.specular = light.specular * floor(specular_luminance * _Quantize_Specular_Steps) / _Quantize_Specular_Steps;
406#endif
407#if defined(_QUANTIZE_DIFFUSE)
408  light.diffuse = light.diffuse * floor(light.diffuse_luminance * _Quantize_Diffuse_Steps) / _Quantize_Diffuse_Steps;
409  light.diffuse_luminance = luminance(light.diffuse);
410#endif
411
412#if defined(_BRIGHTNESS_CONTROL)
413  light.direct *= _Brightness_Multiplier;
414  light.diffuse *= _Brightness_Multiplier;
415  light.specular *= _Brightness_Multiplier;
416#endif
417
418  light.NoL = saturate(dot(pbr.normal, light.dir));
419#if defined(_QUANTIZE_NOL)
420  light.NoL = floor(light.NoL * _Quantize_NoL_Steps) / _Quantize_NoL_Steps;
421#endif
422#if defined(_WRAPPED_LIGHTING)
423  light.NoL_wrapped_s = saturate(wrapNoL(light.NoL, _Wrap_NoL_Specular_Strength));
424  light.NoL_wrapped_d = saturate(wrapNoL(light.NoL, _Wrap_NoL_Diffuse_Strength));
425#endif
426
427	return light;
428}
429
430#endif  // __YUM_LIGHTING_INC