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
|
#ifndef __FOG_INC
#define __FOG_INC
#include "audiolink.cginc"
#include "cnlohr.cginc"
#include "interpolators.cginc"
#include "globals.cginc"
#if defined(_RAYMARCHED_FOG)
struct FogParams {
float3 color;
float steps;
float density;
float y_cutoff;
texture2D dithering_noise;
float4 dithering_noise_texelsize;
texture3D density_noise;
float4 density_noise_scale;
float3 velocity;
#if defined(_RAYMARCHED_FOG_DENSITY_EXPONENT)
float density_exponent;
#endif
#if defined(_RAYMARCHED_FOG_HEIGHT_DENSITY)
float height_density_start;
float height_density_half_life;
#endif
#if defined(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM)
float height_density_minimum;
#endif
#if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE)
texture2D emitter_texture;
float4 emitter_texture_texelsize;
float3 emitter_world_pos;
float3 emitter_normal;
float3 emitter_tangent;
float3 emitter_normal_x_tangent;
float2 emitter_scale; // [tangent scale in meters, bitangent scale in meters]
float2 emitter_scale_rcp;
#endif
};
#if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE)
// Returns weighted color
float3 getEmitterData(FogParams p, float3 pp)
{
// Using identity a_parallel_to_b = (dot(a, b) / dot(b, b)) * b
// float3 along_tangent = dot(p - em_loc, em_tangent) * em_tangent;
// float3 along_normal_x_tangent = dot(p - em_loc, em_normal_x_tangent) *
// em_normal_x_tangent;
// Given that em_tangent and em_normal_x_tangent are normalized, and the fact
// that we really want uvs, we can simplify this:
float2 uv = float2(dot(pp - p.emitter_world_pos, p.emitter_normal_x_tangent), dot(pp - p.emitter_world_pos, p.emitter_tangent));
uv *= p.emitter_scale_rcp;
uv *= 0.5;
uv += 0.5;
bool in_range = uv.x < 1 && uv.y < 1 && uv.x > 0 && uv.y > 0;
[branch]
if (!in_range) {
return p.color;
}
float4 c = p.emitter_texture.SampleLevel(linear_clamp_s, uv, 0);
return lerp(p.color, c.rgb, c.a);
}
#endif
struct FogResult {
float4 color;
float depth;
};
FogResult raymarched_fog(v2f i, FogParams p)
{
float3 ro = _WorldSpaceCameraPos;
float3 rd = normalize(i.eyeVec.xyz);
const float ro_epsilon = 1E-3;
ro += rd * ro_epsilon;
float4 clipPos = UnityObjectToClipPos(i.objPos);
float2 screen_uv = ComputeScreenPos(clipPos) / clipPos.w;
float zDepthFromMap = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screen_uv);
float linearZ =
GetLinearZFromZDepth_WorksWithMirrors(zDepthFromMap, screen_uv);
// Get intersection with plane at elevation y.
float plane_y = p.y_cutoff;
float distance_to_y = 1E3;
if (abs(rd.y) > 1E-6) {
float t = (plane_y - ro.y) / rd.y;
if (t > 0) {
distance_to_y = min(t, 1E3);
}
}
linearZ = min(linearZ, distance_to_y);
linearZ = min(linearZ, 1200);
linearZ -= ro_epsilon;
float dither = p.dithering_noise.SampleLevel(point_repeat_s,
screen_uv * _ScreenParams.xy * p.dithering_noise_texelsize.xy, 0).r;
const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x);
dither = frac(dither + PHI * frame);
ro += rd * dither;
linearZ -= dither;
float step_size = linearZ / p.steps;
float3 pp = ro;
float4 color = 0;
[loop]
for (uint ii = 0; ii < p.steps; ++ii) {
pp += step_size * rd;
float3 noise_coord = (pp + _Time[0] * p.velocity) * p.density_noise_scale.xyz;
float cur_d = p.density_noise.SampleLevel(bilinear_repeat_s,
noise_coord, 0);
#if defined(_RAYMARCHED_FOG_DENSITY_EXPONENT)
cur_d = pow(cur_d, p.density_exponent);
#endif
cur_d *= p.density * step_size;
#if defined(_RAYMARCHED_FOG_HEIGHT_DENSITY)
float height_clamped = max(pp.y - p.height_density_start, 0);
// if half_life = 2 and start = 0, then
// y=2 -> density = 1/2
// y=4 -> density = 1/4
// y=6 -> density = 1/8
// if half_life = 3 and start = 0, then
// y=3 -> density = 1/2
// y=6 -> density = 1/4
// y=9 -> density = 1/8
float exponent = height_clamped / p.height_density_half_life;
float factor = pow(2, -exponent);
#if defined(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM)
factor = max(factor, p.height_density_minimum);
#endif
cur_d *= factor;
#endif
cur_d = saturate(cur_d);
#if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE)
float4 cur_c = float4(getEmitterData(p, pp) * cur_d, cur_d);
#else
float4 cur_c = float4(p.color * cur_d, cur_d);
#endif
color += (1.0f - color.a) * cur_c;
}
FogResult r;
r.color = color;
//r.color.rgb = saturate(log(linearZ) / 5.0);
//r.color.rgb = float3(screen_uv, 0);
//r.color.a = d;
r.depth = 0.0001; // Very small depth value to render in front
return r;
}
#endif // _RAYMARCHED_FOG
#endif // __FOG_INC
|