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
This commit is contained in:
Bastien Montagne 2014-04-13 12:18:51 +02:00
parent a872d0b414
commit 18e4224142
17 changed files with 295 additions and 61 deletions

View File

@ -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()

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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 |

View File

@ -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 {

View File

@ -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

View File

@ -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");