sculpt: add grab mode
This commit is contained in:
@@ -125,6 +125,11 @@ typedef enum {
|
||||
UV_TYPE_PROJECT = 2,
|
||||
} uv_type_t;
|
||||
|
||||
typedef enum {
|
||||
SCULPT_TYPE_DRAW = 0,
|
||||
SCULPT_TYPE_GRAB = 1,
|
||||
} sculpt_type_t;
|
||||
|
||||
typedef enum {
|
||||
PICKER_MASK_NONE = 0,
|
||||
PICKER_MASK_MATERIAL = 1,
|
||||
|
||||
@@ -113,16 +113,16 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
|
||||
.compare_mode = "always",
|
||||
.cull_mode = "none",
|
||||
.vertex_elements = any_array_create_from_raw(
|
||||
(void *[]){
|
||||
GC_ALLOC_INIT(vertex_element_t, {.name = "pos", .data = "float2"}),
|
||||
},
|
||||
1),
|
||||
(void *[]){
|
||||
GC_ALLOC_INIT(vertex_element_t, {.name = "pos", .data = "float2"}),
|
||||
},
|
||||
1),
|
||||
.color_attachments = any_array_create_from_raw(
|
||||
(void *[]){
|
||||
"RGBA128",
|
||||
"R8",
|
||||
},
|
||||
2)});
|
||||
(void *[]){
|
||||
"RGBA128",
|
||||
"R8",
|
||||
},
|
||||
2)});
|
||||
node_shader_context_t *con_paint = node_shader_context_create(data, props);
|
||||
con_paint->data->color_writes_red = u8_array_create_from_raw(
|
||||
(u8[]){
|
||||
@@ -160,8 +160,10 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
|
||||
node_shader_t *kong = node_shader_context_make_kong(con_paint);
|
||||
bool decal = context_is_decal();
|
||||
bool particle = g_context->tool == TOOL_TYPE_PARTICLE;
|
||||
// Grab drags the vertices along with the cursor instead of displacing along the normal
|
||||
bool grab = g_context->tool == TOOL_TYPE_BRUSH && g_context->brush_sculpt == SCULPT_TYPE_GRAB;
|
||||
// Decal fill layer: displacement must be confined to the decal box projection
|
||||
bool decal_layer = g_context->layer->fill_material != NULL && g_context->layer->uv_type == UV_TYPE_PROJECT && g_context->tool == TOOL_TYPE_FILL;
|
||||
bool decal_layer = g_context->layer->fill_material != NULL && g_context->layer->uv_type == UV_TYPE_PROJECT && g_context->tool == TOOL_TYPE_FILL;
|
||||
|
||||
bool has_wposition = 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_PARTICLE || g_context->tool == TOOL_TYPE_FILL || decal;
|
||||
@@ -197,20 +199,51 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
|
||||
|
||||
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_PARTICLE || decal) {
|
||||
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");
|
||||
// node_shader_write_frag(kong, "var winp: float4 = float4(float2(constants.inp.x, 1.0 - constants.inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var winp: float4 = float4(float2(constants.inp.x, 1.0 - constants.inp.y) * 2.0 - 1.0, depth, 1.0);");
|
||||
node_shader_write_frag(kong, "winp = constants.invVP * winp;");
|
||||
node_shader_write_frag(kong, "winp.xyz = winp.xyz / winp.w;");
|
||||
if (grab) {
|
||||
// Anchor a camera-facing plane at the grab_start surface point
|
||||
node_shader_add_constant(kong, "grab_start: float2", "_grab_start");
|
||||
node_shader_write_frag(kong, "var grab_ndc: float2 = float2(constants.grab_start.x, 1.0 - constants.grab_start.y) * 2.0 - 1.0;");
|
||||
node_shader_write_frag(kong, "var grab_adepth: float = sample_lod(gbufferD, sampler_linear, constants.grab_start, 0.0).r;");
|
||||
node_shader_write_frag(kong, "var grab_anchor4: float4 = constants.invVP * float4(grab_ndc, grab_adepth, 1.0);");
|
||||
node_shader_write_frag(kong, "var grab_anchor: float3 = grab_anchor4.xyz / grab_anchor4.w;");
|
||||
node_shader_write_frag(kong, "var grab_near4: float4 = constants.invVP * float4(grab_ndc, 0.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var grab_far4: float4 = constants.invVP * float4(grab_ndc, 1.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var grab_plane_n: float3 = normalize(grab_far4.xyz / grab_far4.w - grab_near4.xyz / grab_near4.w);");
|
||||
// Intersect the cursor ray with the grab plane
|
||||
node_shader_write_frag(kong, "var winp_ndc: float2 = float2(constants.inp.x, 1.0 - constants.inp.y) * 2.0 - 1.0;");
|
||||
node_shader_write_frag(kong, "var winp_o4: float4 = constants.invVP * float4(winp_ndc, 0.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var winp_f4: float4 = constants.invVP * float4(winp_ndc, 1.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var winp_o: float3 = winp_o4.xyz / winp_o4.w;");
|
||||
node_shader_write_frag(kong, "var winp_d: float3 = normalize(winp_f4.xyz / winp_f4.w - winp_o);");
|
||||
node_shader_write_frag(kong,
|
||||
"var winp: float4 = float4(winp_o + winp_d * (dot(grab_anchor - winp_o, grab_plane_n) / dot(winp_d, grab_plane_n)), 1.0);");
|
||||
}
|
||||
else {
|
||||
node_shader_write_frag(kong, "var depth: float = sample_lod(gbufferD, sampler_linear, constants.inp.xy, 0.0).r;");
|
||||
node_shader_write_frag(kong, "var winp: float4 = float4(float2(constants.inp.x, 1.0 - constants.inp.y) * 2.0 - 1.0, depth, 1.0);");
|
||||
node_shader_write_frag(kong, "winp = constants.invVP * winp;");
|
||||
node_shader_write_frag(kong, "winp.xyz = winp.xyz / winp.w;");
|
||||
}
|
||||
node_shader_add_constant(kong, "W: float4x4", "_world_matrix");
|
||||
node_shader_write_attrib_frag(kong, "var read_undo: float4 = texpaint_sculpt_undo[uint2(uint(tex_coord.x * constants.texpaint_undo_size.x), "
|
||||
"uint(tex_coord.y * constants.texpaint_undo_size.y))];");
|
||||
node_shader_write_attrib_frag(kong, "var wposition: float3 = (constants.W * float4(read_undo.xyz, 1.0)).xyz;");
|
||||
node_shader_write_frag(kong, "var depthlast: float = sample_lod(gbufferD, sampler_linear, constants.inplast.xy, 0.0).r;");
|
||||
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;");
|
||||
if (grab) {
|
||||
node_shader_write_frag(kong, "var winpl_ndc: float2 = float2(constants.inplast.x, 1.0 - constants.inplast.y) * 2.0 - 1.0;");
|
||||
node_shader_write_frag(kong, "var winpl_o4: float4 = constants.invVP * float4(winpl_ndc, 0.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var winpl_f4: float4 = constants.invVP * float4(winpl_ndc, 1.0, 1.0);");
|
||||
node_shader_write_frag(kong, "var winpl_o: float3 = winpl_o4.xyz / winpl_o4.w;");
|
||||
node_shader_write_frag(kong, "var winpl_d: float3 = normalize(winpl_f4.xyz / winpl_f4.w - winpl_o);");
|
||||
node_shader_write_frag(
|
||||
kong, "var winplast: float4 = float4(winpl_o + winpl_d * (dot(grab_anchor - winpl_o, grab_plane_n) / dot(winpl_d, grab_plane_n)), 1.0);");
|
||||
}
|
||||
else {
|
||||
node_shader_write_frag(kong, "var depthlast: float = sample_lod(gbufferD, sampler_linear, constants.inplast.xy, 0.0).r;");
|
||||
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;");
|
||||
}
|
||||
|
||||
if (particle) {
|
||||
node_shader_add_constant(kong, "particle_hit: float3", "_particle_hit");
|
||||
@@ -616,6 +649,10 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
|
||||
else if (g_context->tool == TOOL_TYPE_ERASER) {
|
||||
node_shader_write_frag(kong, "output[0] = float4(sample_undo.rgb - n * disp * str, raw_undo.a);");
|
||||
}
|
||||
else if (grab) {
|
||||
node_shader_write_frag(kong, "var grab_delta: float3 = (winp.xyz - winplast.xyz) * falloff * opacity;");
|
||||
node_shader_write_frag(kong, "output[0] = float4(sample_undo.rgb + grab_delta, raw_undo.a);");
|
||||
}
|
||||
else {
|
||||
node_shader_write_frag(kong, string("var sculpt_disp: float = %s;", sculpt_blend_mode(kong, g_context->brush_blending, "0.0", "disp.x", "str")));
|
||||
node_shader_write_frag(kong, "output[0] = float4(sample_undo.rgb + n * sculpt_disp, raw_undo.a);");
|
||||
@@ -1043,7 +1080,6 @@ void render_path_sculpt_commands() {
|
||||
}
|
||||
|
||||
void render_path_sculpt_snapshot_gbuffer() {
|
||||
// Freeze the current surface (depth + packed normal) as the reference the displacement pass reads
|
||||
render_path_set_target("gbuffer0_undo", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
|
||||
render_path_bind_target("gbuffer0", "tex");
|
||||
render_path_draw_shader("Scene/copy_pass/copyRGBA64_pass");
|
||||
@@ -1060,6 +1096,8 @@ void render_path_sculpt_begin() {
|
||||
if (history_push_undo && history_undo_layers != NULL) {
|
||||
history_paint();
|
||||
render_path_sculpt_snapshot_gbuffer();
|
||||
g_context->grab_start_x = g_context->paint_vec.x;
|
||||
g_context->grab_start_y = g_context->paint_vec.y;
|
||||
}
|
||||
sculpt_push_undo = false;
|
||||
}
|
||||
|
||||
@@ -239,6 +239,8 @@ typedef struct context {
|
||||
f32 clone_start_y;
|
||||
f32 clone_delta_x;
|
||||
f32 clone_delta_y;
|
||||
f32 grab_start_x;
|
||||
f32 grab_start_y;
|
||||
bool show_compass;
|
||||
i32 project_type;
|
||||
f32 last_paint_vec_x;
|
||||
@@ -362,6 +364,7 @@ typedef struct context {
|
||||
f32 brush_lazy_x;
|
||||
f32 brush_lazy_y;
|
||||
uv_type_t brush_paint;
|
||||
sculpt_type_t brush_sculpt;
|
||||
f32 brush_angle_reject_dot;
|
||||
bake_type_t bake_type;
|
||||
bake_axis_t bake_axis;
|
||||
|
||||
@@ -384,7 +384,7 @@ void ui_header_draw_tool_properties() {
|
||||
g_context->brush_hardness = ui_slider(h, tr("Hardness"), 0.0, 1.0, true, 100.0, true, UI_ALIGN_RIGHT, true);
|
||||
}
|
||||
|
||||
if (g_context->tool != TOOL_TYPE_ERASER) {
|
||||
if (g_context->tool != TOOL_TYPE_ERASER && g_config->workflow != WORKFLOW_SCULPT) {
|
||||
ui_handle_t *brush_blending_handle = ui_handle(__ID__);
|
||||
brush_blending_handle->i = g_context->brush_blending;
|
||||
string_array_t *brush_blending_combo = any_array_create_from_raw(
|
||||
@@ -415,7 +415,7 @@ void ui_header_draw_tool_properties() {
|
||||
}
|
||||
}
|
||||
|
||||
if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_FILL) {
|
||||
if ((g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_FILL) && g_config->workflow != WORKFLOW_SCULPT) {
|
||||
ui_handle_t *paint_handle = ui_handle(__ID__);
|
||||
string_array_t *texcoord_combo = any_array_create_from_raw(
|
||||
(void *[]){
|
||||
@@ -430,6 +430,20 @@ void ui_header_draw_tool_properties() {
|
||||
}
|
||||
}
|
||||
|
||||
if (g_context->tool == TOOL_TYPE_BRUSH && g_config->workflow == WORKFLOW_SCULPT) {
|
||||
ui_handle_t *sculpt_handle = ui_handle(__ID__);
|
||||
string_array_t *mode_combo = any_array_create_from_raw(
|
||||
(void *[]){
|
||||
tr("Draw"),
|
||||
tr("Grab"),
|
||||
},
|
||||
2);
|
||||
g_context->brush_sculpt = ui_combo(sculpt_handle, mode_combo, tr("Mode"), false, UI_ALIGN_LEFT, true);
|
||||
if (sculpt_handle->changed) {
|
||||
make_material_parse_paint_material(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_context->tool == TOOL_TYPE_TEXT) {
|
||||
ui_handle_t *h = ui_handle(__ID__);
|
||||
h->text = string_copy(g_context->text_tool_text);
|
||||
|
||||
@@ -173,6 +173,9 @@ vec2_t uniforms_ext_vec2_link(object_t *object, material_data_t *mat, char *link
|
||||
else if (string_equals(link, "_clone_delta")) {
|
||||
return (vec2_t){g_context->clone_delta_x, g_context->clone_delta_y};
|
||||
}
|
||||
else if (string_equals(link, "_grab_start")) {
|
||||
return (vec2_t){g_context->grab_start_x, g_context->grab_start_y};
|
||||
}
|
||||
else if (string_equals(link, "_texpaint_size")) {
|
||||
return (vec2_t){config_get_texture_res_x(), config_get_texture_res_y()};
|
||||
}
|
||||
@@ -202,10 +205,10 @@ vec4_t uniforms_ext_vec3_link(object_t *object, material_data_t *mat, char *link
|
||||
// Discard first paint for directional brush (no prev position yet)
|
||||
bool allow_paint = g_context->prev_paint_vec_x > 0 && g_context->prev_paint_vec_y > 0 &&
|
||||
(g_context->prev_paint_vec_x != g_context->paint_vec.x || g_context->prev_paint_vec_y != g_context->paint_vec.y);
|
||||
f32 x = g_context->paint_vec.x;
|
||||
f32 y = g_context->paint_vec.y;
|
||||
f32 lastx = g_context->prev_paint_vec_x;
|
||||
f32 lasty = g_context->prev_paint_vec_y;
|
||||
f32 x = g_context->paint_vec.x;
|
||||
f32 y = g_context->paint_vec.y;
|
||||
f32 lastx = g_context->prev_paint_vec_x;
|
||||
f32 lasty = g_context->prev_paint_vec_y;
|
||||
if (g_context->paint2d) {
|
||||
x = uniforms_ext_vec2d(x);
|
||||
lastx = uniforms_ext_vec2d(lastx);
|
||||
@@ -311,10 +314,10 @@ mat4_t uniforms_ext_mat4_link(object_t *object, material_data_t *mat, char *link
|
||||
transform_t *t = object->transform;
|
||||
mat4_t W = t->world;
|
||||
vec4_t axes[3] = {
|
||||
vec4_norm((vec4_t){W.m00, W.m10, W.m20, 0.0}),
|
||||
vec4_norm((vec4_t){W.m01, W.m11, W.m21, 0.0}),
|
||||
vec4_norm((vec4_t){W.m02, W.m12, W.m22, 0.0}),
|
||||
};
|
||||
vec4_norm((vec4_t){W.m00, W.m10, W.m20, 0.0}),
|
||||
vec4_norm((vec4_t){W.m01, W.m11, W.m21, 0.0}),
|
||||
vec4_norm((vec4_t){W.m02, W.m12, W.m22, 0.0}),
|
||||
};
|
||||
f32 scale[3] = {t->scale.x, t->scale.y, t->scale.z};
|
||||
mat4_t F = mat4_identity();
|
||||
for (i32 i = 0; i < 3; ++i) {
|
||||
|
||||
Reference in New Issue
Block a user