BMesh: support face-normal calculation in normal & looptri functions
Support calculating face normals when tessellating. When this is done before updating vertex normals it gives ~20% performance improvement. Now vertex normal calculation only needs to perform a single pass on the mesh vertices when called after tessellation. Extended versions of normal & looptri update functions have been added: - BM_mesh_calc_tessellation_ex - BM_mesh_normals_update_ex Most callers don't need to be aware of this detail by using: - BKE_editmesh_looptri_and_normals_calc - BKE_editmesh_looptri_and_normals_calc_with_partial - EDBM_update also takes advantage of this, where calling EDBM_update with calc_looptri & calc_normals enabled uses the faster normal updating logic.
This commit is contained in:
parent
6bef255904
commit
8a1860bd9a
Notes:
blender-bot
2023-02-13 18:36:21 +01:00
Referenced by commit a9d5c8f97f
, Fix error passing in false as instead of a struct
Referenced by issue #88550, Mesh Optimization Project Progress
|
@ -34,6 +34,7 @@ extern "C" {
|
|||
struct BMLoop;
|
||||
struct BMesh;
|
||||
struct BMPartialUpdate;
|
||||
struct BMeshCalcTessellation_Params;
|
||||
struct BoundBox;
|
||||
struct Depsgraph;
|
||||
struct Mesh;
|
||||
|
@ -85,8 +86,17 @@ typedef struct BMEditMesh {
|
|||
} BMEditMesh;
|
||||
|
||||
/* editmesh.c */
|
||||
void BKE_editmesh_looptri_calc_ex(BMEditMesh *em,
|
||||
const struct BMeshCalcTessellation_Params *params);
|
||||
void BKE_editmesh_looptri_calc(BMEditMesh *em);
|
||||
void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em,
|
||||
struct BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshCalcTessellation_Params *params);
|
||||
void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo);
|
||||
void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
|
||||
struct BMPartialUpdate *bmpinfo);
|
||||
|
||||
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em);
|
||||
|
||||
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate);
|
||||
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
|
||||
|
|
|
@ -96,7 +96,8 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob)
|
|||
return ((Mesh *)ob->data)->edit_mesh;
|
||||
}
|
||||
|
||||
static void editmesh_tessface_calc_intern(BMEditMesh *em)
|
||||
static void editmesh_tessface_calc_intern(BMEditMesh *em,
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
/* allocating space before calculating the tessellation */
|
||||
|
||||
|
@ -130,12 +131,13 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
|
|||
em->tottri = looptris_tot;
|
||||
|
||||
/* after allocating the em->looptris, we're ready to tessellate */
|
||||
BM_mesh_calc_tessellation(em->bm, em->looptris);
|
||||
BM_mesh_calc_tessellation_ex(em->bm, em->looptris, params);
|
||||
}
|
||||
|
||||
void BKE_editmesh_looptri_calc(BMEditMesh *em)
|
||||
void BKE_editmesh_looptri_calc_ex(BMEditMesh *em,
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
editmesh_tessface_calc_intern(em);
|
||||
editmesh_tessface_calc_intern(em, params);
|
||||
|
||||
/* commented because editbmesh_build_data() ensures we get tessfaces */
|
||||
#if 0
|
||||
|
@ -149,12 +151,58 @@ void BKE_editmesh_looptri_calc(BMEditMesh *em)
|
|||
#endif
|
||||
}
|
||||
|
||||
void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo)
|
||||
void BKE_editmesh_looptri_calc(BMEditMesh *em)
|
||||
{
|
||||
BKE_editmesh_looptri_calc_ex(em,
|
||||
&(const struct BMeshCalcTessellation_Params){
|
||||
.face_normals = false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performing the face normal calculation at the same time as tessellation
|
||||
* gives a reasonable performance boost (approx ~20% faster).
|
||||
*/
|
||||
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
|
||||
{
|
||||
BKE_editmesh_looptri_calc_ex(em,
|
||||
&(const struct BMeshCalcTessellation_Params){
|
||||
.face_normals = true,
|
||||
});
|
||||
BM_mesh_normals_update_ex(em->bm,
|
||||
&(const struct BMeshNormalsUpdate_Params){
|
||||
.face_normals = false,
|
||||
});
|
||||
}
|
||||
|
||||
void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em,
|
||||
struct BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
BLI_assert(em->tottri == poly_to_tri_count(em->bm->totface, em->bm->totloop));
|
||||
BLI_assert(em->looptris != NULL);
|
||||
|
||||
BM_mesh_calc_tessellation_with_partial(em->bm, em->looptris, bmpinfo);
|
||||
BM_mesh_calc_tessellation_with_partial_ex(em->bm, em->looptris, bmpinfo, params);
|
||||
}
|
||||
|
||||
void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo)
|
||||
{
|
||||
BKE_editmesh_looptri_calc_with_partial_ex(em, bmpinfo, false);
|
||||
}
|
||||
|
||||
void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
|
||||
struct BMPartialUpdate *bmpinfo)
|
||||
{
|
||||
BKE_editmesh_looptri_calc_with_partial_ex(em,
|
||||
bmpinfo,
|
||||
&(const struct BMeshCalcTessellation_Params){
|
||||
.face_normals = true,
|
||||
});
|
||||
BM_mesh_normals_update_with_partial_ex(em->bm,
|
||||
bmpinfo,
|
||||
&(const struct BMeshNormalsUpdate_Params){
|
||||
.face_normals = false,
|
||||
});
|
||||
}
|
||||
|
||||
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
|
||||
|
|
|
@ -240,19 +240,29 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata),
|
|||
*
|
||||
* Updates the normals of a mesh.
|
||||
*/
|
||||
void BM_mesh_normals_update(BMesh *bm)
|
||||
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
|
||||
{
|
||||
/* Calculate all face normals. */
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_mempool_settings_defaults(&settings);
|
||||
settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
|
||||
if (params->face_normals) {
|
||||
/* Calculate all face normals. */
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_mempool_settings_defaults(&settings);
|
||||
settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
|
||||
|
||||
BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings);
|
||||
BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings);
|
||||
}
|
||||
|
||||
/* Add weighted face normals to vertices, and normalize vert normals. */
|
||||
bm_mesh_verts_calc_normals(bm, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void BM_mesh_normals_update(BMesh *bm)
|
||||
{
|
||||
BM_mesh_normals_update_ex(bm,
|
||||
&(const struct BMeshNormalsUpdate_Params){
|
||||
.face_normals = true,
|
||||
});
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -277,7 +287,9 @@ static void bm_partial_verts_parallel_range_calc_normal_cb(
|
|||
* A version of #BM_mesh_normals_update that updates a subset of geometry,
|
||||
* used to avoid the overhead of updating everything.
|
||||
*/
|
||||
void BM_mesh_normals_update_with_partial(BMesh *UNUSED(bm), const BMPartialUpdate *bmpinfo)
|
||||
void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm),
|
||||
const BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshNormalsUpdate_Params *params)
|
||||
{
|
||||
BLI_assert(bmpinfo->params.do_normals);
|
||||
|
||||
|
@ -290,14 +302,25 @@ void BM_mesh_normals_update_with_partial(BMesh *UNUSED(bm), const BMPartialUpdat
|
|||
BLI_parallel_range_settings_defaults(&settings);
|
||||
|
||||
/* Faces. */
|
||||
BLI_task_parallel_range(
|
||||
0, faces_len, faces, bm_partial_faces_parallel_range_calc_normals_cb, &settings);
|
||||
if (params->face_normals) {
|
||||
BLI_task_parallel_range(
|
||||
0, faces_len, faces, bm_partial_faces_parallel_range_calc_normals_cb, &settings);
|
||||
}
|
||||
|
||||
/* Verts. */
|
||||
BLI_task_parallel_range(
|
||||
0, verts_len, verts, bm_partial_verts_parallel_range_calc_normal_cb, &settings);
|
||||
}
|
||||
|
||||
void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpinfo)
|
||||
{
|
||||
BM_mesh_normals_update_with_partial_ex(bm,
|
||||
bmpinfo,
|
||||
&(const struct BMeshNormalsUpdate_Params){
|
||||
.face_normals = true,
|
||||
});
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -22,7 +22,19 @@
|
|||
|
||||
#include "bmesh_class.h"
|
||||
|
||||
struct BMeshNormalsUpdate_Params {
|
||||
/**
|
||||
* When calculating tessellation as well as normals, tessellate & calculate face normals
|
||||
* for improved performance. See #BMeshCalcTessellation_Params
|
||||
*/
|
||||
bool face_normals;
|
||||
};
|
||||
|
||||
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param);
|
||||
void BM_mesh_normals_update(BMesh *bm);
|
||||
void BM_mesh_normals_update_with_partial_ex(BMesh *bm,
|
||||
const struct BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshNormalsUpdate_Params *param);
|
||||
void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo);
|
||||
|
||||
void BM_verts_calc_normal_vcos(BMesh *bm,
|
||||
|
|
|
@ -50,9 +50,13 @@
|
|||
/** \name Default Mesh Tessellation
|
||||
* \{ */
|
||||
|
||||
static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
|
||||
BMFace *efa,
|
||||
MemArena **pf_arena_p)
|
||||
/**
|
||||
* \param face_normal: This will be optimized out as a constant.
|
||||
*/
|
||||
BLI_INLINE int mesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3],
|
||||
BMFace *efa,
|
||||
MemArena **pf_arena_p,
|
||||
const bool face_normal)
|
||||
{
|
||||
switch (efa->len) {
|
||||
case 3: {
|
||||
|
@ -62,6 +66,9 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
|
|||
l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
|
||||
l_ptr[1] = l = l->next;
|
||||
l_ptr[2] = l->next;
|
||||
if (face_normal) {
|
||||
normal_tri_v3(efa->no, l_ptr[0]->v->co, l_ptr[1]->v->co, l_ptr[2]->v->co);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
case 4: {
|
||||
|
@ -74,6 +81,11 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
|
|||
(l_ptr_a[2] = l_ptr_b[1] = l = l->next);
|
||||
(l_ptr_b[2] = l->next);
|
||||
|
||||
if (face_normal) {
|
||||
normal_quad_v3(
|
||||
efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
|
||||
}
|
||||
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast(
|
||||
l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
|
||||
/* Flip out of degenerate 0-2 state. */
|
||||
|
@ -83,6 +95,10 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
|
|||
return 2;
|
||||
}
|
||||
default: {
|
||||
if (face_normal) {
|
||||
BM_face_calc_normal(efa, efa->no);
|
||||
}
|
||||
|
||||
BMLoop *l_iter, *l_first;
|
||||
BMLoop **l_arr;
|
||||
|
||||
|
@ -128,13 +144,29 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
|
|||
}
|
||||
}
|
||||
|
||||
static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
|
||||
BMFace *efa,
|
||||
MemArena **pf_arena_p)
|
||||
{
|
||||
return mesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, false);
|
||||
}
|
||||
|
||||
static int mesh_calc_tessellation_for_face_with_normal(BMLoop *(*looptris)[3],
|
||||
BMFace *efa,
|
||||
MemArena **pf_arena_p)
|
||||
{
|
||||
return mesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh
|
||||
* \param looptris:
|
||||
*
|
||||
* \note \a looptris Must be pre-allocated to at least the size of given by: poly_to_tri_count
|
||||
*/
|
||||
static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, BMLoop *(*looptris)[3])
|
||||
static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const char face_normals)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
|
||||
|
@ -146,9 +178,18 @@ static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, BMLoop *(*loop
|
|||
|
||||
MemArena *pf_arena = NULL;
|
||||
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BLI_assert(efa->len >= 3);
|
||||
i += mesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena);
|
||||
if (face_normals) {
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BLI_assert(efa->len >= 3);
|
||||
BM_face_calc_normal(efa, efa->no);
|
||||
i += mesh_calc_tessellation_for_face_with_normal(looptris + i, efa, &pf_arena);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BLI_assert(efa->len >= 3);
|
||||
i += mesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena);
|
||||
}
|
||||
}
|
||||
|
||||
if (pf_arena) {
|
||||
|
@ -175,6 +216,18 @@ static void mesh_calc_tessellation_for_face_fn(void *__restrict userdata,
|
|||
mesh_calc_tessellation_for_face(looptris + offset, f, &tls_data->pf_arena);
|
||||
}
|
||||
|
||||
static void mesh_calc_tessellation_for_face_with_normals_fn(void *__restrict userdata,
|
||||
MempoolIterData *mp_f,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
struct TessellationUserTLS *tls_data = tls->userdata_chunk;
|
||||
BMLoop *(*looptris)[3] = userdata;
|
||||
BMFace *f = (BMFace *)mp_f;
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
|
||||
mesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &tls_data->pf_arena);
|
||||
}
|
||||
|
||||
static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSED(userdata),
|
||||
void *__restrict tls_v)
|
||||
{
|
||||
|
@ -184,7 +237,9 @@ static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSE
|
|||
}
|
||||
}
|
||||
|
||||
static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, BMLoop *(*looptris)[3])
|
||||
static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const char face_normals)
|
||||
{
|
||||
BM_mesh_elem_index_ensure(bm, BM_LOOP | BM_FACE);
|
||||
|
||||
|
@ -194,17 +249,29 @@ static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, BMLoop *(*loopt
|
|||
settings.userdata_chunk = &tls_dummy;
|
||||
settings.userdata_chunk_size = sizeof(tls_dummy);
|
||||
settings.func_free = mesh_calc_tessellation_for_face_free_fn;
|
||||
BM_iter_parallel(bm, BM_FACES_OF_MESH, mesh_calc_tessellation_for_face_fn, looptris, &settings);
|
||||
BM_iter_parallel(bm,
|
||||
BM_FACES_OF_MESH,
|
||||
face_normals ? mesh_calc_tessellation_for_face_with_normals_fn :
|
||||
mesh_calc_tessellation_for_face_fn,
|
||||
looptris,
|
||||
&settings);
|
||||
}
|
||||
|
||||
void BM_mesh_calc_tessellation_ex(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
if (bm->totface < BM_FACE_TESSELLATE_THREADED_LIMIT) {
|
||||
bm_mesh_calc_tessellation__single_threaded(bm, looptris, params->face_normals);
|
||||
}
|
||||
else {
|
||||
bm_mesh_calc_tessellation__multi_threaded(bm, looptris, params->face_normals);
|
||||
}
|
||||
}
|
||||
|
||||
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3])
|
||||
{
|
||||
if (bm->totface < BM_FACE_TESSELLATE_THREADED_LIMIT) {
|
||||
bm_mesh_calc_tessellation__single_threaded(bm, looptris);
|
||||
}
|
||||
else {
|
||||
bm_mesh_calc_tessellation__multi_threaded(bm, looptris);
|
||||
}
|
||||
BM_mesh_calc_tessellation_ex(bm, looptris, false);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -234,6 +301,17 @@ static void mesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata
|
|||
mesh_calc_tessellation_for_face(data->looptris + offset, f, &tls_data->pf_arena);
|
||||
}
|
||||
|
||||
static void mesh_calc_tessellation_for_face_partial_with_normals_fn(
|
||||
void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
struct PartialTessellationUserTLS *tls_data = tls->userdata_chunk;
|
||||
struct PartialTessellationUserData *data = userdata;
|
||||
BMFace *f = data->faces[index];
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
|
||||
mesh_calc_tessellation_for_face_with_normal(data->looptris + offset, f, &tls_data->pf_arena);
|
||||
}
|
||||
|
||||
static void mesh_calc_tessellation_for_face_partial_free_fn(
|
||||
const void *__restrict UNUSED(userdata), void *__restrict tls_v)
|
||||
{
|
||||
|
@ -243,8 +321,10 @@ static void mesh_calc_tessellation_for_face_partial_free_fn(
|
|||
}
|
||||
}
|
||||
|
||||
static void bm_mesh_calc_tessellation_with_partial__multi_threaded(BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo)
|
||||
static void bm_mesh_calc_tessellation_with_partial__multi_threaded(
|
||||
BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
const int faces_len = bmpinfo->faces_len;
|
||||
BMFace **faces = bmpinfo->faces;
|
||||
|
@ -261,23 +341,40 @@ static void bm_mesh_calc_tessellation_with_partial__multi_threaded(BMLoop *(*loo
|
|||
settings.userdata_chunk_size = sizeof(tls_dummy);
|
||||
settings.func_free = mesh_calc_tessellation_for_face_partial_free_fn;
|
||||
|
||||
BLI_task_parallel_range(
|
||||
0, faces_len, &data, mesh_calc_tessellation_for_face_partial_fn, &settings);
|
||||
BLI_task_parallel_range(0,
|
||||
faces_len,
|
||||
&data,
|
||||
params->face_normals ?
|
||||
mesh_calc_tessellation_for_face_partial_with_normals_fn :
|
||||
mesh_calc_tessellation_for_face_partial_fn,
|
||||
&settings);
|
||||
}
|
||||
|
||||
static void bm_mesh_calc_tessellation_with_partial__single_threaded(BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo)
|
||||
static void bm_mesh_calc_tessellation_with_partial__single_threaded(
|
||||
BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
const int faces_len = bmpinfo->faces_len;
|
||||
BMFace **faces = bmpinfo->faces;
|
||||
|
||||
MemArena *pf_arena = NULL;
|
||||
|
||||
for (int index = 0; index < faces_len; index++) {
|
||||
BMFace *f = faces[index];
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
|
||||
mesh_calc_tessellation_for_face(looptris + offset, f, &pf_arena);
|
||||
if (params->face_normals) {
|
||||
for (int index = 0; index < faces_len; index++) {
|
||||
BMFace *f = faces[index];
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
|
||||
mesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &pf_arena);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int index = 0; index < faces_len; index++) {
|
||||
BMFace *f = faces[index];
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
|
||||
mesh_calc_tessellation_for_face(looptris + offset, f, &pf_arena);
|
||||
}
|
||||
}
|
||||
|
||||
if (pf_arena) {
|
||||
|
@ -285,22 +382,30 @@ static void bm_mesh_calc_tessellation_with_partial__single_threaded(BMLoop *(*lo
|
|||
}
|
||||
}
|
||||
|
||||
void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo)
|
||||
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshCalcTessellation_Params *params)
|
||||
{
|
||||
BLI_assert(bmpinfo->params.do_tessellate);
|
||||
|
||||
BM_mesh_elem_index_ensure(bm, BM_LOOP | BM_FACE);
|
||||
|
||||
if (bmpinfo->faces_len < BM_FACE_TESSELLATE_THREADED_LIMIT) {
|
||||
bm_mesh_calc_tessellation_with_partial__single_threaded(looptris, bmpinfo);
|
||||
bm_mesh_calc_tessellation_with_partial__single_threaded(looptris, bmpinfo, params);
|
||||
}
|
||||
else {
|
||||
bm_mesh_calc_tessellation_with_partial__multi_threaded(looptris, bmpinfo);
|
||||
bm_mesh_calc_tessellation_with_partial__multi_threaded(looptris, bmpinfo, params);
|
||||
}
|
||||
}
|
||||
|
||||
void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const BMPartialUpdate *bmpinfo)
|
||||
{
|
||||
BM_mesh_calc_tessellation_with_partial_ex(bm, looptris, bmpinfo, false);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -22,9 +22,25 @@
|
|||
|
||||
struct BMPartialUpdate;
|
||||
|
||||
struct BMeshCalcTessellation_Params {
|
||||
/**
|
||||
* When calculating normals as well as tessellation, calculate normals after tessellation
|
||||
* for improved performance. See #BMeshCalcTessellation_Params
|
||||
*/
|
||||
bool face_normals;
|
||||
};
|
||||
|
||||
void BM_mesh_calc_tessellation_ex(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const struct BMeshCalcTessellation_Params *params);
|
||||
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
|
||||
|
||||
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
|
||||
|
||||
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const struct BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshCalcTessellation_Params *params);
|
||||
void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
|
||||
BMLoop *(*looptris)[3],
|
||||
const struct BMPartialUpdate *bmpinfo);
|
||||
|
|
|
@ -36,6 +36,7 @@ struct BMFace;
|
|||
struct BMLoop;
|
||||
struct BMVert;
|
||||
struct BMesh;
|
||||
struct BMeshNormalsUpdate_Params;
|
||||
struct Base;
|
||||
struct Depsgraph;
|
||||
struct ID;
|
||||
|
@ -76,6 +77,8 @@ struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *
|
|||
void EDBM_verts_mirror_cache_clear(struct BMEditMesh *em, struct BMVert *v);
|
||||
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em);
|
||||
|
||||
void EDBM_mesh_normals_update_ex(struct BMEditMesh *em,
|
||||
const struct BMeshNormalsUpdate_Params *params);
|
||||
void EDBM_mesh_normals_update(struct BMEditMesh *em);
|
||||
void EDBM_mesh_clear(struct BMEditMesh *em);
|
||||
|
||||
|
|
|
@ -1405,9 +1405,17 @@ bool EDBM_mesh_reveal(BMEditMesh *em, bool select)
|
|||
/** \name Update API
|
||||
* \{ */
|
||||
|
||||
void EDBM_mesh_normals_update_ex(BMEditMesh *em, const struct BMeshNormalsUpdate_Params *params)
|
||||
{
|
||||
BM_mesh_normals_update_ex(em->bm, params);
|
||||
}
|
||||
|
||||
void EDBM_mesh_normals_update(BMEditMesh *em)
|
||||
{
|
||||
BM_mesh_normals_update(em->bm);
|
||||
EDBM_mesh_normals_update_ex(em,
|
||||
&(const struct BMeshNormalsUpdate_Params){
|
||||
.face_normals = true,
|
||||
});
|
||||
}
|
||||
|
||||
void EDBM_stats_update(BMEditMesh *em)
|
||||
|
@ -1449,12 +1457,18 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
|
|||
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
|
||||
|
||||
if (params->calc_normals) {
|
||||
EDBM_mesh_normals_update(em);
|
||||
if (params->calc_normals && params->calc_looptri) {
|
||||
/* Calculating both has some performance gains. */
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
}
|
||||
else {
|
||||
if (params->calc_normals) {
|
||||
EDBM_mesh_normals_update(em);
|
||||
}
|
||||
|
||||
if (params->calc_looptri) {
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
if (params->calc_looptri) {
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
}
|
||||
}
|
||||
|
||||
if (params->is_destructive) {
|
||||
|
|
|
@ -794,9 +794,7 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
|
|||
|
||||
BMEditMesh *em = BKE_editmesh_from_object(ob);
|
||||
if (LIKELY(em)) {
|
||||
/* order doesn't matter */
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL);
|
||||
|
|
|
@ -350,8 +350,7 @@ static bool object_hook_index_array(Main *bmain,
|
|||
|
||||
em = me->edit_mesh;
|
||||
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
|
||||
/* check selected vertices first */
|
||||
if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) {
|
||||
|
|
|
@ -153,8 +153,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
|
|||
|
||||
em = me->edit_mesh;
|
||||
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
|
||||
/* Make sure the evaluated mesh is updated.
|
||||
*
|
||||
|
|
|
@ -1842,13 +1842,11 @@ void recalcData_mesh(TransInfo *t)
|
|||
* It's impractical to calculate this ahead of time.
|
||||
* Further, the down side of using partial updates when their not needed is negligible. */
|
||||
if (em->bm->totvert == em->bm->totvertsel) {
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
}
|
||||
else {
|
||||
BMPartialUpdate *partial_update_cache = tc_mesh_ensure_partial_update(t, tc);
|
||||
BM_mesh_normals_update_with_partial(em->bm, partial_update_cache);
|
||||
BKE_editmesh_looptri_calc_with_partial(em, partial_update_cache);
|
||||
BKE_editmesh_looptri_and_normals_calc_with_partial(em, partial_update_cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,8 +300,7 @@ void recalcData_mesh_skin(TransInfo *t)
|
|||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
}
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -476,8 +476,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *UNUSED(scene), Po
|
|||
|
||||
DEG_id_tag_update(&me->id, 0);
|
||||
|
||||
EDBM_mesh_normals_update(em);
|
||||
BKE_editmesh_looptri_calc(em);
|
||||
BKE_editmesh_looptri_and_normals_calc(em);
|
||||
break;
|
||||
}
|
||||
case OB_CURVE:
|
||||
|
|
Loading…
Reference in New Issue