static void occ_face(const OccFace *face, float co[3], float normal[3], float *area) { ObjectInstanceRen *obi; VlakRen *vlr; float v1[3], v2[3], v3[3], v4[3]; obi = &R.objectinstance[face->obi]; vlr = RE_findOrAddVlak(obi->obr, face->facenr); if (co) { if (vlr->v4) mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co); else cent_tri_v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co); if (obi->flag & R_TRANSFORMED) mul_m4_v3(obi->mat, co); } if (normal) { normal[0] = -vlr->n[0]; normal[1] = -vlr->n[1]; normal[2] = -vlr->n[2]; if (obi->flag & R_TRANSFORMED) mul_m3_v3(obi->nmat, normal); } if (area) { copy_v3_v3(v1, vlr->v1->co); copy_v3_v3(v2, vlr->v2->co); copy_v3_v3(v3, vlr->v3->co); if (vlr->v4) copy_v3_v3(v4, vlr->v4->co); if (obi->flag & R_TRANSFORMED) { mul_m4_v3(obi->mat, v1); mul_m4_v3(obi->mat, v2); mul_m4_v3(obi->mat, v3); if (vlr->v4) mul_m4_v3(obi->mat, v4); } /* todo: correct area for instances */ if (vlr->v4) *area = area_quad_v3(v1, v2, v3, v4); else *area = area_tri_v3(v1, v2, v3); } }
static void init_laplacian_matrix(LaplacianSystem *sys) { float *v1, *v2, *v3, *v4; float w1, w2, w3, w4; float areaf; int i, j; unsigned int idv1, idv2, idv3, idv4, idv[4]; bool has_4_vert; for (i = 0; i < sys->numEdges; i++) { idv1 = sys->medges[i].v1; idv2 = sys->medges[i].v2; v1 = sys->vertexCos[idv1]; v2 = sys->vertexCos[idv2]; sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1; sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1; w1 = len_v3v3(v1, v2); if (w1 < sys->min_area) { sys->zerola[idv1] = 1; sys->zerola[idv2] = 1; } else { w1 = 1.0f / w1; } sys->eweights[i] = w1; } for (i = 0; i < sys->numFaces; i++) { has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0; idv1 = sys->mfaces[i].v1; idv2 = sys->mfaces[i].v2; idv3 = sys->mfaces[i].v3; idv4 = has_4_vert ? sys->mfaces[i].v4 : 0; sys->numNeFa[idv1] += 1; sys->numNeFa[idv2] += 1; sys->numNeFa[idv3] += 1; if (has_4_vert) sys->numNeFa[idv4] += 1; v1 = sys->vertexCos[idv1]; v2 = sys->vertexCos[idv2]; v3 = sys->vertexCos[idv3]; v4 = has_4_vert ? sys->vertexCos[idv4] : NULL; if (has_4_vert) { areaf = area_quad_v3(v1, v2, v3, sys->vertexCos[sys->mfaces[i].v4]); } else { areaf = area_tri_v3(v1, v2, v3); } if (fabsf(areaf) < sys->min_area) { sys->zerola[idv1] = 1; sys->zerola[idv2] = 1; sys->zerola[idv3] = 1; if (has_4_vert) sys->zerola[idv4] = 1; } if (has_4_vert) { sys->ring_areas[idv1] += average_area_quad_v3(v1, v2, v3, v4); sys->ring_areas[idv2] += average_area_quad_v3(v2, v3, v4, v1); sys->ring_areas[idv3] += average_area_quad_v3(v3, v4, v1, v2); sys->ring_areas[idv4] += average_area_quad_v3(v4, v1, v2, v3); } else { sys->ring_areas[idv1] += areaf; sys->ring_areas[idv2] += areaf; sys->ring_areas[idv3] += areaf; } if (has_4_vert) { idv[0] = idv1; idv[1] = idv2; idv[2] = idv3; idv[3] = idv4; for (j = 0; j < 4; j++) { idv1 = idv[j]; idv2 = idv[(j + 1) % 4]; idv3 = idv[(j + 2) % 4]; idv4 = idv[(j + 3) % 4]; v1 = sys->vertexCos[idv1]; v2 = sys->vertexCos[idv2]; v3 = sys->vertexCos[idv3]; v4 = sys->vertexCos[idv4]; w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f; } } else { w1 = cotangent_tri_weight_v3(v1, v2, v3) / 2.0f; w2 = cotangent_tri_weight_v3(v2, v3, v1) / 2.0f; w3 = cotangent_tri_weight_v3(v3, v1, v2) / 2.0f; sys->fweights[i][0] = sys->fweights[i][0] + w1; sys->fweights[i][1] = sys->fweights[i][1] + w2; sys->fweights[i][2] = sys->fweights[i][2] + w3; sys->vweights[idv1] = sys->vweights[idv1] + w2 + w3; sys->vweights[idv2] = sys->vweights[idv2] + w1 + w3; sys->vweights[idv3] = sys->vweights[idv3] + w1 + w2; } } for (i = 0; i < sys->numEdges; i++) { idv1 = sys->medges[i].v1; idv2 = sys->medges[i].v2; /* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */ if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) { sys->vlengths[idv1] += sys->eweights[i]; sys->vlengths[idv2] += sys->eweights[i]; } } }