paint: improve blur tool

This commit is contained in:
luboslenco
2026-08-23 18:57:24 +02:00
parent ba66c8aebf
commit 6fdf4c576b
4 changed files with 104 additions and 41 deletions
+19 -25
View File
@@ -34,10 +34,6 @@ fun get_blur_tool_weight(i: int): float { \
";
void make_blur_run(node_shader_t *kong) {
// node_shader_write_frag(kong, "var tex_coord_inp: float2 = gbuffer2[uint2(sp.x * constants.gbuffer_size.x, sp.y * constants.gbuffer_size.y)].ba;");
node_shader_write_frag(kong, "var tex_coord_inp4: float4 = gbuffer2[uint2(uint(sp.x * constants.gbuffer_size.x), uint(sp.y * constants.gbuffer_size.y))];");
node_shader_write_frag(kong, "var tex_coord_inp: float2 = tex_coord_inp4.ba;");
node_shader_write_frag(kong, "var basecol: float3 = float3(0.0, 0.0, 0.0);");
node_shader_write_frag(kong, "var roughness: float = 0.0;");
node_shader_write_frag(kong, "var metallic: float = 0.0;");
@@ -59,67 +55,65 @@ void make_blur_run(node_shader_t *kong) {
node_shader_write_frag(kong, "var subs: float = 0.0;");
}
node_shader_add_constant(kong, "texpaint_size: float2", "_texpaint_size");
node_shader_write_frag(kong, "var blur_step: float = 1.0 / constants.texpaint_size.x;");
if (g_context->blur_type == BLUR_TYPE_SMUDGE) {
// node_shader_write_frag(kong, "const blur_weight: float[7] = {1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0};");
node_shader_add_function(kong, str_get_smudge_tool_weight);
node_shader_add_constant(kong, "brush_direction: float3", "_brush_direction");
node_shader_write_frag(kong, "var blur_direction: float2 = constants.brush_direction.yx;");
node_shader_write_frag(kong, "var smudge_delta: float2 = constants.inp.xy - constants.inplast.xy;");
node_shader_write_frag(kong, "for (var i: int = 0; i < 7; i += 1) {");
// node_shader_write_frag(kong, "var tex_coord_inp2: float2 = gbuffer2[uint2((sp.x + blur_direction.x * blur_step * float(i)) *
// constants.gbuffer_size.x, (sp.y + blur_direction.y * blur_step * float(i)) * constants.gbuffer_size.y)].ba;");
node_shader_write_frag(kong, "var tex_coord_inp24: float4 = gbuffer2[uint2(uint((sp.x + blur_direction.x * blur_step * float(i)) * "
"constants.gbuffer_size.x), uint((sp.y + blur_direction.y * blur_step * float(i)) * constants.gbuffer_size.y))];");
node_shader_write_frag(kong, "var smudge_sp: float2 = sp.xy - smudge_delta * ((float(i) + 1.0) / 7.0);");
node_shader_write_frag(kong, "smudge_sp = float2(clamp(smudge_sp.x, 0.0, 0.9999), clamp(smudge_sp.y, 0.0, 0.9999));");
node_shader_write_frag(kong, "var tex_coord_inp24: float4 = gbuffer2[uint2(uint(smudge_sp.x * constants.gbuffer_size.x), uint(smudge_sp.y * "
"constants.gbuffer_size.y))];");
node_shader_write_frag(kong, "var tex_coord_inp2: float2 = tex_coord_inp24.ba;");
node_shader_write_frag(kong, "var texpaint_sample: float4 = sample(texpaint_undo, sampler_linear, tex_coord_inp2);");
node_shader_write_frag(kong, "var texpaint_sample: float4 = sample(texpaint_ref, sampler_linear, tex_coord_inp2);");
node_shader_write_frag(kong, "var blur_weight_i: float = get_smudge_tool_weight(i);");
node_shader_write_frag(kong, "opacity += texpaint_sample.a * blur_weight_i;");
node_shader_write_frag(kong, "basecol += texpaint_sample.rgb * texpaint_sample.a * blur_weight_i;");
node_shader_write_frag(kong, "var texpaint_pack_sample: float4 = sample(texpaint_pack_undo, sampler_linear, tex_coord_inp2) * blur_weight_i;");
node_shader_write_frag(kong, "var texpaint_pack_sample: float4 = sample(texpaint_pack_ref, sampler_linear, tex_coord_inp2) * blur_weight_i;");
node_shader_write_frag(kong, "roughness += texpaint_pack_sample.g;");
node_shader_write_frag(kong, "metallic += texpaint_pack_sample.b;");
node_shader_write_frag(kong, "occlusion += texpaint_pack_sample.r;");
node_shader_write_frag(kong, "height += texpaint_pack_sample.a;");
node_shader_write_frag(kong, "nortan += sample(texpaint_nor_undo, sampler_linear, tex_coord_inp2).rgb * blur_weight_i;");
node_shader_write_frag(kong, "nortan += sample(texpaint_nor_ref, sampler_linear, tex_coord_inp2).rgb * blur_weight_i;");
node_shader_write_frag(kong, "}");
}
else {
// node_shader_write_frag(kong, "const blur_weight: float[15] = {0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0,
// 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0,
// 0.034619 / 2.0};");
node_shader_write_frag(kong,
"var tex_coord_inp4: float4 = gbuffer2[uint2(uint(sp.x * constants.gbuffer_size.x), uint(sp.y * constants.gbuffer_size.y))];");
node_shader_write_frag(kong, "var tex_coord_inp: float2 = tex_coord_inp4.ba;");
node_shader_add_constant(kong, "texpaint_size: float2", "_texpaint_size");
node_shader_write_frag(kong, "var blur_step: float = 1.0 / constants.texpaint_size.x;");
node_shader_add_function(kong, str_get_blur_tool_weight);
// X
node_shader_write_frag(kong, "for (var i: int = 0; i <= 14; i += 1) {");
node_shader_write_frag(kong,
"var texpaint_sample: float4 = sample(texpaint_undo, sampler_linear, tex_coord_inp + float2(blur_step * float(i - 7), 0.0));");
"var texpaint_sample: float4 = sample(texpaint_ref, sampler_linear, tex_coord_inp + float2(blur_step * float(i - 7), 0.0));");
node_shader_write_frag(kong, "var blur_weight_i: float = get_blur_tool_weight(i);");
node_shader_write_frag(kong, "opacity += texpaint_sample.a * blur_weight_i;");
node_shader_write_frag(kong, "basecol += texpaint_sample.rgb * texpaint_sample.a * blur_weight_i;");
node_shader_write_frag(kong, "var texpaint_pack_sample: float4 = sample(texpaint_pack_undo, sampler_linear, tex_coord_inp + float2(blur_step * float(i "
node_shader_write_frag(kong, "var texpaint_pack_sample: float4 = sample(texpaint_pack_ref, sampler_linear, tex_coord_inp + float2(blur_step * float(i "
"- 7), 0.0)) * blur_weight_i;");
node_shader_write_frag(kong, "roughness += texpaint_pack_sample.g;");
node_shader_write_frag(kong, "metallic += texpaint_pack_sample.b;");
node_shader_write_frag(kong, "occlusion += texpaint_pack_sample.r;");
node_shader_write_frag(kong, "height += texpaint_pack_sample.a;");
node_shader_write_frag(
kong, "nortan += sample(texpaint_nor_undo, sampler_linear, tex_coord_inp + float2(blur_step * float(i - 7), 0.0)).rgb * blur_weight_i;");
kong, "nortan += sample(texpaint_nor_ref, sampler_linear, tex_coord_inp + float2(blur_step * float(i - 7), 0.0)).rgb * blur_weight_i;");
node_shader_write_frag(kong, "}");
// Y
node_shader_write_frag(kong, "for (var j: int = 0; j <= 14; j += 1) {");
node_shader_write_frag(kong,
"var texpaint_sample: float4 = sample(texpaint_undo, sampler_linear, tex_coord_inp + float2(0.0, blur_step * float(j - 7)));");
"var texpaint_sample: float4 = sample(texpaint_ref, sampler_linear, tex_coord_inp + float2(0.0, blur_step * float(j - 7)));");
node_shader_write_frag(kong, "var blur_weight_j: float = get_blur_tool_weight(j);");
node_shader_write_frag(kong, "opacity += texpaint_sample.a * blur_weight_j;");
node_shader_write_frag(kong, "basecol += texpaint_sample.rgb * texpaint_sample.a * blur_weight_j;");
node_shader_write_frag(kong, "var texpaint_pack_sample: float4 = sample(texpaint_pack_undo, sampler_linear, tex_coord_inp + float2(0.0, blur_step * "
node_shader_write_frag(kong, "var texpaint_pack_sample: float4 = sample(texpaint_pack_ref, sampler_linear, tex_coord_inp + float2(0.0, blur_step * "
"float(j - 7))) * blur_weight_j;");
node_shader_write_frag(kong, "roughness += texpaint_pack_sample.g;");
node_shader_write_frag(kong, "metallic += texpaint_pack_sample.b;");
node_shader_write_frag(kong, "occlusion += texpaint_pack_sample.r;");
node_shader_write_frag(kong, "height += texpaint_pack_sample.a;");
node_shader_write_frag(
kong, "nortan += sample(texpaint_nor_undo, sampler_linear, tex_coord_inp + float2(0.0, blur_step * float(j - 7))).rgb * blur_weight_j;");
kong, "nortan += sample(texpaint_nor_ref, sampler_linear, tex_coord_inp + float2(0.0, blur_step * float(j - 7))).rgb * blur_weight_j;");
node_shader_write_frag(kong, "}");
}
node_shader_write_frag(kong, "var blur_src_alpha: float = opacity;");
+24 -11
View File
@@ -195,6 +195,14 @@ node_shader_context_t *make_paint_run_context(material_t *data, material_context
bool uv_island_fill = g_context->tool == TOOL_TYPE_FILL && g_context->fill_type == FILL_TYPE_UV_ISLAND;
bool decal = context_is_decal();
bool accum = g_context->tool == TOOL_TYPE_BLUR;
char *tex_src = accum ? "texpaint_ref" : "texpaint_undo";
char *tex_nor_src = accum ? "texpaint_nor_ref" : "texpaint_nor_undo";
char *tex_pack_src = accum ? "texpaint_pack_ref" : "texpaint_pack_undo";
char *tex_src_link = accum ? "_texpaint_ref" : "_texpaint_undo";
char *tex_nor_link = accum ? "_texpaint_nor_ref" : "_texpaint_nor_undo";
char *tex_pack_link = accum ? "_texpaint_pack_ref" : "_texpaint_pack_undo";
char *tuv = g_context->layer->uv_map == 1 ? "input.tex1" : "input.tex";
if (is_atlas) {
node_shader_add_constant(kong, "atlas_transform: float3", "_atlas_transform");
@@ -316,9 +324,9 @@ node_shader_context_t *make_paint_run_context(material_t *data, material_context
if (g_context->tool == TOOL_TYPE_CLONE || g_context->tool == TOOL_TYPE_BLUR) {
node_shader_add_texture(kong, "gbuffer2", NULL);
node_shader_add_constant(kong, "gbuffer_size: float2", "_gbuffer_size");
node_shader_add_texture(kong, "texpaint_undo", "_texpaint_undo");
node_shader_add_texture(kong, "texpaint_nor_undo", "_texpaint_nor_undo");
node_shader_add_texture(kong, "texpaint_pack_undo", "_texpaint_pack_undo");
node_shader_add_texture(kong, tex_src, tex_src_link);
node_shader_add_texture(kong, tex_nor_src, tex_nor_link);
node_shader_add_texture(kong, tex_pack_src, tex_pack_link);
if (g_context->tool == TOOL_TYPE_CLONE) {
make_clone_run(kong);
@@ -495,11 +503,16 @@ node_shader_context_t *make_paint_run_context(material_t *data, material_context
node_shader_write_frag(kong, "sample_tc.y = 1.0 - sample_tc.y;");
node_shader_add_texture(kong, "paintmask", NULL);
node_shader_write_frag(kong, "var sample_mask: float = sample_lod(paintmask, sampler_linear, sample_tc, 0.0).r;");
node_shader_write_frag(kong, "var base_str: float = max(str, sample_mask);");
node_shader_write_frag(kong, "str = base_str + str * (1.0 - base_str) * 0.1;");
if (accum) {
node_shader_write_frag(kong, "str *= 0.5;");
}
else {
node_shader_write_frag(kong, "var base_str: float = max(str, sample_mask);");
node_shader_write_frag(kong, "str = base_str + str * (1.0 - base_str) * 0.1;");
}
node_shader_add_texture(kong, "texpaint_undo", "_texpaint_undo");
node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_undo, sampler_linear, sample_tc, 0.0);");
node_shader_add_texture(kong, tex_src, tex_src_link);
node_shader_write_frag(kong, string_tmp("var sample_undo: float4 = sample_lod(%s, sampler_linear, sample_tc, 0.0);", tex_src));
f32 matid = g_context->material->id / 255.0;
if (g_context->picker_paint_mask) {
@@ -532,10 +545,10 @@ node_shader_context_t *make_paint_run_context(material_t *data, material_context
}
// Output
node_shader_add_texture(kong, "texpaint_nor_undo", "_texpaint_nor_undo");
node_shader_add_texture(kong, "texpaint_pack_undo", "_texpaint_pack_undo");
node_shader_write_frag(kong, "var sample_nor_undo: float4 = sample_lod(texpaint_nor_undo, sampler_linear, sample_tc, 0.0);");
node_shader_write_frag(kong, "var sample_pack_undo: float4 = sample_lod(texpaint_pack_undo, sampler_linear, sample_tc, 0.0);");
node_shader_add_texture(kong, tex_nor_src, tex_nor_link);
node_shader_add_texture(kong, tex_pack_src, tex_pack_link);
node_shader_write_frag(kong, string_tmp("var sample_nor_undo: float4 = sample_lod(%s, sampler_linear, sample_tc, 0.0);", tex_nor_src));
node_shader_write_frag(kong, string_tmp("var sample_pack_undo: float4 = sample_lod(%s, sampler_linear, sample_tc, 0.0);", tex_pack_src));
bool is_mask = slot_layer_is_mask(g_context->layer);
if (g_context->tool == TOOL_TYPE_ERASER && !is_mask) {
+47
View File
@@ -169,6 +169,49 @@ void render_path_paint_commands_particle(i32 tid, char *texpaint, bool is_mask)
}
}
static void render_path_paint_ref_target(char *name, char *format) {
render_target_t *rt = any_map_get(render_path_render_targets, name);
if (rt != NULL && (rt->width != config_get_texture_res_x() || rt->height != config_get_texture_res_y() || !string_equals(rt->format, format))) {
gpu_delete_texture(rt->_image);
map_delete(render_path_render_targets, name);
rt = NULL;
}
if (rt == NULL) {
render_target_t *t = render_target_create();
t->name = name;
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = format;
render_path_create_render_target(t);
}
}
static void render_path_paint_ref_snapshot(i32 tid, bool is_mask) {
if (is_mask) {
render_path_paint_ref_target("texpaint_ref", "RGBA32");
render_path_set_target("texpaint_ref", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
render_path_bind_target(string_tmp("texpaint%d", tid), "tex");
render_path_draw_shader("Scene/copy_pass/copy_pass");
return;
}
char *format = base_bits_handle->i == TEXTURE_BITS_BITS8 ? "RGBA32" : base_bits_handle->i == TEXTURE_BITS_BITS16 ? "RGBA64" : "RGBA128";
render_path_paint_ref_target("texpaint_ref", format);
render_path_paint_ref_target("texpaint_nor_ref", format);
render_path_paint_ref_target("texpaint_pack_ref", format);
string_array_t *additional = any_array_create_from_raw_tmp(
(void *[]){
"texpaint_nor_ref",
"texpaint_pack_ref",
},
2);
render_path_set_target("texpaint_ref", additional, NULL, GPU_CLEAR_NONE, 0, 0.0);
render_path_bind_target(string_tmp("texpaint%d", tid), "tex0");
render_path_bind_target(string_tmp("texpaint_nor%d", tid), "tex1");
render_path_bind_target(string_tmp("texpaint_pack%d", tid), "tex2");
char *pipe = string_equals(format, "RGBA32") ? "copy_mrt3_pass" : string_equals(format, "RGBA64") ? "copy_mrt3RGBA64_pass" : "copy_mrt3RGBA128_pass";
render_path_draw_shader(string_tmp("Scene/copy_mrt3_pass/%s", pipe));
}
void render_path_paint_commands_paint(bool dilation) {
i32 tid = g_context->layer->id;
@@ -418,6 +461,10 @@ void render_path_paint_commands_paint(bool dilation) {
bool read_tc = (g_context->tool == TOOL_TYPE_FILL && g_context->fill_type == FILL_TYPE_FACE) || g_context->tool == TOOL_TYPE_CLONE ||
g_context->tool == TOOL_TYPE_BLUR;
if (g_context->tool == TOOL_TYPE_BLUR) {
render_path_paint_ref_snapshot(tid, is_mask);
}
if (g_context->tool == TOOL_TYPE_PARTICLE) {
render_path_paint_commands_particle(tid, texpaint, is_mask);
}
+14 -5
View File
@@ -365,7 +365,7 @@ void uniforms_ext_cache_uv_map(void *_) {
util_uv_cache_uv_map();
}
static gpu_texture_t *_uniforms_ext_undo_target(char *name) {
static gpu_texture_t *_uniforms_ext_get_target(char *name) {
render_target_t *rt = any_map_get(render_path_render_targets, name);
if (rt == NULL) {
rt = any_map_get(render_path_render_targets, "empty_black");
@@ -376,18 +376,27 @@ static gpu_texture_t *_uniforms_ext_undo_target(char *name) {
gpu_texture_t *uniforms_ext_tex_link(object_t *object, material_data_t *mat, char *link) {
if (string_equals(link, "_texpaint_undo")) {
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
return _uniforms_ext_undo_target(string_tmp("texpaint_undo%d", i));
return _uniforms_ext_get_target(string_tmp("texpaint_undo%d", i));
}
else if (string_equals(link, "_texpaint_nor_undo")) {
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
return _uniforms_ext_undo_target(string_tmp("texpaint_nor_undo%d", i));
return _uniforms_ext_get_target(string_tmp("texpaint_nor_undo%d", i));
}
else if (string_equals(link, "_texpaint_pack_undo")) {
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
return _uniforms_ext_undo_target(string_tmp("texpaint_pack_undo%d", i));
return _uniforms_ext_get_target(string_tmp("texpaint_pack_undo%d", i));
}
else if (string_equals(link, "_texpaint_ref")) {
return _uniforms_ext_get_target("texpaint_ref");
}
else if (string_equals(link, "_texpaint_nor_ref")) {
return _uniforms_ext_get_target("texpaint_nor_ref");
}
else if (string_equals(link, "_texpaint_pack_ref")) {
return _uniforms_ext_get_target("texpaint_pack_ref");
}
else if (string_equals(link, "_texpaint_sculpt_undo")) {
return _uniforms_ext_undo_target("texpaint_sculpt_ref"); // Per-frame accumulation reference
return _uniforms_ext_get_target("texpaint_sculpt_ref"); // Per-frame accumulation reference
}
else if (string_equals(link, "_texcolorid")) {
if (g_project->_->assets->length == 0) {