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);