Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2014-04-13 14:18:51 +0400
committerBastien Montagne <montagne29@wanadoo.fr>2014-04-13 14:19:00 +0400
commit18e4224142261cd8a1086c5872efb406b82f8330 (patch)
treea1a9f7680ab45158ec2c2755f76a966532cad8b8
parenta872d0b414f406a7d53ce77f7b43e7a831a68fa7 (diff)
Split Normals I (1/5): basis for split normals (nearly nothing user-visible here):
* Add a new calcLoopNormals function to DerivedMesh struct, and implement it for CDDM and CCGDM (subsurf). EditDerivedBMesh (edit mode DM) only gets a dummy one in this commit. * Add a tessellated version of CD_LOOPNORMAL layer (CD_TESSLOOPNORMAL), with relevant code to handle it (tessellation, rna access, etc.). * Change auto_smooth options of Mesh (angle now in radian internaly, and toggle is now used to enable/disable split normals in DM creation process). Note BI render code is not touched here, hence its behavior regarding this option is now incoherent, will be addressed in a separate commit. Reviewers: campbellbarton CC: brecht Differential Revision: https://developer.blender.org/D365
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py19
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h3
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c71
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c49
-rw-r--r--source/blender/blenkernel/intern/customdata.c18
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c39
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c1
-rw-r--r--source/blender/blenloader/intern/versioning_270.c11
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c7
-rw-r--r--source/blender/editors/space_view3d/drawobject.c46
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h9
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h8
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c61
17 files changed, 294 insertions, 60 deletions
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)
- sub = row.row(align=True)
- sub.prop(mesh, "show_normal_vertex", text="", icon='VERTEXSEL')
- sub.prop(mesh, "show_normal_face", text="", icon='FACESEL')
+ 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.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");