Fix T44604 bad quality of rake with bezier curves.

We can calculate tangents analytically for bezier curves, so just make
them awesome. New code uses forward differencing calculation for
efficiency just like curve calculation.

Picture before/after:

http://www.pasteall.org/pic/87843
This commit is contained in:
Antonis Ryakiotakis 2015-05-07 18:10:34 +02:00
parent a2eb94b470
commit a5dead2e8c
Notes: blender-bot 2023-02-14 11:34:30 +01:00
Referenced by issue #44604, rake doesn't properly align the strokes
5 changed files with 57 additions and 6 deletions

View File

@ -120,6 +120,7 @@ void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBa
const bool for_render, const bool use_render_resolution);
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect);

View File

@ -144,6 +144,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
/* stroke related */
void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]);
void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation);
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);

View File

@ -1384,6 +1384,30 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float
}
}
/* forward differencing method for first derivative of cubic bezier curve */
void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
float rt0, rt1, rt2, f;
int a;
f = 1.0f / (float)it;
rt0 = 3.0f * (q1 - q0);
rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
rt2 = 6.0f * (q0 + q2)- 12.0f * q1;
q0 = rt0;
q1 = f * (rt1 + rt2);
q2 = 2.0f * f * rt1;
for (a = 0; a <= it; a++) {
*p = q0;
p = (float *)(((char *)p) + stride);
q0 += q1;
q1 += q2;
}
}
static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3],
float p[3], int it, int stride)
{

View File

@ -519,7 +519,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
/* threshold to move before updating the brush rotation */
#define RAKE_THRESHHOLD 20
static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
{
if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
ups->brush_rotation = rotation;
@ -527,7 +527,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
ups->brush_rotation = 0.0f;
if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
/* here, translation contains the mouse coordinates. */
ups->brush_rotation_sec = rotation;
else
ups->brush_rotation_sec = 0.0f;
@ -549,12 +548,12 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
ups->last_rake_angle = rotation;
update_brush_rake_rotation(ups, brush, rotation);
paint_update_brush_rake_rotation(ups, brush, rotation);
}
/* make sure we reset here to the last rotation to avoid accumulating
* values in case a random rotation is also added */
else {
update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
}
}
else {

View File

@ -347,7 +347,8 @@ static bool paint_brush_update(bContext *C,
if (!stroke->brush_init) {
copy_v2_v2(ups->last_rake, mouse_init);
}
else {
/* curve strokes do their own rake calculation */
else if (!(brush->flag & BRUSH_CURVE)) {
paint_calculate_rake_rotation(ups, brush, mouse_init);
}
}
@ -954,6 +955,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
Brush *br = stroke->brush;
if (br->flag & BRUSH_CURVE) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
PaintCurve *pc = br->paint_curve;
@ -974,29 +976,53 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
int j;
float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
PaintCurvePoint *pcp_next = pcp + 1;
bool do_rake = false;
for (j = 0; j < 2; j++)
for (j = 0; j < 2; j++) {
BKE_curve_forward_diff_bezier(
pcp->bez.vec[1][j],
pcp->bez.vec[2][j],
pcp_next->bez.vec[0][j],
pcp_next->bez.vec[1][j],
data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
}
if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
(br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
{
do_rake = true;
for (j = 0; j < 2; j++) {
BKE_curve_forward_diff_tangent_bezier(
pcp->bez.vec[1][j],
pcp->bez.vec[2][j],
pcp_next->bez.vec[0][j],
pcp_next->bez.vec[1][j],
tangents + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
}
}
for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
float rotation = 0.0f;
if (do_rake) {
normalize_v2_v2(&tangents[2 * j], &tangents[2 * j]);
rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
}
if (!stroke->stroke_started) {
stroke->last_pressure = 1.0;
copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
if (stroke->stroke_started) {
paint_update_brush_rake_rotation(ups, br, rotation);
paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
}
}
else {
paint_update_brush_rake_rotation(ups, br, rotation);
paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
}
}