[Bf-blender-cvs] [1cd4070] master: Fix T43786: Cycles bake disregards Auto Smooth (vertex per-face normals)

Sergey Sharybin noreply at git.blender.org
Fri Mar 20 08:48:13 CET 2015


Commit: 1cd4070e35fa8439bffcf500487e9922e11bd1d4
Author: Sergey Sharybin
Date:   Fri Mar 20 12:41:31 2015 +0500
Branches: master
https://developer.blender.org/rB1cd4070e35fa8439bffcf500487e9922e11bd1d4

Fix T43786: Cycles bake disregards Auto Smooth (vertex per-face normals)

Added an utility function which performs vertex split based on the loop
normal so now backing API matches to what's happening in Cycles and BI
in terms of autosplit.

Reviewers: dfelinto, campbellbarton

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D1174

===================================================================

M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/intern/mesh.c
M	source/blender/editors/object/object_bake_api.c
M	source/blender/makesrna/intern/rna_mesh_api.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 224be0f..1f3458c 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -130,6 +130,9 @@ bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const cha
 
 float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3];
 
+void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+void BKE_mesh_split_faces(struct Mesh *mesh);
+
 struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob,
                                       int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
 
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 809d213..8ebc318 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2124,6 +2124,146 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
 	           (me->mselect[me->totselect - 1].type  == type));
 }
 
+void BKE_mesh_calc_normals_split(Mesh *mesh)
+{
+	float (*r_loopnors)[3];
+	float (*polynors)[3];
+	short (*clnors)[2] = NULL;
+	bool free_polynors = false;
+
+	if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+		r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+		memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
+	}
+	else {
+		r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
+		CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
+	}
+
+	/* may be NULL */
+	clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+
+	if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+		/* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
+		polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+		free_polynors = false;
+	}
+	else {
+		polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
+		BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
+		                           polynors, false);
+		free_polynors = true;
+	}
+
+	BKE_mesh_normals_loop_split(
+	        mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
+	        mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
+	        (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
+
+	if (free_polynors) {
+		MEM_freeN(polynors);
+	}
+}
+
+/* Spli faces based on the edge angle.
+ * Matches behavior of face splitting in render engines.
+ */
+void BKE_mesh_split_faces(Mesh *mesh)
+{
+	const int num_verts = mesh->totvert;
+	const int num_edges = mesh->totedge;
+	const int num_polys = mesh->totpoly;
+	MVert *mvert = mesh->mvert;
+	MEdge *medge = mesh->medge;
+	MLoop *mloop = mesh->mloop;
+	MPoly *mpoly = mesh->mpoly;
+	float (*lnors)[3];
+	int poly, num_new_verts = 0;
+	if ((mesh->flag & ME_AUTOSMOOTH) == 0) {
+		return;
+	}
+	BKE_mesh_tessface_clear(mesh);
+	/* Compute loop normals if needed. */
+	if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+		BKE_mesh_calc_normals_split(mesh);
+	}
+	lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+	/* Count. */
+	for (poly = 0; poly < num_polys; poly++) {
+		MPoly *mp = &mpoly[poly];
+		int loop;
+		for (loop = 0; loop < mp->totloop; loop++) {
+			MLoop *ml = &mloop[mp->loopstart + loop];
+			MVert *mv = &mvert[ml->v];
+			float vn[3];
+			normal_short_to_float_v3(vn, mv->no);
+			if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
+				num_new_verts++;
+			}
+		}
+	}
+	if (num_new_verts == 0) {
+		/* No new vertices are to be added, can do early exit. */
+		return;
+	}
+	/* Actual split. */
+	mesh->totvert += num_new_verts;
+	mesh->totedge += 2 * num_new_verts;
+	mvert = mesh->mvert = MEM_reallocN(mesh->mvert,
+	                                   sizeof(MVert) * mesh->totvert);
+	medge = mesh->medge = MEM_reallocN(mesh->medge,
+	                                   sizeof(MEdge) * mesh->totedge);
+	CustomData_set_layer(&mesh->vdata, CD_MVERT, mesh->mvert);
+	CustomData_set_layer(&mesh->edata, CD_MEDGE, mesh->medge);
+	num_new_verts = 0;
+	for (poly = 0; poly < num_polys; poly++) {
+		MPoly *mp = &mpoly[poly];
+		int loop;
+		for (loop = 0; loop < mp->totloop; loop++) {
+			int poly_loop = mp->loopstart + loop;
+			MLoop *ml = &mloop[poly_loop];
+			MVert *mv = &mvert[ml->v];
+			float vn[3];
+			normal_short_to_float_v3(vn, mv->no);
+			if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
+				int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop;
+				MLoop *ml_prev = &mloop[poly_loop_prev];
+				int new_edge_prev, new_edge;
+				/* Cretae new vertex. */
+				int new_vert = num_verts + num_new_verts;
+				CustomData_copy_data(&mesh->vdata, &mesh->vdata,
+				                     ml->v, new_vert, 1);
+				normal_float_to_short_v3(mvert[new_vert].no,
+				                         lnors[poly_loop]);
+				/* Create new edges. */
+				new_edge_prev = num_edges + 2 * num_new_verts;
+				new_edge = num_edges + 2 * num_new_verts + 1;
+				CustomData_copy_data(&mesh->edata, &mesh->edata,
+				                     ml_prev->e, new_edge_prev, 1);
+				CustomData_copy_data(&mesh->edata, &mesh->edata,
+				                     ml->e, new_edge, 1);
+				if (medge[new_edge_prev].v1 == ml->v) {
+					medge[new_edge_prev].v1 = new_vert;
+				}
+				else {
+					medge[new_edge_prev].v2 = new_vert;
+				}
+				if (medge[new_edge].v1 == ml->v) {
+					medge[new_edge].v1 = new_vert;
+				}
+				else {
+					medge[new_edge].v2 = new_vert;
+				}
+
+				ml->v = new_vert;
+				ml_prev->e = new_edge_prev;
+				ml->e = new_edge;
+				num_new_verts++;
+			}
+		}
+	}
+}
+
 /* settings: 1 - preview, 2 - render */
 Mesh *BKE_mesh_new_from_object(
         Main *bmain, Scene *sce, Object *ob,
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 97cb45d..fe9ee71 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -685,7 +685,9 @@ static int bake(
 	result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
 
 	/* get the mesh as it arrives in the renderer */
-	me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+	me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+	BKE_mesh_split_faces(me_low);
+	BKE_mesh_tessface_ensure(me_low);
 
 	/* populate the pixel array with the face data */
 	if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -700,7 +702,9 @@ static int bake(
 
 		/* prepare cage mesh */
 		if (ob_cage) {
-			me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
+			me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0);
+			BKE_mesh_split_faces(me_cage);
+			BKE_mesh_tessface_ensure(me_cage);
 			if (me_low->totface != me_cage->totface) {
 				BKE_report(reports, RPT_ERROR,
 				           "Invalid cage object, the cage mesh must have the same number "
@@ -732,7 +736,9 @@ static int bake(
 			ob_low->modifiers = modifiers_tmp;
 
 			/* get the cage mesh as it arrives in the renderer */
-			me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+			me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+			BKE_mesh_split_faces(me_cage);
+			BKE_mesh_tessface_ensure(me_cage);
 			RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
 		}
 
@@ -760,8 +766,10 @@ static int bake(
 			tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
 			tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
 
-			highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 1, 0);
+			highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0);
 			highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
+			BKE_mesh_split_faces(highpoly[i].me);
+			BKE_mesh_tessface_ensure(highpoly[i].me);
 
 			/* lowpoly to highpoly transformation matrix */
 			copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
@@ -867,7 +875,9 @@ cage_cleanup:
 						md->mode &= ~eModifierMode_Render;
 					}
 
-					me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+					me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+					BKE_mesh_split_faces(me_nores);
+					BKE_mesh_tessface_ensure(me_nores);
 					RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
 
 					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index abf29ef..48a5f09 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -69,47 +69,6 @@ static void rna_Mesh_create_normals_split(Mesh *mesh)
 	}
 }
 
-static void rna_Mesh_calc_normals_split(Mesh *mesh)
-{
-	float (*r_loopnors)[3];
-	float (*polynors)[3];
-	short (*clnors)[2] = NULL;
-	bool free_polynors = false;
-
-	if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
-		r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
-		memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
-	}
-	else {
-		r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
-		CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
-	}
-
-	/* may be NULL */
-	clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
-
-	if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
-		/* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
-		polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
-		free_polynors = false;
-	}
-	else {
-		polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
-		BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
-		                           polynors, false);
-		free_polynors = true;
-	}
-
-	BKE_mesh_normals_loop_split(
-	        mesh->mvert,

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list