yum-archive/Tooner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum-archive/Tooner

yumRestore spherical boundary to fog gimmick8d2c110

master
19.8 KiB594 linesraw
1#include "UnityCG.cginc"
2
3#include "audiolink.cginc"
4#include "atrix256.cginc"
5#include "cnlohr.cginc"
6#include "globals.cginc"
7#include "interpolators.cginc"
8#include "math.cginc"
9#include "noise.cginc"
10#include "oklab.cginc"
11#include "pbr.cginc"
12#include "poi.cginc"
13#include "tone.cginc"
14
15#ifndef __FOG_INC
16#define __FOG_INC
17
18#if defined(_GIMMICK_FOG_00)
19
20struct Fog00PBR {
21  float4 albedo;
22  float depth;
23};
24
25#define FOG_PERLIN_NOISE_SCALE 1
26
27float3 perlin_noise_3d_tex(float3 p)
28{
29  // 1/256 = 0.00390625
30  return _Gimmick_Fog_00_Noise.SampleLevel(trilinear_repeat_s, p.xyz * 0.00390625, 0);
31}
32
33#define FBM_OCTAVES 3
34
35float3 perlin_noise_3d_tex_fbm(float3 p)
36{
37  float3 res = perlin_noise_3d_tex(p);
38  float p_scale = 1;
39  //float d_scale = .66666;
40  float d_scale = .571428571;
41  for (uint i = 1; i < FBM_OCTAVES; i++) {
42    p_scale *= 2;
43    d_scale *= .5;
44    res += perlin_noise_3d_tex(p*p_scale)*d_scale;
45  }
46  return res;
47}
48
49// idea from here https://iquilezles.org/articles/warp/
50float3 perlin_noise_3d_tex_warp(float3 p)
51{
52  p = perlin_noise_3d_tex(p);
53  p = perlin_noise_3d_tex(p * 255);
54  p = perlin_noise_3d_tex(p * 255);
55  return p;
56}
57
58float3 light_fog00(
59    float3 albedo,
60    float NoL,
61    float3 direct,
62    float3 diffuse
63    ) {
64  half diffuseTerm = NoL;
65  float wrappedDiffuse = saturate((diffuseTerm + _WrappingFactor) /
66      (1.0f + _WrappingFactor)) * 2 / (2 * (1 + _WrappingFactor));
67#if 0
68  float3 direct_unlit = .01;
69  direct = lerp(direct, direct_unlit, wrappedDiffuse);
70#endif
71  float3 diffCol = albedo * (diffuse + direct * wrappedDiffuse);
72  return diffCol;
73}
74
75float map(float3 p, out float3 normal) {
76#if 1
77  float3 t = float3(0, -_Time[0] * FOG_PERLIN_NOISE_SCALE, 0) * _Gimmick_Fog_00_Motion_Vector;
78#else
79  float3 t = 0;
80#endif
81#define RADIUS_TRANS_WIDTH .5
82#define RADIUS_TRANS_WIDTH_RCP (1.0 / RADIUS_TRANS_WIDTH)
83  // Try to create a smooth transition without doing any length() or other
84  // transcendental ops.
85#if 1 && defined(_GIMMICK_FOG_00_BOUNDARY_CYLINDER)
86  float radius2 = clamp(_Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius - dot(p.xz, p.xz), 0, RADIUS_TRANS_WIDTH) * RADIUS_TRANS_WIDTH_RCP;
87#elif 1 && defined(_GIMMICK_FOG_00_BOUNDARY_SPHERE)
88  float radius2 = clamp(_Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius - dot(p, p), 0, RADIUS_TRANS_WIDTH) * RADIUS_TRANS_WIDTH_RCP;
89#else
90  float radius2 = 1;
91#endif
92
93	float3 pp = p * _Gimmick_Fog_00_Noise_Scale * FOG_PERLIN_NOISE_SCALE;
94  normal = normalize(perlin_noise_3d_tex(pp+t) * 2 - 1);
95  float density = perlin_noise_3d_tex_warp(pp+t) * radius2;
96  //float density = perlin_noise_3d_tex(pp+t) * radius2;
97  //float density = 0.5 * radius2;
98  //density = pow(density, _Gimmick_Fog_00_Noise_Exponent);
99  // EV is 0.5, so apply corrective factor of pow(2, _Gimmick_Fog_00_Noise_Exponent - 1)
100  //density *= pow(2, _Gimmick_Fog_00_Noise_Exponent - 1);
101  //density *= 8;
102  density *= density * 2;
103
104  return density;
105}
106
107#if defined(_GIMMICK_FOG_00_EMITTER_TEXTURE)
108// Returns weighted color
109void getEmitterData(float3 p,
110    float dither,
111    float step_size,
112    float3 em_loc,
113    float3 em_normal,
114    float3 em_tangent,
115    float3 em_normal_x_tangent,
116    float2 emitter_scale,
117    float2 emitter_scale_rcp,
118    out float3 diffuse,
119    out float3 direct)
120{
121  // Using identity a_parallel_to_b = (dot(a, b) / dot(b, b)) * b
122  //   float3 along_tangent = dot(p - em_loc, em_tangent) * em_tangent;
123  //   float3 along_normal_x_tangent = dot(p - em_loc, em_normal_x_tangent) *
124  //       em_normal_x_tangent;
125  // Given that em_tangent and em_normal_x_tangent are normalized, and the fact
126  // that we really want uvs, we can simplify this:
127  float2 uv = float2(dot(p - em_loc, em_normal_x_tangent), dot(p - em_loc, em_tangent));
128  uv *= emitter_scale_rcp;
129  uv *= 0.5;
130  uv += 0.5;
131
132  //uv.x += dither * .01;
133  const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x);
134  //uv.x += ign_anim((dither+1000) * 1000, frame, /*speed=*/1.0) * .01;
135  //uv.y += ign_anim(dither * 1000, frame, /*speed=*/1.0) * .01;
136
137  bool in_range = uv.x < 1 && uv.y < 1 && uv.x > 0 && uv.y > 0;
138
139#if 0
140  uv.y = FOG_PERLIN_NOISE(float3(uv*100, _Time[2]));
141  uv.x = FOG_PERLIN_NOISE(p);
142  uv.y = FOG_PERLIN_NOISE(float3(uv*100, _Time[2]));
143#endif
144
145  const float3 p_to_emitter = p - em_loc;
146  const float t = dot(p_to_emitter, em_normal);
147
148  const float raw_noise_sample = _Gimmick_Fog_00_Noise_2D.SampleLevel(point_repeat_s, uv * 1000, 0).x;
149  float emitter_lod = floor((abs(t) + dither) / ((_Gimmick_Fog_00_Emitter_Lod_Half_Life*(1+raw_noise_sample*2.5) * step_size)));
150  float3 em_color = _Gimmick_Fog_00_Emitter_Texture.SampleLevel(point_clamp_s, uv, emitter_lod);
151  float emitter_dist = in_range ? abs(t) : 1000;
152  float emitter_falloff = min(1, rcp(emitter_dist));
153
154  direct = in_range * emitter_falloff * em_color;
155
156#if 1
157  float e = 0.1;
158  float2 uv_inv = 1.0 - uv;
159  diffuse = _Gimmick_Fog_00_Emitter_Texture.SampleLevel(point_clamp_s, float2(uv.x, uv.y), 16) +
160    _Gimmick_Fog_00_Emitter_Texture.SampleLevel(point_clamp_s, float2(uv.x, uv_inv.y), 16) +
161    _Gimmick_Fog_00_Emitter_Texture.SampleLevel(point_clamp_s, float2(uv_inv.x, uv.y), 16);
162  diffuse *= 0.3333;
163  float3 em_loc_clamp = em_loc + (saturate(uv.x) *2 - 1) * em_tangent + (saturate(uv.y) * 2 - 1) * em_normal_x_tangent;
164  em_loc_clamp += em_loc;
165  // TODO parameterize shaping constants
166  float diffuse_length = dot(p - em_loc_clamp, p - em_loc_clamp);
167  diffuse /= diffuse_length;
168#else
169  diffuse = 0;
170#endif
171}
172#endif  // defined(_GIMMICK_FOG_00_EMITTER_TEXTURE)
173
174#if defined(_GIMMICK_FOG_00_RAY_MARCH_0)
175float fog00_map(float3 p, float rid_entropy)
176{
177  float sin_term = sin(rid_entropy*2*TAU+_Time[0]*2)+1.0;
178  sin_term *= sin_term;
179  sin_term *= 0.7;
180  return length(p)+0.7-rid_entropy*2.3*
181    sin_term*.2;
182}
183float fog00_map_dr(
184    float3 p,
185    float3 period,
186    float3 count,
187    float seed,
188    out float3 which
189    )
190{
191  p -= float3(0, period.y * floor(count.y/2) + 1, 0);
192  p -= unity_ObjectToWorld._m03_m13_m23;
193
194  which = round(p / period);
195  // Direction to nearest neighboring cell.
196  float3 min_d = p - period * which;
197  float3 o = sign(min_d);
198
199  float d = 1E9;
200  float3 which_tmp = which;
201#if 1
202  for (uint xi = 0; xi < 2; xi++)
203  for (uint yi = 0; yi < 2; yi++)
204  for (uint zi = 0; zi < 2; zi++)
205#else
206  uint xi = 0;
207  uint yi = 0;
208  uint zi = 0;
209#endif
210  {
211    float3 rid = which + float3(xi, yi, zi) * o;
212    rid = clamp(rid, ceil(-(count)*0.5), floor((count-1)*0.5));
213    float3 r = p - period * rid;
214    float3 rid_entropy = float3(
215        ign(rid.yz+seed),
216        ign(rid.xz+seed),
217        ign(rid.xy+seed));
218    float3 random_dir = normalize(rid_entropy);
219    r +=
220      (sin(_Time[0] * 2 + (rid_entropy.x + rid_entropy.y + rid_entropy.z) * TAU * .6666) * 2 - 1.0) *
221      period * 0.5 *
222      random_dir *
223      float3(1, 1, 1) * .3;
224    float cur_d = fog00_map(r, FOG_PERLIN_NOISE((rid+seed)*100));
225    which_tmp = cur_d < d ? rid : which_tmp;
226    d = min(d, cur_d);
227  }
228
229  which = which_tmp;
230  return d;
231}
232#endif
233
234Fog00PBR __getFog00(v2f i, ToonerData tdata,
235    float3 obj_pos_depth_hit,
236    float2 screen_uv);
237
238Fog00PBR getFog00(v2f i, ToonerData tdata)
239{
240  float3 obj_pos_depth_hit;
241  float2 screen_uv;
242  {
243    float3 full_vec_eye_to_geometry = i.worldPos - _WorldSpaceCameraPos;
244    float3 world_dir = normalize(i.worldPos - _WorldSpaceCameraPos);
245    float perspective_divide = 1.0 / i.pos.w;
246    float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide);
247    screen_uv = i.screenPos.xy * perspective_divide;
248    float eye_depth_world =
249      GetLinearZFromZDepth_WorksWithMirrors(
250          SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, tdata.screen_uv),
251          screen_uv) * perspective_factor;
252    float3 world_pos_depth_hit = _WorldSpaceCameraPos + eye_depth_world * world_dir;
253    obj_pos_depth_hit = mul(unity_WorldToObject, float4(world_pos_depth_hit, 1.0)).xyz;
254  }
255
256  return __getFog00(i, tdata, obj_pos_depth_hit, screen_uv);
257}
258
259Fog00PBR __getFog00(v2f i, ToonerData tdata,
260    float3 obj_pos_depth_hit,
261    float2 screen_uv)
262{
263  float3 cam_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)).xyz;
264  float3 obj_pos = i.objPos;
265
266  const float3 rd = normalize(obj_pos - cam_pos);
267  float3 ro = cam_pos;
268
269#if defined(_GIMMICK_FOG_00_BOUNDARY_CYLINDER)
270  {
271    // Raytrace distance to cylinder
272    bool no_intersection = false;
273    float distance_to_cylinder = 1E6;
274    {
275      float a = dot(rd.xz, rd.xz);
276      float b = 2 * dot(rd.xz, ro.xz);
277      float c = dot(ro.xz, ro.xz) - _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius;
278      float t0, t1;
279      if (solveQuadratic(a, b, c, t0, t1)) {
280        no_intersection = (t0 < 0) * (t1 < 0);
281        const bool inside_cylinder = (t0 < 0) * (t1 > 0);
282        if (!inside_cylinder) {
283          distance_to_cylinder = no_intersection ? distance_to_cylinder : min(max(t0, 0), max(t1, 0));
284          ro += distance_to_cylinder * rd;
285        }
286      }
287    }
288    clip(no_intersection ? -1 : 1);
289  }
290#elif defined(_GIMMICK_FOG_00_BOUNDARY_PLANE)
291  {
292    // Raytrace distance to plane
293    bool no_intersection = false;
294    float distance_to_plane = 1E6;
295    {
296      // Define the plane by normal and point
297      float3 n = normalize(mul(unity_WorldToObject, float4(_Gimmick_Fog_00_Plane_Normal, 0.0)).xyz);
298      float3 p0 = _Gimmick_Fog_00_Plane_Center;
299
300      float denom = dot(n, rd);
301      if (abs(denom) > 1e-6) {
302        // The ray is not parallel to the plane
303        float t = dot(n, (p0 - ro)) / denom;
304        if (t >= 0) {
305          distance_to_plane = t;
306          ro += distance_to_plane * rd;
307        } else {
308          no_intersection = true; // Intersection is behind the ray origin
309        }
310      } else {
311        no_intersection = true; // Ray is parallel to the plane
312      }
313    }
314    clip(no_intersection ? -1 : 1);
315  }
316#elif defined(_GIMMICK_FOG_00_BOUNDARY_SPHERE)
317  {
318    bool no_intersection = false;
319    float distance_to_sphere = 1E6;
320    {
321      float3 l = ro;
322      float a = 1;
323      float b = 2 * dot(rd, l);
324      float c = dot(l, l) - _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius;
325      float t0, t1;
326      if (solveQuadratic(a, b, c, t0, t1)) {
327        no_intersection = (t0 < 0) * (t1 < 0);
328        const bool inside_sphere = (t0 < 0) * (t1 > 0);
329        if (!inside_sphere) {
330          distance_to_sphere = no_intersection ? distance_to_sphere : min(max(t0, 0), max(t1, 0));
331          ro += distance_to_sphere * rd;
332        }
333      }
334    }
335    clip(no_intersection ? -1 : 1);
336  }
337#endif
338
339  float density_ss_term = 1 / _Gimmick_Fog_00_Density;
340  //density_ss_term = dclamp(density_ss_term, 0.33, 3.00, 5);
341  const float step_size = _Gimmick_Fog_00_Step_Size_Factor * density_ss_term;
342  const float step_size_sqrt = sqrt(step_size);
343  const float step_size_sqrt_max1 = max(1, step_size_sqrt);
344  //step_size = clamp(step_size, 1E-2, 1E2);
345  uint2 screen_uv_round = floor(screen_uv * _ScreenParams.xy);
346  const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x);
347#if defined(_GIMMICK_FOG_00_NOISE_2D)
348  const float raw_noise_sample = _Gimmick_Fog_00_Noise_2D.SampleLevel(point_repeat_s, screen_uv * _ScreenParams.xy * _Gimmick_Fog_00_Noise_2D_TexelSize.xy, 0).x;
349  const float dither_seed = frac(raw_noise_sample + frame * PHI);
350#elif 1
351  const float dither_seed = frac(ign_anim(screen_uv_round, frame, /*speed=*/0.000) + frame * 1.618033989);
352#else
353  const float dither_seed = rand2(float2(screen_uv_round.x, screen_uv_round.y)*.001);
354#endif
355  float dither = dither_seed * step_size * _Gimmick_Fog_00_Ray_Origin_Randomization;
356  ro += rd * (_Gimmick_Fog_00_Initial_Offset + dither);
357
358  const float depth_hit_l = length(obj_pos_depth_hit - ro);
359
360  // Get common lighting data
361  UnityLight direct_light;
362  UnityIndirect indirect_light;
363  direct_light.dir = getDirectLightDirection(i);
364  direct_light.ndotl = 0;  // Not used
365  direct_light.color = getDirectLightColor() *_Direct_Lighting_Factor;
366  // TODO try per-sample baked lighting
367  indirect_light.diffuse = getIndirectDiffuse(i, /*vertex_light_color=*/0) * _Indirect_Diffuse_Lighting_Factor;
368  // TODO consider doing specular. At time of writing it seems pointless.
369  indirect_light.specular = 0;
370
371  float4 acc = 0;
372  uint step_count = floor(min(_Gimmick_Fog_00_Max_Ray, depth_hit_l) / step_size);
373  //step_count *= (1 - no_intersection);
374#define FOG_MAX_LOOP 20
375  step_count = min(step_count, FOG_MAX_LOOP);
376
377#if defined(_GIMMICK_FOG_00_EMITTER_TEXTURE)
378  const float3 em_loc = mul(unity_WorldToObject, float4(_Gimmick_Fog_00_Emitter0_Location, 1.0)).xyz;
379  const float3 em_normal = normalize(mul(unity_WorldToObject, float4(_Gimmick_Fog_00_Emitter0_Normal, 0.0)).xyz);
380  const float3 em_tangent = normalize(mul(unity_WorldToObject, float4(_Gimmick_Fog_00_Emitter0_Tangent, 0.0)).xyz);
381  const float3 em_normal_x_tangent = normalize(cross(em_normal, em_tangent));
382  const float em_scale_t   = _Gimmick_Fog_00_Emitter0_Scale_T * length(mul(unity_WorldToObject, float4(_Gimmick_Fog_00_Emitter0_Normal, 0.0)));
383  const float em_scale_nxt = _Gimmick_Fog_00_Emitter0_Scale_NxT * length(mul(unity_WorldToObject, float4(cross(_Gimmick_Fog_00_Emitter0_Normal, _Gimmick_Fog_00_Emitter0_Tangent), 0.0)));
384  const float2 em_scale = float2(em_scale_t, em_scale_nxt);
385  const float2 em_scale_rcp = rcp(em_scale);
386#endif
387
388  const float3 ro_world = mul(unity_ObjectToWorld, float4(ro, 1.0)).xyz;
389  const float3 rd_world = mul(unity_ObjectToWorld, float4(rd, 0.0)).xyz;
390  const float3 rd_world_normalized = normalize(rd_world);
391  const float step_size_world = step_size * length(rd_world);
392  const float3 view_dir_world = normalize(_WorldSpaceCameraPos - i.worldPos);
393
394  const float3 noise_scale_rcp = 1.0 / _Gimmick_Fog_00_Noise_Scale;
395  uint ii;
396  for (ii = 0; ii < step_count; ii++) {
397    const float3 p = ro + rd * ii * step_size;
398
399    float4 c;
400    float3 c_lit = 0;
401#if 1
402    float3 map_normal;
403    const float map_p_raw = map(p, map_normal);
404    const float map_p = map_p_raw * _Gimmick_Fog_00_Density * step_size;
405    c = float4(_Color.rgb, map_p);
406    float3 diffuse = 0;
407    float3 direct = 0;
408#if defined(_GIMMICK_FOG_00_EMITTER_TEXTURE) && !defined(_GIMMICK_FOG_00_EMITTER_VARIABLE_DENSITY)
409    // We put the emitter color into diffuse instead of doing a directional
410    // calculation because it looks better and it's cheaper. Less accurate
411    // though!
412    if (_Gimmick_Fog_00_Enable_Area_Lighting) {
413      // Note that I'm intentionally passing in `direct` and `diffuse`
414      // backwards. It looks better if the collimated light is immune to normal
415      // dimming, and if the diffuse light is not.
416      getEmitterData(p, dither, step_size, em_loc, em_normal, em_tangent, em_normal_x_tangent, em_scale,
417          em_scale_rcp, direct, diffuse);
418    }
419    diffuse *= _Gimmick_Fog_00_Emitter_Brightness_Diffuse;
420    direct *= _Gimmick_Fog_00_Emitter_Brightness_Direct;
421#else
422#endif
423
424    // Scaling brightness by sqrt(step_size) seems to look more consistent as
425    // you vary density. No idea why :(
426    float NoL = dot(map_normal, direct_light.dir);
427    c_lit += light_fog00(
428        c.rgb,
429        NoL, 
430        (direct_light.color + direct) * step_size_sqrt_max1,
431        (indirect_light.diffuse + diffuse) * step_size_sqrt_max1);
432#else
433    c_lit = .05 * step_size;
434    c.a = 0.1;
435#endif
436#if defined(_GIMMICK_FOG_00_EMITTER_TEXTURE) && defined(_GIMMICK_FOG_00_EMITTER_VARIABLE_DENSITY)
437    float3 em_c = getEmitterData(p, step_size, em_loc, em_normal, em_scale, em_scale_rcp) * step_size;
438    float em_NoL = saturate((map(p + dd_e * em_normal, lod) - map_p_raw) / dd_e);
439    c_lit += light_fog00(
440        c.rgb,
441        em_NoL, 
442        em_c,
443        0);
444#endif
445    c.rgb = c_lit;
446
447    // Intuition: add c scaled by the remaining transparent portion of acc.
448    acc = acc + (1 - acc.a) * c;
449
450#if 1
451    // For performance, stop if we...
452    //  1. accumulate enough alpha
453    //  2. go outside of the sphere
454    if (acc.a > _Gimmick_Fog_00_Alpha_Cutoff) {
455      break;
456    }
457#if defined(_GIMMICK_FOG_00_BOUNDARY_SPHERE) || defined(_GIMMICK_FOG_00_BOUNDARY_CYLINDER)
458    if (dot(p.xz, p.xz) > _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius) {
459      break;
460    }
461#endif
462#endif
463  }
464  if (acc.a > _Gimmick_Fog_00_Alpha_Cutoff || ii == FOG_MAX_LOOP) {
465    acc /= acc.a;
466  }
467  acc.rgb = LRGBtoOKLAB(acc.rgb);
468  acc.x = smooth_min(acc.x, _Gimmick_Fog_00_Max_Brightness * .85, _Gimmick_Fog_00_Max_Brightness);
469  acc.rgb = OKLABtoLRGB(acc.rgb);
470
471  Fog00PBR pbr;
472  pbr.albedo = acc;
473  pbr.albedo.a = smooth_min(pbr.albedo.a, .999, 1);
474
475  // Add some dithering to lit color to break up banding
476  //const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x);
477  //pbr.albedo.rgb += ign_anim(dither * 1000, frame, /*speed=*/1.0) * .00390625;
478
479  // Remap onto [0, 1]
480  pbr.albedo.rgb = aces_filmic(pbr.albedo.rgb);
481  // Clamp so max brightness is comfortable. Do it in perceptually uniform
482  // space to avoid affecting saturation.
483  //pbr.albedo.rgb = LRGBtoOKLAB(pbr.albedo.rgb);
484  //pbr.albedo.x = smooth_min(pbr.albedo.x, _Gimmick_Fog_00_Max_Brightness * .9, _Gimmick_Fog_00_Max_Brightness);
485  //pbr.albedo.rgb = OKLABtoLRGB(pbr.albedo.rgb);
486
487  float4 clip_pos = mul(UNITY_MATRIX_VP, float4(mul(unity_ObjectToWorld, float4(ro, 1.0))));
488  pbr.depth = clip_pos.z / clip_pos.w;
489
490#if 0
491  //pbr.albedo.rgb = eye_depth_world / 100;
492  pbr.albedo.rgb = dither_seed;
493  pbr.albedo.a = 1;
494#endif
495
496  return pbr;
497}
498
499#endif  // _GIMMICK_FOG_00
500
501#if defined(_GIMMICK_FOG_01) || defined(_GIMMICK_DS2)
502
503struct Fog01PBR {
504  float4 albedo;
505  float depth;
506};
507
508float4 apply_fog(
509    float t,
510    float density,
511    float3 rd,
512    float3 sun_dir,
513    float4 sun_color,
514    float sun_exponent,
515    float sun_color_2_enable,
516    float4 sun_color_2,
517    float sun_exponent_2,
518    float4 fog_color) {
519  float fog_amount = 1 - exp(-t * density);
520  float4 color = fog_color;
521  float ndotl = dot(rd, sun_dir);
522  // Wrap ndotl
523  ndotl = (ndotl + 1) / (2);
524  ndotl *= ndotl;
525  ndotl = max(ndotl, 0);
526  [branch]
527  if (sun_color_2_enable) {
528    float sun_amount_2 = saturate(pow(ndotl, sun_exponent_2) * fog_amount);
529    color = lerp(color, sun_color_2, sun_amount_2);
530  }
531  float sun_amount = saturate(pow(ndotl, sun_exponent) * fog_amount);
532  color = lerp(color, sun_color, sun_amount);
533  //return float4(color.rgb, fog_amount * color.a);
534  return float4(color.rgb, fog_amount * color.a);
535}
536
537Fog01PBR getFog01(v2f i, ToonerData tdata) {
538  float3 cam_pos = _WorldSpaceCameraPos;
539  float3 obj_pos = i.worldPos;
540
541  if (_Gimmick_Fog_01_Distance_Culling_Enable) {
542    float3 activation_center = _Gimmick_Fog_01_Activation_Center;
543    float activation_radius = _Gimmick_Fog_01_Activation_Radius;
544    float cur_radius = length(_WorldSpaceCameraPos - activation_center);
545    [branch]
546    if (getCenterCamPos().y > activation_center.y + activation_radius) {
547      return (Fog01PBR)0;
548    }
549  }
550
551  float3 world_pos_depth_hit;
552  float2 screen_uv;
553  float eye_depth_world;
554  {
555    float3 full_vec_eye_to_geometry = i.worldPos - _WorldSpaceCameraPos;
556    float3 world_dir = normalize(i.worldPos - _WorldSpaceCameraPos);
557    float perspective_divide = 1.0 / i.pos.w;
558    float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide);
559    screen_uv = i.screenPos.xy * perspective_divide;
560    eye_depth_world =
561      GetLinearZFromZDepth_WorksWithMirrors(
562          SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, tdata.screen_uv),
563          screen_uv) * perspective_factor;
564    world_pos_depth_hit = _WorldSpaceCameraPos + eye_depth_world * world_dir;
565  }
566
567  const float3 rd = normalize(obj_pos - cam_pos);
568  float3 ro = cam_pos + rd * 1E-5;
569
570  Fog01PBR pbr;
571  pbr.albedo = apply_fog(eye_depth_world,
572      _Gimmick_Fog_01_Density, rd,
573      normalize(_Gimmick_Fog_01_Sun_Direction),
574      _Gimmick_Fog_01_Sun_Color,
575      _Gimmick_Fog_01_Sun_Exponent,
576      _Gimmick_Fog_01_Sun_Color_2_Enable,
577      _Gimmick_Fog_01_Sun_Color_2,
578      _Gimmick_Fog_01_Sun_Exponent_2,
579      _Gimmick_Fog_01_Color);
580  pbr.albedo.rgb = aces_filmic(pbr.albedo.rgb);
581
582  //pbr.albedo.rgb = eye_depth_world / 100000;
583  //pbr.albedo.a = 1;
584
585  float4 clip_pos = mul(UNITY_MATRIX_VP, float4(ro, 1));
586  pbr.depth = clip_pos.z / clip_pos.w;
587
588  return pbr;
589}
590
591#endif  // _GIMMICK_FOG_01
592
593#endif  // __FOG_INC
594