Sculpt: Cleanup duplicate code in clay strips brush
Clay strips was using it's own brush local matrix, which wasn't quite compatible with texture matrices. This could lead to brush textures not lining up with the stroke dabs. There was also a bug where the stroke was starting 20 pixels into the stroke, which is much higher than necassary to derive the initial rake angle. Notes: * The clay strips brush now uses SCULPT_cube_tip_init to calculate the local brush matrix. * SCULPT_cube_tip_init now accepts custom brush location and radius arguments. * The mouse sample preroll used to calculate initial brush rotation angle is now smaller than the update interval. * Clay strips now supports tip_scale_x, which has also been added to DNA defaults.
This commit is contained in:
@@ -635,6 +635,9 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
row = layout.row()
|
||||
row.prop(brush, "tip_roundness")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(brush, "tip_scale_x")
|
||||
|
||||
elif sculpt_tool == 'ELASTIC_DEFORM':
|
||||
layout.separator()
|
||||
layout.prop(brush, "elastic_deform_type")
|
||||
|
||||
@@ -247,7 +247,8 @@ void BKE_paint_face_set_overlay_color_get(int face_set, int seed, uchar r_color[
|
||||
bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups,
|
||||
struct Brush *brush,
|
||||
const float mouse_pos[2],
|
||||
ePaintMode paint_mode);
|
||||
ePaintMode paint_mode,
|
||||
bool stroke_has_started);
|
||||
void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups,
|
||||
struct Brush *brush,
|
||||
float rotation);
|
||||
|
||||
@@ -527,6 +527,8 @@ static void brush_defaults(Brush *brush)
|
||||
FROM_DEFAULT(mtex);
|
||||
FROM_DEFAULT(mask_mtex);
|
||||
FROM_DEFAULT(falloff_shape);
|
||||
FROM_DEFAULT(tip_scale_x);
|
||||
FROM_DEFAULT(tip_roundness);
|
||||
|
||||
#undef FROM_DEFAULT
|
||||
#undef FROM_DEFAULT_PTR
|
||||
@@ -1939,8 +1941,6 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->spacing = 10;
|
||||
br->alpha = 1.0f;
|
||||
br->flow = 1.0f;
|
||||
br->tip_scale_x = 1.0f;
|
||||
br->tip_roundness = 1.0f;
|
||||
br->density = 1.0f;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
zero_v3(br->rgb);
|
||||
@@ -2660,7 +2660,7 @@ bool BKE_brush_has_cube_tip(const Brush *brush, ePaintMode paint_mode)
|
||||
}
|
||||
|
||||
if (ELEM(brush->sculpt_tool, SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_PAINT) &&
|
||||
brush->tip_roundness < 1.0f)
|
||||
(brush->tip_roundness < 1.0f || brush->tip_scale_x != 1.0f))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1332,8 +1332,11 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, uint level, uint x, uint y
|
||||
return gpm->data[(y * factor) * gridsize + (x * factor)];
|
||||
}
|
||||
|
||||
/* Threshold to move before updating the brush rotation. */
|
||||
#define RAKE_THRESHHOLD 20
|
||||
/* Threshold to move before updating the brush rotation, reduces jitter. */
|
||||
static float paint_rake_rotation_spacing(UnifiedPaintSettings * /*ups*/, Brush *brush)
|
||||
{
|
||||
return brush->sculpt_tool == SCULPT_TOOL_CLAY_STRIPS ? 1.0f : 20.0f;
|
||||
}
|
||||
|
||||
void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
|
||||
{
|
||||
@@ -1361,16 +1364,25 @@ static const bool paint_rake_rotation_active(const Brush &brush, ePaintMode pain
|
||||
bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups,
|
||||
Brush *brush,
|
||||
const float mouse_pos[2],
|
||||
ePaintMode paint_mode)
|
||||
ePaintMode paint_mode,
|
||||
bool stroke_has_started)
|
||||
{
|
||||
bool ok = false;
|
||||
if (paint_rake_rotation_active(*brush, paint_mode)) {
|
||||
const float r = RAKE_THRESHHOLD;
|
||||
float r = paint_rake_rotation_spacing(ups, brush);
|
||||
float rotation;
|
||||
|
||||
/* Use a smaller limit if the stroke hasn't started
|
||||
* to prevent excessive preroll.
|
||||
*/
|
||||
if (!stroke_has_started) {
|
||||
r = min_ff(r, 4.0f);
|
||||
}
|
||||
|
||||
float dpos[2];
|
||||
sub_v2_v2v2(dpos, ups->last_rake, mouse_pos);
|
||||
|
||||
/* Limit how often we update the angle to prevent jitter. */
|
||||
if (len_squared_v2(dpos) >= r * r) {
|
||||
rotation = atan2f(dpos[0], dpos[1]);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_light_types.h"
|
||||
#include "DNA_lightprobe_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
@@ -316,6 +317,13 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix brush->tip_scale_x which should never be zero. */
|
||||
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
|
||||
if (brush->tip_scale_x == 0.0f) {
|
||||
brush->tip_scale_x = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
||||
@@ -1870,7 +1870,7 @@ static void paint_cursor_update_rake_rotation(PaintCursorContext *pcontext)
|
||||
* For line strokes, such interference is visible. */
|
||||
if (!pcontext->ups->stroke_active) {
|
||||
paint_calculate_rake_rotation(
|
||||
pcontext->ups, pcontext->brush, pcontext->translation, pcontext->mode);
|
||||
pcontext->ups, pcontext->brush, pcontext->translation, pcontext->mode, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -444,7 +444,7 @@ static bool paint_brush_update(bContext *C,
|
||||
}
|
||||
/* curve strokes do their own rake calculation */
|
||||
else if (!(brush->flag & BRUSH_CURVE)) {
|
||||
if (!paint_calculate_rake_rotation(ups, brush, mouse_init, mode)) {
|
||||
if (!paint_calculate_rake_rotation(ups, brush, mouse_init, mode, stroke->rake_started)) {
|
||||
/* Not enough motion to define an angle. */
|
||||
if (!stroke->rake_started) {
|
||||
is_dry_run = true;
|
||||
@@ -1575,7 +1575,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
|
||||
{
|
||||
copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
|
||||
}
|
||||
paint_calculate_rake_rotation(stroke->ups, br, mouse, mode);
|
||||
paint_calculate_rake_rotation(stroke->ups, br, mouse, mode, true);
|
||||
}
|
||||
}
|
||||
else if (first_modal ||
|
||||
|
||||
@@ -1809,7 +1809,8 @@ bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3])
|
||||
bool SCULPT_brush_test_cube(SculptBrushTest *test,
|
||||
const float co[3],
|
||||
const float local[4][4],
|
||||
const float roundness)
|
||||
const float roundness,
|
||||
const float /*tip_scale_x*/)
|
||||
{
|
||||
float side = 1.0f;
|
||||
float local_co[3];
|
||||
@@ -2984,7 +2985,9 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3])
|
||||
static void calc_brush_local_mat(const float rotation,
|
||||
Object *ob,
|
||||
float local_mat[4][4],
|
||||
float local_mat_inv[4][4])
|
||||
float local_mat_inv[4][4],
|
||||
const float *co,
|
||||
const float *no)
|
||||
{
|
||||
const StrokeCache *cache = ob->sculpt->cache;
|
||||
float tmat[4][4];
|
||||
@@ -2993,6 +2996,13 @@ static void calc_brush_local_mat(const float rotation,
|
||||
float angle, v[3];
|
||||
float up[3];
|
||||
|
||||
if (!co) {
|
||||
co = cache->location;
|
||||
}
|
||||
if (!no) {
|
||||
no = cache->sculpt_normal;
|
||||
}
|
||||
|
||||
/* Ensure `ob->world_to_object` is up to date. */
|
||||
invert_m4_m4(ob->world_to_object, ob->object_to_world);
|
||||
|
||||
@@ -3003,20 +3013,20 @@ static void calc_brush_local_mat(const float rotation,
|
||||
mat[3][3] = 1.0f;
|
||||
|
||||
/* Get view's up vector in object-space. */
|
||||
calc_local_y(cache->vc, cache->location, up);
|
||||
calc_local_y(cache->vc, co, up);
|
||||
|
||||
/* Calculate the X axis of the local matrix. */
|
||||
cross_v3_v3v3(v, up, cache->sculpt_normal);
|
||||
cross_v3_v3v3(v, up, no);
|
||||
/* Apply rotation (user angle, rake, etc.) to X axis. */
|
||||
angle = rotation - cache->special_rotation;
|
||||
rotate_v3_v3v3fl(mat[0], v, cache->sculpt_normal, angle);
|
||||
rotate_v3_v3v3fl(mat[0], v, no, angle);
|
||||
|
||||
/* Get other axes. */
|
||||
cross_v3_v3v3(mat[1], cache->sculpt_normal, mat[0]);
|
||||
copy_v3_v3(mat[2], cache->sculpt_normal);
|
||||
cross_v3_v3v3(mat[1], no, mat[0]);
|
||||
copy_v3_v3(mat[2], no);
|
||||
|
||||
/* Set location. */
|
||||
copy_v3_v3(mat[3], cache->location);
|
||||
copy_v3_v3(mat[3], co);
|
||||
|
||||
/* Scale by brush radius. */
|
||||
float radius = cache->radius;
|
||||
@@ -3069,7 +3079,8 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
|
||||
if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) {
|
||||
const Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
|
||||
calc_brush_local_mat(mask_tex->rot, ob, cache->brush_local_mat, cache->brush_local_mat_inv);
|
||||
calc_brush_local_mat(
|
||||
mask_tex->rot, ob, cache->brush_local_mat, cache->brush_local_mat_inv, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6411,7 +6422,8 @@ void SCULPT_topology_islands_ensure(Object *ob)
|
||||
ss->islands_valid = true;
|
||||
}
|
||||
|
||||
void SCULPT_cube_tip_init(Sculpt * /*sd*/, Object *ob, Brush *brush, float mat[4][4])
|
||||
void SCULPT_cube_tip_init(
|
||||
Sculpt * /*sd*/, Object *ob, Brush *brush, float mat[4][4], const float *co, const float *no)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
float scale[4][4];
|
||||
@@ -6419,7 +6431,7 @@ void SCULPT_cube_tip_init(Sculpt * /*sd*/, Object *ob, Brush *brush, float mat[4
|
||||
float unused[4][4];
|
||||
|
||||
zero_m4(mat);
|
||||
calc_brush_local_mat(0.0, ob, unused, mat);
|
||||
calc_brush_local_mat(0.0, ob, unused, mat, co, no);
|
||||
|
||||
/* Note: we ignore the radius scaling done inside of calc_brush_local_mat to
|
||||
* duplicate prior behavior.
|
||||
|
||||
@@ -1058,7 +1058,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
|
||||
data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
|
||||
if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness, brush->tip_scale_x)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1130,15 +1130,6 @@ void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, Span<PBVHNode *> nodes)
|
||||
copy_v3_v3(area_no, area_no_sp);
|
||||
}
|
||||
|
||||
/* Delay the first daub because grab delta is not setup. */
|
||||
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
|
||||
mul_v3_fl(temp, displace);
|
||||
add_v3_v3(area_co, temp);
|
||||
@@ -1155,6 +1146,20 @@ void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, Span<PBVHNode *> nodes)
|
||||
madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
|
||||
|
||||
/* Initialize brush local-space matrix. */
|
||||
SCULPT_cube_tip_init(sd, ob, brush, mat, area_co, area_no);
|
||||
|
||||
/* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
|
||||
* Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
|
||||
* during big deformation while keeping the surface as uniform as possible. */
|
||||
invert_m4(mat);
|
||||
mul_v3_fl(mat[2], 1.25f);
|
||||
invert_m4(mat);
|
||||
|
||||
#if 0 /* The original matrix construction code, preserved here for reference. */
|
||||
if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
|
||||
mat[0][3] = 0.0f;
|
||||
cross_v3_v3v3(mat[1], area_no, mat[0]);
|
||||
@@ -1169,12 +1174,8 @@ void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, Span<PBVHNode *> nodes)
|
||||
scale_m4_fl(scale, ss->cache->radius);
|
||||
mul_m4_m4m4(tmat, mat, scale);
|
||||
|
||||
/* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
|
||||
* Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
|
||||
* during big deformation while keeping the surface as uniform as possible. */
|
||||
mul_v3_fl(tmat[2], 1.25f);
|
||||
|
||||
invert_m4_m4(mat, tmat);
|
||||
#endif
|
||||
|
||||
SculptThreadedTaskData data{};
|
||||
data.sd = sd;
|
||||
|
||||
@@ -1232,7 +1232,8 @@ bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3
|
||||
bool SCULPT_brush_test_cube(SculptBrushTest *test,
|
||||
const float co[3],
|
||||
const float local[4][4],
|
||||
float roundness);
|
||||
const float roundness,
|
||||
const float tip_scale_x);
|
||||
bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
|
||||
/**
|
||||
* Test AABB against sphere.
|
||||
@@ -1257,7 +1258,12 @@ SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
|
||||
char falloff_shape);
|
||||
const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
|
||||
char falloff_shape);
|
||||
void SCULPT_cube_tip_init(Sculpt *sd, Object *ob, Brush *brush, float mat[4][4]);
|
||||
void SCULPT_cube_tip_init(Sculpt *sd,
|
||||
Object *ob,
|
||||
Brush *brush,
|
||||
float mat[4][4],
|
||||
const float *co = nullptr, /* Custom brush center. */
|
||||
const float *no = nullptr); /* Custom brush normal. */
|
||||
|
||||
/**
|
||||
* Return a multiplier for brush strength on a particular vertex.
|
||||
|
||||
@@ -143,7 +143,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
|
||||
bool affect_vertex = false;
|
||||
float distance_to_stroke_location = 0.0f;
|
||||
if (brush->tip_roundness < 1.0f) {
|
||||
affect_vertex = SCULPT_brush_test_cube(&test, vd.co, data->mat, brush->tip_roundness);
|
||||
affect_vertex = SCULPT_brush_test_cube(
|
||||
&test, vd.co, data->mat, brush->tip_roundness, brush->tip_scale_x);
|
||||
distance_to_stroke_location = ss->cache->radius * test.dist;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -102,6 +102,8 @@
|
||||
.mtex = _DNA_DEFAULT_MTex, \
|
||||
.mask_mtex = _DNA_DEFAULT_MTex, \
|
||||
.falloff_shape = 0,\
|
||||
.tip_scale_x = 1.0f,\
|
||||
.tip_roundness = 1.0f,\
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -2864,7 +2864,7 @@ static void rna_def_brush(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "tip_scale_x", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "tip_scale_x");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
|
||||
RNA_def_property_ui_range(prop, 0.0001f, 1.0f, 0.001, 3);
|
||||
RNA_def_property_ui_text(prop, "Tip Scale X", "Scale of the brush tip in the X axis");
|
||||
RNA_def_property_update(prop, 0, "rna_Brush_update");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user