Welcome to mirror list, hosted at ThFree Co, Russian Federation.

irradiance_lib.glsl « shaders « eevee « engines « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 2274bf8b9509e09c0cbe23c29e140a153d62c812 (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

#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
#pragma BLENDER_REQUIRE(octahedron_lib.glsl)

#define IRRADIANCE_LIB

/* ---------------------------------------------------------------------- */
/** \name Structure
 * \{ */

#if defined(IRRADIANCE_SH_L2)
struct IrradianceData {
  vec3 shcoefs[9];
};

#else /* defined(IRRADIANCE_HL2) */
struct IrradianceData {
  vec3 cubesides[3];
};

#endif

/** \} */

/* ---------------------------------------------------------------------- */
/** \name Resources
 * \{ */

uniform sampler2DArray irradianceGrid;

/** \} */

/* ---------------------------------------------------------------------- */
/** \name Functions
 * \{ */

vec4 irradiance_encode(vec3 rgb)
{
  float maxRGB = max_v3(rgb);
  float fexp = ceil(log2(maxRGB));
  return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
}

vec3 irradiance_decode(vec4 data)
{
  float fexp = data.a * 255.0 - 128.0;
  return data.rgb * exp2(fexp);
}

vec4 visibility_encode(vec2 accum, float range)
{
  accum /= range;

  vec4 data;
  data.x = fract(accum.x);
  data.y = floor(accum.x) / 255.0;
  data.z = fract(accum.y);
  data.w = floor(accum.y) / 255.0;

  return data;
}

vec2 visibility_decode(vec4 data, float range)
{
  return (data.xz + data.yw * 255.0) * range;
}

IrradianceData load_irradiance_cell(int cell, vec3 N)
{
  /* Keep in sync with diffuse_filter_probe() */

#if defined(IRRADIANCE_SH_L2)

  ivec2 cell_co = ivec2(3, 3);
  int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
  cell_co.x *= cell % cell_per_row;
  cell_co.y *= cell / cell_per_row;

  ivec3 ofs = ivec3(0, 1, 2);

  IrradianceData ir;
  ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb;
  ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb;
  ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb;
  ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb;
  ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb;
  ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb;
  ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb;
  ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb;
  ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb;

#else /* defined(IRRADIANCE_HL2) */

  ivec2 cell_co = ivec2(3, 2);
  int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
  cell_co.x *= cell % cell_per_row;
  cell_co.y *= cell / cell_per_row;

  ivec3 is_negative = ivec3(step(0.0, -N));

  IrradianceData ir;
  ir.cubesides[0] = irradiance_decode(
      texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0));
  ir.cubesides[1] = irradiance_decode(
      texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0));
  ir.cubesides[2] = irradiance_decode(
      texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0));

#endif

  return ir;
}

float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range)
{
  /* Keep in sync with diffuse_filter_probe() */
  ivec2 cell_co = ivec2(prbIrradianceVisSize);
  ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize;
  cell_co.x *= (cell % cell_per_row_col.x);
  cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y;
  float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y);

  vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy);
  vec2 co = vec2(cell_co) * texel_size;

  vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize)));
  uv *= vec2(prbIrradianceVisSize) * texel_size;

  vec4 data = texture(irradianceGrid, vec3(co + uv, layer));

  /* Decoding compressed data */
  vec2 moments = visibility_decode(data, range);

  /* Doing chebishev test */
  float variance = abs(moments.x * moments.x - moments.y);
  variance = max(variance, bias / 10.0);

  float d = dist - moments.x;
  float p_max = variance / (variance + d * d);

  /* Increase contrast in the weight by squaring it */
  p_max *= p_max;

  /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
  p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0);

  return (dist <= moments.x) ? 1.0 : p_max;
}

/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4])
{
  vec3 sh = vec3(0.0);

  sh += 0.282095 * shcoefs[0];

  sh += -0.488603 * N.z * shcoefs[1];
  sh += 0.488603 * N.y * shcoefs[2];
  sh += -0.488603 * N.x * shcoefs[3];

  return sh;
}

vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9])
{
  vec3 sh = vec3(0.0);

  sh += 0.282095 * shcoefs[0];

  sh += -0.488603 * N.z * shcoefs[1];
  sh += 0.488603 * N.y * shcoefs[2];
  sh += -0.488603 * N.x * shcoefs[3];

  sh += 1.092548 * N.x * N.z * shcoefs[4];
  sh += -1.092548 * N.z * N.y * shcoefs[5];
  sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoefs[6];
  sh += -1.092548 * N.x * N.y * shcoefs[7];
  sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoefs[8];

  return sh;
}

vec3 hl2_basis(vec3 N, vec3 cubesides[3])
{
  vec3 irradiance = vec3(0.0);

  vec3 n_squared = N * N;

  irradiance += n_squared.x * cubesides[0];
  irradiance += n_squared.y * cubesides[1];
  irradiance += n_squared.z * cubesides[2];

  return irradiance;
}

vec3 compute_irradiance(vec3 N, IrradianceData ird)
{
#if defined(IRRADIANCE_SH_L2)
  return spherical_harmonics_L2(N, ird.shcoefs);
#else /* defined(IRRADIANCE_HL2) */
  return hl2_basis(N, ird.cubesides);
#endif
}

vec3 irradiance_from_cell_get(int cell, vec3 ir_dir)
{
  IrradianceData ir_data = load_irradiance_cell(cell, ir_dir);
  return compute_irradiance(ir_dir, ir_data);
}

/** \} */