#include "../global.h" gpu_texture_t *image_to_pbr_node_result_base = NULL; gpu_texture_t *image_to_pbr_node_result_normal = NULL; gpu_texture_t *image_to_pbr_node_result_occlusion = NULL; gpu_texture_t *image_to_pbr_node_result_height = NULL; gpu_texture_t *image_to_pbr_node_result_roughness = NULL; i32 image_to_pbr_node_node_id = -1; char *image_to_pbr_node_vector(ui_node_t *node, ui_node_socket_t *socket) { gpu_texture_t *result = NULL; if (socket == node->outputs->buffer[0]) { // base color result = image_to_pbr_node_result_base; } else if (socket == node->outputs->buffer[3]) { // normal map result = image_to_pbr_node_result_normal; } if (result == NULL) { return "float3(0.0, 0.0, 0.0)"; } char *tex_name = string("%s%s", parser_material_node_name(node, NULL), i32_to_string(socket->id)); any_map_set(data_cached_images, tex_name, result); bind_tex_t *tex = parser_material_make_bind_tex(tex_name, tex_name); char *texstore = parser_material_texture_store(node, tex, tex_name, COLOR_SPACE_AUTO); return string("%s.rgb", texstore); } char *image_to_pbr_node_value(ui_node_t *node, ui_node_socket_t *socket) { gpu_texture_t *result = NULL; if (socket == node->outputs->buffer[1]) { // occlusion result = image_to_pbr_node_result_occlusion; } else if (socket == node->outputs->buffer[2]) { // roughness result = image_to_pbr_node_result_roughness; } else if (socket == node->outputs->buffer[4]) { // height result = image_to_pbr_node_result_height; } if (result == NULL) { return "0.0"; } char *tex_name = string("%s%s", parser_material_node_name(node, NULL), i32_to_string(socket->id)); any_map_set(data_cached_images, tex_name, result); bind_tex_t *tex = parser_material_make_bind_tex(tex_name, tex_name); char *texstore = parser_material_texture_store(node, tex, tex_name, COLOR_SPACE_AUTO); return string("%s.r", texstore); } void image_to_pbr_node_check_result(void (*done)(gpu_texture_t *)) { iron_delay_idle_sleep(); if (iron_exec_async_done == 1) { char *dir = neural_node_dir(); char *file = string("%s%soutput.png", dir, PATH_SEP); if (iron_file_exists(file)) { gpu_texture_t *tex = iron_load_texture(file); done(tex); } sys_remove_update(image_to_pbr_node_check_result); } } void image_to_pbr_node_run_da3(bool tile, int width, int height, void (*done)(gpu_texture_t *)) { char *dir = neural_node_dir(); string_array_t *argv = any_array_create_from_raw( (void *[]){ string("%s/%s", dir, neural_node_iris_bin()), "-d", string("%s", dir), "--depth", "-W", string("%d", width), "-H", string("%d", height), "-i", string("%s/input.png", dir), "-o", string("%s/output.png", dir), }, 12); if (tile) { string_array_push(argv, "--tile"); } string_array_push(argv, NULL); iron_exec_async(argv->buffer[0], argv->buffer); sys_notify_on_update(image_to_pbr_node_check_result, done); } void image_to_pbr_node_all_done(void *_) { int res_w = image_to_pbr_node_result_height->width; int res_h = image_to_pbr_node_result_height->height; render_target_t *occmap; { render_target_t *t = render_target_create(); t->name = "occmap"; t->width = res_w; t->height = res_h; t->format = "RGBA32"; render_path_create_render_target(t); occmap = t; } render_target_t *normmap; { render_target_t *t = render_target_create(); t->name = "normmap"; t->width = res_w; t->height = res_h; t->format = "RGBA32"; render_path_create_render_target(t); normmap = t; } { render_target_t *t = render_target_create(); t->name = "_height_map"; t->width = res_w; t->height = res_h; t->format = "RGBA32"; t->_image = image_to_pbr_node_result_height; any_map_set(render_path_render_targets, t->name, t); } render_target_t *normal_map_rt; { render_target_t *t = render_target_create(); t->name = "_normal_map"; t->width = res_w; t->height = res_h; t->format = "RGBA32"; t->_image = image_to_pbr_node_result_normal; any_map_set(render_path_render_targets, t->name, t); normal_map_rt = t; } render_path_load_shader("Scene/depth_to_normal_pass/depth_to_normal_pass"); render_path_load_shader("Scene/depth_to_ao_pass/depth_to_ao_pass"); render_path_load_shader("Scene/ssao_blur_pass/ssao_blur_pass_x"); render_path_load_shader("Scene/ssao_blur_pass/ssao_blur_pass_y"); // Normal map render_path_set_target("normmap", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target("_height_map", "height_map"); render_path_draw_shader("Scene/depth_to_normal_pass/depth_to_normal_pass"); gc_unroot(image_to_pbr_node_result_normal); image_to_pbr_node_result_normal = normmap->_image; gc_root(image_to_pbr_node_result_normal); normal_map_rt->_image = normmap->_image; // Occlusion render_path_set_target("occmap", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target("_height_map", "height_map"); render_path_bind_target("_normal_map", "normal_map"); render_path_draw_shader("Scene/depth_to_ao_pass/depth_to_ao_pass"); gc_unroot(image_to_pbr_node_result_occlusion); image_to_pbr_node_result_occlusion = occmap->_image; gc_root(image_to_pbr_node_result_occlusion); // Base color char *dir = neural_node_dir(); gpu_texture_t *input_tex = iron_load_texture(string("%s%sinput.png", dir, PATH_SEP)); buffer_t *in_px = gpu_get_texture_pixels(input_tex); buffer_t *occ_px = gpu_get_texture_pixels(occmap->_image); int bw = occmap->_image->width; int bh = occmap->_image->height; const float linear_light_fac = 0.3f; const float subtract_fac = 0.3f; const float bright = 0.1f; const float contr = 0.0f; const float bc_a = 1.0f + contr; const float bc_b = bright - contr * 0.5f; buffer_t *base_px = buffer_create(bw * bh * 4); for (int y = 0; y < bh; ++y) { for (int x = 0; x < bw; ++x) { int bi = (y * bw + x) * 4; float occ = occ_px->buffer[bi] / 255.0f; float inv_occ = 1.0f - occ; for (int c = 0; c < 3; ++c) { float col = in_px->buffer[bi + c] / 255.0f; col += linear_light_fac * (2.0f * (inv_occ - 0.5f)); col -= subtract_fac * inv_occ; col = bc_a * col + bc_b; if (col < 0.0f) col = 0.0f; if (col > 1.0f) col = 1.0f; base_px->buffer[bi + c] = (int)(col * 255.0f); } base_px->buffer[bi + 3] = 255; } } gpu_texture_t *base = gpu_create_texture_from_bytes(base_px, bw, bh, GPU_TEXTURE_FORMAT_RGBA32); gc_unroot(image_to_pbr_node_result_base); image_to_pbr_node_result_base = base; gc_root(image_to_pbr_node_result_base); // Roughness buffer_t *rough_px = buffer_create(bw * bh * 4); for (int y = 0; y < bh; ++y) { for (int x = 0; x < bw; ++x) { int bi = (y * bw + x) * 4; float lum = (base_px->buffer[bi] * 0.299f + base_px->buffer[bi + 1] * 0.587f + base_px->buffer[bi + 2] * 0.114f) / 255.0f; float detail = 0.0f; int count = 0; for (int oy = -1; oy <= 1; ++oy) { for (int ox = -1; ox <= 1; ++ox) { int sx = x + ox; int sy = y + oy; if (sx < 0 || sx >= bw || sy < 0 || sy >= bh) { continue; } int si = (sy * bw + sx) * 4; float slum = (base_px->buffer[si] * 0.299f + base_px->buffer[si + 1] * 0.587f + base_px->buffer[si + 2] * 0.114f) / 255.0f; float d = slum - lum; detail += d < 0.0f ? -d : d; count += 1; } } detail = count > 0 ? detail / count : 0.0f; float rough = 0.5f + detail * 4.0f; if (rough > 1.0f) { rough = 1.0f; } int v = (int)(rough * 255.0f); rough_px->buffer[bi] = v; rough_px->buffer[bi + 1] = v; rough_px->buffer[bi + 2] = v; rough_px->buffer[bi + 3] = 255; } } gpu_texture_t *rough = gpu_create_texture_from_bytes(rough_px, bw, bh, GPU_TEXTURE_FORMAT_RGBA32); gc_unroot(image_to_pbr_node_result_roughness); image_to_pbr_node_result_roughness = rough; gc_root(image_to_pbr_node_result_roughness); ui_node_canvas_t *canvas = ui_nodes_get_canvas(true); ui_node_t *node = ui_get_node(canvas->nodes, image_to_pbr_node_node_id); if (node != NULL) { any_imap_set(neural_node_results, node->outputs->buffer[0]->id, image_to_pbr_node_result_base); any_imap_set(neural_node_results, node->outputs->buffer[1]->id, image_to_pbr_node_result_occlusion); any_imap_set(neural_node_results, node->outputs->buffer[2]->id, image_to_pbr_node_result_roughness); any_imap_set(neural_node_results, node->outputs->buffer[3]->id, image_to_pbr_node_result_normal); any_imap_set(neural_node_results, node->outputs->buffer[4]->id, image_to_pbr_node_result_height); } } void image_to_pbr_node_depth_done(gpu_texture_t *tex) { gc_unroot(image_to_pbr_node_result_height); image_to_pbr_node_result_height = tex; gc_root(image_to_pbr_node_result_height); sys_notify_on_next_frame(&image_to_pbr_node_all_done, NULL); } void image_to_pbr_node_button(i32 node_id) { ui_node_canvas_t *canvas = ui_nodes_get_canvas(true); ui_node_t *node = ui_get_node(canvas->nodes, node_id); char *node_name = parser_material_node_name(node, NULL); ui_handle_t *h = ui_handle(node_name); string_array_t *models = any_array_create_from_raw( (void *[]){ "DA3MONO", }, 1); i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); if (neural_node_button(node, models->buffer[model])) { ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); gpu_texture_t *input = ui_nodes_get_node_preview_image(from_node); if (input != NULL) { char *dir = neural_node_dir(); #ifdef IRON_BGRA buffer_t *input_buf = buffer_bgra_swap(gpu_get_texture_pixels(input)); // Vulkan non-rt textures need a flip #else buffer_t *input_buf = gpu_get_texture_pixels(input); #endif iron_write_png(string("%s%sinput.png", dir, PATH_SEP), input_buf, input->width, input->height, 0); bool tile = node->buttons->buffer[1]->default_value->buffer[0] > 0.0; image_to_pbr_node_node_id = node_id; image_to_pbr_node_run_da3(tile, input->width, input->height, &image_to_pbr_node_depth_done); } } } void image_to_pbr_node_init() { ui_node_t *image_to_pbr_node_def = GC_ALLOC_INIT(ui_node_t, {.id = 0, .name = _tr("Image to PBR"), .type = "NEURAL_IMAGE_TO_PBR", .x = 0, .y = 0, .color = 0xff4982a0, .inputs = any_array_create_from_raw( (void *[]){ GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Color"), .type = "RGBA", .color = 0xffc7c729, .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), .min = 0.0, .max = 1.0, .precision = 100, .display = 0}), }, 1), .outputs = any_array_create_from_raw( (void *[]){ GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Base Color"), .type = "RGBA", .color = 0xffc7c729, .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), .min = 0.0, .max = 1.0, .precision = 100, .display = 0}), GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Occlusion"), .type = "VALUE", .color = 0xffa1a1a1, .default_value = f32_array_create_x(1.0), .min = 0.0, .max = 1.0, .precision = 100, .display = 0}), GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Roughness"), .type = "VALUE", .color = 0xffa1a1a1, .default_value = f32_array_create_x(1.0), .min = 0.0, .max = 1.0, .precision = 100, .display = 0}), GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Normal Map"), .type = "VECTOR", .color = 0xffc7c729, .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), .min = 0.0, .max = 1.0, .precision = 100, .display = 0}), GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Height"), .type = "VALUE", .color = 0xffa1a1a1, .default_value = f32_array_create_x(1.0), .min = 0.0, .max = 1.0, .precision = 100, .display = 0}), }, 5), .buttons = any_array_create_from_raw( (void *[]){ GC_ALLOC_INIT(ui_node_button_t, {.name = "image_to_pbr_node_button", .type = "CUSTOM", .output = -1, .default_value = f32_array_create_x(0), .data = NULL, .min = 0.0, .max = 1.0, .precision = 100, .height = 2}), GC_ALLOC_INIT(ui_node_button_t, {.name = _tr("Tile"), .type = "BOOL", .output = 0, .default_value = f32_array_create_x(0), .data = NULL, .min = 0.0, .max = 1.0, .precision = 100, .height = 0}), }, 2), .width = 0, .flags = 0}); any_array_push(nodes_material_neural, image_to_pbr_node_def); any_map_set(parser_material_node_vectors, "NEURAL_IMAGE_TO_PBR", image_to_pbr_node_vector); any_map_set(parser_material_node_values, "NEURAL_IMAGE_TO_PBR", image_to_pbr_node_value); any_map_set(ui_nodes_custom_buttons, "image_to_pbr_node_button", image_to_pbr_node_button); }