import_envmap.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. let import_envmap_pipeline: gpu_pipeline_t = null;
  2. let import_envmap_params_loc: i32;
  3. let import_envmap_params: vec4_t = vec4_create();
  4. let import_envmap_n: vec4_t = vec4_create();
  5. let import_envmap_radiance_loc: i32;
  6. let import_envmap_radiance: gpu_texture_t = null;
  7. let import_envmap_noise_loc: i32;
  8. let import_envmap_mips: gpu_texture_t[] = null;
  9. function import_envmap_run(path: string, image: gpu_texture_t) {
  10. // Init
  11. if (import_envmap_pipeline == null) {
  12. import_envmap_pipeline = gpu_create_pipeline();
  13. import_envmap_pipeline.vertex_shader = sys_get_shader("prefilter_envmap.vert");
  14. import_envmap_pipeline.fragment_shader = sys_get_shader("prefilter_envmap.frag");
  15. let vs: gpu_vertex_structure_t = {};
  16. gpu_vertex_struct_add(vs, "pos", gpu_vertex_data_t.F32_2X);
  17. import_envmap_pipeline.input_layout = vs;
  18. import_envmap_pipeline.color_attachment_count = 1;
  19. ARRAY_ACCESS(import_envmap_pipeline.color_attachment, 0) = gpu_texture_format_t.RGBA128;
  20. gpu_pipeline_compile(import_envmap_pipeline);
  21. import_envmap_params_loc = 0;
  22. import_envmap_radiance_loc = 0;
  23. import_envmap_noise_loc = 1;
  24. import_envmap_radiance = gpu_create_render_target(1024, 512, gpu_texture_format_t.RGBA128);
  25. import_envmap_mips = [];
  26. let w: i32 = 512;
  27. for (let i: i32 = 0; i < 5; ++i) {
  28. array_push(import_envmap_mips, gpu_create_render_target(w, w > 1 ? math_floor(w / 2) : 1, gpu_texture_format_t.RGBA128));
  29. w = math_floor(w / 2);
  30. }
  31. }
  32. // Down-scale to 1024x512
  33. draw_begin(import_envmap_radiance);
  34. draw_set_pipeline(pipes_copy128);
  35. draw_scaled_image(image, 0, 0, 1024, 512);
  36. draw_set_pipeline(null);
  37. draw_end();
  38. // Radiance
  39. for (let i: i32 = 0; i < import_envmap_mips.length; ++i) {
  40. import_envmap_get_radiance_mip(import_envmap_mips[i], i, import_envmap_radiance);
  41. }
  42. // Irradiance
  43. let radiance_pixels: buffer_t = gpu_get_texture_pixels(import_envmap_radiance);
  44. scene_world._.irradiance = import_envmap_get_spherical_harmonics(radiance_pixels, import_envmap_radiance.width, import_envmap_radiance.height);
  45. // World
  46. scene_world.strength = 1.0;
  47. scene_world.radiance_mipmaps = import_envmap_mips.length - 2;
  48. scene_world._.envmap = image;
  49. scene_world.envmap = path;
  50. scene_world._.radiance = import_envmap_radiance;
  51. scene_world._.radiance_mipmaps = import_envmap_mips;
  52. context_raw.saved_envmap = image;
  53. context_raw.show_envmap = true;
  54. if (context_raw.show_envmap_blur) {
  55. scene_world._.envmap = scene_world._.radiance_mipmaps[0];
  56. }
  57. context_raw.ddirty = 2;
  58. project_raw.envmap = path;
  59. }
  60. function import_envmap_get_radiance_mip(mip: gpu_texture_t, level: i32, radiance: gpu_texture_t) {
  61. _gpu_begin(mip);
  62. gpu_set_vertex_buffer(const_data_screen_aligned_vb);
  63. gpu_set_index_buffer(const_data_screen_aligned_ib);
  64. gpu_set_pipeline(import_envmap_pipeline);
  65. import_envmap_params.x = (level + 1) / 10;
  66. /// if (arm_macos || arm_ios)
  67. import_envmap_params.y = 1024 * 2; // Prevent gpu hang
  68. /// else
  69. import_envmap_params.y = 1024 * 16;
  70. /// end
  71. gpu_set_float4(import_envmap_params_loc, import_envmap_params.x, import_envmap_params.y, import_envmap_params.z, import_envmap_params.w);
  72. gpu_set_texture(import_envmap_radiance_loc, radiance);
  73. let noise: gpu_texture_t = data_get_image("bnoise256.k");
  74. gpu_set_texture(import_envmap_noise_loc, noise);
  75. gpu_draw();
  76. gpu_end();
  77. }
  78. function import_envmap_reverse_equirect(x: f32, y: f32): vec4_t {
  79. let theta: f32 = x * math_pi() * 2 - math_pi();
  80. let phi: f32 = y * math_pi();
  81. // return n.set(math_sin(phi) * math_cos(theta), -(math_sin(phi) * math_sin(theta)), math_cos(phi));
  82. import_envmap_n = vec4_create(-math_cos(phi), math_sin(phi) * math_cos(theta), -(math_sin(phi) * math_sin(theta)));
  83. return import_envmap_n;
  84. }
  85. // https://ndotl.wordpress.com/2015/03/07/pbr-cubemap-filtering
  86. // https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering
  87. function import_envmap_get_spherical_harmonics(source: buffer_t, source_width: i32, source_height: i32): f32_array_t {
  88. let sh: f32_array_t = f32_array_create(9 * 3 + 1); // Align to mult of 4 - 27->28
  89. let accum: f32 = 0.0;
  90. let weight: f32 = 1.0;
  91. let weight1: f32 = weight * 4 / 17;
  92. let weight2: f32 = weight * 8 / 17;
  93. let weight3: f32 = weight * 15 / 17;
  94. let weight4: f32 = weight * 5 / 68;
  95. let weight5: f32 = weight * 15 / 68;
  96. for (let x: i32 = 0; x < source_width; ++x) {
  97. for (let y: i32 = 0; y < source_height; ++y) {
  98. import_envmap_n = import_envmap_reverse_equirect(x / source_width, y / source_height);
  99. for (let i: i32 = 0; i < 3; ++i) {
  100. let value: f32 = buffer_get_f32(source, ((x + y * source_width) * 16 + i * 4));
  101. value = math_pow(value, 1.0 / 2.2);
  102. sh[0 + i] += value * weight1;
  103. sh[3 + i] += value * weight2 * import_envmap_n.x;
  104. sh[6 + i] += value * weight2 * import_envmap_n.y;
  105. sh[9 + i] += value * weight2 * import_envmap_n.z;
  106. sh[12 + i] += value * weight3 * import_envmap_n.x * import_envmap_n.z;
  107. sh[15 + i] += value * weight3 * import_envmap_n.z * import_envmap_n.y;
  108. sh[18 + i] += value * weight3 * import_envmap_n.y * import_envmap_n.x;
  109. sh[21 + i] += value * weight4 * (3.0 * import_envmap_n.z * import_envmap_n.z - 1.0);
  110. sh[24 + i] += value * weight5 * (import_envmap_n.x * import_envmap_n.x - import_envmap_n.y * import_envmap_n.y);
  111. accum += weight;
  112. }
  113. }
  114. }
  115. for (let i: i32 = 0; i < sh.length; ++i) {
  116. sh[i] /= accum / 16;
  117. }
  118. return sh;
  119. }