Make use/computation of lnors consistant.

Issue was, when requesting (building) lnors for a mesh that has
autosmooth disabled, one would expect to simply get vnors as lnors.

Until now, it wasn't the case, which was bad e.g. for normal projections
of loops in recent remap code (projecting along split loop normals
when you would expect projection along vertex normals...).

Also, removed the 'angle' parameter from RNA's `mesh.calc_normals_split`.
This should *always* use mesh settings (both autosmooth and smoothresh),
otherwise once again we'd get inconsistencies in some cases.
Will update fbx and obj addons too.
This commit is contained in:
Bastien Montagne 2015-01-19 14:11:40 +01:00
parent 694806a9cf
commit 0af11a1742
14 changed files with 107 additions and 50 deletions

View File

@ -45,7 +45,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL:
BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
if ((bool)me) {
if (me.use_auto_smooth()) {
me.calc_normals_split(me.auto_smooth_angle());
me.calc_normals_split();
}
me.calc_tessface();
}

View File

@ -197,7 +197,7 @@ struct DerivedMesh {
void (*calcNormals)(DerivedMesh *dm);
/** Calculate loop (split) normals */
void (*calcLoopNormals)(DerivedMesh *dm, const float split_angle);
void (*calcLoopNormals)(DerivedMesh *dm, const bool use_split_normals, const float split_angle);
/** Recalculates mesh tessellation */
void (*recalcTessellation)(DerivedMesh *dm);

View File

@ -106,7 +106,7 @@ void CDDM_calc_normals_mapping(struct DerivedMesh *dm);
void CDDM_calc_normals(struct DerivedMesh *dm);
void CDDM_calc_normals_tessface(struct DerivedMesh *dm);
void CDDM_calc_loop_normals(struct DerivedMesh *dm, const float split_angle);
void CDDM_calc_loop_normals(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle);
/* calculates edges for a CDDerivedMesh (from face data)
* this completely replaces the current edge data in the DerivedMesh

View File

@ -177,7 +177,8 @@ void BKE_mesh_calc_normals_tessface(
void BKE_mesh_normals_loop_split(
struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
struct MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle);
struct MPoly *mpolys, float (*polynors)[3], const int numPolys,
const bool use_split_normals, float split_angle);
void BKE_mesh_loop_tangents_ex(
struct MVert *mverts, const int numVerts, struct MLoop *mloops, float (*r_looptangent)[4], float (*loopnors)[3],
struct MLoopUV *loopuv, const int numLoops, struct MPoly *mpolys, const int numPolys,

View File

@ -158,8 +158,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
struct MVert *verts_dst, const int numverts_dst, struct MEdge *edges_dst, const int numedges_dst,
struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst,
struct CustomData *ldata_dst, struct CustomData *pdata_dst,
const float split_angle_dst, const bool dirty_nors_dst,
struct DerivedMesh *dm_src,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
struct DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, struct MeshPairRemap *r_map);
void BKE_mesh_remap_calc_polys_from_dm(

View File

@ -392,9 +392,9 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
static void DM_calc_loop_normals(DerivedMesh *dm, float split_angle)
static void DM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, float split_angle)
{
dm->calcLoopNormals(dm, split_angle);
dm->calcLoopNormals(dm, use_split_normals, split_angle);
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
@ -1500,7 +1500,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* XXX Same as above... For now, only weights preview in WPaint mode. */
const bool do_mod_wmcol = do_init_wmcol;
const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH);
const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH) != 0;
const float loop_normals_split_angle = me->smoothresh;
VirtualModifierData virtualModifierData;
@ -1906,7 +1906,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
if (do_loop_normals) {
/* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
DM_calc_loop_normals(finaldm, loop_normals_split_angle);
DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
}
{
@ -2006,7 +2006,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
const bool do_mod_wmcol = do_init_wmcol;
VirtualModifierData virtualModifierData;
const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH);
const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0;
const float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh;
modifiers_clearErrors(ob);
@ -2222,9 +2222,9 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
if (do_loop_normals) {
/* Compute loop normals */
DM_calc_loop_normals(*final_r, loop_normals_split_angle);
DM_calc_loop_normals(*final_r, do_loop_normals, loop_normals_split_angle);
if (cage_r && *cage_r && (*cage_r != *final_r)) {
DM_calc_loop_normals(*cage_r, loop_normals_split_angle);
DM_calc_loop_normals(*cage_r, do_loop_normals, loop_normals_split_angle);
}
}

View File

@ -2208,7 +2208,7 @@ void CDDM_calc_normals(DerivedMesh *dm)
#endif
void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle)
void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
{
MVert *mverts = dm->getVertArray(dm);
MEdge *medges = dm->getEdgeArray(dm);
@ -2246,7 +2246,7 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle)
dm->dirty &= ~DM_DIRTY_NORMALS;
BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
mpolys, pnors, numPolys, split_angle);
mpolys, pnors, numPolys, use_split_normals, split_angle);
}

View File

@ -963,7 +963,7 @@ bool BKE_object_data_transfer_dm(
#define DATAMAX 4
DerivedMesh *dm_src;
Mesh *me_dst;
Mesh *me_dst, *me_src;
bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */
int i;
@ -983,6 +983,7 @@ bool BKE_object_data_transfer_dm(
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
me_dst = ob_dst->data;
me_src = ob_src->data;
if (dm_dst) {
dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0;
use_create = false; /* Never create needed custom layers on DM (modifier case). */
@ -1139,8 +1140,10 @@ bool BKE_object_data_transfer_dm(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
loops_dst, num_loops_dst, polys_dst, num_polys_dst,
ldata_dst, pdata_dst, me_dst->smoothresh, dirty_nors_dst,
dm_src, island_callback, islands_handling_precision, &geom_map[LDATA]);
ldata_dst, pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh,
island_callback, islands_handling_precision, &geom_map[LDATA]);
geom_map_init[LDATA] = true;
}

View File

@ -169,7 +169,7 @@ static void emDM_calcNormals(DerivedMesh *dm)
dm->dirty &= ~DM_DIRTY_NORMALS;
}
static void emDM_calcLoopNormals(DerivedMesh *dm, const float split_angle)
static void emDM_calcLoopNormals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMesh *bm = bmdm->em->bm;
@ -191,7 +191,7 @@ static void emDM_calcLoopNormals(DerivedMesh *dm, const float split_angle)
loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
}
BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, split_angle, loopNos);
BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos);
}
static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))

View File

@ -320,10 +320,28 @@ void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces,
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle)
void BKE_mesh_normals_loop_split(
MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
MPoly *mpolys, float (*polynors)[3], const int numPolys,
const bool use_split_normals, float split_angle)
{
if (!use_split_normals) {
/* In this case, we simply fill lnors with vnors, quite simple!
* Note this is done here to keep some logic and consistancy in this quite complex code,
* since we may want to use lnors even when mesh's 'autosmooth' is disabled (see e.g. mesh mapping code).
* As usual, we could handle that on case-by-case basis, but simpler to keep it well confined here.
*/
int i;
for (i = 0; i < numLoops; i++) {
normal_short_to_float_v3(r_loopnors[i], mverts[mloops[i].v].no);
}
return;
}
{
#define INDEX_UNSET INT_MIN
#define INDEX_INVALID -1
/* See comment about edge_to_loops below. */
@ -588,6 +606,8 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
#undef INDEX_UNSET
#undef INDEX_INVALID
#undef IS_EDGE_SHARP
}
}

View File

@ -933,8 +933,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst,
MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst,
CustomData *ldata_dst, CustomData *pdata_dst, const float split_angle_dst, const bool dirty_nors_dst,
DerivedMesh *dm_src,
CustomData *ldata_dst, CustomData *pdata_dst,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@ -1048,19 +1049,20 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (need_lnors_dst) {
/* Cache poly nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
if (!loop_nors_dst) {
loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
if (dirty_nors_dst) {
if (dirty_nors_dst || !loop_nors_dst) {
if (!loop_nors_dst) {
loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
BKE_mesh_normals_loop_split(verts_dst, numverts_dst, edges_dst, numedges_dst,
loops_dst, loop_nors_dst, numloops_dst,
polys_dst, poly_nors_dst, numpolys_dst, split_angle_dst);
polys_dst, poly_nors_dst, numpolys_dst,
use_split_nors_dst, split_angle_dst);
}
}
if (need_pnors_src || need_lnors_src) {
/* Simpler for now, calcNormals never stores pnors :( */
dm_src->calcLoopNormals(dm_src, /* TODO */ (float)M_PI);
dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
if (need_pnors_src) {
poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL);

View File

@ -650,6 +650,31 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
}
}
static void bm_mesh_loops_from_vert_normals(BMesh *bm, const float (*vnos)[3], float (*r_lnos)[3])
{
BMIter fiter;
BMFace *f_curr;
{
char htype = BM_LOOP;
if (vnos) {
htype |= BM_VERT;
}
BM_mesh_elem_index_ensure(bm, htype);
}
BM_ITER_MESH (f_curr, &fiter, bm, BM_FACES_OF_MESH) {
BMLoop *l_curr, *l_first;
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
const float *no = vnos ? vnos[BM_elem_index_get(l_curr->v)] : l_curr->v->no;
copy_v3_v3(r_lnos[BM_elem_index_get(l_curr)], no);
} while ((l_curr = l_curr->next) != l_first);
}
}
#if 0 /* Unused currently */
/**
* \brief BMesh Compute Loop Normals
@ -657,13 +682,18 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
* Updates the loop normals of a mesh. Assumes vertex and face normals are valid (else call BM_mesh_normals_update()
* first)!
*/
void BM_mesh_loop_normals_update(BMesh *bm, const float split_angle, float (*r_lnos)[3])
void BM_mesh_loop_normals_update(BMesh *bm, const bool use_split_normals, const float split_angle, float (*r_lnos)[3])
{
/* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
bm_mesh_edges_sharp_tag(bm, NULL, NULL, split_angle, r_lnos);
if (use_split_normals) {
/* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
bm_mesh_edges_sharp_tag(bm, NULL, NULL, split_angle, r_lnos);
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
bm_mesh_loops_calc_normals(bm, NULL, NULL, r_lnos);
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
bm_mesh_loops_calc_normals(bm, NULL, NULL, r_lnos);
}
else {
bm_mesh_loops_from_vert_normals(bm, NULL, r_lnos);
}
}
#endif
@ -674,13 +704,18 @@ void BM_mesh_loop_normals_update(BMesh *bm, const float split_angle, float (*r_l
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
void BM_loops_calc_normal_vcos(BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
const float split_angle, float (*r_lnos)[3])
const bool use_split_normals, const float split_angle, float (*r_lnos)[3])
{
/* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
bm_mesh_edges_sharp_tag(bm, vnos, fnos, split_angle, r_lnos);
if (use_split_normals) {
/* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
bm_mesh_edges_sharp_tag(bm, vnos, fnos, split_angle, r_lnos);
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos);
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos);
}
else {
bm_mesh_loops_from_vert_normals(bm, vnos, r_lnos);
}
}
static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)

View File

@ -40,7 +40,7 @@ void BM_mesh_clear(BMesh *bm);
void BM_mesh_normals_update(BMesh *bm);
void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*vcos)[3], float (*vnos)[3]);
void BM_loops_calc_normal_vcos(BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*pnos)[3],
const float split_angle, float (*r_lnos)[3]);
const bool use_split_normals, const float split_angle, float (*r_lnos)[3]);
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);

View File

@ -61,7 +61,7 @@ static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, struct Mesh *me
return ret;
}
static void rna_Mesh_calc_normals_split(Mesh *mesh, float min_angle)
static void rna_Mesh_calc_normals_split(Mesh *mesh)
{
float (*r_loopnors)[3];
float (*polynors)[3];
@ -90,7 +90,7 @@ static void rna_Mesh_calc_normals_split(Mesh *mesh, float min_angle)
BKE_mesh_normals_loop_split(mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, polynors, mesh->totpoly,
min_angle);
(mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh);
if (free_polynors) {
MEM_freeN(polynors);
@ -117,7 +117,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
/* Compute loop normals if needed. */
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
rna_Mesh_calc_normals_split(mesh, (float)M_PI);
rna_Mesh_calc_normals_split(mesh);
}
BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
@ -164,10 +164,6 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "calc_normals_split", "rna_Mesh_calc_normals_split");
RNA_def_function_ui_description(func, "Calculate split vertex normals, which preserve sharp edges");
parm = RNA_def_float(func, "split_angle", M_PI, 0.0f, M_PI, "",
"Angle between polys' normals above which an edge is always sharp (180° to disable)",
0.0f, M_PI);
RNA_def_property_subtype(parm, (PropertySubType)PROP_UNIT_ROTATION);
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
RNA_def_function_ui_description(func, "Free split vertex normals");