[Bf-blender-cvs] [443b117] temp_custom_loop_normals: First basic code for supporting custom loop normals.

Bastien Montagne noreply at git.blender.org
Wed Aug 6 21:36:31 CEST 2014


Commit: 443b11748865def4343e9ba18dd00db0097ea0f2
Author: Bastien Montagne
Date:   Wed Jun 4 19:25:24 2014 +0200
Branches: temp_custom_loop_normals
https://developer.blender.org/rB443b11748865def4343e9ba18dd00db0097ea0f2

First basic code for supporting custom loop normals.

This only affects Object mode currently, and is more proof-of-concept than anything else.

Next step: do same thing for bmesh!

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

M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/intern/cdderivedmesh.c
M	source/blender/blenkernel/intern/mesh_evaluate.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 d0c268d..6869539 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -36,6 +36,8 @@ struct BoundBox;
 struct DispList;
 struct EdgeHash;
 struct ListBase;
+struct LinkNode;
+struct MemArena;
 struct BMEditMesh;
 struct BMesh;
 struct Main;
@@ -173,10 +175,6 @@ void BKE_mesh_calc_normals_tessface(
         struct MVert *mverts, int numVerts,
         struct MFace *mfaces, int numFaces,
         float (*r_faceNors)[3]);
-void BKE_mesh_normals_loop_split(
-        struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
-        struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
-        struct MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle);
 void BKE_mesh_loop_tangents_ex(
         struct MVert *mverts, const int numVerts, struct MLoop *mloops, float (*r_looptangent)[4], float (*loopnors)[3],
         struct MLoopUV *loopuv, const int numLoops, struct MPoly *mpolys, const int numPolys,
@@ -184,6 +182,29 @@ void BKE_mesh_loop_tangents_ex(
 void BKE_mesh_loop_tangents(
         struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
 
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+
+typedef struct MLoopNorSpace {
+	float vec_lnor[3];   /* Automatically computed loop normal. */
+	float vec_ref[3];    /* Reference vector, orthogonal to vec_lnor. */
+	float vec_ortho[3];  /* Third vector, orthogonal to vec_lnor and vec_ref. */
+	float angle;         /* Reference angle, around vec_lnor, in ]0, 2pi] range (0.0 marks that space as invalid). */
+	LinkNode *loops;     /* All indices (uint_in_ptr) of loops using this lnor space (i.e. smooth fan of loops). */
+} MLoopNorSpace;
+typedef struct MLoopsNorSpaces {
+	MLoopNorSpace **lspaces;
+	MemArena *mem;
+} MLoopsNorSpaces;
+void BKE_init_loops_normal_spaces(MLoopsNorSpaces *lnors_spaces, const int numLoops);
+void BKE_free_loops_normal_spaces(MLoopsNorSpaces *lnors_spaces);
+
+void BKE_mesh_normals_loop_split(
+        struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
+        struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
+        struct MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle,
+        MLoopsNorSpaces *r_lnor_spaces, const float (*clnors_data)[2]);
+
 void BKE_mesh_calc_poly_normal(
         struct MPoly *mpoly, struct MLoop *loopstart,
         struct MVert *mvarray, float no[3]);
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index ca4a4b3..e7af8ef 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -2542,8 +2542,39 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle)
 
 	dm->dirty &= ~DM_DIRTY_NORMALS;
 
-	BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
-	                            mpolys, pnors, numPolys, split_angle);
+	{
+		MLoopsNorSpaces lnors_spaces = {NULL};
+		int i;
+		float (*clnor_data)[2] = MEM_mallocN(sizeof(*clnor_data) * (size_t)numLoops, __func__);
+
+		for (i = 0; i < numLoops; i++) {
+			clnor_data[i][0] = 0.7f;
+			clnor_data[i][1] = 0.5f;
+		}
+
+		BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
+		                            mpolys, pnors, numPolys, split_angle, &lnors_spaces, clnor_data);
+		for (i = 0; i < numLoops; i++) {
+			if (lnors_spaces.lspaces[i]) {
+				LinkNode *loops = lnors_spaces.lspaces[i]->loops;
+				printf("Loop %d uses lnor space %p:\n", i, lnors_spaces.lspaces[i]);
+				print_v3("\tfinal lnor:", lnors[i]);
+				print_v3("\tauto lnor:", lnors_spaces.lspaces[i]->vec_lnor);
+				print_v3("\tref_vec:", lnors_spaces.lspaces[i]->vec_ref);
+				printf("\tangle: %f\n\tloops: %p\n", lnors_spaces.lspaces[i]->angle, lnors_spaces.lspaces[i]->loops);
+				printf("\t\t(shared with loops");
+				while(loops) {
+					printf(" %d", GET_INT_FROM_POINTER(loops->link));
+					loops = loops->next;
+				}
+				printf(")\n");
+			}
+			else {
+				printf("Loop %d has no lnor space\n", i);
+			}
+		}
+		BKE_free_loops_normal_spaces(&lnors_spaces);
+	}
 }
 
 
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index d244dcc..01dfffc 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -316,13 +316,155 @@ void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces,
 		MEM_freeN(fnors);
 }
 
+void BKE_init_loops_normal_spaces(MLoopsNorSpaces *lnors_spaces, const int numLoops)
+{
+	MemArena *mem = lnors_spaces->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+	lnors_spaces->lspaces = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
+}
+
+void BKE_free_loops_normal_spaces(MLoopsNorSpaces *lnors_spaces)
+{
+	BLI_memarena_free(lnors_spaces->mem);
+	lnors_spaces->lspaces = NULL;
+	lnors_spaces->mem = NULL;
+}
+
+static MLoopNorSpace *lnor_space_create(MLoopsNorSpaces *lnors_spaces)
+{
+	return BLI_memarena_calloc(lnors_spaces->mem, sizeof(MLoopNorSpace));
+}
+
+/* Should only be called once.
+ * Beware, this modifies ref_vec and other_vec in place!
+ * Might set *lnor_space to NULL in case no valid space can be generated.
+ */
+static void lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], float vec_ref[3], float vec_other[3])
+{
+	float tvec[3], dtp;
+	const float pi2 = (float)M_PI * 2.0f;
+
+	/* Project ref_vec on lnor's ortho plane. */
+	dtp = dot_v3v3(vec_ref, lnor);
+	if (fabsf(dtp) > (1.0f - 1e-8f)) {
+		/* If ref_vec is too much aligned with lnor, we can't build lnor space, tag it as invalid and abort. */
+		lnor_space->angle = 0.0f;
+		return;
+	}
+	mul_v3_v3fl(tvec, lnor, dtp);
+	sub_v3_v3(vec_ref, tvec);
+	normalize_v3_v3(lnor_space->vec_ref, vec_ref);
+
+	copy_v3_v3(lnor_space->vec_lnor, lnor);
+
+	cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref);
+	normalize_v3_v3(lnor_space->vec_ortho, tvec);
+
+	lnor_space->angle = pi2;
+
+	if (vec_other) {
+		/* Project other_vec on lnor's ortho plane. */
+		dtp = dot_v3v3(vec_other, lnor);
+		if (fabsf(dtp) > (1.0f - 1e-8f)) {
+			/* If other_vec is too much aligned with lnor, we can't build lnor space, tag it as invalid and abort. */
+			lnor_space->angle = 0.0f;
+			return;
+		}
+		mul_v3_v3fl(tvec, lnor, dtp);
+		sub_v3_v3(vec_other, tvec);
+		normalize_v3(vec_other);
+
+		/* Angle between ref_vec and other_vec. */
+		dtp = dot_v3v3(vec_ref, vec_other);
+		if (dtp < (1.0f - 1e-8f)) {
+			const float angle = saacos(dtp);
+			lnor_space->angle = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - angle : angle;
+		}
+	}
+}
+
+static void lnor_space_add_loop(MLoopsNorSpaces *lnors_spaces, MLoopNorSpace *lnor_space, MLoop *ml, int ml_index)
+{
+	if (lnor_space == NULL) {
+		return;
+	}
+
+	lnors_spaces->lspaces[ml_index] = lnor_space;
+	if (ml && lnor_space) {
+		BLI_linklist_prepend_arena(&lnor_space->loops, SET_INT_IN_POINTER(ml_index), lnors_spaces->mem);
+	}
+}
+
+static void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, float r_custom_lnor[3],
+                                                 const float clnor_data[2])
+{
+	/* NOP custom normal data or invalid lnor space, return. */
+	if (clnor_data[0] == 1.0f || lnor_space->angle == 0.0f) {
+		copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
+		return;
+	}
+
+	{
+		const float cosfac = clnor_data[0];
+		const float sinfac = sqrtf(1.0f - cosfac * cosfac);
+		const float phifac = clnor_data[1];
+		const float pi2 = (float)M_PI * 2.0f;
+
+		mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosfac);
+
+		if (phifac == 0.0f) {
+			madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinfac);
+		}
+		else {
+			const float phi = phifac * (phifac > 0.0f ? lnor_space->angle : pi2 - lnor_space->angle);
+			madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinfac * cosf(phi));
+			madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinfac * sinf(phi));
+		}
+	}
+}
+
+static void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3],
+                                                 float r_custom_data[2])
+{
+	if (equals_v3v3(lnor_space->vec_lnor, custom_lnor)) {
+		r_custom_data[0] = 1.0f;
+		r_custom_data[1] = 0.0f;
+		return;
+	}
+
+	{
+		const float co = dot_v3v3(lnor_space->vec_ref, custom_lnor);
+		const float pi2 = (float)M_PI * 2.0f;
+
+		r_custom_data[0] = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
+
+		if (co > (1.0f - 1e-6f)) {
+			r_custom_data[1] = 0.0f;
+		}
+		else {
+			float phi = saacos(co);
+
+			if (dot_v3v3(lnor_space->vec_ortho, custom_lnor) < 0.0f) {
+				phi = pi2 - phi;
+			}
+
+			if (phi > lnor_space->angle) {
+				r_custom_data[1] = -(pi2 - phi) / (pi2 - lnor_space->angle);
+			}
+			else {
+				r_custom_data[1] = phi / lnor_space->angle;
+			}
+		}
+	}
+}
+
 /**
  * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
  * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
  */
-void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
+void BKE_mesh_normals_loop_split(MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
                                  MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
-                                 MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle)
+                                 MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle,
+                                 MLoopsNorSpaces *r_lnor_spaces, const float (*clnors_data)[2])
 {
 #define INDEX_UNSET INT_MIN
 #define INDEX_INVALID -1
@@ -344,9 +486,12 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
 	int *loop_to_poly = MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
 
 	MPoly *mp;
-	int mp_index

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list