Fix T96308: Mesh to BMesh conversion doesn't calculate vertex normals
Currently there is a "calc_face_normal" argument to mesh to bmesh
conversion, but vertex normals had always implicitly inherited whatever
dirty state the mesh input's vertex normals were in. Probably they were
most often assumed to not be dirty, but this was never really correct in
the general case.
Ever since the refactor to move vertex normals out of mesh vertices,
cfa53e0fbe
, the copying logic has been explicit: copy the
normals when they are not dirty. But it turns out that more control is
needed, and sometimes normals should be calculated for the resulting
BMesh.
This commit adds an option to the conversion to calculate vertex
normals, true by default. In almost all places except the decimate
and edge split modifiers, I just copied the value of the
"calc_face_normals" argument.
Differential Revision: https://developer.blender.org/D14406
This commit is contained in:
parent
86d87fcbdb
commit
64cd927519
Notes:
blender-bot
2023-02-14 09:19:09 +01:00
Referenced by commit 77db370cb6
, Fix: BMesh Python API errors after vertex_normals addition
Referenced by issue #97213, Regression: Crash when creating a BMesh with "use_shape_key" on
Referenced by issue #96308, Regression: Script using bmesh.ops.wireframe and bmesh.ops.bevel does not work the same in 3.1 and in 3.01.
Referenced by issue #96241, 3.1: Potential candidates for corrective releases
|
@ -1166,6 +1166,7 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
|
|||
{
|
||||
BMeshFromMeshParams bmesh_from_mesh_params{};
|
||||
bmesh_from_mesh_params.calc_face_normal = false;
|
||||
bmesh_from_mesh_params.calc_vert_normal = false;
|
||||
bmesh_from_mesh_params.add_key_index = add_key_index;
|
||||
bmesh_from_mesh_params.use_shapekey = true;
|
||||
bmesh_from_mesh_params.active_shapekey = ob->shapenr;
|
||||
|
|
|
@ -46,6 +46,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
|
|||
&(struct BMeshCreateParams){0},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
.cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
|
||||
.emask = CD_MASK_ORIGINDEX,
|
||||
.pmask = CD_MASK_ORIGINDEX},
|
||||
|
@ -92,6 +93,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
|
|||
},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
.cd_mask_extra =
|
||||
{
|
||||
.vmask = CD_MASK_SHAPEKEY,
|
||||
|
|
|
@ -401,6 +401,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
|
|||
|
||||
BMeshFromMeshParams bmesh_from_mesh_params{};
|
||||
bmesh_from_mesh_params.calc_face_normal = true;
|
||||
bmesh_from_mesh_params.calc_vert_normal = true;
|
||||
BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
|
||||
|
||||
BMVert *v;
|
||||
|
|
|
@ -869,6 +869,7 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
|
|||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
return bm;
|
||||
|
|
|
@ -17,7 +17,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm);
|
|||
void BM_mesh_elem_toolflags_clear(BMesh *bm);
|
||||
|
||||
struct BMeshCreateParams {
|
||||
uint use_toolflags : 1;
|
||||
bool use_toolflags : true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -229,7 +229,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
* work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
|
||||
* in edit mode. */
|
||||
const float(*vert_normals)[3] = nullptr;
|
||||
if (!BKE_mesh_vertex_normals_are_dirty(me)) {
|
||||
if (params->calc_vert_normal) {
|
||||
vert_normals = BKE_mesh_vertex_normals_ensure(me);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
|
|||
|
||||
struct BMeshFromMeshParams {
|
||||
uint calc_face_normal : 1;
|
||||
uint calc_vert_normal : 1;
|
||||
/* add a vertex CD_SHAPE_KEYINDEX layer */
|
||||
uint add_key_index : 1;
|
||||
/* set vertex coordinates from the shapekey */
|
||||
|
|
|
@ -108,6 +108,7 @@ static int geometry_extract_apply(bContext *C,
|
|||
new_mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
BMEditMesh *em = BKE_editmesh_create(bm);
|
||||
|
|
|
@ -673,6 +673,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em)
|
|||
(&(struct BMeshFromMeshParams){
|
||||
/* Handled with tessellation. */
|
||||
.calc_face_normal = false,
|
||||
.calc_vert_normal = false,
|
||||
.active_shapekey = um->shapenr,
|
||||
}));
|
||||
|
||||
|
|
|
@ -962,6 +962,7 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
|
|||
trim_mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
|
||||
BMO_op_callf(bm,
|
||||
|
@ -1214,12 +1215,14 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
|
|||
trim_mesh,
|
||||
&((struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
BM_mesh_bm_from_me(bm,
|
||||
sculpt_mesh,
|
||||
&((struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
|
||||
|
|
|
@ -147,6 +147,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
|
|||
me,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
.use_shapekey = true,
|
||||
.active_shapekey = ob->shapenr,
|
||||
}));
|
||||
|
|
|
@ -379,6 +379,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
|||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
BMIter iter;
|
||||
|
@ -574,6 +575,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
|
|||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
|
||||
|
@ -652,6 +654,7 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode)
|
|||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
|
@ -1184,6 +1187,7 @@ static void sculpt_face_set_delete_geometry(Object *ob,
|
|||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
|
||||
BM_mesh_elem_table_init(bm, BM_FACE);
|
||||
|
|
|
@ -2969,6 +2969,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
|
|||
me,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
|
||||
ED_uvedit_select_all(bm);
|
||||
|
|
|
@ -1753,6 +1753,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
|
|||
obi->original_me,
|
||||
&((struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context)
|
|||
BMeshCreateParams bmesh_create_params{};
|
||||
BMeshFromMeshParams bmesh_from_mesh_params{};
|
||||
bmesh_from_mesh_params.calc_face_normal = true;
|
||||
bmesh_from_mesh_params.calc_vert_normal = true;
|
||||
BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
|
||||
|
||||
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr);
|
||||
|
|
|
@ -411,6 +411,7 @@ void bc_triangulate_mesh(Mesh *me)
|
|||
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params);
|
||||
BMeshFromMeshParams bm_from_me_params{};
|
||||
bm_from_me_params.calc_face_normal = true;
|
||||
bm_from_me_params.calc_vert_normal = true;
|
||||
BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
|
||||
BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr);
|
||||
|
||||
|
|
|
@ -89,8 +89,13 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
|||
if (export_mesh_eval_->totpoly <= 0) {
|
||||
return {export_mesh_eval_, false};
|
||||
}
|
||||
const struct BMeshCreateParams bm_create_params = {0u};
|
||||
const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0};
|
||||
const BMeshCreateParams bm_create_params = {0u};
|
||||
BMeshFromMeshParams bm_convert_params{};
|
||||
bm_convert_params.calc_face_normal = true;
|
||||
bm_convert_params.calc_vert_normal = true;
|
||||
bm_convert_params.add_key_index = false;
|
||||
bm_convert_params.use_shapekey = false;
|
||||
|
||||
/* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
|
||||
* triangulated here. */
|
||||
const int triangulate_min_verts = 4;
|
||||
|
@ -377,8 +382,8 @@ void OBJMesh::store_normal_coords_and_indices()
|
|||
normal_to_index.reserve(export_mesh_eval_->totpoly);
|
||||
loop_to_normal_index_.resize(export_mesh_eval_->totloop);
|
||||
loop_to_normal_index_.fill(-1);
|
||||
const float(
|
||||
*lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
|
||||
const float(*lnors)[3] = (const float(*)[3])(
|
||||
CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
|
||||
for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
|
||||
const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
|
||||
bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
|
||||
|
|
|
@ -111,6 +111,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||
&(struct BMeshCreateParams){0},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
.add_key_index = false,
|
||||
.use_shapekey = false,
|
||||
.active_shapekey = 0,
|
||||
|
|
|
@ -244,6 +244,7 @@ static BMesh *BMD_mesh_bm_create(
|
|||
|
||||
BMeshFromMeshParams bmesh_from_mesh_params{};
|
||||
bmesh_from_mesh_params.calc_face_normal = true;
|
||||
bmesh_from_mesh_params.calc_vert_normal = true;
|
||||
BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params);
|
||||
|
||||
if (UNLIKELY(*r_is_flip)) {
|
||||
|
|
|
@ -91,6 +91,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||
DecimateModifierData *dmd = (DecimateModifierData *)md;
|
||||
Mesh *mesh = meshData, *result = NULL;
|
||||
BMesh *bm;
|
||||
bool calc_vert_normal;
|
||||
bool calc_face_normal;
|
||||
float *vweights = NULL;
|
||||
|
||||
|
@ -107,18 +108,21 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||
return mesh;
|
||||
}
|
||||
calc_face_normal = true;
|
||||
calc_vert_normal = true;
|
||||
break;
|
||||
case MOD_DECIM_MODE_UNSUBDIV:
|
||||
if (dmd->iter == 0) {
|
||||
return mesh;
|
||||
}
|
||||
calc_face_normal = false;
|
||||
calc_vert_normal = false;
|
||||
break;
|
||||
case MOD_DECIM_MODE_DISSOLVE:
|
||||
if (dmd->angle == 0.0f) {
|
||||
return mesh;
|
||||
}
|
||||
calc_face_normal = true;
|
||||
calc_vert_normal = false;
|
||||
break;
|
||||
default:
|
||||
return mesh;
|
||||
|
@ -160,6 +164,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||
&(struct BMeshCreateParams){0},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = calc_face_normal,
|
||||
.calc_vert_normal = calc_vert_normal,
|
||||
.cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
|
||||
.emask = CD_MASK_ORIGINDEX,
|
||||
.pmask = CD_MASK_ORIGINDEX},
|
||||
|
|
|
@ -57,6 +57,7 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd)
|
|||
&(struct BMeshCreateParams){0},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = calc_face_normals,
|
||||
.calc_vert_normal = false,
|
||||
.add_key_index = false,
|
||||
.use_shapekey = false,
|
||||
.active_shapekey = 0,
|
||||
|
|
|
@ -61,6 +61,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
|
|||
&((struct BMeshCreateParams){0}),
|
||||
&((struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = false,
|
||||
.cd_mask_extra = cd_mask_extra,
|
||||
}));
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
|
|||
&(struct BMeshCreateParams){0},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
.calc_vert_normal = true,
|
||||
.add_key_index = false,
|
||||
.use_shapekey = false,
|
||||
.active_shapekey = 0,
|
||||
|
|
|
@ -44,7 +44,13 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh,
|
|||
CustomData_MeshMasks cd_mask_extra = {
|
||||
CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX};
|
||||
BMeshCreateParams create_params{0};
|
||||
BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra};
|
||||
BMeshFromMeshParams from_mesh_params{};
|
||||
from_mesh_params.calc_face_normal = true;
|
||||
from_mesh_params.calc_vert_normal = true;
|
||||
from_mesh_params.add_key_index = true;
|
||||
from_mesh_params.use_shapekey = true;
|
||||
from_mesh_params.active_shapekey = 1;
|
||||
from_mesh_params.cd_mask_extra = cd_mask_extra;
|
||||
BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
|
||||
|
||||
/* Tag faces to be triangulated from the selection mask. */
|
||||
|
|
|
@ -1050,7 +1050,8 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(bpy_bmesh_from_object_doc,
|
||||
".. method:: from_object(object, depsgraph, cage=False, face_normals=True)\n"
|
||||
".. method:: from_object(object, depsgraph, cage=False, face_normals=True, "
|
||||
"vertex_normals=True)\n"
|
||||
"\n"
|
||||
" Initialize this bmesh from existing object data-block (only meshes are currently "
|
||||
"supported).\n"
|
||||
|
@ -1060,10 +1061,12 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc,
|
|||
" :arg cage: Get the mesh as a deformed cage.\n"
|
||||
" :type cage: boolean\n"
|
||||
" :arg face_normals: Calculate face normals.\n"
|
||||
" :arg vertex_normals: Calculate vertex normals.\n"
|
||||
" :type face_normals: boolean\n");
|
||||
static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static const char *kwlist[] = {"object", "depsgraph", "cage", "face_normals", NULL};
|
||||
static const char *kwlist[] = {
|
||||
"object", "depsgraph", "cage", "face_normals", "vertex_normals", NULL};
|
||||
PyObject *py_object;
|
||||
PyObject *py_depsgraph;
|
||||
Object *ob, *ob_eval;
|
||||
|
@ -1073,6 +1076,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
|
|||
BMesh *bm;
|
||||
bool use_cage = false;
|
||||
bool use_fnorm = true;
|
||||
bool use_vert_normal = true;
|
||||
const CustomData_MeshMasks data_masks = CD_MASK_BMESH;
|
||||
|
||||
BPY_BM_CHECK_OBJ(self);
|
||||
|
@ -1086,7 +1090,9 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
|
|||
PyC_ParseBool,
|
||||
&use_cage,
|
||||
PyC_ParseBool,
|
||||
&use_fnorm) ||
|
||||
&use_fnorm,
|
||||
PyC_ParseBool,
|
||||
&use_vert_normal) ||
|
||||
!(ob = PyC_RNA_AsPointer(py_object, "Object")) ||
|
||||
!(depsgraph = PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))) {
|
||||
return NULL;
|
||||
|
@ -1137,6 +1143,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
|
|||
me_eval,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = use_fnorm,
|
||||
.calc_vert_normal = use_vert_normal,
|
||||
}));
|
||||
|
||||
if (need_free) {
|
||||
|
@ -1148,7 +1155,8 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
|
|||
|
||||
PyDoc_STRVAR(
|
||||
bpy_bmesh_from_mesh_doc,
|
||||
".. method:: from_mesh(mesh, face_normals=True, use_shape_key=False, shape_key_index=0)\n"
|
||||
".. method:: from_mesh(mesh, face_normals=True, vertex_normals=True, use_shape_key=False, "
|
||||
"shape_key_index=0)\n"
|
||||
"\n"
|
||||
" Initialize this bmesh from existing mesh datablock.\n"
|
||||
"\n"
|
||||
|
@ -1168,11 +1176,13 @@ PyDoc_STRVAR(
|
|||
"mesh won't be added.\n");
|
||||
static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static const char *kwlist[] = {"mesh", "face_normals", "use_shape_key", "shape_key_index", NULL};
|
||||
static const char *kwlist[] = {
|
||||
"mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", NULL};
|
||||
BMesh *bm;
|
||||
PyObject *py_mesh;
|
||||
Mesh *me;
|
||||
bool use_fnorm = true;
|
||||
bool use_vert_normal = true;
|
||||
bool use_shape_key = false;
|
||||
int shape_key_index = 0;
|
||||
|
||||
|
@ -1186,6 +1196,8 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
|
|||
PyC_ParseBool,
|
||||
&use_fnorm,
|
||||
PyC_ParseBool,
|
||||
&use_vert_normal,
|
||||
PyC_ParseBool,
|
||||
&use_shape_key,
|
||||
&shape_key_index) ||
|
||||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh"))) {
|
||||
|
@ -1198,6 +1210,7 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
|
|||
me,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = use_fnorm,
|
||||
.calc_vert_normal = use_vert_normal,
|
||||
.use_shapekey = use_shape_key,
|
||||
.active_shapekey = shape_key_index + 1,
|
||||
}));
|
||||
|
|
Loading…
Reference in New Issue