Fix T39279 Vertex paint modes do not work well with mirror modifier

Issue here is that coordinates used for projection would not fit the
closest candidate. So it was possible to paint against the mirrored part
of the mesh, which would get clipped on reprojection.

Fix avoids reprojection by storing squared distance, and screen space
coordinates, which we will need again later anyway. Also we now always
paint against the closest vertex always. This is ensured because squared
distances for uninitialized vertices will be MAXFLOAT, thus failing the
strength test.
This commit is contained in:
2014-03-21 20:37:00 +02:00
parent 44dc72334d
commit 0da3e97433
3 changed files with 82 additions and 88 deletions

View File

@@ -118,12 +118,16 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct VPaint *vp); unsigned int vpaint_get_current_col(struct VPaint *vp);
typedef struct VertProjData {
struct DMCoNo *vcosnos;
float *dists_sq;
float (*ss_co)[2];
} VertProjData;
/* paint_vertex_proj.c */ /* paint_vertex_proj.c */
struct VertProjHandle; struct VertProjHandle;
struct VertProjHandle *ED_vpaint_proj_handle_create( struct VertProjHandle *ED_vpaint_proj_handle_create(struct Scene *scene, struct Object *ob,
struct Scene *scene, struct Object *ob, VertProjData **r_vcosnos);
struct DMCoNo **r_vcosnos);
void ED_vpaint_proj_handle_update( void ED_vpaint_proj_handle_update(
struct VertProjHandle *vp_handle, struct VertProjHandle *vp_handle,
/* runtime vars */ /* runtime vars */

View File

@@ -910,37 +910,29 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
} }
/* whats _dl mean? */ /* whats _dl mean? */
static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3], static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const VertProjData *data, const int index,
const float mval[2], const float brush_size_pressure, float rgba[4]) const float brush_size_pressure, float rgba[4])
{ {
float co_ss[2]; /* screenspace */ float dist_sq = data->dists_sq[index];
if (dist_sq <= brush_size_pressure * brush_size_pressure) {
Brush *brush = BKE_paint_brush(&vp->paint);
const float dist = sqrtf(dist_sq);
float factor;
if (ED_view3d_project_float_object(vc->ar, if (brush->mtex.tex && rgba) {
co, co_ss, if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) BKE_brush_sample_tex_3D(vc->scene, brush, data->vcosnos[index].co, rgba, 0, NULL);
{
const float dist_sq = len_squared_v2v2(mval, co_ss);
if (dist_sq <= brush_size_pressure * brush_size_pressure) {
Brush *brush = BKE_paint_brush(&vp->paint);
const float dist = sqrtf(dist_sq);
float factor;
if (brush->mtex.tex && rgba) {
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL);
}
else {
const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL);
}
factor = rgba[3];
} }
else { else {
factor = 1.0f; const float co_ss_3d[3] = {data->ss_co[index][0], data->ss_co[index][1], 0.0f}; /* we need a 3rd empty value */
BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL);
} }
return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); factor = rgba[3];
} }
else {
factor = 1.0f;
}
return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure);
} }
if (rgba) if (rgba)
zero_v4(rgba); zero_v4(rgba);
@@ -948,11 +940,11 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co
} }
static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc,
float vpimat[3][3], const DMCoNo *v_co_no, float vpimat[3][3], const VertProjData *data,
const float mval[2], const int index,
const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4])
{ {
float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba); float strength = calc_vp_strength_col_dl(vp, vc, data, index, brush_size_pressure, rgba);
if (strength > 0.0f) { if (strength > 0.0f) {
float alpha = brush_alpha_pressure * strength; float alpha = brush_alpha_pressure * strength;
@@ -961,10 +953,10 @@ static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc,
float dvec[3]; float dvec[3];
/* transpose ! */ /* transpose ! */
dvec[2] = dot_v3v3(vpimat[2], v_co_no->no); dvec[2] = dot_v3v3(vpimat[2], data->vcosnos[index].no);
if (dvec[2] > 0.0f) { if (dvec[2] > 0.0f) {
dvec[0] = dot_v3v3(vpimat[0], v_co_no->no); dvec[0] = dot_v3v3(vpimat[0], data->vcosnos[index].no);
dvec[1] = dot_v3v3(vpimat[1], v_co_no->no); dvec[1] = dot_v3v3(vpimat[1], data->vcosnos[index].no);
alpha *= dvec[2] / len_v3(dvec); alpha *= dvec[2] / len_v3(dvec);
} }
@@ -2131,7 +2123,7 @@ struct WPaintData {
int vgroup_mirror; int vgroup_mirror;
void *vp_handle; void *vp_handle;
DMCoNo *vertexcosnos; VertProjData *data;
float wpimat[3][3]; float wpimat[3][3];
@@ -2241,7 +2233,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN
} }
/* painting on subsurfs should give correct points too, this returns me->totvert amount */ /* painting on subsurfs should give correct points too, this returns me->totvert amount */
wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos); wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->data);
wpd->indexar = get_indexarray(me); wpd->indexar = get_indexarray(me);
copy_wpaint_prev(wp, me->dvert, me->totvert); copy_wpaint_prev(wp, me->dvert, me->totvert);
@@ -2385,7 +2377,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
#define WP_BLUR_ACCUM(v_idx_var) \ #define WP_BLUR_ACCUM(v_idx_var) \
{ \ { \
const unsigned int vidx = v_idx_var; \ const unsigned int vidx = v_idx_var; \
const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \ const float fac = calc_vp_strength_col_dl(wp, vc, wpd->data, vidx, brush_size_pressure, NULL); \
if (fac > 0.0f) { \ if (fac > 0.0f) { \
MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \ MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \
paintweight += dw ? (dw->weight * fac) : 0.0f; \ paintweight += dw ? (dw->weight * fac) : 0.0f; \
@@ -2455,8 +2447,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
{ \ { \
unsigned int vidx = v_idx_var; \ unsigned int vidx = v_idx_var; \
if (me->dvert[vidx].flag) { \ if (me->dvert[vidx].flag) { \
alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, wpd->data, vidx, \
mval, brush_size_pressure, brush_alpha_pressure, NULL); \ brush_size_pressure, brush_alpha_pressure, NULL); \
if (alpha) { \ if (alpha) { \
do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
} \ } \
@@ -2743,7 +2735,7 @@ typedef struct VPaintData {
int *indexar; int *indexar;
struct VertProjHandle *vp_handle; struct VertProjHandle *vp_handle;
DMCoNo *vertexcosnos; VertProjData *data;
float vpimat[3][3]; float vpimat[3][3];
@@ -2811,7 +2803,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
paint_stroke_set_mode_data(stroke, vpd); paint_stroke_set_mode_data(stroke, vpd);
view3d_set_viewcontext(C, &vpd->vc); view3d_set_viewcontext(C, &vpd->vc);
vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos); vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->data);
vpd->indexar = get_indexarray(me); vpd->indexar = get_indexarray(me);
vpd->paintcol = vpaint_get_current_col(vp); vpd->paintcol = vpaint_get_current_col(vp);
@@ -2849,9 +2841,8 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
return 1; return 1;
} }
static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me, static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me, const unsigned int index,
const unsigned int index, const float mval[2], const float brush_size_pressure, const float brush_alpha_pressure)
const float brush_size_pressure, const float brush_alpha_pressure)
{ {
ViewContext *vc = &vpd->vc; ViewContext *vc = &vpd->vc;
Brush *brush = BKE_paint_brush(&vp->paint); Brush *brush = BKE_paint_brush(&vp->paint);
@@ -2901,7 +2892,7 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
float rgba[4]; float rgba[4];
unsigned int paintcol; unsigned int paintcol;
alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat, alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat,
&vpd->vertexcosnos[ml->v], mval, vpd->data, ml->v,
brush_size_pressure, brush_alpha_pressure, rgba); brush_size_pressure, brush_alpha_pressure, rgba);
if (vpd->is_texbrush) { if (vpd->is_texbrush) {
@@ -3005,7 +2996,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
for (index = 0; index < totindex; index++) { for (index = 0; index < totindex; index++) {
if (indexar[index] && indexar[index] <= me->totpoly) { if (indexar[index] && indexar[index] <= me->totpoly) {
vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure); vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, brush_size_pressure, brush_alpha_pressure);
} }
} }

View File

@@ -52,13 +52,10 @@
/* stored while painting */ /* stored while painting */
struct VertProjHandle { struct VertProjHandle {
DMCoNo *vcosnos; VertProjData *data;
bool use_update; bool use_update;
/* use for update */
float *dists_sq;
Object *ob; Object *ob;
Scene *scene; Scene *scene;
}; };
@@ -80,7 +77,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData, int index, co
const float no_f[3], const short no_s[3]) const float no_f[3], const short no_s[3])
{ {
struct VertProjHandle *vp_handle = userData; struct VertProjHandle *vp_handle = userData;
DMCoNo *co_no = &vp_handle->vcosnos[index]; DMCoNo *co_no = &vp_handle->data->vcosnos[index];
/* check if we've been here before (normal should not be 0) */ /* check if we've been here before (normal should not be 0) */
if (!is_zero_v3(co_no->no)) { if (!is_zero_v3(co_no->no)) {
@@ -107,11 +104,10 @@ static void vpaint_proj_dm_map_cosnos_init(Scene *scene, Object *ob,
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
if (dm->foreachMappedVert) { if (dm->foreachMappedVert) {
memset(vp_handle->vcosnos, 0, sizeof(DMCoNo) * me->totvert);
dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, DM_FOREACH_USE_NORMAL); dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, DM_FOREACH_USE_NORMAL);
} }
else { else {
DMCoNo *v_co_no = vp_handle->vcosnos; DMCoNo *v_co_no = vp_handle->data->vcosnos;
int a; int a;
for (a = 0; a < me->totvert; a++, v_co_no++) { for (a = 0; a < me->totvert; a++, v_co_no++) {
dm->getVertCo(dm, a, v_co_no->co); dm->getVertCo(dm, a, v_co_no->co);
@@ -129,44 +125,41 @@ static void vpaint_proj_dm_map_cosnos_init(Scene *scene, Object *ob,
/* Same as init but take mouse location into account */ /* Same as init but take mouse location into account */
static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData, int index, const float co[3], static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData, int index, const float co[3],
const float no_f[3], const short no_s[3]) const float no_f[3], const short no_s[3])
{ {
struct VertProjUpdate *vp_update = userData; struct VertProjUpdate *vp_update = userData;
struct VertProjHandle *vp_handle = vp_update->vp_handle;
DMCoNo *co_no = &vp_handle->vcosnos[index]; VertProjData *data = vp_update->vp_handle->data;
DMCoNo *co_no = &data->vcosnos[index];
/* find closest vertex */ /* first find distance to this vertex */
float co_ss[2]; /* screenspace */
if (ED_view3d_project_float_object(vp_update->ar,
co, co_ss,
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{ {
/* first find distance to this vertex */ const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss);
float co_ss[2]; /* screenspace */ if (dist_sq > data->dists_sq[index]) {
/* bail out! */
if (ED_view3d_project_float_object(vp_update->ar, return;
co, co_ss,
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss);
if (dist_sq > vp_handle->dists_sq[index]) {
/* bail out! */
return;
}
vp_handle->dists_sq[index] = dist_sq;
} }
}
/* continue with regular functionality */
copy_v3_v3(co_no->co, co); data->dists_sq[index] = dist_sq;
if (no_f) { copy_v2_v2(data->ss_co[index], co_ss);
copy_v3_v3(co_no->no, no_f);
} copy_v3_v3(co_no->co, co);
else { if (no_f) {
normal_short_to_float_v3(co_no->no, no_s); copy_v3_v3(co_no->no, no_f);
}
else {
normal_short_to_float_v3(co_no->no, no_s);
}
} }
} }
static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle, static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle,
ARegion *ar, const float mval_fl[2]) ARegion *ar, const float mval_fl[2])
{ {
struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl}; struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl};
@@ -182,7 +175,7 @@ static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle,
/* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */ /* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */
if (LIKELY(dm->foreachMappedVert)) { if (LIKELY(dm->foreachMappedVert)) {
fill_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX); fill_vn_fl(vp_handle->data->dists_sq, me->totvert, FLT_MAX);
dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL); dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
} }
@@ -195,32 +188,36 @@ static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle,
/* Public Functions */ /* Public Functions */
struct VertProjHandle *ED_vpaint_proj_handle_create(Scene *scene, Object *ob, struct VertProjHandle *ED_vpaint_proj_handle_create(Scene *scene, Object *ob,
DMCoNo **r_vcosnos) VertProjData **r_vcosnos)
{ {
struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__); struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__);
Mesh *me = ob->data; Mesh *me = ob->data;
/* setup the handle */ /* setup the handle */
vp_handle->vcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); vp_handle->data = MEM_mallocN(sizeof(VertProjData), AT);
vp_handle->data->vcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map");
vp_handle->use_update = false; vp_handle->use_update = false;
/* sets 'use_update' if needed */ /* sets 'use_update' if needed */
vpaint_proj_dm_map_cosnos_init(scene, ob, vp_handle); vpaint_proj_dm_map_cosnos_init(scene, ob, vp_handle);
if (vp_handle->use_update) { if (vp_handle->use_update) {
vp_handle->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, __func__); vp_handle->data->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, AT);
vp_handle->data->ss_co = MEM_mallocN(2 * sizeof(float) * me->totvert, AT);
vp_handle->ob = ob; vp_handle->ob = ob;
vp_handle->scene = scene; vp_handle->scene = scene;
} }
else { else {
vp_handle->dists_sq = NULL; vp_handle->data->dists_sq = NULL;
vp_handle->data->ss_co = NULL;
vp_handle->ob = NULL; vp_handle->ob = NULL;
vp_handle->scene = NULL; vp_handle->scene = NULL;
} }
*r_vcosnos = vp_handle->vcosnos; *r_vcosnos = vp_handle->data;
return vp_handle; return vp_handle;
} }
@@ -235,9 +232,11 @@ void ED_vpaint_proj_handle_update(struct VertProjHandle *vp_handle,
void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle) void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle)
{ {
if (vp_handle->use_update) { if (vp_handle->use_update) {
MEM_freeN(vp_handle->dists_sq); MEM_freeN(vp_handle->data->dists_sq);
MEM_freeN(vp_handle->data->ss_co);
} }
MEM_freeN(vp_handle->vcosnos); MEM_freeN(vp_handle->data->vcosnos);
MEM_freeN(vp_handle->data);
MEM_freeN(vp_handle); MEM_freeN(vp_handle);
} }