[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [14653] branches/soc-2008-jaguarandi/ source/blender: +normal projection optimized with RayTree (RE_raytrace.h)

André Pinto andresusanopinto at gmail.com
Fri May 2 02:16:48 CEST 2008


Revision: 14653
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=14653
Author:   jaguarandi
Date:     2008-05-02 02:16:48 +0200 (Fri, 02 May 2008)

Log Message:
-----------
+normal projection optimized with RayTree (RE_raytrace.h)
+control for normal projection direction (default,inverted,both)

There are some bugs on projection over quads.. it seems to work 100% on fully triangulized meshs

Modified Paths:
--------------
    branches/soc-2008-jaguarandi/source/blender/blenkernel/intern/shrinkwrap.c
    branches/soc-2008-jaguarandi/source/blender/makesdna/DNA_modifier_types.h
    branches/soc-2008-jaguarandi/source/blender/src/buttons_editing.c

Modified: branches/soc-2008-jaguarandi/source/blender/blenkernel/intern/shrinkwrap.c
===================================================================
--- branches/soc-2008-jaguarandi/source/blender/blenkernel/intern/shrinkwrap.c	2008-05-01 22:28:18 UTC (rev 14652)
+++ branches/soc-2008-jaguarandi/source/blender/blenkernel/intern/shrinkwrap.c	2008-05-02 00:16:48 UTC (rev 14653)
@@ -48,11 +48,12 @@
 #include "BLI_arithb.h"
 #include "BLI_kdtree.h"
 
+#include "RE_raytrace.h"
 
 #define TO_STR(a)	#a
 #define JOIN(a,b)	a##b
 
-#define OUT_OF_MEMORY()	((void)puts("Shrinkwrap: Out of memory"))
+#define OUT_OF_MEMORY()	((void)printf("Shrinkwrap: Out of memory\n"))
 
 /* Benchmark macros */
 #if 1
@@ -85,15 +86,129 @@
 typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *co, float *normal);
 
 
-static void normal_short2float(CONST short *ns, float *nf)
+static void normal_short2float(const short *ns, float *nf)
 {
 	nf[0] = ns[0] / 32767.0f;
 	nf[1] = ns[1] / 32767.0f;
 	nf[2] = ns[2] / 32767.0f;
 }
 
+static float vertexgroup_get_weight(MDeformVert *dvert, int index, int vgroup)
+{
+	if(dvert && vgroup >= 0)
+	{
+		int j;
+		for(j = 0; j < dvert[index].totweight; j++)
+			if(dvert[index].dw[j].def_nr == vgroup)
+				return dvert[index].dw[j].weight;
+	}
+	return -1;
+}
 
 /*
+ * Raytree from mesh
+ */
+static MVert *raytree_from_mesh_verts = NULL;
+static float raytree_from_mesh_start[3] = { 1e10f, 1e10f, 1e10f }; 
+static int raytree_check_always(Isect *is, int ob, RayFace *face)
+{
+	return TRUE;
+}
+
+static void raytree_from_mesh_get_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+{
+	MFace *mface= (MFace*)face;
+
+	if(mface == NULL)
+	{
+		*v1 = raytree_from_mesh_start;
+		*v2 = raytree_from_mesh_start;
+		*v3 = raytree_from_mesh_start;
+		*v4 = NULL;
+		return;
+	}
+
+	*v1= raytree_from_mesh_verts[mface->v1].co;
+	*v2= raytree_from_mesh_verts[mface->v2].co;
+	*v3= raytree_from_mesh_verts[mface->v3].co;
+	*v4= (mface->v4)? raytree_from_mesh_verts[mface->v4].co: NULL;
+}
+
+/*
+ * Creates a raytree from the given mesh
+ * No copy of the mesh is done, so it must exist and remain
+ * imutable as long the tree is intended to be used
+ *
+ * No more than 1 raytree can exist.. since this code uses a static variable
+ * to pass data to raytree_from_mesh_get_coords
+ */
+static RayTree* raytree_create_from_mesh(DerivedMesh *mesh)
+{
+	int i;
+	float min[3], max[3];
+
+	RayTree*tree= NULL;
+
+	int numFaces= mesh->getNumFaces(mesh);
+	MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE);
+	int numVerts= mesh->getNumVerts(mesh);
+	raytree_from_mesh_verts = mesh->getVertDataArray(mesh, CD_MVERT);
+
+
+	//calculate bounding box
+	INIT_MINMAX(min, max);
+
+	for(i=0; i<numVerts; i++)
+		DO_MINMAX(raytree_from_mesh_verts[i].co, min, max);
+	
+	tree = RE_ray_tree_create(64, numFaces, min, max, raytree_from_mesh_get_coords, raytree_check_always, NULL, NULL);
+	if(tree == NULL)
+		return NULL;
+
+	//Add faces to the RayTree
+	for(i=0; i<numFaces; i++)
+		RE_ray_tree_add_face(tree, 0, (RayFace*)(face+i));
+
+	RE_ray_tree_done(tree);
+
+	return tree;
+}
+
+static void free_raytree_from_mesh(RayTree *tree)
+{
+	raytree_from_mesh_verts = NULL;
+	RE_ray_tree_free(tree);
+}
+
+/*
+ * Cast a ray on the specified direction
+ * Returns the distance the ray must travel until intersect something
+ * Returns FLT_MAX in case of nothing intersection
+ */
+static float raytree_cast_ray(RayTree *tree, const float *coord, const float *direction)
+{
+	Isect isec = {};
+
+	//Setup intersection
+	isec.mode		= RE_RAY_MIRROR; //We want closest intersection
+	isec.lay		= -1;
+	isec.face_last	= NULL;
+	isec.faceorig	= NULL;
+	isec.labda		= 1e10f;
+
+	VECCOPY(isec.start, coord);
+	VECCOPY(isec.vec, direction);
+	VECADDFAC(isec.end, isec.start, isec.vec, isec.labda);
+
+	if(!RE_ray_tree_intersect(tree, &isec))
+		return FLT_MAX;
+
+	isec.labda = ABS(isec.labda);
+	VECADDFAC(isec.end, isec.start, isec.vec, isec.labda);
+	return VecLenf(coord, isec.end);
+}
+
+/*
  * This calculates the distance (in dir units) that the ray must travel to intersect plane
  * It can return negative values
  *
@@ -296,7 +411,7 @@
 
 static void shrinkwrap_calc_foreach_vertex(ShrinkwrapCalcData *calc, Shrinkwrap_ForeachVertexCallback callback)
 {
-	int i, j;
+	int i;
 	int vgroup		= get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
 	int	numVerts	= 0;
 
@@ -310,23 +425,11 @@
 	//Shrink (calculate each vertex final position)
 	for(i = 0; i<numVerts; i++)
 	{
-		float weight;
+		float weight = vertexgroup_get_weight(dvert, i, vgroup);
 
 		float orig[3], final[3]; //Coords relative to target
 		float normal[3];
 
-		if(dvert && vgroup >= 0)
-		{
-			weight = 0.0f;
-			for(j = 0; j < dvert[i].totweight; j++)
-				if(dvert[i].dw[j].def_nr == vgroup)
-				{
-					weight = dvert[i].dw[j].weight;
-					break;
-				}
-		}
-		else weight = 1.0f;
-
 		if(weight == 0.0f) continue;	//Skip vertexs where we have no influence
 
 		VecMat4MulVecfl(orig, calc->local2target, vert[i].co);
@@ -402,7 +505,8 @@
 			break;
 
 			case MOD_SHRINKWRAP_NORMAL:
-				BENCH(shrinkwrap_calc_foreach_vertex(&calc, bruteforce_shrinkwrap_calc_normal_projection));
+				BENCH(shrinkwrap_calc_normal_projection(&calc));
+//				BENCH(shrinkwrap_calc_foreach_vertex(&calc, bruteforce_shrinkwrap_calc_normal_projection));
 			break;
 
 			case MOD_SHRINKWRAP_NEAREST_VERTEX:
@@ -424,9 +528,18 @@
 	return calc.final;
 }
 
+
+/*
+ * Shrinkwrap to the nearest vertex
+ *
+ * it builds a kdtree of vertexs we can attach to and then
+ * for each vertex on performs a nearest vertex search on the tree
+ */
 void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
 {
 	int i;
+	int vgroup		= get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
+
 	KDTree* target = NULL;
 	KDTreeNearest nearest;
 	float tmp_co[3];
@@ -436,6 +549,7 @@
 
 	int	numVerts;
 	MVert *vert = NULL;
+	MDeformVert *dvert = NULL;
 
 	//Generate kd-tree with target vertexs
 	BENCH_BEGIN(build);
@@ -446,6 +560,7 @@
 	numVerts= calc->target->getNumVerts(calc->target);
 	vert	= calc->target->getVertDataArray(calc->target, CD_MVERT);	
 
+
 	for( ;numVerts--; vert++)
 		BLI_kdtree_insert(target, 0, vert->co, NULL);
 
@@ -453,12 +568,18 @@
 
 	BENCH_END(build);
 
+
 	//Find the nearest vertex 
 	numVerts= calc->final->getNumVerts(calc->final);
 	vert	= calc->final->getVertDataArray(calc->final, CD_MVERT);	
+	dvert	= calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT);
+
 	for(i=0; i<numVerts; i++)
 	{
 		int t;
+		float weight = vertexgroup_get_weight(dvert, i, vgroup);
+		if(weight == 0.0f) continue;
+
 		VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co);
 
 		BENCH_BEGIN(query);
@@ -486,3 +607,90 @@
 	BENCH_REPORT(query);
 }
 
+/*
+ * Shrinkwrap projecting vertexs allong their normals over the target
+ *
+ * it builds a RayTree from the target mesh and then performs a
+ * raycast for each vertex (ray direction = normal)
+ */
+void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
+{
+	int i;
+	int vgroup		= get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
+	char use_normal = calc->smd->shrinkOpts;
+	RayTree *target = NULL;
+
+	int	numVerts;
+	MVert *vert = NULL;
+	MDeformVert *dvert = NULL;
+	float tmp_co[3], tmp_no[3];
+
+	if( (use_normal & (MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL | MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL)) == 0)
+		return;	//Nothing todo
+
+	//setup raytracing
+	target = raytree_create_from_mesh(calc->target);
+	if(target == NULL) return OUT_OF_MEMORY();
+
+
+
+	//Project each vertex along normal
+	numVerts= calc->final->getNumVerts(calc->final);
+	vert	= calc->final->getVertDataArray(calc->final, CD_MVERT);	
+	dvert	= calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT);
+
+	for(i=0; i<numVerts; i++)
+	{
+		float dist = FLT_MAX;
+		float weight = vertexgroup_get_weight(dvert, i, vgroup);
+//		if(weight == 0.0f) continue;
+		weight = 1.0;
+
+		//Transform coordinates local->target
+		VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co);
+
+		normal_short2float(vert[i].no, tmp_no);
+		Mat4Mul3Vecfl(calc->local2target, tmp_no);	//Watch out for scaling on normal
+		Normalize(tmp_no);							//(TODO: do we really needed a unit-len normal? and we could know the scale factor before hand?)
+
+
+		if(use_normal & MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL)
+		{
+			dist = raytree_cast_ray(target, tmp_co, tmp_no);
+		}
+
+		normal_short2float(vert[i].no, tmp_no);
+		Mat4Mul3Vecfl(calc->local2target, tmp_no);	//Watch out for scaling on normal
+		Normalize(tmp_no);							//(TODO: do we really needed a unit-len normal? and we could know the scale factor before hand?)
+
+		if(use_normal & MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL)
+		{
+			float inv[3]; // = {-tmp_no[0], -tmp_no[1], -tmp_no[2]};
+			float tdist;
+
+			inv[0] = -tmp_no[0];
+			inv[1] = -tmp_no[1];
+			inv[2] = -tmp_no[2];
+
+			tdist = raytree_cast_ray(target, tmp_co, inv);
+
+			if(ABS(tdist) < ABS(dist))
+				dist = -tdist;
+		}
+
+		if(ABS(dist) != FLT_MAX)
+		{
+			VECADDFAC(tmp_co, tmp_co, tmp_no, dist);
+			VecMat4MulVecfl(tmp_co, calc->target2local, tmp_co);
+			VecLerpf(vert[i].co, vert[i].co, tmp_co, weight);	//linear interpolation
+
+			if(calc->moved)
+				calc->moved[i] = TRUE;
+		}
+
+	}
+
+	free_raytree_from_mesh(target);
+}
+
+

Modified: branches/soc-2008-jaguarandi/source/blender/makesdna/DNA_modifier_types.h
===================================================================
--- branches/soc-2008-jaguarandi/source/blender/makesdna/DNA_modifier_types.h	2008-05-01 22:28:18 UTC (rev 14652)
+++ branches/soc-2008-jaguarandi/source/blender/makesdna/DNA_modifier_types.h	2008-05-02 00:16:48 UTC (rev 14653)
@@ -495,7 +495,8 @@
 	struct Object *target;	/* shrink target */
 	char vgroup_name[32];	/* optional vertexgroup name */
 	short shrinkType;		/* shrink type projection */
-	short pad[3];
+	short shrinkOpts;		/* shrink options */
+	short pad[2];
 } ShrinkwrapModifierData;
 
 /* Shrinkwrap->shrinkType */
@@ -503,5 +504,8 @@
 #define MOD_SHRINKWRAP_NORMAL			1
 #define MOD_SHRINKWRAP_NEAREST_VERTEX	2
 
+/* Shrinkwrap->shrinkOpts */
+#define MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL		(1<<0)
+#define MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL	(1<<1)
 
 #endif

Modified: branches/soc-2008-jaguarandi/source/blender/src/buttons_editing.c
===================================================================
--- branches/soc-2008-jaguarandi/source/blender/src/buttons_editing.c	2008-05-01 22:28:18 UTC (rev 14652)

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list