diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-05-10 14:07:01 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-05-10 14:07:01 +0400 |
commit | 4392fc6f1d4950ab0e0e60aae1bd5dea5baf26de (patch) | |
tree | 119985340414ffbbf749ef0ef41efdacf7cdd8c5 /source/blender/blenkernel/intern/mesh.c | |
parent | a961b683fc62f893e70d9e0fbf80ed4d1e31b857 (diff) |
Optimize BKE_mesh_calc_normals(), gives approx 25% speedup.
- no need to allocate polygon normal array.
- no need to use BLI_array_ functions (realloc's).
- reduce some of the looping.
Diffstat (limited to 'source/blender/blenkernel/intern/mesh.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 91 |
1 files changed, 56 insertions, 35 deletions
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 0575407937a..4bf0ed5737e 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1941,51 +1941,74 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, int numVerts, } -void BKE_mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys, - int UNUSED(numLoops), int numPolys, float (*polyNors_r)[3]) +static void mesh_calc_normals_poly_accum(MPoly *mp, MLoop *ml, + MVert *mvert, float polyno[3], float (*tnorms)[3]) { - float (*pnors)[3] = polyNors_r; + const int nverts = mp->totloop; + float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, nverts); + int i; - float (*tnorms)[3], (*edgevecbuf)[3] = NULL; - float **vertcos = NULL, **vertnos = NULL; - BLI_array_declare(vertcos); - BLI_array_declare(vertnos); - BLI_array_declare(edgevecbuf); + /* Polygon Normal and edge-vector */ + /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ + { + float const *v_prev = mvert[ml[nverts - 1].v].co; + float const *v_curr; + int i_prev = nverts - 1; - int i, j; - MPoly *mp; - MLoop *ml; + zero_v3(polyno); + /* Newell's Method */ + for (i = 0; i < nverts; i++) { + v_curr = mvert[ml[i].v].co; + add_newell_cross_v3_v3v3(polyno, v_prev, v_curr); - if (!pnors) pnors = MEM_callocN(sizeof(float) * 3 * numPolys, "poly_nors mesh.c"); + /* Unrelated to normalize, calcualte edge-vector */ + sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr); + i_prev = i; - /* first go through and calculate normals for all the polys */ - tnorms = MEM_callocN(sizeof(float) * 3 * numVerts, "tnorms mesh.c"); + v_prev = v_curr; + } + if (UNLIKELY(normalize_v3(polyno) == 0.0f)) { + polyno[2] = 1.0f; /* other axis set to 0.0 */ + } + } - mp = mpolys; - for (i = 0; i < numPolys; i++, mp++) { - BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); - ml = mloop + mp->loopstart; + /* accumulate angle weighted face normal */ + /* inline version of #accumulate_vertex_normals_poly */ + { + const float *prev_edge = edgevecbuf[nverts - 1]; - BLI_array_empty(vertcos); - BLI_array_empty(vertnos); - BLI_array_grow_items(vertcos, mp->totloop); - BLI_array_grow_items(vertnos, mp->totloop); + for (i = 0; i < nverts; i++) { + const float *cur_edge = edgevecbuf[i]; + unsigned int vindex = ml[i].v; - for (j = 0; j < mp->totloop; j++) { - int vindex = ml[j].v; - vertcos[j] = mverts[vindex].co; - vertnos[j] = tnorms[vindex]; + /* calculate angle between the two poly edges incident on + * this vertex */ + const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); + + /* accumulate */ + madd_v3_v3fl(tnorms[vindex], polyno, fac); + prev_edge = cur_edge; } + } - BLI_array_empty(edgevecbuf); - BLI_array_grow_items(edgevecbuf, mp->totloop); +} - accumulate_vertex_normals_poly(vertnos, pnors[i], vertcos, edgevecbuf, mp->totloop); - } +void BKE_mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys, + int UNUSED(numLoops), int numPolys, float (*polyNors_r)[3]) +{ + float (*pnors)[3] = polyNors_r; + float (*tnorms)[3]; + float tpnor[3]; /* temp poly normal */ + int i; + MPoly *mp; + + /* first go through and calculate normals for all the polys */ + tnorms = MEM_callocN(sizeof(*tnorms) * numVerts, __func__); - BLI_array_free(vertcos); - BLI_array_free(vertnos); - BLI_array_free(edgevecbuf); + mp = mpolys; + for (i = 0; i < numPolys; i++, mp++) { + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors ? pnors[i] : tpnor, tnorms); + } /* following Mesh convention; we use vertex coordinate itself for normal in this case */ for (i = 0; i < numVerts; i++) { @@ -2000,8 +2023,6 @@ void BKE_mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpo } MEM_freeN(tnorms); - - if (pnors != polyNors_r) MEM_freeN(pnors); } void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) |