From 46839d1f4386f3639caaef6d6c00e9503c9ca396 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Thu, 20 Oct 2022 15:19:54 -0700 Subject: sculpt-dev: Roll mapping * Fixed errors in second derivative of stroke spline * Fix error on surfaces at an oblique angle to the viewport * Fix roll mapping not working for sculpt texture paint --- source/blender/blenkernel/BKE_brush_engine.h | 1 + source/blender/blenlib/BLI_arc_spline.hh | 43 ++++++++--- source/blender/editors/sculpt_paint/paint_intern.h | 10 ++- .../blender/editors/sculpt_paint/paint_stroke.cc | 86 ++++++++++++++++++++-- source/blender/editors/sculpt_paint/sculpt.c | 25 +++---- .../editors/sculpt_paint/sculpt_paint_color.c | 5 +- 6 files changed, 133 insertions(+), 37 deletions(-) diff --git a/source/blender/blenkernel/BKE_brush_engine.h b/source/blender/blenkernel/BKE_brush_engine.h index 6c3a3384deb..93be0de672f 100644 --- a/source/blender/blenkernel/BKE_brush_engine.h +++ b/source/blender/blenkernel/BKE_brush_engine.h @@ -207,6 +207,7 @@ typedef struct BrushCommand { struct BrushChannelSet *params_mapped; /* with pressure etc applied */ BrushTex *texture_slots[MAKE_BRUSHTEX_SLOTS]; /* currently unused */ + float initial_radius; } BrushCommand; typedef struct BrushCommandList { diff --git a/source/blender/blenlib/BLI_arc_spline.hh b/source/blender/blenlib/BLI_arc_spline.hh index 8f88c281b5c..9c7078a4970 100644 --- a/source/blender/blenlib/BLI_arc_spline.hh +++ b/source/blender/blenlib/BLI_arc_spline.hh @@ -10,6 +10,8 @@ #include #include +//#define FINITE_DIFF + /* * Arc length parameterized spline library. */ @@ -263,7 +265,7 @@ template class CubicBezier { #endif } - Vector evaluate(Float s) + inline Vector evaluate(Float s) { Float t = arc_to_t(s); Vector r; @@ -298,13 +300,31 @@ template class CubicBezier { Vector derivative2(Float s) { +#ifdef FINITE_DIFF + const Float df = 0.0005; + Float s1, s2; + + if (s >= 1.0 - df) { + s1 = s - df; + s2 = s; + } + else { + s1 = s; + s2 = s + df; + } + + Vector a = derivative(s1); + Vector b = derivative(s2); + + return (b - a) / df; +#else Float t = arc_to_t(s); Vector r; Float dx = dcubic(ps[0][0], ps[1][0], ps[2][0], ps[3][0], t); - Float d2x = dcubic(ps[0][0], ps[1][0], ps[2][0], ps[3][0], t); + Float d2x = d2cubic(ps[0][0], ps[1][0], ps[2][0], ps[3][0], t); Float dy = dcubic(ps[0][1], ps[1][1], ps[2][1], ps[3][1], t); - Float d2y = dcubic(ps[0][1], ps[1][1], ps[2][1], ps[3][1], t); + Float d2y = d2cubic(ps[0][1], ps[1][1], ps[2][1], ps[3][1], t); /* comment: arc length second derivative; @@ -344,7 +364,7 @@ template class CubicBezier { r[0] = ((d2x * dy - d2y * dx) * dy) / div; r[1] = (-(d2x * dy - d2y * dx) * dx) / div; } - else if (constexpr(axes == 3)) { + else if constexpr (axes == 3) { Float dz = dcubic(ps[0][2], ps[1][2], ps[2][2], ps[3][2], t); Float d2z = d2cubic(ps[0][2], ps[1][2], ps[2][2], ps[3][2], t); @@ -361,6 +381,7 @@ template class CubicBezier { } return r; +#endif } Float curvature(Float s) @@ -510,12 +531,8 @@ template class BezierSpline { } } - Vector evaluate(Float s) + inline Vector evaluate(Float s) { - if (segments.size() == 0) { - return Vector(); - } - if (s == 0.0) { return segments[0].bezier.ps[0]; } @@ -565,8 +582,16 @@ template class BezierSpline { return seg->bezier.curvature(s - seg->start); } + /* Find the closest point on the spline. Uses a bisecting root finding approach. + * Note: in thoery we could split the spline into quadratic segments and solve + * for the closest point directy. + */ Vector closest_point(const Vector p, Float &r_s, Vector &r_tan, Float &r_dis) { + if (segments.size() == 0) { + return Vector(); + } + const int steps = 5; Float s = 0.0, ds = length / steps; Float mindis = FLT_MAX; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 871d7de0f84..8fbf2ff1804 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -128,7 +128,8 @@ typedef struct PaintStroke { /* space distance covered so far */ int stroke_sample_index; float stroke_distance; - float stroke_distance_t; // divided by brush radius + float stroke_distance_t; /* Divided by brush radius. */ + float stroke_distance_world; /* Created by .world_spline. */ /* Set whether any stroke step has yet occurred * e.g. in sculpt mode, stroke doesn't start until cursor @@ -656,8 +657,11 @@ void paint_project_spline(struct bContext *C, struct StrokeCache *cache, struct PaintStroke *stroke); ; -void paint_calc_cubic_uv_v3( - PaintStroke *stroke, struct StrokeCache *cache, const float co[3], float r_out[3], float r_tan[3]); +void paint_calc_cubic_uv_v3(PaintStroke *stroke, + struct StrokeCache *cache, + const float co[3], + float r_out[3], + float r_tan[3]); float paint_stroke_spline_length(PaintStroke *stroke); #ifdef __cplusplus diff --git a/source/blender/editors/sculpt_paint/paint_stroke.cc b/source/blender/editors/sculpt_paint/paint_stroke.cc index f4043d6ea8f..388140903ce 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.cc +++ b/source/blender/editors/sculpt_paint/paint_stroke.cc @@ -112,7 +112,7 @@ static void paint_brush_cubic_vis(const bContext *C, ARegion *region, void *user immVertex3fv(pos, ss->cache->world_cubic[3]); immEnd(); - const int steps = 256; + int steps = 256; float t = 0.0f, dt = 1.0f / (float)(steps - 1); immUniformColor4ub(45, 75, 255, 255); @@ -145,8 +145,43 @@ static void paint_brush_cubic_vis(const bContext *C, ARegion *region, void *user } immEnd(); - immUniformColor4ub(0, 255, 25, 55); +# if 1 + + s = 0.0f; + ds = 0.1f; + steps = (int)floorf(stroke->world_spline->length / ds + 0.5f); + + immUniformColor4ub(255, 0, 0, 170); + immBegin(GPU_PRIM_POINTS, steps); + for (int i = 0; i < steps; i++, s += ds) { + float3 co = stroke->world_spline->evaluate(s); + mul_v3_m4v3(co, ob->obmat, co); + + immVertex3fv(pos, co); + } + + immEnd(); + + s = 0.0f; + immUniformColor4ub(255, 0, 0, 170); + immBegin(GPU_PRIM_LINES, steps * 2); + for (int i = 0; i < steps; i++, s += ds) { + float3 co = stroke->world_spline->evaluate(s); + float3 dv2 = stroke->world_spline->derivative2(s); + + mul_v3_m4v3(co, ob->obmat, co); + + immVertex3fv(pos, co); + + co += dv2; + immVertex3fv(pos, co); + } + immEnd(); + +# endif + + immUniformColor4ub(0, 255, 25, 55); for (int is_points = 0; is_points < 2; is_points++) { immBegin(is_points ? GPU_PRIM_POINTS : GPU_PRIM_LINE_STRIP, stroke->num_points); for (int i = 0; i < stroke->num_points; i++) { @@ -366,10 +401,37 @@ static void paint_stroke_add_point(const Paint *paint, } } -static void paint_brush_make_cubic(PaintStroke *stroke) +static void paint_project_cubic(bContext *C, + PaintStroke *stroke, + blender::CubicBezier &bezier2d, + blender::CubicBezier &bezier3d) +{ + Object *ob = CTX_data_active_object(C); + float2 mvals[4]; + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 2; j++) { + mvals[i][j] = bezier2d.ps[i][j]; + } + } + + for (int i = 0; i < 4; i++) { + if (!SCULPT_stroke_get_location(C, bezier3d.ps[i], mvals[i], true)) { + ED_view3d_win_to_3d(CTX_wm_view3d(C), + CTX_wm_region(C), + stroke->last_world_space_position, + mvals[i], + bezier3d.ps[i]); + } + } + + bezier3d.update(); +} + +static void paint_brush_make_cubic(bContext *C, PaintStroke *stroke) { float a[2], b[2], c[2], d[2]; - int count = paint_stroke_max_points(NULL, stroke); + int count = paint_stroke_max_points(nullptr, stroke); if (stroke->num_points < 4) { return; @@ -432,13 +494,25 @@ static void paint_brush_make_cubic(PaintStroke *stroke) bez.update(); stroke->spline->add(bez); + blender::CubicBezier bez3d; + paint_project_cubic(C, stroke, bez, bez3d); + bez3d.update(); + + stroke->world_spline->add(bez3d); + while (stroke->spline->segments.size() > paint_stroke_max_points(nullptr, stroke) + 1) { stroke->spline->pop_front(); } + + while (stroke->world_spline->segments.size() > paint_stroke_max_points(nullptr, stroke) + 1) { + stroke->stroke_distance_world += stroke->world_spline->segments[0].bezier.length; + stroke->world_spline->pop_front(); + } } void paint_project_spline(bContext *C, StrokeCache *cache, PaintStroke *stroke) { + return; Object *ob = CTX_data_active_object(C); stroke->world_spline->clear(); @@ -488,6 +562,8 @@ void paint_calc_cubic_uv_v3( if (dot_v3v3(vec2, cache->view_normal) < 0.0f) { r_out[0] = -r_out[0]; } + + r_out[1] += stroke->stroke_distance_world; } float paint_stroke_spline_length(struct PaintStroke *stroke) @@ -881,7 +957,7 @@ static void paint_brush_stroke_add_step( stroke->x_tilt, stroke->y_tilt); if (stroke->has_cubic_stroke) { - paint_brush_make_cubic(stroke); + paint_brush_make_cubic(C, stroke); } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 44f71677573..6276000b207 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4130,20 +4130,12 @@ float SCULPT_brush_strength_factor(SculptSession *ss, // calc_cubic_uv_v3(ss->cache->world_cubic, SCULPT_vertex_co_get(ss, vertex), point_3d); float tan[3], curv[3]; - paint_calc_cubic_uv_v3( - ss->cache->stroke, ss->cache, SCULPT_vertex_co_get(ss, vertex), point_3d, tan); - - /* Calc global distance. */ - float t1 = ss->cache->last_stroke_distance_t; - float t2 = point_3d[1] / ss->cache->radius; - - point_3d[1] = t1 + t2; - point_3d[1] *= ss->cache->radius; + paint_calc_cubic_uv_v3(ss->cache->stroke, ss->cache, brush_point, point_3d, tan); #if 0 if (SCULPT_has_colors(ss)) { float color[4] = {point_3d[0], point_3d[1], 0.0f, 1.0f}; - mul_v3_fl(color, 0.25f / ss->cache->radius); + mul_v3_fl(color, 0.25f / ss->cache->initial_radius); color[0] -= floorf(color[0]); color[1] -= floorf(color[1]); color[2] -= floorf(color[2]); @@ -4153,15 +4145,11 @@ float SCULPT_brush_strength_factor(SculptSession *ss, // avg = 0.0f; #endif - //#else - // point_3d[0] /= ss->cache->radius; - // point_3d[0] -= floorf(point_3d[0]); float pixel_radius = br->size; - mul_v3_fl(point_3d, pixel_radius / ss->cache->radius); + mul_v3_fl(point_3d, pixel_radius / ss->cache->initial_radius); avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, thread_id, ss->tex_pool); - //#endif } else { const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; @@ -5401,7 +5389,12 @@ static void SCULPT_run_command(Sculpt *sd, ss->cache->radius = radius; ss->cache->radius_squared = radius * radius; - ss->cache->initial_radius = radius; + + if (SCULPT_stroke_is_first_brush_step(ss->cache)) { + cmd->initial_radius = radius; + } + + ss->cache->initial_radius = cmd->initial_radius; get_nodes_undo(sd, ob, ss->cache->brush, ups, paint_mode_settings, data, cmd->tool); diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index d4835784f1a..964ea136315 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -132,9 +132,6 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, float alpha = BKE_brush_channelset_get_final_float( BKE_paint_brush(&data->sd->paint)->channels, data->sd->channels, "strength", NULL); - bool do_test = brush->mtex.brush_map_mode != MTEX_MAP_MODE_ROLL && - brush->mtex.brush_map_mode != MTEX_MAP_MODE_ROLL; - AutomaskingNodeData automask_data; SCULPT_automasking_node_begin( data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); @@ -185,7 +182,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, distance_to_stroke_location = sqrtf(test.dist); } - if (do_test && !affect_vertex) { + if (!affect_vertex) { continue; } -- cgit v1.2.3