diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index a9e2e1c..0799abd 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -548,10 +548,11 @@ static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, cons for (a = 0; a < 4; a++) { if (asf->vlr[a] && asf->vlr[a] != vlr) { /* this face already made a copy for this vertex! */ - if (asf->nver[a]) { - if (equals_v3v3(lnor, asf->nver[a]->n)) { - return asf->nver[a]; - } + VertRen *nver = asf->nver[a]; + + /* this face already made a copy for this vertex! */ + if (!ELEM(nver, NULL, ver) && equals_v3v3(lnor, nver->n)) { + return nver; } } } @@ -583,8 +584,8 @@ static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen * v1 = RE_vertren_copy(obr, ver); copy_v3_v3(v1->n, lnor); } + asf->nver[asf_idx] = v1; if (v1 != ver) { - asf->nver[asf_idx] = v1; if (vlr->v1 == ver) vlr->v1 = v1; if (vlr->v2 == ver) vlr->v2 = v1; if (vlr->v3 == ver) vlr->v3 = v1; @@ -592,6 +593,110 @@ static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen * } } +static bool as_ver_in_array(VertRen *ver, VertRen **arr, int size) +{ + VertRen **ver_it = arr; + int a; + + for (a = 0; a < size && *ver_it != ver; ++a, ++ver_it) {} + + return (a != size); +} + +static void as_tweak_vcos(ASvert *asv) +{ + ASface *asf; + const float fac = 1e-4f; + const int tot_asf = asv->totface; + int a, tot_done_verts = 0; + + VertRen *done_verts_buff[16] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + VertRen **done_verts = (tot_asf < 17) ? done_verts_buff : MEM_callocN(sizeof(VertRen *) * tot_asf, __func__); + + VertRen *work_verts_buff[32] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + VertRen **work_verts = (tot_asf < 17) ? work_verts_buff : MEM_callocN(sizeof(VertRen *) * tot_asf * 2, __func__); + + asf = asv->faces.first; + while (asf) { + for (a = 0; a < 4; ++a) { + VertRen *ver = asf->nver[a]; + float n[3], d[3] = {0.0f, 0.0f, 0.0f}; + ASface *asf_it = asf; + int b = a, tot_work_verts = 0; + + if (!ver || as_ver_in_array(ver, done_verts, tot_asf)) { + continue; + } + + /* this ver has not yet been handled. */ + while (asf_it) { + for (; b < 4; ++b) { + if (asf_it->nver[b] == ver) { + VlakRen *vlr = asf_it->vlr[b]; + VertRen *v1, *v2; + + BLI_assert(vlr != NULL); + + if (ver == vlr->v1) { + v1 = vlr->v2; + v2 = vlr->v4 ? vlr->v4 : vlr->v3; + } + else if (ver == vlr->v2) { + v1 = vlr->v3; + v2 = vlr->v1; + } + else if (ver == vlr->v3) { + v1 = vlr->v4 ? vlr->v4 : vlr->v1; + v2 = vlr->v2; + } + else if (ver == vlr->v4) { + v1 = vlr->v1; + v2 = vlr->v3; + } + + if (!as_ver_in_array(v1, work_verts, tot_work_verts)) { + sub_v3_v3v3(n, ver->co, v1->co); + madd_v3_v3fl(d, n, fac); + work_verts[tot_work_verts++] = v1; + } + if (!as_ver_in_array(v2, work_verts, tot_work_verts)) { + sub_v3_v3v3(n, ver->co, v2->co); + madd_v3_v3fl(d, n, fac); + work_verts[tot_work_verts++] = v2; + } + + BLI_assert(tot_work_verts <= tot_asf * 2); + } + } + + b = 0; + asf_it = asf_it->next; + } + + if (!is_zero_v3(d)) { + add_v3_v3(ver->co, d); + } + + done_verts[tot_done_verts++] = ver; + + BLI_assert(tot_done_verts <= tot_asf); + } + asf = asf->next; + } + + if (done_verts != done_verts_buff) { + MEM_freeN(done_verts); + } + if (work_verts != work_verts_buff) { + MEM_freeN(work_verts); + } +} + /* note; autosmooth happens in object space still, after applying autosmooth we rotate */ /* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3]) @@ -624,13 +729,14 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor } } - /* free */ + /* tweak slightly coordinates of 'split' vertices, to avoids blackdots artifacts (see T39735), and free.*/ for (a = 0; a < totvert; a++) { + as_tweak_vcos(&asverts[a]); BLI_freelistN(&asverts[a].faces); } MEM_freeN(asverts); - /* rotate vertices and calculate normal of faces */ + /* rotate vertices */ for (a = 0; a < obr->totvert; a++) { ver = RE_findOrAddVert(obr, a); mul_m4_v3(mat, ver->co); @@ -640,6 +746,7 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor normalize_v3(ver->n); } } + /* calculate normal of faces */ for (a = 0; a < obr->totvlak; a++) { vlr = RE_findOrAddVlak(obr, a);