forked from bartvdbraak/blender
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:
parent
a2eb94b470
commit
a5dead2e8c
@ -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);
|
||||
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user