Files
armorpaint/base/sources/ts/import_envmap.ts
T

158 lines
6.4 KiB
TypeScript
Raw Normal View History

2024-03-13 23:50:11 +01:00
2025-03-10 20:38:53 +01:00
let import_envmap_pipeline: iron_gpu_pipeline_t = null;
let import_envmap_params_loc: iron_gpu_constant_location_t;
2024-03-13 23:50:11 +01:00
let import_envmap_params: vec4_t = vec4_create();
let import_envmap_n: vec4_t = vec4_create();
2025-03-10 20:38:53 +01:00
let import_envmap_radiance_loc: iron_gpu_texture_unit_t;
let import_envmap_radiance: iron_gpu_texture_t = null;
let import_envmap_radiance_cpu: iron_gpu_texture_t = null;
let import_envmap_mips: iron_gpu_texture_t[] = null;
let import_envmap_mips_cpu: iron_gpu_texture_t[] = null;
2024-03-13 23:50:11 +01:00
2025-03-10 20:38:53 +01:00
function import_envmap_run(path: string, image: iron_gpu_texture_t) {
2024-03-13 23:50:11 +01:00
// Init
if (import_envmap_pipeline == null) {
2025-03-10 20:38:53 +01:00
import_envmap_pipeline = gpu_create_pipeline();
2025-03-26 20:56:40 +01:00
import_envmap_pipeline.vertex_shader = sys_get_shader("prefilter_envmap.vert");
2024-03-13 23:50:11 +01:00
import_envmap_pipeline.fragment_shader = sys_get_shader("prefilter_envmap.frag");
2025-03-10 20:38:53 +01:00
let vs: iron_gpu_vertex_structure_t = gpu_vertex_struct_create();
gpu_vertex_struct_add(vs, "pos", vertex_data_t.F32_2X);
2025-02-11 10:51:57 +01:00
import_envmap_pipeline.input_layout = vs;
2024-03-13 23:50:11 +01:00
import_envmap_pipeline.color_attachment_count = 1;
2025-03-03 22:50:40 +01:00
ARRAY_ACCESS(import_envmap_pipeline.color_attachment, 0) = tex_format_t.RGBA128;
2025-03-26 20:56:40 +01:00
2025-03-10 20:38:53 +01:00
gpu_compile_pipeline(import_envmap_pipeline);
2025-03-26 20:56:40 +01:00
2025-03-10 20:38:53 +01:00
import_envmap_params_loc = gpu_get_constant_location(import_envmap_pipeline, "params");
2025-03-26 20:56:40 +01:00
let ptr: gpu_constant_location_impl_t = ADDRESS(import_envmap_params_loc.impl);
2025-04-18 13:51:24 +02:00
ptr.vertexOffset = 0;
2025-03-26 20:56:40 +01:00
2025-03-10 20:38:53 +01:00
import_envmap_radiance_loc = gpu_get_texture_unit(import_envmap_pipeline, "radiance");
2025-04-19 16:55:29 +02:00
import_envmap_radiance_loc.offset = 0;
2024-03-13 23:50:11 +01:00
2025-03-10 20:38:53 +01:00
import_envmap_radiance = gpu_create_render_target(1024, 512, tex_format_t.RGBA128);
2024-03-13 23:50:11 +01:00
import_envmap_mips = [];
let w: i32 = 512;
for (let i: i32 = 0; i < 10; ++i) {
2025-03-10 20:38:53 +01:00
array_push(import_envmap_mips, gpu_create_render_target(w, w > 1 ? math_floor(w / 2) : 1, tex_format_t.RGBA128));
2024-03-13 23:50:11 +01:00
w = math_floor(w / 2);
}
}
// Down-scale to 1024x512
2025-03-10 20:26:45 +01:00
draw_begin(import_envmap_radiance);
2025-03-03 22:50:40 +01:00
draw_set_pipeline(pipes_copy128);
2025-03-02 19:44:26 +01:00
draw_scaled_image(image, 0, 0, 1024, 512);
2025-03-03 22:50:40 +01:00
draw_set_pipeline(null);
2025-03-10 20:26:45 +01:00
draw_end();
2024-03-13 23:50:11 +01:00
2025-03-10 20:38:53 +01:00
let radiance_pixels: buffer_t = gpu_get_texture_pixels(import_envmap_radiance);
2024-03-13 23:50:11 +01:00
if (import_envmap_radiance_cpu != null) {
2025-03-10 20:38:53 +01:00
let _radiance_cpu: iron_gpu_texture_t = import_envmap_radiance_cpu;
2025-03-11 19:49:42 +01:00
sys_notify_on_next_frame(function (_radiance_cpu: iron_gpu_texture_t) {
2025-03-06 20:42:54 +01:00
iron_unload_image(_radiance_cpu);
2024-04-07 09:52:45 +02:00
}, _radiance_cpu);
2024-03-13 23:50:11 +01:00
}
2025-03-10 20:38:53 +01:00
import_envmap_radiance_cpu = gpu_create_texture_from_bytes(radiance_pixels, import_envmap_radiance.width, import_envmap_radiance.height, tex_format_t.RGBA128);
2024-03-13 23:50:11 +01:00
// Radiance
if (import_envmap_mips_cpu != null) {
2024-03-21 21:06:41 +01:00
for (let i: i32 = 0; i < import_envmap_mips_cpu.length; ++i) {
2025-03-10 20:38:53 +01:00
let mip: iron_gpu_texture_t = import_envmap_mips_cpu[i];
2025-03-11 19:49:42 +01:00
sys_notify_on_next_frame(function (mip: iron_gpu_texture_t) {
2024-09-06 21:11:46 +02:00
///if (!arm_direct3d12) // TODO: crashes after 50+ imports
2025-03-06 20:42:54 +01:00
iron_unload_image(mip);
2024-03-13 23:50:11 +01:00
///end
2024-04-07 09:52:45 +02:00
}, mip);
2024-03-13 23:50:11 +01:00
}
}
import_envmap_mips_cpu = [];
for (let i: i32 = 0; i < import_envmap_mips.length; ++i) {
import_envmap_get_radiance_mip(import_envmap_mips[i], i, import_envmap_radiance);
2025-03-10 20:38:53 +01:00
array_push(import_envmap_mips_cpu, gpu_create_texture_from_bytes(gpu_get_texture_pixels(import_envmap_mips[i]), import_envmap_mips[i].width, import_envmap_mips[i].height, tex_format_t.RGBA128));
2024-03-13 23:50:11 +01:00
}
2025-03-10 20:38:53 +01:00
gpu_set_mipmaps(import_envmap_radiance_cpu, import_envmap_mips_cpu);
2024-03-13 23:50:11 +01:00
// Irradiance
scene_world._.irradiance = import_envmap_get_spherical_harmonics(radiance_pixels, import_envmap_radiance.width, import_envmap_radiance.height);
// World
scene_world.strength = 1.0;
scene_world.radiance_mipmaps = import_envmap_mips_cpu.length - 2;
scene_world._.envmap = image;
scene_world.envmap = path;
scene_world._.radiance = import_envmap_radiance_cpu;
scene_world._.radiance_mipmaps = import_envmap_mips_cpu;
context_raw.saved_envmap = image;
if (context_raw.show_envmap_blur) {
scene_world._.envmap = scene_world._.radiance_mipmaps[0];
}
context_raw.ddirty = 2;
project_raw.envmap = path;
}
2025-03-10 20:38:53 +01:00
function import_envmap_get_radiance_mip(mip: iron_gpu_texture_t, level: i32, radiance: iron_gpu_texture_t) {
_gpu_begin(mip);
gpu_set_vertex_buffer(const_data_screen_aligned_vb);
gpu_set_index_buffer(const_data_screen_aligned_ib);
2025-04-24 22:19:44 +02:00
gpu_set_pipeline(import_envmap_pipeline);
2024-03-13 23:50:11 +01:00
import_envmap_params.x = 0.1 + level / 8;
2025-03-18 12:14:21 +01:00
gpu_set_float4(import_envmap_params_loc, import_envmap_params.x, import_envmap_params.y, import_envmap_params.z, import_envmap_params.w);
gpu_set_texture(import_envmap_radiance_loc, radiance);
2025-04-24 22:19:44 +02:00
gpu_draw();
2025-03-10 20:38:53 +01:00
_gpu_end();
2024-03-13 23:50:11 +01:00
}
function import_envmap_reverse_equirect(x: f32, y: f32): vec4_t {
let theta: f32 = x * math_pi() * 2 - math_pi();
let phi: f32 = y * math_pi();
// return n.set(math_sin(phi) * math_cos(theta), -(math_sin(phi) * math_sin(theta)), math_cos(phi));
2024-09-15 21:40:04 +02:00
import_envmap_n = vec4_create(-math_cos(phi), math_sin(phi) * math_cos(theta), -(math_sin(phi) * math_sin(theta)));
2024-09-08 21:53:39 +02:00
return import_envmap_n;
2024-03-13 23:50:11 +01:00
}
// https://ndotl.wordpress.com/2015/03/07/pbr-cubemap-filtering
// https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering
2024-03-20 16:13:54 +01:00
function import_envmap_get_spherical_harmonics(source: buffer_t, source_width: i32, source_height: i32): f32_array_t {
let sh: f32_array_t = f32_array_create(9 * 3 + 1); // Align to mult of 4 - 27->28
2024-03-13 23:50:11 +01:00
let accum: f32 = 0.0;
let weight: f32 = 1.0;
let weight1: f32 = weight * 4 / 17;
let weight2: f32 = weight * 8 / 17;
let weight3: f32 = weight * 15 / 17;
let weight4: f32 = weight * 5 / 68;
let weight5: f32 = weight * 15 / 68;
for (let x: i32 = 0; x < source_width; ++x) {
for (let y: i32 = 0; y < source_height; ++y) {
import_envmap_n = import_envmap_reverse_equirect(x / source_width, y / source_height);
for (let i: i32 = 0; i < 3; ++i) {
2024-07-24 20:04:49 +02:00
let value: f32 = buffer_get_f32(source, ((x + y * source_width) * 16 + i * 4));
2024-03-13 23:50:11 +01:00
value = math_pow(value, 1.0 / 2.2);
sh[0 + i] += value * weight1;
sh[3 + i] += value * weight2 * import_envmap_n.x;
sh[6 + i] += value * weight2 * import_envmap_n.y;
sh[9 + i] += value * weight2 * import_envmap_n.z;
sh[12 + i] += value * weight3 * import_envmap_n.x * import_envmap_n.z;
sh[15 + i] += value * weight3 * import_envmap_n.z * import_envmap_n.y;
sh[18 + i] += value * weight3 * import_envmap_n.y * import_envmap_n.x;
sh[21 + i] += value * weight4 * (3.0 * import_envmap_n.z * import_envmap_n.z - 1.0);
sh[24 + i] += value * weight5 * (import_envmap_n.x * import_envmap_n.x - import_envmap_n.y * import_envmap_n.y);
accum += weight;
}
}
}
for (let i: i32 = 0; i < sh.length; ++i) {
sh[i] /= accum / 16;
}
return sh;
}