|
|
|
@ -169,6 +169,20 @@ static float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool test_brush_angle_falloff(const Brush &brush,
|
|
|
|
|
const NormalAnglePrecalc &normal_angle_precalc,
|
|
|
|
|
const float angle_cos,
|
|
|
|
|
float *brush_strength)
|
|
|
|
|
{
|
|
|
|
|
if (((brush.flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush.flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(&normal_angle_precalc, angle_cos, brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool vwpaint_use_normal(const VPaint *vp)
|
|
|
|
|
{
|
|
|
|
|
return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) ||
|
|
|
|
@ -1927,14 +1941,18 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
|
vd.vert_indices[vd.i];
|
|
|
|
|
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
|
|
|
|
|
/* If the vertex is selected */
|
|
|
|
|
if (!(use_face_sel || use_vert_sel) || select_vert[v_index]) {
|
|
|
|
|
if ((use_face_sel || use_vert_sel) && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Get the average poly weight */
|
|
|
|
|
int total_hit_loops = 0;
|
|
|
|
|
float weight_final = 0.0f;
|
|
|
|
@ -1948,20 +1966,20 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Apply the weight to the vertex. */
|
|
|
|
|
if (total_hit_loops != 0) {
|
|
|
|
|
if (total_hit_loops == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ?
|
|
|
|
|
dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
const float final_alpha = brush_fade * brush_strength * grid_alpha *
|
|
|
|
|
brush_alpha_pressure;
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, data->wpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
const float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure;
|
|
|
|
|
|
|
|
|
|
if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
|
|
|
|
|
if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
|
|
|
|
@ -1974,12 +1992,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
|
|
|
|
|
weight_final /= total_hit_loops;
|
|
|
|
|
/* Only paint visible verts */
|
|
|
|
|
do_weight_paint_vertex(
|
|
|
|
|
data->vp, data->ob, data->wpi, v_index, final_alpha, weight_final);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
do_weight_paint_vertex(data->vp, data->ob, data->wpi, v_index, final_alpha, weight_final);
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
@ -1997,6 +2010,10 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
const Brush *brush = data->brush;
|
|
|
|
|
const Scene *scene = CTX_data_scene(data->C);
|
|
|
|
|
const StrokeCache *cache = ss->cache;
|
|
|
|
|
if (!cache->is_last_valid) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
|
|
|
|
|
get_brush_alpha_data(
|
|
|
|
|
scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
|
|
|
|
@ -2007,13 +2024,14 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
|
|
|
|
|
sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
|
|
|
|
|
project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
|
|
|
|
|
if (normalize_v3(brush_dir) == 0.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const blender::bke::AttributeAccessor attributes = data->me->attributes();
|
|
|
|
|
const blender::VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
|
|
|
|
|
".select_vert", ATTR_DOMAIN_POINT, false);
|
|
|
|
|
|
|
|
|
|
if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
|
|
|
|
|
|
|
|
|
|
SculptBrushTest test;
|
|
|
|
|
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
|
|
|
|
|
ss, &test, data->brush->falloff_shape);
|
|
|
|
@ -2024,7 +2042,10 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
@ -2033,16 +2054,18 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
const float3 &mv_curr = ss->vert_positions[v_index];
|
|
|
|
|
|
|
|
|
|
/* If the vertex is selected */
|
|
|
|
|
if (!(use_face_sel || use_vert_sel) || select_vert[v_index]) {
|
|
|
|
|
if ((use_face_sel || use_vert_sel) && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ?
|
|
|
|
|
dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, data->wpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool do_color = false;
|
|
|
|
|
/* Minimum dot product between brush direction and current
|
|
|
|
|
* to neighbor direction is 0.0, meaning orthogonal. */
|
|
|
|
@ -2053,12 +2076,13 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
float weight_final = 0.0;
|
|
|
|
|
for (const int p_index : gmap->vert_to_poly[v_index]) {
|
|
|
|
|
for (const int v_other_index : ss->corner_verts.slice(ss->polys[p_index])) {
|
|
|
|
|
if (v_other_index != v_index) {
|
|
|
|
|
const float3 &mv_other = ss->vert_positions[v_other_index];
|
|
|
|
|
if (v_other_index == v_index) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the direction from the selected vert to the neighbor. */
|
|
|
|
|
float other_dir[3];
|
|
|
|
|
sub_v3_v3v3(other_dir, mv_curr, mv_other);
|
|
|
|
|
sub_v3_v3v3(other_dir, mv_curr, ss->vert_positions[v_other_index]);
|
|
|
|
|
project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
|
|
|
|
|
|
|
|
|
|
normalize_v3(other_dir);
|
|
|
|
@ -2071,14 +2095,12 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
do_color = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Apply weight to vertex */
|
|
|
|
|
if (do_color) {
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
const float final_alpha = brush_fade * brush_strength * grid_alpha *
|
|
|
|
|
brush_alpha_pressure;
|
|
|
|
|
if (!do_color) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
const float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure;
|
|
|
|
|
|
|
|
|
|
if (final_alpha <= 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
@ -2088,11 +2110,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
data->vp, data->ob, data->wpi, v_index, final_alpha, float(weight_final));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
|
|
|
|
@ -2131,7 +2149,9 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* NOTE: grids are 1:1 with corners (aka loops).
|
|
|
|
|
* For multires, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
@ -2140,19 +2160,18 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
|
|
|
|
|
|
|
|
|
|
/* If the vertex is selected */
|
|
|
|
|
if (!(use_face_sel || use_vert_sel) || select_vert[v_index]) {
|
|
|
|
|
if ((use_face_sel || use_vert_sel) && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
const float final_alpha = brush_fade * brush_strength * grid_alpha *
|
|
|
|
|
brush_alpha_pressure;
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, data->wpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
const float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure;
|
|
|
|
|
|
|
|
|
|
if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
|
|
|
|
|
if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
|
|
|
|
@ -2165,9 +2184,6 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
|
|
|
|
|
do_weight_paint_vertex(data->vp, data->ob, data->wpi, v_index, final_alpha, paintweight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2203,24 +2219,29 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(void *__restrict userdata,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (angle_cos > 0.0 &&
|
|
|
|
|
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0)
|
|
|
|
|
if (angle_cos <= 0.0f ||
|
|
|
|
|
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) <= 0.0f)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
|
vd.vert_indices[vd.i];
|
|
|
|
|
|
|
|
|
|
/* If the vertex is selected. */
|
|
|
|
|
if (!(use_face_sel || use_vert_sel) || select_vert[v_index]) {
|
|
|
|
|
if ((use_face_sel || use_vert_sel) && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MDeformVert *dv = &data->wpi->dvert[v_index];
|
|
|
|
|
accum->len += 1;
|
|
|
|
|
accum->value += wpaint_get_active_weight(dv, data->wpi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2842,12 +2863,11 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
|
|
|
|
|
VPaint *vp = ts->vpaint;
|
|
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
|
Mesh *me;
|
|
|
|
|
SculptSession *ss = ob->sculpt;
|
|
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
|
|
|
|
|
|
|
|
|
/* context checks could be a poll() */
|
|
|
|
|
me = BKE_mesh_from_object(ob);
|
|
|
|
|
Mesh *me = BKE_mesh_from_object(ob);
|
|
|
|
|
if (me == nullptr || me->totpoly == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -2922,7 +2942,9 @@ static void do_vpaint_brush_blur_loops(bContext *C,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
@ -2930,18 +2952,19 @@ static void do_vpaint_brush_blur_loops(bContext *C,
|
|
|
|
|
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
|
|
|
|
|
|
|
|
|
|
/* If the vertex is selected for painting. */
|
|
|
|
|
if (!use_vert_sel || select_vert[v_index]) {
|
|
|
|
|
if (use_vert_sel && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ?
|
|
|
|
|
dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&vpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, vpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
|
|
|
|
|
/* Get the average poly color */
|
|
|
|
|
Color color_final(0, 0, 0, 0);
|
|
|
|
@ -2950,7 +2973,9 @@ static void do_vpaint_brush_blur_loops(bContext *C,
|
|
|
|
|
Blend blend[4] = {0};
|
|
|
|
|
|
|
|
|
|
for (const int p_index : gmap->vert_to_poly[v_index]) {
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const blender::IndexRange poly = ss->polys[p_index];
|
|
|
|
|
total_hit_loops += poly.size();
|
|
|
|
|
for (const int corner : poly) {
|
|
|
|
@ -2963,20 +2988,18 @@ static void do_vpaint_brush_blur_loops(bContext *C,
|
|
|
|
|
blend[3] += (Blend)col->a * (Blend)col->a;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (total_hit_loops == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (total_hit_loops != 0) {
|
|
|
|
|
/* Use rgb^2 color averaging. */
|
|
|
|
|
Color *col = &color_final;
|
|
|
|
|
Color *col = &;
|
|
|
|
|
|
|
|
|
|
color_final.r = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
|
|
|
|
|
color_final.g = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
|
|
|
|
|
color_final.b = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
|
|
|
|
|
color_final.a = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
|
|
|
|
|
color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
|
|
|
|
|
color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
|
|
|
|
|
color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
|
|
|
|
|
color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
|
|
|
|
|
|
|
|
|
|
/* For each poly owning this vert,
|
|
|
|
|
* paint each loop belonging to this vert. */
|
|
|
|
@ -2984,10 +3007,12 @@ static void do_vpaint_brush_blur_loops(bContext *C,
|
|
|
|
|
const int p_index = gmap->vert_to_poly[v_index][j];
|
|
|
|
|
const int l_index = gmap->vert_to_loop[v_index][j];
|
|
|
|
|
BLI_assert(ss->corner_verts[l_index] == v_index);
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
|
|
|
|
|
|
|
|
|
|
if (!previous_color.is_empty()) {
|
|
|
|
|
if (previous_color != nullptr) {
|
|
|
|
|
/* Get the previous loop color */
|
|
|
|
|
if (isZero(previous_color[l_index])) {
|
|
|
|
|
previous_color[l_index] = lcol[l_index];
|
|
|
|
@ -2998,17 +3023,8 @@ static void do_vpaint_brush_blur_loops(bContext *C,
|
|
|
|
|
brush_alpha_pressure * grid_alpha;
|
|
|
|
|
/* Mix the new color with the original
|
|
|
|
|
* based on the brush strength and the curve. */
|
|
|
|
|
lcol[l_index] = vpaint_blend<Color, Traits>(vp,
|
|
|
|
|
lcol[l_index],
|
|
|
|
|
color_orig,
|
|
|
|
|
*col,
|
|
|
|
|
final_alpha,
|
|
|
|
|
Traits::range * brush_strength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lcol[l_index] = vpaint_blend<Color, Traits>(
|
|
|
|
|
vp, lcol[l_index], color_orig, *col, final_alpha, Traits::range * brush_strength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
@ -3064,7 +3080,9 @@ static void do_vpaint_brush_blur_verts(bContext *C,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
@ -3072,18 +3090,18 @@ static void do_vpaint_brush_blur_verts(bContext *C,
|
|
|
|
|
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
|
|
|
|
|
|
|
|
|
|
/* If the vertex is selected for painting. */
|
|
|
|
|
if (!use_vert_sel || select_vert[v_index]) {
|
|
|
|
|
if (use_vert_sel && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ?
|
|
|
|
|
dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&vpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, vpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
|
|
|
|
|
/* Get the average poly color */
|
|
|
|
|
Color color_final(0, 0, 0, 0);
|
|
|
|
@ -3092,11 +3110,13 @@ static void do_vpaint_brush_blur_verts(bContext *C,
|
|
|
|
|
Blend blend[4] = {0};
|
|
|
|
|
|
|
|
|
|
for (const int p_index : gmap->vert_to_poly[v_index]) {
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const blender::IndexRange poly = ss->polys[p_index];
|
|
|
|
|
total_hit_loops += poly.size();
|
|
|
|
|
for (const int vert : ss->corner_verts.slice(poly)) {
|
|
|
|
|
const Color &col = lcol[vert];
|
|
|
|
|
Color *col = lcol + vert;
|
|
|
|
|
|
|
|
|
|
/* Color is squared to compensate the `sqrt` color encoding. */
|
|
|
|
|
blend[0] += (Blend)col->r * (Blend)col->r;
|
|
|
|
@ -3105,28 +3125,27 @@ static void do_vpaint_brush_blur_verts(bContext *C,
|
|
|
|
|
blend[3] += (Blend)col->a * (Blend)col->a;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (total_hit_loops != 0) {
|
|
|
|
|
if (total_hit_loops == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Use rgb^2 color averaging. */
|
|
|
|
|
Color *col = &color_final;
|
|
|
|
|
|
|
|
|
|
color_final.r = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
|
|
|
|
|
color_final.g = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
|
|
|
|
|
color_final.b = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
|
|
|
|
|
color_final.a = Traits::round(
|
|
|
|
|
sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
|
|
|
|
|
color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
|
|
|
|
|
color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
|
|
|
|
|
color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
|
|
|
|
|
color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
|
|
|
|
|
|
|
|
|
|
/* For each poly owning this vert,
|
|
|
|
|
* paint each loop belonging to this vert. */
|
|
|
|
|
for (const int p_index : gmap->vert_to_poly[v_index]) {
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
|
|
|
|
|
|
|
|
|
|
if (!previous_color.is_empty()) {
|
|
|
|
|
if (previous_color != nullptr) {
|
|
|
|
|
/* Get the previous loop color */
|
|
|
|
|
if (isZero(previous_color[v_index])) {
|
|
|
|
|
previous_color[v_index] = lcol[v_index];
|
|
|
|
@ -3137,17 +3156,8 @@ static void do_vpaint_brush_blur_verts(bContext *C,
|
|
|
|
|
brush_alpha_pressure * grid_alpha;
|
|
|
|
|
/* Mix the new color with the original
|
|
|
|
|
* based on the brush strength and the curve. */
|
|
|
|
|
lcol[v_index] = vpaint_blend<Color, Traits>(vp,
|
|
|
|
|
lcol[v_index],
|
|
|
|
|
color_orig,
|
|
|
|
|
*col,
|
|
|
|
|
final_alpha,
|
|
|
|
|
Traits::range * brush_strength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lcol[v_index] = vpaint_blend<Color, Traits>(
|
|
|
|
|
vp, lcol[v_index], color_orig, *col, final_alpha, Traits::range * brush_strength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
@ -3168,6 +3178,9 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
|
|
|
|
|
const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
|
|
|
|
|
const StrokeCache *cache = ss->cache;
|
|
|
|
|
if (!cache->is_last_valid) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
|
|
|
|
|
const bool has_grids = (pbvh_type == PBVH_GRIDS);
|
|
|
|
|
|
|
|
|
@ -3188,16 +3201,17 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
|
|
|
|
|
get_brush_alpha_data(
|
|
|
|
|
scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
|
|
|
|
|
float brush_dir[3];
|
|
|
|
|
const bool use_normal = vwpaint_use_normal(vp);
|
|
|
|
|
const bool use_vert_sel = (me->editflag &
|
|
|
|
|
(ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
|
|
|
|
|
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
|
|
|
|
|
|
|
|
|
|
float brush_dir[3];
|
|
|
|
|
sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
|
|
|
|
|
project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
|
|
|
|
|
|
|
|
|
|
if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
|
|
|
|
|
if (normalize_v3(brush_dir) == 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SculptBrushTest test;
|
|
|
|
|
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
|
|
|
|
@ -3209,7 +3223,9 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
@ -3218,20 +3234,20 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
const float3 &mv_curr = &ss->vert_positions[v_index];
|
|
|
|
|
|
|
|
|
|
/* if the vertex is selected for painting. */
|
|
|
|
|
if (!use_vert_sel || select_vert[v_index]) {
|
|
|
|
|
if (use_vert_sel && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate the dot prod. between ray norm on surf and current vert
|
|
|
|
|
* (ie splash prevention factor), and only paint front facing verts. */
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ?
|
|
|
|
|
dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&vpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, vpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
|
|
|
|
|
bool do_color = false;
|
|
|
|
|
/* Minimum dot product between brush direction and current
|
|
|
|
@ -3247,16 +3263,19 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
const int l_index = gmap->vert_to_loop[v_index][j];
|
|
|
|
|
BLI_assert(ss->corner_verts[l_index] == v_index);
|
|
|
|
|
UNUSED_VARS_NDEBUG(l_index);
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (const int corner : ss->polys[p_index]) {
|
|
|
|
|
const int v_other_index = ss->corner_verts[corner];
|
|
|
|
|
if (v_other_index != v_index) {
|
|
|
|
|
const float3 &mv_other = &ss->vert_positions[v_other_index];
|
|
|
|
|
if (v_other_index == v_index) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the direction from the
|
|
|
|
|
* selected vert to the neighbor. */
|
|
|
|
|
float other_dir[3];
|
|
|
|
|
sub_v3_v3v3(other_dir, mv_curr, mv_other);
|
|
|
|
|
sub_v3_v3v3(other_dir, mv_curr, ss->vert_positions[v_other_index]);
|
|
|
|
|
project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
|
|
|
|
|
|
|
|
|
|
normalize_v3(other_dir);
|
|
|
|
@ -3264,7 +3283,7 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
const float stroke_dot = dot_v3v3(other_dir, brush_dir);
|
|
|
|
|
int elem_index;
|
|
|
|
|
|
|
|
|
|
if (vpd->domain == ATTR_DOMAIN_POINT) {
|
|
|
|
|
if constexpr (domain == ATTR_DOMAIN_POINT) {
|
|
|
|
|
elem_index = v_other_index;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
@ -3278,10 +3297,11 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!do_color) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (do_color) {
|
|
|
|
|
const float final_alpha = Traits::range * brush_fade * brush_strength *
|
|
|
|
|
brush_alpha_pressure * grid_alpha;
|
|
|
|
|
|
|
|
|
@ -3291,7 +3311,7 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
const int p_index = gmap->vert_to_poly[v_index][j];
|
|
|
|
|
|
|
|
|
|
int elem_index;
|
|
|
|
|
if (vpd->domain == ATTR_DOMAIN_POINT) {
|
|
|
|
|
if constexpr (domain == ATTR_DOMAIN_POINT) {
|
|
|
|
|
elem_index = v_index;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
@ -3299,12 +3319,14 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
elem_index = l_index;
|
|
|
|
|
BLI_assert(ss->corner_verts[l_index] == v_index);
|
|
|
|
|
}
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
/* Get the previous element color */
|
|
|
|
|
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
|
|
|
|
|
|
|
|
|
|
if (!color_prev.is_empty()) {
|
|
|
|
|
if (color_prev != nullptr) {
|
|
|
|
|
/* Get the previous element color */
|
|
|
|
|
if (isZero(color_prev[elem_index])) {
|
|
|
|
|
color_prev[elem_index] = lcol[elem_index];
|
|
|
|
@ -3318,20 +3340,13 @@ static void do_vpaint_brush_smear(bContext *C,
|
|
|
|
|
color_orig,
|
|
|
|
|
color_final,
|
|
|
|
|
final_alpha,
|
|
|
|
|
Traits::range *
|
|
|
|
|
brush_strength);
|
|
|
|
|
Traits::range * brush_strength);
|
|
|
|
|
|
|
|
|
|
color_curr[elem_index] = lcol[elem_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3372,25 +3387,32 @@ static void calculate_average_color(VPaintData *vpd,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (BKE_brush_curve_strength(brush, 0.0, cache->radius) <= 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
|
vd.vert_indices[vd.i];
|
|
|
|
|
if (BKE_brush_curve_strength(brush, 0.0, cache->radius) > 0.0) {
|
|
|
|
|
/* If the vertex is selected for painting. */
|
|
|
|
|
if (!use_vert_sel || select_vert[v_index]) {
|
|
|
|
|
if (use_vert_sel && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accum2->len += gmap->vert_to_poly[v_index].size();
|
|
|
|
|
/* if a vertex is within the brush region, then add its color to the blend. */
|
|
|
|
|
for (int j = 0; j < gmap->vert_to_poly[v_index].size(); j++) {
|
|
|
|
|
int elem_index;
|
|
|
|
|
|
|
|
|
|
if (vpd->domain == ATTR_DOMAIN_CORNER) {
|
|
|
|
|
if constexpr (domain == ATTR_DOMAIN_CORNER) {
|
|
|
|
|
elem_index = gmap->vert_to_loop[v_index][j];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
elem_index = v_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Color &col = lcol[elem_index];
|
|
|
|
|
Color *col = lcol + elem_index;
|
|
|
|
|
|
|
|
|
|
/* Color is squared to compensate the `sqrt` color encoding. */
|
|
|
|
|
accum2->value[0] += col->r * col->r;
|
|
|
|
@ -3398,9 +3420,6 @@ static void calculate_average_color(VPaintData *vpd,
|
|
|
|
|
accum2->value[2] += col->b * col->b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
@ -3491,29 +3510,31 @@ static void vpaint_do_draw(bContext *C,
|
|
|
|
|
PBVHVertexIter vd;
|
|
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
|
|
|
|
/* Test to see if the vertex coordinates are within the spherical brush region. */
|
|
|
|
|
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* NOTE: Grids are 1:1 with corners (aka loops).
|
|
|
|
|
* For grid based pbvh, take the vert whose loop corresponds to the current grid.
|
|
|
|
|
* Otherwise, take the current vert. */
|
|
|
|
|
const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] :
|
|
|
|
|
vd.vert_indices[vd.i];
|
|
|
|
|
/* If the vertex is selected for painting. */
|
|
|
|
|
if (use_vert_sel && !select_vert[v_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
|
|
|
|
|
|
|
|
|
|
/* If the vertex is selected for painting. */
|
|
|
|
|
if (!use_vert_sel || select_vert[v_index]) {
|
|
|
|
|
/* Calc the dot prod. between ray norm on surf and current vert
|
|
|
|
|
* (ie splash prevention factor), and only paint front facing verts. */
|
|
|
|
|
float brush_strength = cache->bstrength;
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ?
|
|
|
|
|
dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
|
|
|
|
|
1.0f;
|
|
|
|
|
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
|
|
|
|
|
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
|
|
|
|
|
view_angle_limits_apply_falloff(
|
|
|
|
|
&vpd->normal_angle_precalc, angle_cos, &brush_strength)))
|
|
|
|
|
{
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(
|
|
|
|
|
brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
if (!test_brush_angle_falloff(
|
|
|
|
|
*brush, vpd->normal_angle_precalc, angle_cos, &brush_strength)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
|
|
|
|
|
|
|
|
|
|
Color color_final = paintcol;
|
|
|
|
|
|
|
|
|
@ -3521,24 +3542,24 @@ static void vpaint_do_draw(bContext *C,
|
|
|
|
|
float tex_alpha = 1.0;
|
|
|
|
|
if (vpd->is_texbrush) {
|
|
|
|
|
/* NOTE: we may want to paint alpha as vertex color alpha. */
|
|
|
|
|
tex_alpha = paint_and_tex_color_alpha<Color>(
|
|
|
|
|
tex_alpha = paint_and_tex_color_alpha<Color, Traits, domain>(
|
|
|
|
|
vp, vpd, vpd->vertexcosnos[v_index].co, &color_final);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Color color_orig(0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (vpd->domain == ATTR_DOMAIN_POINT) {
|
|
|
|
|
if constexpr (domain == ATTR_DOMAIN_POINT) {
|
|
|
|
|
int v_index = vd.index;
|
|
|
|
|
|
|
|
|
|
if (!previous_color.is_empty()) {
|
|
|
|
|
if (previous_color != nullptr) {
|
|
|
|
|
/* Get the previous loop color */
|
|
|
|
|
if (isZero(previous_color[v_index])) {
|
|
|
|
|
previous_color[v_index] = lcol[v_index];
|
|
|
|
|
}
|
|
|
|
|
color_orig = previous_color[v_index];
|
|
|
|
|
}
|
|
|
|
|
const float final_alpha = Traits::frange * brush_fade * brush_strength *
|
|
|
|
|
tex_alpha * brush_alpha_pressure * grid_alpha;
|
|
|
|
|
const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
|
|
|
|
|
brush_alpha_pressure * grid_alpha;
|
|
|
|
|
|
|
|
|
|
lcol[v_index] = vpaint_blend<Color, Traits>(vp,
|
|
|
|
|
lcol[v_index],
|
|
|
|
@ -3553,18 +3574,20 @@ static void vpaint_do_draw(bContext *C,
|
|
|
|
|
const int p_index = gmap->vert_to_poly[v_index][j];
|
|
|
|
|
const int l_index = gmap->vert_to_loop[v_index][j];
|
|
|
|
|
BLI_assert(ss->corner_verts[l_index] == v_index);
|
|
|
|
|
if (!use_face_sel || select_poly[p_index]) {
|
|
|
|
|
if (use_face_sel && !select_poly[p_index]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */
|
|
|
|
|
|
|
|
|
|
if (!previous_color.is_empty()) {
|
|
|
|
|
if (previous_color != nullptr) {
|
|
|
|
|
/* Get the previous loop color */
|
|
|
|
|
if (isZero(previous_color[l_index])) {
|
|
|
|
|
previous_color[l_index] = lcol[l_index];
|
|
|
|
|
}
|
|
|
|
|
color_orig = previous_color[l_index];
|
|
|
|
|
}
|
|
|
|
|
const float final_alpha = Traits::frange * brush_fade * brush_strength *
|
|
|
|
|
tex_alpha * brush_alpha_pressure * grid_alpha;
|
|
|
|
|
const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
|
|
|
|
|
brush_alpha_pressure * grid_alpha;
|
|
|
|
|
|
|
|
|
|
/* Mix the new color with the original based on final_alpha. */
|
|
|
|
|
lcol[l_index] = vpaint_blend<Color, Traits>(vp,
|
|
|
|
@ -3576,10 +3599,6 @@ static void vpaint_do_draw(bContext *C,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
@ -3611,7 +3630,6 @@ static void vpaint_paint_leaves(bContext *C,
|
|
|
|
|
GMutableSpan lcol,
|
|
|
|
|
Span<PBVHNode *> nodes)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
for (PBVHNode *node : nodes) {
|
|
|
|
|
SCULPT_undo_push_node(ob, node, SCULPT_UNDO_COLOR);
|
|
|
|
|
}
|
|
|
|
|