paint: sculpt layer fixes

This commit is contained in:
luboslenco
2026-04-15 10:10:17 +02:00
parent 5f974b598b
commit 2c07730e96
7 changed files with 67 additions and 19 deletions
+3 -2
View File
@@ -2247,7 +2247,7 @@ void ui_base_set_viewport_col(i32 col) {
void base_update_workspace() {
config_init_layout();
if (g_config->workspace == WORKSPACE_PAINT_3D || g_config->workspace == WORKSPACE_SCULPT) {
if (g_config->workspace == WORKSPACE_PAINT_3D) {
base_view3d_show = true;
ui_menubar_tab->i = 0;
ui_view2d_show = false;
@@ -2297,7 +2297,8 @@ void base_update_workflow() {
ui_node_array_t *nodes = project_materials->buffer[i]->canvas->nodes;
for (i32 j = 0; j < nodes->length; ++j) {
if (string_equals(nodes->buffer[j]->type, "OUTPUT_MATERIAL_PBR")) {
nodes->buffer[j]->inputs->length = g_config->workflow == WORKFLOW_BASE ? 2 : 9;
nodes->buffer[j]->inputs->length = g_config->workflow == WORKFLOW_PBR ? 9 : 2;
nodes->buffer[j]->inputs->buffer[0]->name = g_config->workflow == WORKFLOW_SCULPT ? tr("Displacement") : tr("Base Color");
}
}
}
+4 -4
View File
@@ -74,13 +74,13 @@ typedef enum {
WORKSPACE_PAINT_2D = 1,
WORKSPACE_NODES = 2,
WORKSPACE_SCRIPT = 3,
WORKSPACE_SCULPT = 4,
WORKSPACE_PLAYER = 5,
WORKSPACE_PLAYER = 4,
} workspace_t;
typedef enum {
WORKFLOW_PBR = 0,
WORKFLOW_BASE = 1,
WORKFLOW_PBR = 0,
WORKFLOW_BASE = 1,
WORKFLOW_SCULPT = 2,
} workflow_t;
typedef enum {
+47 -11
View File
@@ -78,6 +78,8 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
node_shader_write_vert(kong, "output.tex_coord.y = 1.0 - output.tex_coord.y;");
node_shader_write_vert(kong, "output.pos = float4(input.pos.xy, 0.0, 1.0);");
node_shader_write_attrib_frag(kong, "var tex_coord: float2 = input.tex_coord;");
node_shader_write_attrib_frag(kong, "var sculpt_uv: float2 = tex_coord;");
node_shader_add_constant(kong, "inp: float4", "_input_brush");
node_shader_add_constant(kong, "inplast: float4", "_input_brush_last");
node_shader_add_texture(kong, "gbufferD", NULL);
@@ -86,8 +88,8 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
node_shader_add_constant(kong, "brush_opacity: float", "_brush_opacity");
node_shader_add_constant(kong, "brush_hardness: float", "_brush_hardness");
if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_ERASER || g_context->tool == TOOL_TYPE_CLONE ||
g_context->tool == TOOL_TYPE_BLUR || g_context->tool == TOOL_TYPE_SMUDGE || g_context->tool == TOOL_TYPE_PARTICLE || decal) {
if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_ERASER || g_context->tool == TOOL_TYPE_CLONE || g_context->tool == TOOL_TYPE_BLUR ||
g_context->tool == TOOL_TYPE_SMUDGE || g_context->tool == TOOL_TYPE_PARTICLE || decal) {
node_shader_write_frag(kong, "var dist: float = 0.0;");
node_shader_write_frag(kong, "var depth: float = sample_lod(gbufferD, sampler_linear, constants.inp.xy, 0.0).r;");
node_shader_add_constant(kong, "invVP: float4x4", "_inv_view_proj_matrix");
@@ -105,8 +107,11 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
node_shader_write_frag(kong, "var winplast: float4 = float4(float2(constants.inplast.x, 1.0 - constants.inplast.y) * 2.0 - 1.0, depthlast, 1.0);");
node_shader_write_frag(kong, "winplast = constants.invVP * winplast;");
node_shader_write_frag(kong, "winplast.xyz = winplast.xyz / winplast.w;");
node_shader_write_frag(kong, "dist = distance(wposition.xyz, winp.xyz);");
node_shader_write_frag(kong, "if (dist > constants.brush_radius) { discard; }");
if (!decal) {
node_shader_write_frag(kong, "dist = distance(wposition.xyz, winp.xyz);");
node_shader_write_frag(kong, "if (dist > constants.brush_radius) { discard; }");
}
}
else if (g_context->tool == TOOL_TYPE_FILL) {
node_shader_write_frag(kong, "var dist: float = 0.0;");
@@ -116,11 +121,41 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
kong, "var wposition: float3 = (constants.W * texpaint_sculpt_undo[uint2(uint(tex_coord.x * 2048.0), uint(tex_coord.y * 2048.0))]).xyz;");
}
parser_material_parse_height = true;
parser_material_parse_height_as_channel = true;
shader_out_t *sout = parser_material_parse(g_context->material->canvas, con_paint, kong, matcon);
char *height = sout->out_height;
node_shader_write_frag(kong, string("var height: float = %s;", height));
if (decal) {
// Project wposition to screen-space and compute decal tex_coord
node_shader_add_constant(kong, "VP: float4x4", "_view_proj_matrix");
node_shader_write_attrib_frag(kong, "var decal_ndc: float4 = constants.VP * float4(wposition.xyz, 1.0);");
node_shader_write_attrib_frag(kong, "var sp: float3 = decal_ndc.xyz / decal_ndc.w;");
node_shader_write_attrib_frag(kong, "sp.x = sp.x * 0.5 + 0.5;");
node_shader_write_attrib_frag(kong, "sp.y = sp.y * 0.5 + 0.5;");
node_shader_write_attrib_frag(kong, "sp.y = 1.0 - sp.y;");
node_shader_add_constant(kong, "aspect_ratio: float", "_aspect_ratio_window");
node_shader_add_constant(kong, "decal_mask: float4", "_decal_mask");
node_shader_write_attrib_frag(kong, "var uvsp: float2 = sp.xy;");
node_shader_write_attrib_frag(kong, "uvsp = uvsp - constants.decal_mask.xy;");
node_shader_write_attrib_frag(kong, "uvsp.x *= constants.aspect_ratio;");
node_shader_write_attrib_frag(kong, "uvsp = uvsp * (0.21 / (constants.decal_mask.w * 0.9));");
f32 angle = g_context->brush_angle + g_context->brush_nodes_angle;
if (angle != 0.0) {
node_shader_add_constant(kong, "brush_angle: float2", "_brush_angle");
node_shader_write_attrib_frag(kong, "uvsp = float2(uvsp.x * constants.brush_angle.x - uvsp.y * constants.brush_angle.y, uvsp.x * "
"constants.brush_angle.y + uvsp.y * constants.brush_angle.x);");
}
node_shader_add_constant(kong, "brush_scale_x: float", "_brush_scale_x");
node_shader_write_attrib_frag(kong, "uvsp.x *= constants.brush_scale_x;");
node_shader_write_attrib_frag(kong, "uvsp += float2(0.5, 0.5);");
node_shader_write_attrib_frag(kong, "if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) { discard; }");
node_shader_add_constant(kong, "brush_scale: float", "_brush_scale");
node_shader_write_attrib_frag(kong, "tex_coord = uvsp * constants.brush_scale;");
}
// parser_material_parse may add vertex elements
i32 velen = con_paint->data->vertex_elements->length;
parser_material_parse_height = true;
parser_material_parse_height_as_channel = true;
shader_out_t *sout = parser_material_parse(g_context->material->canvas, con_paint, kong, matcon);
con_paint->data->vertex_elements->length = velen;
node_shader_write_frag(kong, string("var height: float = %s.r;", sout->out_basecol));
if (kong->frag_bposition) {
kong->frag_bposition = false;
@@ -128,11 +163,12 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
}
node_shader_write_frag(kong, "var basecol: float3 = float3(1.0, 1.0, 1.0);");
node_shader_write_frag(kong, "var opacity: float = 1.0;");
node_shader_write_frag(kong, string("var opacity: float = %s;", sout->out_opacity));
node_shader_write_frag(kong, "if (opacity == 0.0) { discard; }");
node_shader_write_frag(kong, "var str: float = clamp((constants.brush_radius - dist) * constants.brush_hardness * 1.0, 0.0, 1.0) * opacity;");
node_shader_add_texture(kong, "texpaint_sculpt_undo", "_texpaint_sculpt_undo");
node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_sculpt_undo, sampler_linear, tex_coord, 0.0);");
node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_sculpt_undo, sampler_linear, sculpt_uv, 0.0);");
node_shader_write_frag(kong, "if (sample_undo.r == 0.0 && sample_undo.g == 0.0 && sample_undo.b == 0.0) { discard; }");
node_shader_add_function(kong, str_octahedron_wrap);
node_shader_add_texture(kong, "gbuffer0_undo", NULL);
+1
View File
@@ -341,6 +341,7 @@ void project_new(bool reset_layers) {
if (in_use)
draw_begin(current, false, 0);
base_update_workflow();
project_set_default_envmap();
context_init_tool();
viewport_reset();
+1 -1
View File
@@ -982,7 +982,7 @@ void tab_layers_button_new_sculpt_layer(void *_) {
void tab_layers_button_new_menu() {
slot_layer_t *l = g_context->layer;
if (g_config->workspace == WORKSPACE_SCULPT) {
if (g_config->workflow == WORKFLOW_SCULPT) {
if (ui_menu_button(tr("Sculpt Layer"), "", ICON_PAINT)) {
sys_notify_on_next_frame(&tab_layers_button_new_sculpt_layer, NULL);
}
+6
View File
@@ -28,6 +28,7 @@ void tab_materials_update_material() {
if (decal) {
util_render_make_decal_preview();
}
base_update_workflow();
}
void tab_materials_draw_slots_duplicate(void *_) {
@@ -103,6 +104,11 @@ void tab_materials_draw_slots_menu() {
tab_materials_delete_material(m);
}
if (g_config->experimental && ui_menu_button(tr("Inspect as Script"), "", ICON_SEARCH)) {
node_shader_dump_to_script = true;
context_select_material(i);
}
ui_handle_t *base_handle = ui_nest(ui_handle(__ID__), m->id);
if (base_handle->init) {
base_handle->b = m->paint_base;
+5 -1
View File
@@ -784,7 +784,6 @@ void ui_menubar_draw_category_items() {
4);
if (g_config->experimental) {
any_array_push(modes, tr("Sculpt"));
any_array_push(modes, tr("Player"));
}
@@ -810,6 +809,11 @@ void ui_menubar_draw_category_items() {
tr("Base"),
},
2);
if (g_config->experimental) {
any_array_push(workflow_items, tr("Sculpt"));
}
g_config->workflow = ui_inline_radio(workflow_handle, workflow_items, UI_ALIGN_LEFT);
if (workflow_handle->changed) {
g_config->workflow = workflow_handle->i;