diff --git a/paint/sources/enums.h b/paint/sources/enums.h index 143a7944..c672700b 100644 --- a/paint/sources/enums.h +++ b/paint/sources/enums.h @@ -465,3 +465,8 @@ typedef enum { HISTORY_ACTION_DELETE_MATERIAL, HISTORY_ACTION_DUPLICATE_MATERIAL, } history_action_t; + +typedef enum { + OPACITY_MODE_ALPHA, + OPACITY_MODE_TRANSLUC, +} opacity_mode_t; diff --git a/paint/sources/functions.h b/paint/sources/functions.h index 43aa40c4..4cb7317d 100644 --- a/paint/sources/functions.h +++ b/paint/sources/functions.h @@ -447,6 +447,7 @@ rect_t *resource_tile50(gpu_texture_t *img, i32 i); rect_t *resource_tile18(gpu_texture_t *img, i32 i); bool render_path_raytrace_bake_commands(void (*parse_paint_material)(bool)); void make_material_parse_mesh_material(); +void make_material_parse_depth_material(); void make_material_parse_mesh_preview_material(material_data_t *md); void make_material_parse_paint_material(bool bake_previews); parse_node_preview_result_t *make_material_parse_node_preview_material(ui_node_t *node, ui_node_canvas_t *group, ui_node_t_array_t *parents); @@ -502,6 +503,7 @@ ui_node_t *nodes_material_create_node(char *node_type, node_gr raw_mesh_t *geom_make_plane(f32 size_x, f32 size_y, i32 verts_x, i32 verts_y, f32 uv_scale); raw_mesh_t *geom_make_uv_sphere(f32 radius, i32 width_segments, i32 height_segments, bool stretch_uv, f32 uv_scale); node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass); +node_shader_context_t *make_depth_run(material_t *data, material_context_t *matcon); void ui_sidebar_render_ui(); void ui_sidebar_show(bool b); void console_toast(char *s); diff --git a/paint/sources/globals.h b/paint/sources/globals.h index 8f8b2d36..884a26f7 100644 --- a/paint/sources/globals.h +++ b/paint/sources/globals.h @@ -232,7 +232,7 @@ any_map_t *resource_bundled; i32 render_path_raytrace_bake_rays_pix = 0; i32 render_path_raytrace_bake_rays_sec = 0; i32 render_path_raytrace_bake_current_sample = 0; -bool make_material_opac_used = false; +bool make_material_transluc_used = false; bool make_material_height_used = false; bool make_material_emis_used = false; bool make_material_subs_used = false; diff --git a/paint/sources/main.c b/paint/sources/main.c index 389eabfb..932e0d16 100644 --- a/paint/sources/main.c +++ b/paint/sources/main.c @@ -130,6 +130,7 @@ #include "make_brush.c" #include "make_clone.c" #include "make_colorid_picker.c" +#include "make_depth.c" #include "make_discard.c" #include "make_material.c" #include "make_mesh.c" diff --git a/paint/sources/make_brush.c b/paint/sources/make_brush.c index f5cac7a9..481dcb4e 100644 --- a/paint/sources/make_brush.c +++ b/paint/sources/make_brush.c @@ -35,7 +35,7 @@ void make_brush_run(node_shader_t *kong) { node_shader_write_frag(kong, "wn = normalize(wn);"); node_shader_write_frag(kong, "var plane_dist: float = dot(wn, winp.xyz - input.wposition);"); - if (g_config->brush_angle_reject && !g_context->xray) { + if (g_config->brush_angle_reject && !g_context->xray && !make_material_transluc_used) { // constants.inp.w = paint2d ? 0.0 : 1.0 node_shader_write_frag(kong, "if (plane_dist < -0.03 && constants.inp.w == 0.0) { discard; }"); kong->frag_n = true; diff --git a/paint/sources/make_depth.c b/paint/sources/make_depth.c new file mode 100644 index 00000000..17ae60f8 --- /dev/null +++ b/paint/sources/make_depth.c @@ -0,0 +1,93 @@ + +#include "global.h" + +node_shader_context_t *make_depth_run(material_t *data, material_context_t *matcon) { + shader_context_t *props = GC_ALLOC_INIT(shader_context_t, {.name = "depth", + .depth_write = true, + .compare_mode = "less", + .cull_mode = g_context->cull_backfaces ? "clockwise" : "none", + .vertex_elements = any_array_create_from_raw( + (void *[]){ + GC_ALLOC_INIT(vertex_element_t, {.name = "pos", .data = "short4norm"}), + GC_ALLOC_INIT(vertex_element_t, {.name = "nor", .data = "short2norm"}), + GC_ALLOC_INIT(vertex_element_t, {.name = "tex", .data = "short2norm"}), + }, + 3), + .color_attachments = any_array_create_from_raw( + (void *[]){ + "RGBA64", + }, + 1), + .depth_attachment = "D32"}); + node_shader_context_t *con_depth = node_shader_context_create(data, props); + + node_shader_t *kong = node_shader_context_make_kong(con_depth); + kong->frag_wposition = true; + + node_shader_add_constant(kong, "VP: float4x4", "_view_proj_matrix"); + + // f32 displace_strength = make_material_get_displace_strength(); + // if (make_material_height_used && displace_strength > 0.0) { + // kong->vert_n = true; + // node_shader_write_vert(kong, "var height: float = 0.0;"); + // i32 num_layers = 0; + // for (i32 i = 0; i < project_layers->length; ++i) { + // slot_layer_t *l = project_layers->buffer[i]; + // if (!slot_layer_is_visible(l) || !l->paint_height || !slot_layer_is_layer(l)) { + // continue; + // } + // if (num_layers > 16) { + // break; + // } + // num_layers++; + // node_shader_add_texture(kong, string("texpaint_pack_vert%s", i32_to_string(l->id)), string("_texpaint_pack_vert%s", i32_to_string(l->id))); + // node_shader_write_vert(kong, string("height += sample_lod(texpaint_pack_vert%s, sampler_linear, input.tex, 0.0).a;", i32_to_string(l->id))); + // slot_layer_t_array_t *masks = slot_layer_get_masks(l, true); + // if (masks != NULL) { + // for (i32 i = 0; i < masks->length; ++i) { + // slot_layer_t *m = masks->buffer[i]; + // if (!slot_layer_is_visible(m)) { + // continue; + // } + // node_shader_add_texture(kong, string("texpaint_vert%s", i32_to_string(m->id)), string("_texpaint_vert%s", i32_to_string(m->id))); + // node_shader_write_vert(kong, string("height *= sample_lod(texpaint_vert%s, sampler_linear, input.tex, 0.0).r;", i32_to_string(m->id))); + // } + // } + // } + // node_shader_write_vert(kong, string("output.wposition += wnormal * float3(height, height, height) * float3(%s, %s, %s);", + // f32_to_string(displace_strength), f32_to_string(displace_strength), f32_to_string(displace_strength))); + // } + + node_shader_write_vert(kong, "output.pos = constants.VP * float4(output.wposition.xyz, 1.0);"); + + con_depth->data->color_writes_red = u8_array_create_from_raw( + (u8[]){ + false, + }, + 1); + + con_depth->data->color_writes_green = u8_array_create_from_raw( + (u8[]){ + false, + }, + 1); + + con_depth->data->color_writes_blue = u8_array_create_from_raw( + (u8[]){ + false, + }, + 1); + + con_depth->data->color_writes_alpha = u8_array_create_from_raw( + (u8[]){ + false, + }, + 1); + + parser_material_finalize(con_depth); + + con_depth->data->shader_from_source = true; + gpu_create_shaders_from_kong(node_shader_get(kong), &con_depth->data->vertex_shader, &con_depth->data->fragment_shader, + &con_depth->data->_->vertex_shader_size, &con_depth->data->_->fragment_shader_size); + return con_depth; +} diff --git a/paint/sources/make_material.c b/paint/sources/make_material.c index 92f53045..b54263a4 100644 --- a/paint/sources/make_material.c +++ b/paint/sources/make_material.c @@ -87,6 +87,10 @@ void make_material_parse_mesh_material() { if (g_context->viewport_mode == VIEWPORT_MODE_PATH_TRACE) { g_context->pdirty = 1; } + + if (make_material_transluc_used) { + make_material_parse_depth_material(); + } } void make_material_parse_mesh_preview_material(material_data_t *md) { @@ -513,3 +517,43 @@ f32 make_material_get_displace_strength() { vec4_t sc = context_main_object()->base->transform->scale; return g_config->displace_strength * 0.02 * sc.x; } + +void make_material_parse_depth_material() { + material_data_t *m = project_materials->buffer[0]->data; + + for (i32 i = 0; i < m->_->shader->contexts->length; ++i) { + shader_context_t *c = m->_->shader->contexts->buffer[i]; + if (string_equals(c->name, "depth")) { + array_remove(m->_->shader->contexts, c); + make_material_delete_context(c); + break; + } + } + for (i32 i = 0; i < m->contexts->length; ++i) { + material_context_t *c = m->contexts->buffer[i]; + if (string_equals(c->name, "depth")) { + array_remove(m->contexts, c); + break; + } + } + + material_t *sdata = GC_ALLOC_INIT(material_t, {.name = "Material", .canvas = g_context->material->canvas}); + material_context_t *tmcon = GC_ALLOC_INIT(material_context_t, {.name = "depth", .bind_textures = any_array_create_from_raw((void *[]){}, 0)}); + node_shader_context_t *con = make_depth_run(sdata, tmcon); + + bool compile_error = false; + shader_context_t *scon; + shader_context_load(con->data); + if (con->data == NULL) { + compile_error = true; + } + scon = con->data; + if (compile_error) { + return; + } + material_context_load(tmcon); + material_context_t *mcon = tmcon; + + any_array_push(m->_->shader->contexts, scon); + any_array_push(m->contexts, mcon); +} diff --git a/paint/sources/make_mesh.c b/paint/sources/make_mesh.c index 249be59e..3c9ea1c6 100644 --- a/paint/sources/make_mesh.c +++ b/paint/sources/make_mesh.c @@ -1,7 +1,7 @@ #include "global.h" -char *str_sh_irradiance = "\ +char *str_sh_irradiance = "\ fun sh_irradiance(nor: float3): float3 { \ var c1: float = 0.429043; \ var c2: float = 0.511664; \ @@ -32,7 +32,7 @@ fun sh_irradiance(nor: float3): float3 { \ } \ "; -char *str_envmap_equirect = "\ +char *str_envmap_equirect = "\ fun envmap_equirect(normal: float3, angle: float): float2 { \ var PI: float = 3.1415926535; \ var PI2: float = PI * 2.0; \ @@ -42,7 +42,7 @@ fun envmap_equirect(normal: float3, angle: float): float2 { \ } \ "; -char *str_envmap_sample = "\ +char *str_envmap_sample = "\ fun envmap_sample(lod: float, coord: float2): float3 { \ if (lod == 0.0) { \ return sample_lod(senvmap_radiance, sampler_linear, coord, 0.0).rgb; \ @@ -64,7 +64,7 @@ fun envmap_sample(lod: float, coord: float2): float3 { \ "; // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile -char *str_env_brdf_approx = "\ +char *str_env_brdf_approx = "\ fun env_brdf_approx(specular: float3, roughness: float, dotnv: float): float3 { \ var c0: float4 = float4(-1.0, -0.0275, -0.572, 0.022); \ var c1: float4 = float4(1.0, 0.0425, 1.04, -0.04); \ @@ -304,14 +304,16 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) { node_shader_write_frag(kong, string("texpaint_sample = sample_lod(texpaint%s, sampler_linear, %s, 0.0);", i32_to_string(l->id), tex_coord)); node_shader_write_frag(kong, "texpaint_opac = texpaint_sample.a;"); - // if (g_context.viewport_mode == viewport_mode_t.LIT && make_material_opac_used) { - // kong.frag_wvpposition = true; - // node_shader_add_function(kong, str_dither_bayer); - // node_shader_add_constant(kong, "gbuffer_size: float2", "_gbuffer_size"); - // node_shader_write_frag(kong, "var fragcoord1: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / - // input.wvpposition.w) * 0.5 + 0.5;"); node_shader_write_frag(kong, "var dither: float = dither_bayer(fragcoord1 * constants.gbuffer_size);"); - // node_shader_write_frag(kong, "if (texpaint_opac < dither) { discard; }"); - // } + if (g_context->viewport_mode == VIEWPORT_MODE_LIT && make_material_transluc_used) { + con_mesh->data->cull_mode = "none"; + kong->frag_wvpposition = true; + node_shader_add_function(kong, str_dither_bayer); + node_shader_add_constant(kong, "gbuffer_size: float2", "_gbuffer_size"); + node_shader_write_frag( + kong, "var fragcoord1: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / input.wvpposition.w) * 0.5 + 0.5;"); + node_shader_write_frag(kong, "var dither: float = dither_bayer(fragcoord1 * constants.gbuffer_size);"); + node_shader_write_frag(kong, "if (texpaint_opac < dither) { discard; }"); + } slot_layer_t_array_t *masks = slot_layer_get_masks(l, true); if (masks != NULL) { diff --git a/paint/sources/make_mesh_preview.c b/paint/sources/make_mesh_preview.c index 81ffd520..77cea1dc 100644 --- a/paint/sources/make_mesh_preview.c +++ b/paint/sources/make_mesh_preview.c @@ -79,13 +79,13 @@ node_shader_context_t *make_mesh_preview_run(material_t *data, material_context_ node_shader_add_function(kong, str_cotangent_frame); node_shader_add_function(kong, str_octahedron_wrap); - // if (make_material_opac_used) { - // kong.frag_wvpposition = true; - // node_shader_add_function(kong, str_dither_bayer); - // node_shader_write_frag(kong, "var fragcoord1: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / input.wvpposition.w) * - // 0.5 + 0.5;"); node_shader_write_frag(kong, "var dither: float = dither_bayer(fragcoord1 * float2(256.0, 256.0));"); node_shader_write_frag(kong, "if - // (opacity < dither) { discard; }"); - // } + if (g_context->material->paint_opac_mode == OPACITY_MODE_TRANSLUC) { + kong->frag_wvpposition = true; + node_shader_add_function(kong, str_dither_bayer); + node_shader_write_frag(kong, "var fragcoord1: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / input.wvpposition.w) * 0.5 + 0.5;"); + node_shader_write_frag(kong, "var dither: float = dither_bayer(fragcoord1 * float2(256.0, 256.0));"); + node_shader_write_frag(kong, "if (opacity < dither) { discard; }"); + } if (make_material_height_used) { node_shader_write_frag(kong, "if (height > 0.0) {"); diff --git a/paint/sources/make_paint.c b/paint/sources/make_paint.c index 79e467d2..20d36369 100644 --- a/paint/sources/make_paint.c +++ b/paint/sources/make_paint.c @@ -328,7 +328,8 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc node_shader_write_frag(kong, string("var nortan: float3 = %s;", nortan)); node_shader_write_frag(kong, string("var height: float = %s;", height)); node_shader_write_frag(kong, string("var mat_opacity: float = %s;", opac)); - if (make_material_opac_used) { + if (g_context->material->paint_opac_mode == OPACITY_MODE_TRANSLUC) { + make_material_transluc_used = true; node_shader_write_frag(kong, "var opacity: float = 1.0;"); } else { @@ -349,11 +350,6 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc if (g_context->material->paint_subs) { node_shader_write_frag(kong, string("var subs: float = %s;", subs)); } - if (!make_material_opac_used && parse_float(opac) != 1.0 && g_context->viewport_mode == VIEWPORT_MODE_PATH_TRACE && - g_config->pathtrace_mode == PATHTRACE_MODE_QUALITY) { - make_material_opac_used = true; - return make_paint_run(data, matcon); - } if (!make_material_height_used && parse_float(height) != 0.0) { make_material_height_used = true; // Height used for the first time, also rebuild vertex shader @@ -510,7 +506,7 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc node_shader_write_frag(kong, "output[0] = float4((basecol * t_blur + sample_undo.rgb * sample_undo.a * (1.0 - t_blur)) / max(out_a, 0.0000001), out_a);"); } - else if (make_material_opac_used || g_context->tool == TOOL_TYPE_GIZMO || g_context->layer->fill_layer != NULL) { + else if (g_context->material->paint_opac_mode == OPACITY_MODE_TRANSLUC || g_context->tool == TOOL_TYPE_GIZMO || g_context->layer->fill_layer != NULL) { node_shader_write_frag(kong, string("output[0] = float4(%s, %s);", make_material_blend_mode(kong, g_context->brush_blending, "sample_undo.rgb", "basecol", "str"), "mat_opacity")); } diff --git a/paint/sources/render_path_base.c b/paint/sources/render_path_base.c index 46e19152..3d430a2f 100644 --- a/paint/sources/render_path_base.c +++ b/paint/sources/render_path_base.c @@ -405,6 +405,12 @@ void render_path_base_copy_to_gbuffer() { } void render_path_base_draw_gbuffer() { + + if (make_material_transluc_used) { + render_path_set_target("gbuffer0", NULL, NULL, GPU_CLEAR_COLOR, 0x00000000, 0.0); + render_path_set_target("gbuffer1", NULL, NULL, GPU_CLEAR_COLOR, 0x00000000, 0.0); + } + render_path_set_target("gbuffer0", NULL, "main", GPU_CLEAR_DEPTH, 0, 1.0); // Only clear gbuffer0 string_array_t *additional = any_array_create_from_raw( (void *[]){ @@ -445,6 +451,11 @@ void render_path_base_draw_gbuffer() { } } + if (make_material_transluc_used) { + render_path_set_target("gbuffer0", NULL, "main", GPU_CLEAR_NONE, 0, 1.0); + render_path_draw_meshes("depth"); + } + bool hide = operator_shortcut(any_map_get(config_keymap, "stencil_hide"), SHORTCUT_TYPE_DOWN) || keyboard_down("control"); bool is_decal = base_is_decal_layer(); if (is_decal && !hide) { diff --git a/paint/sources/slot_material.c b/paint/sources/slot_material.c index 4df2fb3b..fd5f8093 100644 --- a/paint/sources/slot_material.c +++ b/paint/sources/slot_material.c @@ -10,6 +10,7 @@ slot_material_t *slot_material_create(material_data_t *m, ui_node_canvas_t *c) { raw->id = 0; raw->paint_base = true; raw->paint_opac = true; + raw->paint_opac_mode = OPACITY_MODE_ALPHA; raw->paint_occ = true; raw->paint_rough = true; raw->paint_met = true; diff --git a/paint/sources/tab_materials.c b/paint/sources/tab_materials.c index 7a2c4632..45354c3d 100644 --- a/paint/sources/tab_materials.c +++ b/paint/sources/tab_materials.c @@ -154,6 +154,20 @@ void tab_materials_draw_slots_menu() { subs_handle->b = m->paint_subs; } + ui_menu_separator(); + ui_menu_align(); + ui_menu_label(tr("Opacity Mode"), NULL); + ui_menu_align(); + ui_handle_t *opac_mode_handle = ui_handle(__ID__); + opac_mode_handle->i = m->paint_opac_mode; + string_array_t *opac_mode_items = any_array_create_from_raw( + (void *[]){ + tr("Alpha"), + tr("Translucency"), + }, + 2); + m->paint_opac_mode = ui_inline_radio(opac_mode_handle, opac_mode_items, UI_ALIGN_LEFT); + ui_menu_separator(); ui_menu_align(); ui_menu_label(tr("Channels"), NULL); @@ -176,8 +190,11 @@ void tab_materials_draw_slots_menu() { } if (base_handle->changed || opac_handle->changed || nor_handle->changed || occ_handle->changed || rough_handle->changed || met_handle->changed || - height_handle->changed || emis_handle->changed || subs_handle->changed) { + height_handle->changed || emis_handle->changed || subs_handle->changed || opac_mode_handle->changed) { make_material_parse_paint_material(true); + if (opac_mode_handle->changed) { + sys_notify_on_next_frame(util_render_make_material_preview, NULL); + } ui_menu_keep_open = true; } } diff --git a/paint/sources/types.h b/paint/sources/types.h index a68cfe8b..7c14ca2e 100644 --- a/paint/sources/types.h +++ b/paint/sources/types.h @@ -149,6 +149,7 @@ typedef struct slot_material { i32 id; bool paint_base; bool paint_opac; + i32 paint_opac_mode; bool paint_occ; bool paint_rough; bool paint_met;