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
This commit is contained in:
parent
9b7561f16a
commit
46839d1f43
|
@ -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 {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <cstdio>
|
||||
#include <utility>
|
||||
|
||||
//#define FINITE_DIFF
|
||||
|
||||
/*
|
||||
* Arc length parameterized spline library.
|
||||
*/
|
||||
|
@ -263,7 +265,7 @@ template<typename Float, int axes = 2, int table_size = 512> 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<typename Float, int axes = 2, int table_size = 512> 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<typename Float, int axes = 2, int table_size = 512> 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<typename Float, int axes = 2, int table_size = 512> class CubicBezier {
|
|||
}
|
||||
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
Float curvature(Float s)
|
||||
|
@ -510,12 +531,8 @@ template<typename Float, int axes = 2> 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<typename Float, int axes = 2> 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<float, 2> &bezier2d,
|
||||
blender::CubicBezier<float, 3> &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<float, 3> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue