diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index d43e6d1f697..56f612abe3a 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2760,6 +2760,15 @@ class VIEW3D_PT_view3d_name(Panel): row.label(text="", icon='BONE_DATA') row.prop(bone, "name", text="") + elif ob.type == 'MESH': + me = ob.data + row = layout.row() + row.prop(me, "use_auto_smooth") + row = row.row() + if not me.use_auto_smooth: + row.active = False + row.prop(me, "auto_smooth_angle", text="") + class VIEW3D_PT_view3d_display(Panel): bl_space_type = 'VIEW_3D' @@ -2936,14 +2945,14 @@ class VIEW3D_PT_view3d_meshdisplay(Panel): col.separator() col.label(text="Normals:") - row = col.row() + row = col.row(align=True) + + row.prop(mesh, "show_normal_vertex", text="", icon='VERTEXSEL') + row.prop(mesh, "show_normal_loop", text="", icon='VERTEXSEL') + row.prop(mesh, "show_normal_face", text="", icon='FACESEL') sub = row.row(align=True) - sub.prop(mesh, "show_normal_vertex", text="", icon='VERTEXSEL') - sub.prop(mesh, "show_normal_face", text="", icon='FACESEL') - - sub = row.row(align=True) - sub.active = mesh.show_normal_vertex or mesh.show_normal_face + sub.active = mesh.show_normal_vertex or mesh.show_normal_face or mesh.show_normal_loop sub.prop(context.scene.tool_settings, "normal_size", text="Size") col.separator() diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 3afd7d851cb..5206f8bf299 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -193,6 +193,9 @@ struct DerivedMesh { /** Calculate vert and face normals */ void (*calcNormals)(DerivedMesh *dm); + /** Calculate loop (split) normals */ + void (*calcLoopNormals)(DerivedMesh *dm, const float split_angle); + /** Recalculates mesh tessellation */ void (*recalcTessellation)(DerivedMesh *dm); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 3eb2fabdd56..9a67284304c 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 270 -#define BLENDER_SUBVERSION 1 +#define BLENDER_SUBVERSION 2 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 262 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index 4e6d69503c0..dffc2b665c2 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -100,6 +100,8 @@ 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); + /* calculates edges for a CDDerivedMesh (from face data) * this completely replaces the current edge data in the DerivedMesh * builds edges from the tessellated face data. diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 9c57b7c9a71..d6c3734fa2d 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -215,7 +215,7 @@ void BKE_mesh_loops_to_mface_corners( struct CustomData *pdata, unsigned int lindex[4], int findex, const int polyindex, const int mf_len, const int numTex, const int numCol, - const bool hasPCol, const bool hasOrigSpace); + const bool hasPCol, const bool hasOrigSpace, const bool hasLNor); void BKE_mesh_loops_to_tessdata( struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface, int *polyindices, unsigned int (*loopindices)[4], const int num_faces); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 84b54ff2b84..0c4e71448cd 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -399,6 +399,11 @@ 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) +{ + dm->calcLoopNormals(dm, split_angle); +} + /* note: until all modifiers can take MPoly's as input, * use this at the start of modifiers */ void DM_ensure_tessface(DerivedMesh *dm) @@ -453,7 +458,8 @@ void DM_update_tessface_data(DerivedMesh *dm) if (CustomData_has_layer(fdata, CD_MTFACE) || CustomData_has_layer(fdata, CD_MCOL) || CustomData_has_layer(fdata, CD_PREVIEW_MCOL) || - CustomData_has_layer(fdata, CD_ORIGSPACE)) + CustomData_has_layer(fdata, CD_ORIGSPACE) || + CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) { loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__); @@ -1471,6 +1477,9 @@ 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 float loop_normals_split_angle = me->smoothresh; + VirtualModifierData virtualModifierData; ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0; @@ -1865,7 +1874,21 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos add_orco_dm(ob, NULL, *deform_r, NULL, CD_ORCO); } - { + 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); + + if (finaldm->getNumTessFaces(finaldm) == 0) { + finaldm->recalcTessellation(finaldm); + } + /* Even if tessellation is not needed, we have for sure modified loop normals layer! */ + else { + /* A tessellation already exists, it should always have a CD_ORIGINDEX. */ + BLI_assert(CustomData_has_layer(&finaldm->faceData, CD_ORIGINDEX)); + DM_update_tessface_data(finaldm); + } + } + else { /* calculating normals can re-calculate tessfaces in some cases */ #if 0 int num_tessface = finaldm->getNumTessFaces(finaldm); @@ -1982,7 +2005,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D ModifierData *md, *previewmd = NULL; float (*deformedVerts)[3] = NULL; CustomDataMask mask, previewmask = 0, append_mask = 0; - DerivedMesh *dm, *orcodm = NULL; + DerivedMesh *dm = NULL, *orcodm = NULL; int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); CDMaskLink *datamasks, *curr; int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; @@ -1998,13 +2021,15 @@ 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 float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh; + modifiers_clearErrors(ob); if (cage_r && cageIndex == -1) { *cage_r = getEditDerivedBMesh(em, ob, NULL); } - dm = NULL; md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* copied from mesh_calc_modifiers */ @@ -2212,6 +2237,14 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D DM_update_statvis_color(scene, ob, *final_r); } + if (do_loop_normals) { + /* Compute loop normals */ + DM_calc_loop_normals(*final_r, loop_normals_split_angle); + if (cage_r && *cage_r && (*cage_r != *final_r)) { + DM_calc_loop_normals(*cage_r, loop_normals_split_angle); + } + } + /* --- */ /* BMESH_ONLY, ensure tessface's used for drawing, * but don't recalculate if the last modifier in the stack gives us tessfaces @@ -2229,8 +2262,10 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } /* --- */ - /* same as mesh_calc_modifiers */ - dm_ensure_display_normals(*final_r); + /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */ + if (!do_loop_normals) { + dm_ensure_display_normals(*final_r); + } /* add an orco layer if needed */ if (dataMask & CD_MASK_ORCO) @@ -2542,7 +2577,8 @@ DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) /* ******************* GLSL ******************** */ typedef struct { - float *precomputedFaceNormals; + float (*precomputedFaceNormals)[3]; + short (*precomputedLoopNormals)[4][3]; MTFace *mtface; /* texture coordinates */ MFace *mface; /* indices */ MVert *mvert; /* vertices & normals */ @@ -2594,11 +2630,14 @@ static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const i { //assert(vert_index >= 0 && vert_index < 4); SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; + const bool smoothnormal = (pMesh->mface[face_num].flag & ME_SMOOTH) != 0; - const int smoothnormal = (pMesh->mface[face_num].flag & ME_SMOOTH); - if (!smoothnormal) { // flat + if (pMesh->precomputedLoopNormals) { + normal_short_to_float_v3(r_no, pMesh->precomputedLoopNormals[face_num][vert_index]); + } + else if (!smoothnormal) { // flat if (pMesh->precomputedFaceNormals) { - copy_v3_v3(r_no, &pMesh->precomputedFaceNormals[3 * face_num]); + copy_v3_v3(r_no, pMesh->precomputedFaceNormals[face_num]); } else { MFace *mf = &pMesh->mface[face_num]; @@ -2638,12 +2677,17 @@ void DM_add_tangent_layer(DerivedMesh *dm) MFace *mface; float (*orco)[3] = NULL, (*tangent)[4]; int /* totvert, */ totface; - float *nors; + float (*fnors)[3]; + short (*tlnors)[4][3]; if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1) return; - nors = dm->getTessFaceDataArray(dm, CD_NORMAL); + fnors = dm->getTessFaceDataArray(dm, CD_NORMAL); + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + tlnors = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); /* check we have all the needed layers */ /* totvert = dm->getNumVerts(dm); */ /* UNUSED */ @@ -2669,7 +2713,8 @@ void DM_add_tangent_layer(DerivedMesh *dm) SMikkTSpaceContext sContext = {NULL}; SMikkTSpaceInterface sInterface = {NULL}; - mesh2tangent.precomputedFaceNormals = nors; + mesh2tangent.precomputedFaceNormals = fnors; + mesh2tangent.precomputedLoopNormals = tlnors; mesh2tangent.mtface = mtface; mesh2tangent.mface = mface; mesh2tangent.mvert = mvert; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 0c58b7e66e7..9af6220e4b2 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1738,6 +1738,7 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->getTessFaceDataArray = DM_get_tessface_data_layer; dm->calcNormals = CDDM_calc_normals; + dm->calcLoopNormals = CDDM_calc_loop_normals; dm->recalcTessellation = CDDM_recalc_tessellation; dm->getVertCos = cdDM_getVertCos; @@ -2289,8 +2290,7 @@ void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals) CustomData_free_layers(&dm->faceData, CD_NORMAL, dm->numTessFaceData); } - - face_nors = MEM_mallocN(sizeof(float) * 3 * dm->numTessFaceData, "face_nors"); + face_nors = MEM_mallocN(sizeof(*face_nors) * dm->numTessFaceData, "face_nors"); /* calculate face normals */ BKE_mesh_calc_normals_mapping_ex(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), @@ -2298,8 +2298,7 @@ void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals) CustomData_get_layer(&dm->faceData, CD_ORIGINDEX), face_nors, only_face_normals); - CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, - face_nors, dm->numTessFaceData); + CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, face_nors, dm->numTessFaceData); cddm->dm.dirty &= ~DM_DIRTY_NORMALS; } @@ -2353,6 +2352,48 @@ void CDDM_calc_normals(DerivedMesh *dm) #endif +void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle) +{ + MVert *mverts = dm->getVertArray(dm); + MEdge *medges = dm->getEdgeArray(dm); + MLoop *mloops = dm->getLoopArray(dm); + MPoly *mpolys = dm->getPolyArray(dm); + + CustomData *ldata, *pdata; + + float (*lnors)[3]; + float (*pnors)[3]; + + const int numVerts = dm->getNumVerts(dm); + const int numEdges = dm->getNumEdges(dm); + const int numLoops = dm->getNumLoops(dm); + const int numPolys = dm->getNumPolys(dm); + + ldata = dm->getLoopDataLayout(dm); + if (CustomData_has_layer(ldata, CD_NORMAL)) { + lnors = CustomData_get_layer(ldata, CD_NORMAL); + } + else { + lnors = CustomData_add_layer(ldata, CD_NORMAL, CD_CALLOC, NULL, numLoops); + } + + /* Compute poly (always needed) and vert normals. */ + /* Note we can't use DM_ensure_normals, since it won't keep computed poly nors... */ + pdata = dm->getPolyDataLayout(dm); + pnors = CustomData_get_layer(pdata, CD_NORMAL); + if (!pnors) { + pnors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys); + } + BKE_mesh_calc_normals_poly(mverts, numVerts, mloops, mpolys, numLoops, numPolys, pnors, + (dm->dirty & DM_DIRTY_NORMALS) ? false : true); + + dm->dirty &= ~DM_DIRTY_NORMALS; + + BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops, + mpolys, pnors, numPolys, split_angle); +} + + void CDDM_calc_normals_tessface(DerivedMesh *dm) { CDDerivedMesh *cddm = (CDDerivedMesh *)dm; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 41eb2f5982e..61261959ea8 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1170,6 +1170,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL}, /* 39: CD_MLOOPTANGENT */ {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 40: CD_TESSLOOPNORMAL */ + {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, }; /* note, numbers are from trunk and need updating for bmesh */ @@ -1185,7 +1187,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight", /* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask", /* 35-36 */ "CDGridPaintMask", "CDMVertSkin", - /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace", "CDMLoopTangent", + /* 37-40 */ "CDFreestyleEdge", "CDFreestyleFace", "CDMLoopTangent", "CDTessLoopNormal", }; @@ -1217,9 +1219,9 @@ const CustomDataMask CD_MASK_BMESH = CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS | CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; -const CustomDataMask CD_MASK_FACECORNERS = +const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */ CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | - CD_MASK_MLOOPCOL; + CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT; const CustomDataMask CD_MASK_EVERYTHING = CD_MASK_MVERT | CD_MASK_MSTICKY /* DEPRECATED */ | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT | @@ -1229,7 +1231,9 @@ const CustomDataMask CD_MASK_EVERYTHING = CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_BM_ELEM_PYPTR | /* BMESH ONLY END */ - CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; + CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | + CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | + CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL; static const LayerTypeInfo *layerType_getInfo(int type) { @@ -2283,6 +2287,9 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l else if (fdata->layers[i].type == CD_MDISPS) { CustomData_add_layer_named(ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name); } + else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { + CustomData_add_layer_named(ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name); + } } } @@ -2304,6 +2311,9 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { CustomData_add_layer_named(fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name); } + else if (ldata->layers[i].type == CD_NORMAL) { + CustomData_add_layer_named(fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name); + } } CustomData_bmesh_update_active_layers(fdata, pdata, ldata); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index b7c5c605254..152540041f7 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -171,6 +171,11 @@ static void emDM_calcNormals(DerivedMesh *dm) dm->dirty &= ~DM_DIRTY_NORMALS; } +static void emDM_calcLoopNormals(DerivedMesh *dm, const float split_angle) +{ + /* Do nothing for now! */ +} + static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm)) { /* do nothing */ @@ -1654,6 +1659,7 @@ DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, bmdm->dm.getTessFaceDataArray = emDM_getTessFaceDataArray; bmdm->dm.calcNormals = emDM_calcNormals; + bmdm->dm.calcLoopNormals = emDM_calcLoopNormals; bmdm->dm.recalcTessellation = emDM_recalcTessellation; bmdm->dm.foreachMappedVert = emDM_foreachMappedVert; diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 5d10c12b8e0..edd0a8540e3 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -574,6 +574,7 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg #undef IS_EDGE_SHARP } + /** \} */ @@ -1103,7 +1104,8 @@ void BKE_mesh_loops_to_mface_corners( const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */ const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */ const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */ - const bool hasOrigSpace /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */ + const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */ + const bool hasLNor /* CustomData_has_layer(ldata, CD_NORMAL) */ ) { MTFace *texface; @@ -1152,6 +1154,14 @@ void BKE_mesh_loops_to_mface_corners( copy_v2_v2(of->uv[j], lof->uv); } } + + if (hasLNor) { + short (*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL); + + for (j = 0; j < mf_len; j++) { + normal_float_to_short_v3(tlnors[j], CustomData_get(ldata, (int)lindex[j], CD_NORMAL)); + } + } } /** @@ -1172,6 +1182,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); + const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL); int findex, i, j; int *pidx; unsigned int (*lidx)[4]; @@ -1225,6 +1236,17 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData } } } + + if (hasLoopNormal) { + short (*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL); + float (*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL); + + for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) { + for (j = (*lidx)[3] ? 4 : 3; j--;) { + normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]); + } + } + } } /** @@ -1516,6 +1538,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); + const bool hasLNor = CustomData_has_layer(ldata, CD_NORMAL); /* over-alloc, ngons will be skipped */ mface = MEM_mallocN(sizeof(*mface) * (size_t)totpoly, __func__); @@ -1575,7 +1598,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, lindex, k, i, 3, - numTex, numCol, hasPCol, hasOrigSpace); + numTex, numCol, hasPCol, hasOrigSpace, hasLNor); test_index_face(mf, fdata, k, 3); } else { @@ -1595,7 +1618,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, lindex, k, i, 4, - numTex, numCol, hasPCol, hasOrigSpace); + numTex, numCol, hasPCol, hasOrigSpace, hasLNor); test_index_face(mf, fdata, k, 4); } @@ -1651,6 +1674,16 @@ static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, } } + if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) { + float (*lnors)[3] = CustomData_get(ldata, loopstart, CD_NORMAL); + short (*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL); + const int max = mf->v4 ? 4 : 3; + + for (i = 0; i < max; i++, lnors++, tlnors++) { + normal_short_to_float_v3(*lnors, *tlnors); + } + } + if (CustomData_has_layer(fdata, CD_MDISPS)) { MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS); MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 87de748eace..0b2d772978d 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -3243,6 +3243,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.getPBVH = ccgDM_getPBVH; ccgdm->dm.calcNormals = ccgDM_calcNormals; + ccgdm->dm.calcLoopNormals = CDDM_calc_loop_normals; ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation; ccgdm->dm.getVertCos = ccgdm_getVertCos; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index d310c836f59..2dd227ef036 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -40,11 +40,13 @@ #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_object_types.h" +#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_sdna_types.h" #include "DNA_genfile.h" +#include "BLI_math.h" #include "BKE_main.h" #include "BKE_node.h" @@ -160,4 +162,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!MAIN_VERSION_ATLEAST(main, 270, 2)) { + Mesh *me; + + /* Mesh smoothresh deg->rad. */ + for (me = main->mesh.first; me; me = me->id.next) { + me->smoothresh = DEG2RADF(me->smoothresh); + } + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index b14402e72db..d6caf16f7aa 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -26,6 +26,7 @@ */ #include "BLI_utildefines.h" +#include "BLI_math.h" #include "DNA_freestyle_types.h" #include "DNA_linestyle_types.h" @@ -33,6 +34,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" +#include "DNA_mesh_types.h" #include "BKE_main.h" @@ -45,6 +47,7 @@ void BLO_update_defaults_startup_blend(Main *main) Scene *scene; SceneRenderLayer *srl; FreestyleLineStyle *linestyle; + Mesh *me; for (scene = main->scene.first; scene; scene = scene->id.next) { scene->r.im_format.planes = R_IMF_PLANES_RGBA; @@ -75,5 +78,9 @@ void BLO_update_defaults_startup_blend(Main *main) } } } + + for (me = main->mesh.first; me; me = me->id.next) { + me->smoothresh = DEG2RADF(180.0f); + } } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 6b055d34b13..24e00dd49e2 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2403,6 +2403,48 @@ static int draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa) #endif +/* Draw loop normals. */ +static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm) +{ + /* XXX Would it be worth adding a dm->foreachMappedLoop func just for this? I doubt it... */ + + /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would + * return loop data from bmesh itself. */ + float (*lnors)[3] = DM_get_loop_data_layer(dm, CD_NORMAL); + + if (lnors) { + drawDMNormal_userData data; + MLoop *mloops = dm->getLoopArray(dm); + MVert *mverts = dm->getVertArray(dm); + int i, totloops = dm->getNumLoops(dm); + + data.bm = em->bm; + data.normalsize = scene->toolsettings->normalsize; + + calcDrawDMNormalScale(ob, &data); + + glBegin(GL_LINES); + for (i = 0; i < totloops; i++, mloops++, lnors++) { + float no[3]; + float *co = mverts[mloops->v].co; + + if (!data.uniform_scale) { + mul_v3_m3v3(no, data.tmat, (float *)lnors); + normalize_v3(no); + mul_m3_v3(data.imat, no); + } + else { + copy_v3_v3(no,(float *)lnors); + } + mul_v3_fl(no, data.normalsize); + add_v3_v3(no, co); + glVertex3fv(co); + glVertex3fv(no); + } + glEnd(); + } +} + /* Draw faces with color set based on selection * return 2 for the active face so it renders with stipple enabled */ static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index) @@ -3351,6 +3393,10 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, UI_ThemeColor(TH_VNORMAL); draw_dm_vert_normals(em, scene, ob, cageDM); } + if (me->drawflag & ME_DRAW_LNORMALS) { + UI_ThemeColor(TH_VNORMAL); + draw_dm_loop_normals(em, scene, ob, cageDM); + } if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_FACEAREA | diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index b6ae49cad61..d1844b34a0a 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -63,10 +63,9 @@ typedef struct CustomDataExternal { * layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */ typedef struct CustomData { CustomDataLayer *layers; /* CustomDataLayers, ordered by type */ - int typemap[40]; /* runtime only! - maps types to indices of first layer of that type, + int typemap[41]; /* runtime only! - maps types to indices of first layer of that type, * MUST be >= CD_NUMTYPES, but we cant use a define here. * Correct size is ensured in CustomData_update_typemap assert() */ - int pad[1]; int totlayer, maxlayer; /* number of layers, size of layers array */ int totsize; /* in editmode, total size of all data layers */ struct BLI_mempool *pool; /* (BMesh Only): Memory pool for allocation of blocks */ @@ -119,7 +118,8 @@ enum { CD_FREESTYLE_EDGE = 37, CD_FREESTYLE_FACE = 38, CD_MLOOPTANGENT = 39, - CD_NUMTYPES = 40, + CD_TESSLOOPNORMAL = 40, + CD_NUMTYPES = 41, }; /* Bits for CustomDataMask */ @@ -164,7 +164,8 @@ enum { #define CD_MASK_MVERT_SKIN (1LL << CD_MVERT_SKIN) #define CD_MASK_FREESTYLE_EDGE (1LL << CD_FREESTYLE_EDGE) #define CD_MASK_FREESTYLE_FACE (1LL << CD_FREESTYLE_FACE) -#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT) +#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT) +#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL) /* CustomData.flag */ enum { diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index b942197e52c..e535e6012b3 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -116,8 +116,9 @@ typedef struct Mesh { float rot[3]; int drawflag; - short texflag, pad2[3]; - short smoothresh, flag; + short texflag, flag; + float smoothresh; + int pad2; /* customdata flag, for bevel-weight and crease, which are now optional */ char cd_flag, pad; @@ -212,6 +213,9 @@ typedef struct TFace { /* draw stats */ #define ME_DRAW_STATVIS (1 << 17) +/* draw loop normals */ +#define ME_DRAW_LNORMALS (1 << 18) + /* Subsurf Type */ #define ME_CC_SUBSURF 0 #define ME_SIMPLE_SUBSURF 1 diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index bdd94b73c44..99c35bdcff2 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -413,6 +413,21 @@ static void rna_MeshTessFace_normal_get(PointerRNA *ptr, float *values) normal_tri_v3(values, me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co); } +static void rna_MeshTessFace_split_normals_get(PointerRNA *ptr, float *values) +{ + Mesh *me = rna_mesh(ptr); + MFace *mface = (MFace *)ptr->data; + const short (*vec)[4][3] = CustomData_get(&me->fdata, (int)(mface - me->mface), CD_TESSLOOPNORMAL); + int i = 4; + + if (!vec) { + while (i--) zero_v3(&values[i * 3]); + } + else { + while (i--) normal_short_to_float_v3(&values[i * 3], (const short*)(*vec)[i]); + } +} + static float rna_MeshTessFace_area_get(PointerRNA *ptr) { Mesh *me = rna_mesh(ptr); @@ -1105,20 +1120,6 @@ static void rna_TextureFace_image_set(PointerRNA *ptr, PointerRNA value) tf->tpage = (struct Image *)id; } -static void rna_Mesh_auto_smooth_angle_set(PointerRNA *ptr, float value) -{ - Mesh *me = rna_mesh(ptr); - value = RAD2DEGF(value); - CLAMP(value, 1.0f, 80.0f); - me->smoothresh = (int)value; -} - -static float rna_Mesh_auto_smooth_angle_get(PointerRNA *ptr) -{ - Mesh *me = rna_mesh(ptr); - return DEG2RADF((float)me->smoothresh); -} - static int rna_MeshTessFace_verts_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) { MFace *face = (MFace *)ptr->data; @@ -1817,6 +1818,7 @@ static void rna_def_mface(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + const int splitnor_dim[] = {4, 3}; srna = RNA_def_struct(brna, "MeshTessFace", NULL); RNA_def_struct_sdna(srna, "MFace"); @@ -1868,6 +1870,16 @@ static void rna_def_mface(BlenderRNA *brna) RNA_def_property_float_funcs(prop, "rna_MeshTessFace_normal_get", NULL, NULL); RNA_def_property_ui_text(prop, "Face Normal", "Local space unit length normal vector for this face"); + prop = RNA_def_property(srna, "split_normals", PROP_FLOAT, PROP_DIRECTION); + RNA_def_property_multi_array(prop, 2, splitnor_dim); + RNA_def_property_range(prop, -1.0f, 1.0f); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_funcs(prop, "rna_MeshTessFace_split_normals_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Split Normals", + "Local space unit length split normals vectors of the vertices of this face " + "(must be computed beforehand using calc_normals_split or calc_tangents, " + "and then calc_tessface)"); + prop = RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_MeshTessFace_area_get", NULL, NULL); @@ -3113,19 +3125,17 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_AUTOSMOOTH); RNA_def_property_ui_text(prop, "Auto Smooth", "Treat all set-smoothed faces with angles less than the specified angle " - "as 'smooth' during render"); + "as 'smooth', unless they are linked by a sharp edge"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); -#if 1 /* expose as radians */ prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_float_funcs(prop, "rna_Mesh_auto_smooth_angle_get", "rna_Mesh_auto_smooth_angle_set", NULL); - RNA_def_property_ui_range(prop, DEG2RAD(1.0), DEG2RAD(80), 1.0, 1); -#else - prop = RNA_def_property(srna, "auto_smooth_angle", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "smoothresh"); - RNA_def_property_range(prop, 1, 80); -#endif + RNA_def_property_float_sdna(prop, NULL, "smoothresh"); + RNA_def_property_float_default(prop, DEG2RADF(180.0f)); + RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); + RNA_def_property_ui_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f), 1.0, 1); RNA_def_property_ui_text(prop, "Auto Smooth Angle", "Maximum angle between face normals that 'Auto Smooth' will operate on"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "show_double_sided", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_TWOSIDED); @@ -3183,6 +3193,11 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "show_normal_loop", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_LNORMALS); + RNA_def_property_ui_text(prop, "Draw Split Normals", "Display vertex-per-face normals as lines"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "show_normal_vertex", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_VNORMALS); RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines");