diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2015-02-05 16:38:59 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2015-02-05 16:38:59 +0300 |
commit | 2c3e4fbd7e91e7faeaaed3946874beb4be4e7817 (patch) | |
tree | c4710b2c578efacc67007a63ffd9f656405a19d1 | |
parent | 138c9dba9be67a93c91717ae3fcd8855aced9185 (diff) |
Add Custom Loop Normals to Data Transfer.
Titles says everything, just two notes:
* We have to actually transfer plain *normals*, not 'compressed' clnors,
so had to add pre/post process to transfer to make the conversions.
* Also added interpolation and advanced copy/mixing to CD_NORMAL, for same reasons.
-rw-r--r-- | source/blender/blenkernel/BKE_customdata.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_data_transfer.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 46 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/data_transfer.c | 119 | ||||
-rw-r--r-- | source/blender/editors/object/object_data_transfer.c | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_modifier.c | 1 |
6 files changed, 171 insertions, 3 deletions
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index f11aad27e4b..f3f1e0a407e 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -397,6 +397,8 @@ enum { CD_FAKE_BWEIGHT = CD_FAKE | CD_BWEIGHT, /* *sigh*. */ CD_FAKE_UV = CD_FAKE | CD_MLOOPUV, /* UV flag, because we handle both loop's UVs and poly's textures. */ + CD_FAKE_LNOR = CD_FAKE | CD_CUSTOMLOOPNORMAL, /* Because we play with clnor and temp lnor layers here. */ + CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */ }; diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h index d31804b3cae..cea093adca4 100644 --- a/source/blender/blenkernel/BKE_data_transfer.h +++ b/source/blender/blenkernel/BKE_data_transfer.h @@ -57,6 +57,7 @@ enum { DT_TYPE_FREESTYLE_EDGE = 1 << 12, DT_TYPE_VCOL = 1 << 16, + DT_TYPE_LNOR = 1 << 17, DT_TYPE_UV = 1 << 24, DT_TYPE_SHARP_FACE = 1 << 25, @@ -67,7 +68,7 @@ enum { DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT, DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE | DT_TYPE_FREESTYLE_EDGE, - DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_UV, + DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV, DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE, }; @@ -85,7 +86,7 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type); #define DT_DATATYPE_IS_EDGE(_dt) \ ELEM(_dt, DT_TYPE_CREASE, DT_TYPE_SHARP_EDGE, DT_TYPE_SEAM, DT_TYPE_BWEIGHT_EDGE, DT_TYPE_FREESTYLE_EDGE) #define DT_DATATYPE_IS_LOOP(_dt) \ - ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL) + ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL, DT_TYPE_LNOR) #define DT_DATATYPE_IS_POLY(_dt) \ ELEM(_dt, DT_TYPE_UV, DT_TYPE_SHARP_FACE, DT_TYPE_FREESTYLE_FACE) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 0c437f6e02f..0436ec0ef22 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -300,6 +300,49 @@ static void layerInterp_mdeformvert(void **sources, const float *weights, } } +static void layerInterp_normal(void **sources, const float *weights, + const float *UNUSED(sub_weights), int count, void *dest) +{ + float no[3] = {0.0f}; + + while (count--) { + madd_v3_v3fl(no, (float *)sources[count], weights[count]); + } + + copy_v3_v3((float *)dest, no); +} + +static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor) +{ + const float *no_src = source; + float *no_dst = dest; + float no_tmp[3]; + + if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* Above/below threshold modes are not supported here, fallback to nomix (just in case). */ + copy_v3_v3(no_dst, no_src); + } + else { /* Modes that support 'real' mix factor. */ + /* Since we normalize in the end, MIX and ADD are the same op here. */ + if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) { + add_v3_v3v3(no_tmp, no_dst, no_src); + normalize_v3(no_tmp); + } + else if (mixmode == CDT_MIX_SUB) { + sub_v3_v3v3(no_tmp, no_dst, no_src); + normalize_v3(no_tmp); + } + else if (mixmode == CDT_MIX_MUL) { + mul_v3_v3v3(no_tmp, no_dst, no_src); + normalize_v3(no_tmp); + } + else { + copy_v3_v3(no_tmp, no_src); + } + interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor); + } +} + static void layerCopy_tface(const void *source, void *dest, int count) { const MTFace *source_tf = (const MTFace *)source; @@ -1165,7 +1208,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex}, /* 8: CD_NORMAL */ /* 3 floats per normal vector */ - {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal}, /* 9: CD_POLYINDEX (deprecated) */ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, /* 10: CD_PROP_FLT */ diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 3704174be6e..5ac7b928d96 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -47,6 +47,7 @@ #include "BKE_data_transfer.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" #include "BKE_object.h" @@ -79,6 +80,9 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types else if (cddata_type == CD_FAKE_UV) { cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV; } + else if (cddata_type == CD_FAKE_LNOR) { + cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; + } } return cddata_mask; @@ -143,6 +147,10 @@ bool BKE_object_data_transfer_get_dttypes_capacity( *r_threshold = true; ret = true; break; + case DT_TYPE_LNOR: + *r_advanced_mixing = true; + ret = true; + break; case DT_TYPE_SHARP_FACE: *r_threshold = true; ret = true; @@ -217,6 +225,8 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type) case DT_TYPE_VCOL: return CD_MLOOPCOL; + case DT_TYPE_LNOR: + return CD_FAKE_LNOR; default: BLI_assert(0); @@ -242,6 +252,105 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type) /* ********** */ +/* Generic pre/post processing, only used by custom loop normals currently. */ + +static void data_transfer_dtdata_type_preprocess( + Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst, + const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src) +{ + if (dtdata_type == DT_TYPE_LNOR) { + /* Compute custom normals into regular loop normals, which will be used for the transfer. */ + MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; + const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; + const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; + MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; + const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; + MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; + const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; + CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + + const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0; + const float split_angle_dst = me_dst->smoothresh; + + dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src); + + if (dm_dst) { + dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst); + } + else { + float (*poly_nors_dst)[3]; + float (*loop_nors_dst)[3]; + short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); + + /* Cache poly nors into a temp CDLayer. */ + poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + if (dirty_nors_dst || !poly_nors_dst) { + if (!poly_nors_dst) { + poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst); + CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst, + num_loops_dst, num_polys_dst, poly_nors_dst, true); + } + /* Cache loop nors into a temp CDLayer. */ + loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); + if (dirty_nors_dst || loop_nors_dst) { + if (!loop_nors_dst) { + loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); + CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst, + loops_dst, loop_nors_dst, num_loops_dst, + polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst, + use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL); + } + } + } +} + +static void data_transfer_dtdata_type_postprocess( + Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst, + const int dtdata_type, const bool changed) +{ + if (dtdata_type == DT_TYPE_LNOR) { + /* Bake edited destination loop normals into custom normals again. */ + MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; + const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; + const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; + MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; + const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; + MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; + const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; + CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + + const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL); + float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL); + short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); + + BLI_assert(poly_nors_dst); + + if (!changed) { + return; + } + + if (!custom_nors_dst) { + custom_nors_dst = CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst); + } + + /* Note loop_nors_dst contains our custom normals as transferred from source... */ + BKE_mesh_normals_loop_custom_set(verts_dst, num_verts_dst, edges_dst, num_edges_dst, + loops_dst, loop_nors_dst, num_loops_dst, + polys_dst, poly_nors_dst, num_polys_dst, + custom_nors_dst); + } +} + +/* ********** */ + static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int cddata_type) { switch (cddata_type) { @@ -805,6 +914,10 @@ static bool data_transfer_layersmapping_generate( if (cddata_type == CD_FAKE_UV) { cddata_type = CD_MLOOPUV; } + else if (cddata_type == CD_FAKE_LNOR) { + /* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */ + cddata_type = CD_NORMAL; + } if (!(cddata_type & CD_FAKE)) { cd_src = dm_src->getLoopDataLayout(dm_src); @@ -1023,6 +1136,10 @@ bool BKE_object_data_transfer_dm( continue; } + data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, + dtdata_type, dirty_nors_dst, + (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh); + cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); @@ -1217,6 +1334,8 @@ bool BKE_object_data_transfer_dm( BLI_freelistN(&lay_map); } } + + data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed); } for (i = 0; i < DATAMAX; i++) { diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index ec3ae92adc4..c57cae41bf4 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -83,6 +83,7 @@ static EnumPropertyItem DT_layer_items[] = { {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, {0, "", 0, "Face Corner Data", ""}, + {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"}, {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, {0, "", 0, "Face Data", ""}, diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 7b912b9120b..3458d84a85c 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -4148,6 +4148,7 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna) }; static EnumPropertyItem DT_layer_loop_items[] = { + {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem DT_layer_loop_vcol_items[] = { |