[Bf-blender-cvs] [776f8d5] master: Split Normals I (4/5): Add support of split normals to BI renderer.

Bastien Montagne noreply at git.blender.org
Sun Apr 13 15:39:05 CEST 2014


Commit: 776f8d5a6fa00403e6c46887fbb19956edbd4f05
Author: Bastien Montagne
Date:   Sun Apr 13 12:37:40 2014 +0200
https://developer.blender.org/rB776f8d5a6fa00403e6c46887fbb19956edbd4f05

Split Normals I (4/5): Add support of split normals to BI renderer.

Note that this commit completely replaces old behavior of the auto_smooth feature in BI.

Also note that split normals are only handled when no "advanced geometry post-processing" is used
(something like Displace will obviously break it, since it has to re-compute normals after displacement...).

Reviewers: brecht

Reviewed By: brecht

CC: campbellbarton

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

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

M	source/blender/render/intern/source/convertblender.c

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

diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 4e895a3..5204799 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -398,21 +398,23 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
 	}
 }
 
-static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_tangent, bool do_nmap_tangent)
+static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_vertex_normal, bool do_tangent, bool do_nmap_tangent)
 {
 	int a;
 
 		/* clear all vertex normals */
-	for (a=0; a<obr->totvert; a++) {
-		VertRen *ver= RE_findOrAddVert(obr, a);
-		ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
+	if (do_vertex_normal) {
+		for (a=0; a<obr->totvert; a++) {
+			VertRen *ver= RE_findOrAddVert(obr, a);
+			ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
+		}
 	}
 
 		/* calculate cos of angles and point-masses, use as weight factor to
 		 * add face normal to vertex */
 	for (a=0; a<obr->totvlak; a++) {
 		VlakRen *vlr= RE_findOrAddVlak(obr, a);
-		if (vlr->flag & ME_SMOOTH) {
+		if (do_vertex_normal && vlr->flag & ME_SMOOTH) {
 			float *n4= (vlr->v4)? vlr->v4->n: NULL;
 			float *c4= (vlr->v4)? vlr->v4->co: NULL;
 
@@ -430,7 +432,7 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_tange
 	for (a=0; a<obr->totvlak; a++) {
 		VlakRen *vlr= RE_findOrAddVlak(obr, a);
 
-		if ((vlr->flag & ME_SMOOTH)==0) {
+		if (do_vertex_normal && (vlr->flag & ME_SMOOTH)==0) {
 			if (is_zero_v3(vlr->v1->n)) copy_v3_v3(vlr->v1->n, vlr->n);
 			if (is_zero_v3(vlr->v2->n)) copy_v3_v3(vlr->v2->n, vlr->n);
 			if (is_zero_v3(vlr->v3->n)) copy_v3_v3(vlr->v3->n, vlr->n);
@@ -494,12 +496,12 @@ typedef struct ASface {
 	VertRen *nver[4];
 } ASface;
 
-static void as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
+static int as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
 {
 	ASface *asf;
-	int a;
+	int a = -1;
 	
-	if (v1 == NULL) return;
+	if (v1 == NULL) return a;
 	
 	if (asv->faces.first==NULL) {
 		asf= MEM_callocN(sizeof(ASface), "asface");
@@ -517,136 +519,129 @@ static void as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
 	
 	/* new face struct */
 	if (a==4) {
+		a = 0;
 		asf= MEM_callocN(sizeof(ASface), "asface");
 		BLI_addtail(&asv->faces, asf);
-		asf->vlr[0]= vlr;
+		asf->vlr[a]= vlr;
 		asv->totface++;
 	}
+
+	return a;
 }
 
-static int as_testvertex(VlakRen *vlr, VertRen *UNUSED(ver), ASvert *asv, float thresh)
+static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, const float lnor[3])
 {
-	/* return 1: vertex needs a copy */
+	/* return when new vertex already was made, or existing one is OK */
 	ASface *asf;
-	float inp;
 	int a;
-	
-	if (vlr == NULL) return 0;
-	
-	asf= asv->faces.first;
-	while (asf) {
-		for (a=0; a<4; a++) {
-			if (asf->vlr[a] && asf->vlr[a]!=vlr) {
-				inp = fabsf(dot_v3v3(vlr->n, asf->vlr[a]->n));
-				if (inp < thresh) return 1;
-			}
-		}
-		asf= asf->next;
+
+	/* First face, we can use existing vert and assign it current lnor! */
+	if (asv->totface == 1) {
+		copy_v3_v3(ver->n, lnor);
+		return ver;
 	}
-	
-	return 0;
-}
 
-static VertRen *as_findvertex(VlakRen *vlr, VertRen *UNUSED(ver), ASvert *asv, float thresh)
-{
-	/* return when new vertex already was made */
-	ASface *asf;
-	float inp;
-	int a;
-	
-	asf= asv->faces.first;
+	/* In case existing ver has same normal as current lnor, we can simply use it! */
+	if (equals_v3v3(lnor, ver->n)) {
+		return ver;
+	}
+
+	asf = asv->faces.first;
 	while (asf) {
-		for (a=0; a<4; a++) {
-			if (asf->vlr[a] && asf->vlr[a]!=vlr) {
+		for (a = 0; a < 4; a++) {
+			if (asf->vlr[a] && asf->vlr[a] != vlr) {
 				/* this face already made a copy for this vertex! */
 				if (asf->nver[a]) {
-					inp = fabsf(dot_v3v3(vlr->n, asf->vlr[a]->n));
-					if (inp >= thresh) {
+					if (equals_v3v3(lnor, asf->nver[a]->n)) {
 						return asf->nver[a];
 					}
 				}
 			}
 		}
-		asf= asf->next;
+		asf = asf->next;
 	}
-	
+
 	return NULL;
 }
 
+static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen *vlr, const short _lnor[3])
+{
+	VertRen *v1;
+	ASface *asf;
+	int asf_idx;
+	float lnor[3];
+
+	normal_short_to_float_v3(lnor, _lnor);
+
+	asf_idx = as_addvert(asv, ver, vlr);
+	if (asf_idx < 0) {
+		return;
+	}
+	asf = asv->faces.last;
+
+	/* already made a new vertex within threshold? */
+	v1 = as_findvertex_lnor(vlr, ver, asv, lnor);
+	if (v1 == NULL) {
+		/* make a new vertex */
+		v1 = RE_vertren_copy(obr, ver);
+		copy_v3_v3(v1->n, lnor);
+	}
+	if (v1 != ver) {
+		asf->nver[asf_idx] = v1;
+		if (vlr->v1 == ver) vlr->v1 = v1;
+		if (vlr->v2 == ver) vlr->v2 = v1;
+		if (vlr->v3 == ver) vlr->v3 = v1;
+		if (vlr->v4 == ver) vlr->v4 = v1;
+	}
+}
+
 /* note; autosmooth happens in object space still, after applying autosmooth we rotate */
 /* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */
-static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], int degr)
+static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3])
 {
-	ASvert *asv, *asverts;
-	ASface *asf;
-	VertRen *ver, *v1;
+	ASvert *asverts;
+	VertRen *ver;
 	VlakRen *vlr;
-	float thresh;
-	int a, b, totvert;
-	
-	if (obr->totvert==0) return;
-	asverts= MEM_callocN(sizeof(ASvert)*obr->totvert, "all smooth verts");
-	
-	thresh= cosf(DEG2RADF((0.5f + (float)degr)));
-	
-	/* step zero: give faces normals of original mesh, if this is provided */
-	
-	
-	/* step one: construct listbase of all vertices and pointers to faces */
-	for (a=0; a<obr->totvlak; a++) {
-		vlr= RE_findOrAddVlak(obr, a);
-		/* skip wire faces */
-		if (vlr->v2 != vlr->v3) {
-			as_addvert(asverts+vlr->v1->index, vlr->v1, vlr);
-			as_addvert(asverts+vlr->v2->index, vlr->v2, vlr);
-			as_addvert(asverts+vlr->v3->index, vlr->v3, vlr);
-			if (vlr->v4)
-				as_addvert(asverts+vlr->v4->index, vlr->v4, vlr);
-		}
-	}
-	
-	totvert= obr->totvert;
-	/* we now test all vertices, when faces have a normal too much different: they get a new vertex */
-	for (a=0, asv=asverts; a<totvert; a++, asv++) {
-		if (asv->totface > 1) {
-			ver= RE_findOrAddVert(obr, a);
+	int a, totvert;
 
-			asf= asv->faces.first;
-			while (asf) {
-				for (b=0; b<4; b++) {
-				
-					/* is there a reason to make a new vertex? */
-					vlr= asf->vlr[b];
-					if ( as_testvertex(vlr, ver, asv, thresh) ) {
-						
-						/* already made a new vertex within threshold? */
-						v1= as_findvertex(vlr, ver, asv, thresh);
-						if (v1==NULL) {
-							/* make a new vertex */
-							v1= RE_vertren_copy(obr, ver);
-						}
-						asf->nver[b]= v1;
-						if (vlr->v1==ver) vlr->v1= v1;
-						if (vlr->v2==ver) vlr->v2= v1;
-						if (vlr->v3==ver) vlr->v3= v1;
-						if (vlr->v4==ver) vlr->v4= v1;
-					}
-				}
-				asf= asf->next;
+	if (obr->totvert == 0)
+		return;
+
+	totvert = obr->totvert;
+	asverts = MEM_callocN(sizeof(ASvert) * totvert, "all smooth verts");
+
+	if (lnors) {
+		/* We construct listbase of all vertices and pointers to faces, and add new verts when needed
+		 * (i.e. when existing ones do not share the same (loop)normal).
+		 */
+		for (a = 0; a < obr->totvlak; a++, lnors++) {
+			vlr = RE_findOrAddVlak(obr, a);
+			/* skip wire faces */
+			if (vlr->v2 != vlr->v3) {
+				as_addvert_lnor(obr, asverts+vlr->v1->index, vlr->v1, vlr, (const short*)lnors[0][0]);
+				as_addvert_lnor(obr, asverts+vlr->v2->index, vlr->v2, vlr, (const short*)lnors[0][1]);
+				as_addvert_lnor(obr, asverts+vlr->v3->index, vlr->v3, vlr, (const short*)lnors[0][2]);
+				if (vlr->v4)
+					as_addvert_lnor(obr, asverts+vlr->v4->index, vlr->v4, vlr, (const short*)lnors[0][3]);
 			}
 		}
 	}
-	
+
 	/* free */
 	for (a=0; a<totvert; a++) {
 		BLI_freelistN(&asverts[a].faces);
 	}
 	MEM_freeN(asverts);
-	
+
 	/* rotate vertices and calculate normal of faces */
 	for (a=0; a<obr->totvert; a++) {
 		ver= RE_findOrAddVert(obr, a);
 		mul_m4_v3(mat, ver->co);
+		if (lnors) {
+			mul_mat3_m4_v3(mat, ver->n);
+			negate_v3(ver->n);
+			normalize_v3(ver->n);
+		}
 	}
 	for (a=0; a<obr->totvlak; a++) {
 		vlr= RE_findOrAddVlak(obr, a);
@@ -1899,7 +1894,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 	}
 
 	if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0)
-		calc_vertexnormals(re, obr, 0, 0);
+		calc_vertexnormals(re, obr, 1, 0, 0);
 
 	return 1;
 }
@@ -2009,7 +2004,7 @@ static short test_for_displace(Render *re, Object *ob)
 	return 0;
 }
 
-static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale, float mat[4][4], float imat[3][3])
+static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
 {
 	MTFace *tface;
 	short texco= shi->mat->texco;
@@ -2022,15 +2017,6 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
 	/* vertex normal is used for textures type 'col' and 'var' */
 	copy_v3_v3(shi->vn, vr->n);
 
-	if (mat)
-		mul_m4_v3(mat, shi->co);
-
-	if (imat) {
-		shi->vn[0] = dot_v3v3(imat[0], vr->n);
-		shi->vn[1] = dot_v3v3(imat[1], vr->n);
-		shi->vn[2] = dot_v3v3(imat[2], vr->n);
-	}
-
 	if (texco & TEXCO_UV) {
 		shi->totuv= 0;
 		shi->actuv= obr->actmtface;
@@ -2083,9 +2069,6 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
 	displace[0]= shi->displace[0] * scale[0];
 	displace[1]= shi->displace[1] * scale[1];
 	displace[2]= shi->displace[2] * scale[2];
-	
-	if (mat)
-		mul_m3_v3(imat, displace);
 
 	/* 0.5 could become button once?  */
 	vr->co[0] += displace[0]; 
@@ -2108,7 +2091,7 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
 	return;
 }
 
-static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale, float mat[4][4], float imat[3][3])
+static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale)
 {
 	ShadeInput shi;
 
@@ -2137,17 +2120,17 @@ static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float
 
 	/* Displace the verts, flag is se

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list