sdfgi_integrate.glsl 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. #[compute]
  2. #version 450
  3. #VERSION_DEFINES
  4. layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
  5. #define MAX_CASCADES 8
  6. layout(set = 0, binding = 1) uniform texture3D sdf_cascades[MAX_CASCADES];
  7. layout(set = 0, binding = 2) uniform texture3D light_cascades[MAX_CASCADES];
  8. layout(set = 0, binding = 3) uniform texture3D aniso0_cascades[MAX_CASCADES];
  9. layout(set = 0, binding = 4) uniform texture3D aniso1_cascades[MAX_CASCADES];
  10. layout(set = 0, binding = 6) uniform sampler linear_sampler;
  11. struct CascadeData {
  12. vec3 offset; //offset of (0,0,0) in world coordinates
  13. float to_cell; // 1/bounds * grid_size
  14. ivec3 probe_world_offset;
  15. uint pad;
  16. vec4 pad2;
  17. };
  18. layout(set = 0, binding = 7, std140) uniform Cascades {
  19. CascadeData data[MAX_CASCADES];
  20. }
  21. cascades;
  22. layout(r32ui, set = 0, binding = 8) uniform restrict uimage2DArray lightprobe_texture_data;
  23. layout(rgba16i, set = 0, binding = 9) uniform restrict iimage2DArray lightprobe_history_texture;
  24. layout(rgba32i, set = 0, binding = 10) uniform restrict iimage2D lightprobe_average_texture;
  25. //used for scrolling
  26. layout(rgba16i, set = 0, binding = 11) uniform restrict iimage2DArray lightprobe_history_scroll_texture;
  27. layout(rgba32i, set = 0, binding = 12) uniform restrict iimage2D lightprobe_average_scroll_texture;
  28. layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_average_parent_texture;
  29. layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture;
  30. #ifdef USE_CUBEMAP_ARRAY
  31. layout(set = 1, binding = 0) uniform textureCubeArray sky_irradiance;
  32. #else
  33. layout(set = 1, binding = 0) uniform textureCube sky_irradiance;
  34. #endif
  35. layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps;
  36. #define HISTORY_BITS 10
  37. #define SKY_FLAGS_MODE_COLOR 0x01
  38. #define SKY_FLAGS_MODE_SKY 0x02
  39. #define SKY_FLAGS_ORIENTATION_SIGN 0x04
  40. layout(push_constant, std430) uniform Params {
  41. vec3 grid_size;
  42. uint max_cascades;
  43. uint probe_axis_size;
  44. uint cascade;
  45. uint history_index;
  46. uint history_size;
  47. uint ray_count;
  48. float ray_bias;
  49. ivec2 image_size;
  50. ivec3 world_offset;
  51. uint sky_flags;
  52. ivec3 scroll;
  53. float sky_energy;
  54. vec3 sky_color_or_orientation;
  55. float y_mult;
  56. bool store_ambient_texture;
  57. uint pad[3];
  58. }
  59. params;
  60. const float PI = 3.14159265f;
  61. const float GOLDEN_ANGLE = PI * (3.0 - sqrt(5.0));
  62. vec3 vogel_hemisphere(uint p_index, uint p_count, float p_offset) {
  63. float r = sqrt(float(p_index) + 0.5f) / sqrt(float(p_count));
  64. float theta = float(p_index) * GOLDEN_ANGLE + p_offset;
  65. float y = cos(r * PI * 0.5);
  66. float l = sin(r * PI * 0.5);
  67. return vec3(l * cos(theta), l * sin(theta), y * (float(p_index & 1) * 2.0 - 1.0));
  68. }
  69. uvec3 hash3(uvec3 x) {
  70. x = ((x >> 16) ^ x) * 0x45d9f3b;
  71. x = ((x >> 16) ^ x) * 0x45d9f3b;
  72. x = (x >> 16) ^ x;
  73. return x;
  74. }
  75. float hashf3(vec3 co) {
  76. return fract(sin(dot(co, vec3(12.9898, 78.233, 137.13451))) * 43758.5453);
  77. }
  78. vec3 octahedron_encode(vec2 f) {
  79. // https://twitter.com/Stubbesaurus/status/937994790553227264
  80. f = f * 2.0 - 1.0;
  81. vec3 n = vec3(f.x, f.y, 1.0f - abs(f.x) - abs(f.y));
  82. float t = clamp(-n.z, 0.0, 1.0);
  83. n.x += n.x >= 0 ? -t : t;
  84. n.y += n.y >= 0 ? -t : t;
  85. return normalize(n);
  86. }
  87. uint rgbe_encode(vec3 color) {
  88. const float pow2to9 = 512.0f;
  89. const float B = 15.0f;
  90. const float N = 9.0f;
  91. const float LN2 = 0.6931471805599453094172321215;
  92. float cRed = clamp(color.r, 0.0, 65408.0);
  93. float cGreen = clamp(color.g, 0.0, 65408.0);
  94. float cBlue = clamp(color.b, 0.0, 65408.0);
  95. float cMax = max(cRed, max(cGreen, cBlue));
  96. float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B;
  97. float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f);
  98. float exps = expp + 1.0f;
  99. if (0.0 <= sMax && sMax < pow2to9) {
  100. exps = expp;
  101. }
  102. float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
  103. float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
  104. float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
  105. return (uint(sRed) & 0x1FF) | ((uint(sGreen) & 0x1FF) << 9) | ((uint(sBlue) & 0x1FF) << 18) | ((uint(exps) & 0x1F) << 27);
  106. }
  107. struct SH {
  108. #if (SH_SIZE == 16)
  109. float c[48];
  110. #else
  111. float c[28];
  112. #endif
  113. };
  114. shared SH sh_accum[64]; //8x8
  115. void main() {
  116. ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
  117. if (any(greaterThanEqual(pos, params.image_size))) { //too large, do nothing
  118. return;
  119. }
  120. uint probe_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 8;
  121. #ifdef MODE_PROCESS
  122. float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell;
  123. ivec3 probe_cell;
  124. probe_cell.x = pos.x % int(params.probe_axis_size);
  125. probe_cell.y = pos.y;
  126. probe_cell.z = pos.x / int(params.probe_axis_size);
  127. vec3 probe_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size;
  128. vec3 pos_to_uvw = 1.0 / params.grid_size;
  129. for (uint i = 0; i < SH_SIZE * 3; i++) {
  130. sh_accum[probe_index].c[i] = 0.0;
  131. }
  132. // quickly ensure each probe has a different "offset" for the vogel function, based on integer world position
  133. uvec3 h3 = hash3(uvec3(params.world_offset + probe_cell));
  134. float offset = hashf3(vec3(h3 & uvec3(0xFFFFF)));
  135. //for a more homogeneous hemisphere, alternate based on history frames
  136. uint ray_offset = params.history_index;
  137. uint ray_mult = params.history_size;
  138. uint ray_total = ray_mult * params.ray_count;
  139. for (uint i = 0; i < params.ray_count; i++) {
  140. vec3 ray_dir = vogel_hemisphere(ray_offset + i * ray_mult, ray_total, offset);
  141. ray_dir.y *= params.y_mult;
  142. ray_dir = normalize(ray_dir);
  143. //needs to be visible
  144. vec3 ray_pos = probe_pos;
  145. vec3 inv_dir = 1.0 / ray_dir;
  146. bool hit = false;
  147. uint hit_cascade;
  148. float bias = params.ray_bias;
  149. vec3 abs_ray_dir = abs(ray_dir);
  150. ray_pos += ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) * bias / cascades.data[params.cascade].to_cell;
  151. vec3 uvw;
  152. for (uint j = params.cascade; j < params.max_cascades; j++) {
  153. //convert to local bounds
  154. vec3 pos = ray_pos - cascades.data[j].offset;
  155. pos *= cascades.data[j].to_cell;
  156. if (any(lessThan(pos, vec3(0.0))) || any(greaterThanEqual(pos, params.grid_size))) {
  157. continue; //already past bounds for this cascade, goto next
  158. }
  159. //find maximum advance distance (until reaching bounds)
  160. vec3 t0 = -pos * inv_dir;
  161. vec3 t1 = (params.grid_size - pos) * inv_dir;
  162. vec3 tmax = max(t0, t1);
  163. float max_advance = min(tmax.x, min(tmax.y, tmax.z));
  164. float advance = 0.0;
  165. while (advance < max_advance) {
  166. //read how much to advance from SDF
  167. uvw = (pos + ray_dir * advance) * pos_to_uvw;
  168. float distance = texture(sampler3D(sdf_cascades[j], linear_sampler), uvw).r * 255.0 - 1.0;
  169. if (distance < 0.05) {
  170. //consider hit
  171. hit = true;
  172. break;
  173. }
  174. advance += distance;
  175. }
  176. if (hit) {
  177. hit_cascade = j;
  178. break;
  179. }
  180. //change ray origin to collision with bounds
  181. pos += ray_dir * max_advance;
  182. pos /= cascades.data[j].to_cell;
  183. pos += cascades.data[j].offset;
  184. ray_pos = pos;
  185. }
  186. vec4 light;
  187. if (hit) {
  188. //avoid reading different texture from different threads
  189. for (uint j = params.cascade; j < params.max_cascades; j++) {
  190. if (j == hit_cascade) {
  191. const float EPSILON = 0.001;
  192. vec3 hit_normal = normalize(vec3(
  193. texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(EPSILON, 0.0, 0.0)).r,
  194. texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(0.0, EPSILON, 0.0)).r,
  195. texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(0.0, 0.0, EPSILON)).r));
  196. vec3 hit_light = texture(sampler3D(light_cascades[hit_cascade], linear_sampler), uvw).rgb;
  197. vec4 aniso0 = texture(sampler3D(aniso0_cascades[hit_cascade], linear_sampler), uvw);
  198. vec3 hit_aniso0 = aniso0.rgb;
  199. vec3 hit_aniso1 = vec3(aniso0.a, texture(sampler3D(aniso1_cascades[hit_cascade], linear_sampler), uvw).rg);
  200. //one liner magic
  201. light.rgb = hit_light * (dot(max(vec3(0.0), (hit_normal * hit_aniso0)), vec3(1.0)) + dot(max(vec3(0.0), (-hit_normal * hit_aniso1)), vec3(1.0)));
  202. light.a = 1.0;
  203. }
  204. }
  205. } else if (bool(params.sky_flags & SKY_FLAGS_MODE_SKY)) {
  206. // Reconstruct sky orientation as quaternion and rotate ray_dir before sampling.
  207. float sky_sign = bool(params.sky_flags & SKY_FLAGS_ORIENTATION_SIGN) ? 1.0 : -1.0;
  208. vec4 sky_quat = vec4(params.sky_color_or_orientation, sky_sign * sqrt(1.0 - dot(params.sky_color_or_orientation, params.sky_color_or_orientation)));
  209. vec3 sky_dir = cross(sky_quat.xyz, ray_dir);
  210. sky_dir = ray_dir + ((sky_dir * sky_quat.w) + cross(sky_quat.xyz, sky_dir)) * 2.0;
  211. #ifdef USE_CUBEMAP_ARRAY
  212. light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(sky_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
  213. #else
  214. light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), sky_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
  215. #endif
  216. light.rgb *= params.sky_energy;
  217. light.a = 0.0;
  218. } else if (bool(params.sky_flags & SKY_FLAGS_MODE_COLOR)) {
  219. light.rgb = params.sky_color_or_orientation;
  220. light.rgb *= params.sky_energy;
  221. light.a = 0.0;
  222. } else {
  223. light = vec4(0, 0, 0, 0);
  224. }
  225. vec3 ray_dir2 = ray_dir * ray_dir;
  226. #define SH_ACCUM(m_idx, m_value) \
  227. { \
  228. vec3 l = light.rgb * (m_value); \
  229. sh_accum[probe_index].c[m_idx * 3 + 0] += l.r; \
  230. sh_accum[probe_index].c[m_idx * 3 + 1] += l.g; \
  231. sh_accum[probe_index].c[m_idx * 3 + 2] += l.b; \
  232. }
  233. SH_ACCUM(0, 0.282095); //l0
  234. SH_ACCUM(1, 0.488603 * ray_dir.y); //l1n1
  235. SH_ACCUM(2, 0.488603 * ray_dir.z); //l1n0
  236. SH_ACCUM(3, 0.488603 * ray_dir.x); //l1p1
  237. SH_ACCUM(4, 1.092548 * ray_dir.x * ray_dir.y); //l2n2
  238. SH_ACCUM(5, 1.092548 * ray_dir.y * ray_dir.z); //l2n1
  239. SH_ACCUM(6, 0.315392 * (3.0 * ray_dir2.z - 1.0)); //l20
  240. SH_ACCUM(7, 1.092548 * ray_dir.x * ray_dir.z); //l2p1
  241. SH_ACCUM(8, 0.546274 * (ray_dir2.x - ray_dir2.y)); //l2p2
  242. #if (SH_SIZE == 16)
  243. SH_ACCUM(9, 0.590043 * ray_dir.y * (3.0f * ray_dir2.x - ray_dir2.y));
  244. SH_ACCUM(10, 2.890611 * ray_dir.y * ray_dir.x * ray_dir.z);
  245. SH_ACCUM(11, 0.646360 * ray_dir.y * (-1.0f + 5.0f * ray_dir2.z));
  246. SH_ACCUM(12, 0.373176 * (5.0f * ray_dir2.z * ray_dir.z - 3.0f * ray_dir.z));
  247. SH_ACCUM(13, 0.457045 * ray_dir.x * (-1.0f + 5.0f * ray_dir2.z));
  248. SH_ACCUM(14, 1.445305 * (ray_dir2.x - ray_dir2.y) * ray_dir.z);
  249. SH_ACCUM(15, 0.590043 * ray_dir.x * (ray_dir2.x - 3.0f * ray_dir2.y));
  250. #endif
  251. }
  252. for (uint i = 0; i < SH_SIZE; i++) {
  253. // store in history texture
  254. ivec3 prev_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(params.history_index));
  255. ivec2 average_pos = prev_pos.xy;
  256. vec4 value = vec4(sh_accum[probe_index].c[i * 3 + 0], sh_accum[probe_index].c[i * 3 + 1], sh_accum[probe_index].c[i * 3 + 2], 1.0) * 4.0 / float(params.ray_count);
  257. ivec4 ivalue = clamp(ivec4(value * float(1 << HISTORY_BITS)), -32768, 32767); //clamp to 16 bits, so higher values don't break average
  258. ivec4 prev_value = imageLoad(lightprobe_history_texture, prev_pos);
  259. ivec4 average = imageLoad(lightprobe_average_texture, average_pos);
  260. average -= prev_value;
  261. average += ivalue;
  262. imageStore(lightprobe_history_texture, prev_pos, ivalue);
  263. imageStore(lightprobe_average_texture, average_pos, average);
  264. if (params.store_ambient_texture && i == 0) {
  265. ivec3 ambient_pos = ivec3(pos, int(params.cascade));
  266. vec4 ambient_light = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS);
  267. ambient_light *= 0.88622; // SHL0
  268. imageStore(lightprobe_ambient_texture, ambient_pos, ambient_light);
  269. }
  270. }
  271. #endif // MODE PROCESS
  272. #ifdef MODE_STORE
  273. // converting to octahedral in this step is required because
  274. // octahedral is much faster to read from the screen than spherical harmonics,
  275. // despite the very slight quality loss
  276. ivec2 sh_pos = (pos / OCT_SIZE) * ivec2(1, SH_SIZE);
  277. ivec2 oct_pos = (pos / OCT_SIZE) * (OCT_SIZE + 2) + ivec2(1);
  278. ivec2 local_pos = pos % OCT_SIZE;
  279. //compute the octahedral normal for this texel
  280. vec3 normal = octahedron_encode(vec2(local_pos) / float(OCT_SIZE));
  281. // read the spherical harmonic
  282. vec3 normal2 = normal * normal;
  283. float c[SH_SIZE] = float[](
  284. 0.282095, //l0
  285. 0.488603 * normal.y, //l1n1
  286. 0.488603 * normal.z, //l1n0
  287. 0.488603 * normal.x, //l1p1
  288. 1.092548 * normal.x * normal.y, //l2n2
  289. 1.092548 * normal.y * normal.z, //l2n1
  290. 0.315392 * (3.0 * normal2.z - 1.0), //l20
  291. 1.092548 * normal.x * normal.z, //l2p1
  292. 0.546274 * (normal2.x - normal2.y) //l2p2
  293. #if (SH_SIZE == 16)
  294. ,
  295. 0.590043 * normal.y * (3.0f * normal2.x - normal2.y),
  296. 2.890611 * normal.y * normal.x * normal.z,
  297. 0.646360 * normal.y * (-1.0f + 5.0f * normal2.z),
  298. 0.373176 * (5.0f * normal2.z * normal.z - 3.0f * normal.z),
  299. 0.457045 * normal.x * (-1.0f + 5.0f * normal2.z),
  300. 1.445305 * (normal2.x - normal2.y) * normal.z,
  301. 0.590043 * normal.x * (normal2.x - 3.0f * normal2.y)
  302. #endif
  303. );
  304. const float l_mult[SH_SIZE] = float[](
  305. 1.0,
  306. 2.0 / 3.0,
  307. 2.0 / 3.0,
  308. 2.0 / 3.0,
  309. 1.0 / 4.0,
  310. 1.0 / 4.0,
  311. 1.0 / 4.0,
  312. 1.0 / 4.0,
  313. 1.0 / 4.0
  314. #if (SH_SIZE == 16)
  315. , // l4 does not contribute to irradiance
  316. 0.0,
  317. 0.0,
  318. 0.0,
  319. 0.0,
  320. 0.0,
  321. 0.0,
  322. 0.0
  323. #endif
  324. );
  325. vec3 irradiance = vec3(0.0);
  326. vec3 radiance = vec3(0.0);
  327. for (uint i = 0; i < SH_SIZE; i++) {
  328. // store in history texture
  329. ivec2 average_pos = sh_pos + ivec2(0, i);
  330. ivec4 average = imageLoad(lightprobe_average_texture, average_pos);
  331. vec4 sh = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS);
  332. vec3 m = sh.rgb * c[i] * 4.0;
  333. irradiance += m * l_mult[i];
  334. radiance += m;
  335. }
  336. //encode RGBE9995 for the final texture
  337. uint irradiance_rgbe = rgbe_encode(irradiance);
  338. uint radiance_rgbe = rgbe_encode(radiance);
  339. //store in octahedral map
  340. ivec3 texture_pos = ivec3(oct_pos, int(params.cascade));
  341. ivec3 copy_to[4] = ivec3[](ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2));
  342. copy_to[0] = texture_pos + ivec3(local_pos, 0);
  343. if (local_pos == ivec2(0, 0)) {
  344. copy_to[1] = texture_pos + ivec3(OCT_SIZE - 1, -1, 0);
  345. copy_to[2] = texture_pos + ivec3(-1, OCT_SIZE - 1, 0);
  346. copy_to[3] = texture_pos + ivec3(OCT_SIZE, OCT_SIZE, 0);
  347. } else if (local_pos == ivec2(OCT_SIZE - 1, 0)) {
  348. copy_to[1] = texture_pos + ivec3(0, -1, 0);
  349. copy_to[2] = texture_pos + ivec3(OCT_SIZE, OCT_SIZE - 1, 0);
  350. copy_to[3] = texture_pos + ivec3(-1, OCT_SIZE, 0);
  351. } else if (local_pos == ivec2(0, OCT_SIZE - 1)) {
  352. copy_to[1] = texture_pos + ivec3(-1, 0, 0);
  353. copy_to[2] = texture_pos + ivec3(OCT_SIZE - 1, OCT_SIZE, 0);
  354. copy_to[3] = texture_pos + ivec3(OCT_SIZE, -1, 0);
  355. } else if (local_pos == ivec2(OCT_SIZE - 1, OCT_SIZE - 1)) {
  356. copy_to[1] = texture_pos + ivec3(0, OCT_SIZE, 0);
  357. copy_to[2] = texture_pos + ivec3(OCT_SIZE, 0, 0);
  358. copy_to[3] = texture_pos + ivec3(-1, -1, 0);
  359. } else if (local_pos.y == 0) {
  360. copy_to[1] = texture_pos + ivec3(OCT_SIZE - local_pos.x - 1, local_pos.y - 1, 0);
  361. } else if (local_pos.x == 0) {
  362. copy_to[1] = texture_pos + ivec3(local_pos.x - 1, OCT_SIZE - local_pos.y - 1, 0);
  363. } else if (local_pos.y == OCT_SIZE - 1) {
  364. copy_to[1] = texture_pos + ivec3(OCT_SIZE - local_pos.x - 1, local_pos.y + 1, 0);
  365. } else if (local_pos.x == OCT_SIZE - 1) {
  366. copy_to[1] = texture_pos + ivec3(local_pos.x + 1, OCT_SIZE - local_pos.y - 1, 0);
  367. }
  368. for (int i = 0; i < 4; i++) {
  369. if (copy_to[i] == ivec3(-2, -2, -2)) {
  370. continue;
  371. }
  372. imageStore(lightprobe_texture_data, copy_to[i], uvec4(irradiance_rgbe));
  373. imageStore(lightprobe_texture_data, copy_to[i] + ivec3(0, 0, int(params.max_cascades)), uvec4(radiance_rgbe));
  374. }
  375. #endif
  376. #ifdef MODE_SCROLL
  377. ivec3 probe_cell;
  378. probe_cell.x = pos.x % int(params.probe_axis_size);
  379. probe_cell.y = pos.y;
  380. probe_cell.z = pos.x / int(params.probe_axis_size);
  381. ivec3 read_probe = probe_cell - params.scroll;
  382. if (all(greaterThanEqual(read_probe, ivec3(0))) && all(lessThan(read_probe, ivec3(params.probe_axis_size)))) {
  383. // can scroll
  384. ivec2 tex_pos;
  385. tex_pos = read_probe.xy;
  386. tex_pos.x += read_probe.z * int(params.probe_axis_size);
  387. //scroll
  388. for (uint j = 0; j < params.history_size; j++) {
  389. for (int i = 0; i < SH_SIZE; i++) {
  390. // copy from history texture
  391. ivec3 src_pos = ivec3(tex_pos.x, tex_pos.y * SH_SIZE + i, int(j));
  392. ivec3 dst_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(j));
  393. ivec4 value = imageLoad(lightprobe_history_texture, src_pos);
  394. imageStore(lightprobe_history_scroll_texture, dst_pos, value);
  395. }
  396. }
  397. for (int i = 0; i < SH_SIZE; i++) {
  398. // copy from average texture
  399. ivec2 src_pos = ivec2(tex_pos.x, tex_pos.y * SH_SIZE + i);
  400. ivec2 dst_pos = ivec2(pos.x, pos.y * SH_SIZE + i);
  401. ivec4 value = imageLoad(lightprobe_average_texture, src_pos);
  402. imageStore(lightprobe_average_scroll_texture, dst_pos, value);
  403. }
  404. } else if (params.cascade < params.max_cascades - 1) {
  405. //can't scroll, must look for position in parent cascade
  406. //to global coords
  407. float cell_to_probe = float(params.grid_size.x / float(params.probe_axis_size - 1));
  408. float probe_cell_size = cell_to_probe / cascades.data[params.cascade].to_cell;
  409. vec3 probe_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size;
  410. //to parent local coords
  411. float probe_cell_size_next = cell_to_probe / cascades.data[params.cascade + 1].to_cell;
  412. probe_pos -= cascades.data[params.cascade + 1].offset;
  413. probe_pos /= probe_cell_size_next;
  414. ivec3 probe_posi = ivec3(probe_pos);
  415. //add up all light, no need to use occlusion here, since occlusion will do its work afterwards
  416. vec4 average_light[SH_SIZE] = vec4[](vec4(0), vec4(0), vec4(0), vec4(0), vec4(0), vec4(0), vec4(0), vec4(0), vec4(0)
  417. #if (SH_SIZE == 16)
  418. ,
  419. vec4(0), vec4(0), vec4(0), vec4(0), vec4(0), vec4(0), vec4(0)
  420. #endif
  421. );
  422. float total_weight = 0.0;
  423. for (int i = 0; i < 8; i++) {
  424. ivec3 offset = probe_posi + ((ivec3(i) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1));
  425. vec3 trilinear = vec3(1.0) - abs(probe_pos - vec3(offset));
  426. float weight = trilinear.x * trilinear.y * trilinear.z;
  427. ivec2 tex_pos;
  428. tex_pos = offset.xy;
  429. tex_pos.x += offset.z * int(params.probe_axis_size);
  430. for (int j = 0; j < SH_SIZE; j++) {
  431. // copy from history texture
  432. ivec2 src_pos = ivec2(tex_pos.x, tex_pos.y * SH_SIZE + j);
  433. ivec4 average = imageLoad(lightprobe_average_parent_texture, src_pos);
  434. vec4 value = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS);
  435. average_light[j] += value * weight;
  436. }
  437. total_weight += weight;
  438. }
  439. if (total_weight > 0.0) {
  440. total_weight = 1.0 / total_weight;
  441. }
  442. //store the averaged values everywhere
  443. for (int i = 0; i < SH_SIZE; i++) {
  444. ivec4 ivalue = clamp(ivec4(average_light[i] * total_weight * float(1 << HISTORY_BITS)), ivec4(-32768), ivec4(32767)); //clamp to 16 bits, so higher values don't break average
  445. // copy from history texture
  446. ivec3 dst_pos = ivec3(pos.x, pos.y * SH_SIZE + i, 0);
  447. for (uint j = 0; j < params.history_size; j++) {
  448. dst_pos.z = int(j);
  449. imageStore(lightprobe_history_scroll_texture, dst_pos, ivalue);
  450. }
  451. ivalue *= int(params.history_size); //average needs to have all history added up
  452. imageStore(lightprobe_average_scroll_texture, dst_pos.xy, ivalue);
  453. }
  454. } else {
  455. //scroll at the edge of the highest cascade, just copy what is there,
  456. //since its the closest we have anyway
  457. for (uint j = 0; j < params.history_size; j++) {
  458. ivec2 tex_pos;
  459. tex_pos = probe_cell.xy;
  460. tex_pos.x += probe_cell.z * int(params.probe_axis_size);
  461. for (int i = 0; i < SH_SIZE; i++) {
  462. // copy from history texture
  463. ivec3 src_pos = ivec3(tex_pos.x, tex_pos.y * SH_SIZE + i, int(j));
  464. ivec3 dst_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(j));
  465. ivec4 value = imageLoad(lightprobe_history_texture, dst_pos);
  466. imageStore(lightprobe_history_scroll_texture, dst_pos, value);
  467. }
  468. }
  469. for (int i = 0; i < SH_SIZE; i++) {
  470. // copy from average texture
  471. ivec2 spos = ivec2(pos.x, pos.y * SH_SIZE + i);
  472. ivec4 average = imageLoad(lightprobe_average_texture, spos);
  473. imageStore(lightprobe_average_scroll_texture, spos, average);
  474. }
  475. }
  476. #endif
  477. #ifdef MODE_SCROLL_STORE
  478. //do not update probe texture, as these will be updated later
  479. for (uint j = 0; j < params.history_size; j++) {
  480. for (int i = 0; i < SH_SIZE; i++) {
  481. // copy from history texture
  482. ivec3 spos = ivec3(pos.x, pos.y * SH_SIZE + i, int(j));
  483. ivec4 value = imageLoad(lightprobe_history_scroll_texture, spos);
  484. imageStore(lightprobe_history_texture, spos, value);
  485. }
  486. }
  487. for (int i = 0; i < SH_SIZE; i++) {
  488. // copy from average texture
  489. ivec2 spos = ivec2(pos.x, pos.y * SH_SIZE + i);
  490. ivec4 average = imageLoad(lightprobe_average_scroll_texture, spos);
  491. imageStore(lightprobe_average_texture, spos, average);
  492. }
  493. #endif
  494. }