Beispiel #1
0
void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float max_dist, float n_location[3], float n_normal[3], int *index)
{
	BVHTreeFromMesh treeData= {NULL};
	
	if(ob->derivedFinal==NULL) {
		BKE_reportf(reports, RPT_ERROR, "object \"%s\" has no mesh data to be used for finding nearest point", ob->id.name+2);
		return;
	}

	/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
	bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6);

	if(treeData.tree==NULL) {
		BKE_reportf(reports, RPT_ERROR, "object \"%s\" could not create internal data for finding nearest point", ob->id.name+2);
		return;
	}
	else {
		BVHTreeNearest nearest;

		nearest.index = -1;
		nearest.dist = max_dist * max_dist;

		if(BLI_bvhtree_find_nearest(treeData.tree, point_co, &nearest, treeData.nearest_callback, &treeData) != -1) {
			copy_v3_v3(n_location, nearest.co);
			copy_v3_v3(n_normal, nearest.no);
			*index= nearest.index;
			return;
		}
	}

	zero_v3(n_location);
	zero_v3(n_normal);
	*index= -1;
}
Beispiel #2
0
static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3],
                                float r_location[3], float r_normal[3], int *index)
{
	BVHTreeFromMesh treeData = {NULL};
	
	if (ob->derivedFinal == NULL) {
		BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2);
		return;
	}

	/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
	bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6);

	/* may fail if the mesh has no faces, in that case the ray-cast misses */
	if (treeData.tree != NULL) {
		BVHTreeRayHit hit;
		float ray_nor[3], dist;
		sub_v3_v3v3(ray_nor, ray_end, ray_start);

		dist = hit.dist = normalize_v3(ray_nor);
		hit.index = -1;
		
		if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit,
		                         treeData.raycast_callback, &treeData) != -1)
		{
			if (hit.dist <= dist) {
				copy_v3_v3(r_location, hit.co);
				copy_v3_v3(r_normal, hit.no);
				*index = dm_tessface_to_poly_index(ob->derivedFinal, hit.index);
				free_bvhtree_from_mesh(&treeData);
				return;
			}
		}
	}

	zero_v3(r_location);
	zero_v3(r_normal);
	*index = -1;
	free_bvhtree_from_mesh(&treeData);
}
Beispiel #3
0
void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3], float r_location[3], float r_normal[3], int *index)
{
	BVHTreeFromMesh treeData= {NULL};
	
	if(ob->derivedFinal==NULL) {
		BKE_reportf(reports, RPT_ERROR, "object \"%s\" has no mesh data to be used for ray casting", ob->id.name+2);
		return;
	}

	/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
	bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6);

	if(treeData.tree==NULL) {
		BKE_reportf(reports, RPT_ERROR, "object \"%s\" could not create internal data for ray casting", ob->id.name+2);
		return;
	}
	else {
		BVHTreeRayHit hit;
		float ray_nor[3], dist;
		sub_v3_v3v3(ray_nor, ray_end, ray_start);

		dist= hit.dist = normalize_v3(ray_nor);
		hit.index = -1;
		
		if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) {
			if(hit.dist<=dist) {
				copy_v3_v3(r_location, hit.co);
				copy_v3_v3(r_normal, hit.no);
				*index= hit.index;
				return;
			}
		}
	}

	zero_v3(r_location);
	zero_v3(r_normal);
	*index= -1;
}
bool RE_bake_pixels_populate_from_objects(
        struct Mesh *me_low, BakePixel pixel_array_from[],  BakePixel pixel_array_to[],
        BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage,
        const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage)
{
	size_t i;
	int primitive_id;
	float u, v;
	float imat_low[4][4];
	bool is_cage = me_cage != NULL;
	bool result = true;

	DerivedMesh *dm_low = NULL;
	DerivedMesh **dm_highpoly;
	BVHTreeFromMesh *treeData;

	/* Note: all coordinates are in local space */
	TriTessFace *tris_low = NULL;
	TriTessFace *tris_cage = NULL;
	TriTessFace **tris_high;

	/* assume all lowpoly tessfaces can be quads */
	tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array");

	/* assume all highpoly tessfaces are triangles */
	dm_highpoly = MEM_mallocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes");
	treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees");

	if (!is_cage) {
		dm_low = CDDM_from_mesh(me_low);
		tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
		mesh_calc_tri_tessface(tris_low, me_low, true, dm_low);
	}
	else if (is_custom_cage) {
		tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
		mesh_calc_tri_tessface(tris_low, me_low, false, NULL);

		tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh");
		mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL);
	}
	else {
		tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh");
		mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL);
	}

	invert_m4_m4(imat_low, mat_low);

	for (i = 0; i < tot_highpoly; i++) {
		tris_high[i] = MEM_mallocN(sizeof(TriTessFace) * highpoly[i].me->totface, "MVerts Highpoly Mesh");
		mesh_calc_tri_tessface(tris_high[i], highpoly[i].me, false, NULL);

		dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me);
		DM_ensure_tessface(dm_highpoly[i]);

		if (dm_highpoly[i]->getNumTessFaces(dm_highpoly[i]) != 0) {
			/* Create a bvh-tree for each highpoly object */
			bvhtree_from_mesh_faces(&treeData[i], dm_highpoly[i], 0.0, 2, 6);

			if (treeData[i].tree == NULL) {
				printf("Baking: out of memory while creating BHVTree for object \"%s\"\n", highpoly[i].ob->id.name + 2);
				result = false;
				goto cleanup;
			}
		}
	}

	for (i = 0; i < num_pixels; i++) {
		float co[3];
		float dir[3];

		primitive_id = pixel_array_from[i].primitive_id;

		if (primitive_id == -1) {
			pixel_array_to[i].primitive_id = -1;
			continue;
		}

		u = pixel_array_from[i].uv[0];
		v = pixel_array_from[i].uv[1];

		/* calculate from low poly mesh cage */
		if (is_custom_cage) {
			calc_point_from_barycentric_cage(tris_low, tris_cage, mat_low, mat_cage, primitive_id, u, v, co, dir);
		}
		else if (is_cage) {
			calc_point_from_barycentric_extrusion(tris_cage, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, true);
		}
		else {
			calc_point_from_barycentric_extrusion(tris_low, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, false);
		}

		/* cast ray */
		if (!cast_ray_highpoly(treeData, tris_high, pixel_array_to, highpoly, co, dir, i, tot_highpoly,
		                       pixel_array_from[i].du_dx, pixel_array_from[i].du_dy,
		                       pixel_array_from[i].dv_dx, pixel_array_from[i].dv_dy)) {
			/* if it fails mask out the original pixel array */
			pixel_array_from[i].primitive_id = -1;
		}
	}


	/* garbage collection */
cleanup:
	for (i = 0; i < tot_highpoly; i++) {
		free_bvhtree_from_mesh(&treeData[i]);

		if (dm_highpoly[i]) {
			dm_highpoly[i]->release(dm_highpoly[i]);
		}

		if (tris_high[i]) {
			MEM_freeN(tris_high[i]);
		}
	}

	MEM_freeN(tris_high);
	MEM_freeN(treeData);
	MEM_freeN(dm_highpoly);

	if (dm_low) {
		dm_low->release(dm_low);
	}
	if (tris_low) {
		MEM_freeN(tris_low);
	}
	if (tris_cage) {
		MEM_freeN(tris_cage);
	}

	return result;
}
Beispiel #5
0
/*
 * Shrinkwrap moving vertexs to the nearest surface point on the target
 *
 * it builds a BVHTree from the target mesh and then performs a
 * NN matches for each vertex
 */
static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
{
	int i;

	BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
	BVHTreeNearest nearest  = NULL_BVHTreeNearest;

	/* Create a bvh-tree of the given target */
	bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 2, 6);
	if (treeData.tree == NULL) {
		OUT_OF_MEMORY();
		return;
	}

	/* Setup nearest */
	nearest.index = -1;
	nearest.dist_sq = FLT_MAX;


	/* Find the nearest vertex */
#ifndef __APPLE__
#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static)
#endif
	for (i = 0; i < calc->numVerts; ++i) {
		float *co = calc->vertexCos[i];
		float tmp_co[3];
		float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
		if (weight == 0.0f) continue;

		/* Convert the vertex to tree coordinates */
		if (calc->vert) {
			copy_v3_v3(tmp_co, calc->vert[i].co);
		}
		else {
			copy_v3_v3(tmp_co, co);
		}
		space_transform_apply(&calc->local2target, tmp_co);

		/* Use local proximity heuristics (to reduce the nearest search)
		 *
		 * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
		 * so we can initiate the "nearest.dist" with the expected value to that last hit.
		 * This will lead in pruning of the search tree. */
		if (nearest.index != -1)
			nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
		else
			nearest.dist_sq = FLT_MAX;

		BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);

		/* Found the nearest vertex */
		if (nearest.index != -1) {
			if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
				/* Make the vertex stay on the front side of the face */
				madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist);
			}
			else {
				/* Adjusting the vertex weight,
				 * so that after interpolating it keeps a certain distance from the nearest position */
				const float dist = sasqrt(nearest.dist_sq);
				if (dist > FLT_EPSILON) {
					/* linear interpolation */
					interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist);
				}
				else {
					copy_v3_v3(tmp_co, nearest.co);
				}
			}

			/* Convert the coordinates back to mesh coordinates */
			space_transform_invert(&calc->local2target, tmp_co);
			interp_v3_v3v3(co, co, tmp_co, weight);  /* linear interpolation */
		}
	}

	free_bvhtree_from_mesh(&treeData);
}
Beispiel #6
0
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
{
	int i;

	/* Options about projection direction */
	const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
	float proj_axis[3]      = {0.0f, 0.0f, 0.0f};

	/* Raycast and tree stuff */

	/** \note 'hit.dist' is kept in the targets space, this is only used
	 * for finding the best hit, to get the real dist,
	 * measure the len_v3v3() from the input coord to hit.co */
	BVHTreeRayHit hit;
	BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;

	/* auxiliary target */
	DerivedMesh *auxMesh    = NULL;
	BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh;
	SpaceTransform local2aux;

	/* If the user doesn't allows to project in any direction of projection axis
	 * then theres nothing todo. */
	if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
		return;


	/* Prepare data to retrieve the direction in which we should project each vertex */
	if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
		if (calc->vert == NULL) return;
	}
	else {
		/* The code supports any axis that is a combination of X,Y,Z
		 * although currently UI only allows to set the 3 different axis */
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f;
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f;
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f;

		normalize_v3(proj_axis);

		/* Invalid projection direction */
		if (len_squared_v3(proj_axis) < FLT_EPSILON) {
			return;
		}
	}

	if (calc->smd->auxTarget) {
		auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render);
		if (!auxMesh)
			return;
		SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
	}

	/* After sucessufuly build the trees, start projection vertexs */
	if (bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 4, 6) &&
	    (auxMesh == NULL || bvhtree_from_mesh_faces(&auxData, auxMesh, 0.0, 4, 6)))
	{

#ifndef __APPLE__
#pragma omp parallel for private(i, hit) schedule(static)
#endif
		for (i = 0; i < calc->numVerts; ++i) {
			float *co = calc->vertexCos[i];
			float tmp_co[3], tmp_no[3];
			const float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);

			if (weight == 0.0f) {
				continue;
			}

			if (calc->vert) {
				/* calc->vert contains verts from derivedMesh  */
				/* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
				/* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
				if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
					copy_v3_v3(tmp_co, calc->vert[i].co);
					normal_short_to_float_v3(tmp_no, calc->vert[i].no);
				}
				else {
					copy_v3_v3(tmp_co, co);
					copy_v3_v3(tmp_no, proj_axis);
				}
			}
			else {
				copy_v3_v3(tmp_co, co);
				copy_v3_v3(tmp_no, proj_axis);
			}


			hit.index = -1;
			hit.dist = 10000.0f; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */

			/* Project over positive direction of axis */
			if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {

				if (auxData.tree) {
					BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no,
					                              &local2aux, auxData.tree, &hit,
					                              auxData.raycast_callback, &auxData);
				}

				BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no,
				                              &calc->local2target, treeData.tree, &hit,
				                              treeData.raycast_callback, &treeData);
			}

			/* Project over negative direction of axis */
			if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
				float inv_no[3];
				negate_v3_v3(inv_no, tmp_no);

				if (auxData.tree) {
					BKE_shrinkwrap_project_normal(0, tmp_co, inv_no,
					                              &local2aux, auxData.tree, &hit,
					                              auxData.raycast_callback, &auxData);
				}

				BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no,
				                              &calc->local2target, treeData.tree, &hit,
				                              treeData.raycast_callback, &treeData);
			}

			/* don't set the initial dist (which is more efficient),
			 * because its calculated in the targets space, we want the dist in our own space */
			if (proj_limit_squared != 0.0f) {
				if (len_squared_v3v3(hit.co, co) > proj_limit_squared) {
					hit.index = -1;
				}
			}

			if (hit.index != -1) {
				madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist);
				interp_v3_v3v3(co, co, hit.co, weight);
			}
		}
	}

	/* free data structures */
	free_bvhtree_from_mesh(&treeData);
	free_bvhtree_from_mesh(&auxData);
}
Beispiel #7
0
static void deformVerts(ModifierData *md, Object *ob,
						DerivedMesh *derivedData,
						float (*vertexCos)[3],
						int UNUSED(numVerts),
						int UNUSED(useRenderParams),
						int UNUSED(isFinalCalc))
{
	SurfaceModifierData *surmd = (SurfaceModifierData*) md;
	
	if(surmd->dm)
		surmd->dm->release(surmd->dm);

	/* if possible use/create DerivedMesh */
	if(derivedData) surmd->dm = CDDM_copy(derivedData);
	else surmd->dm = get_dm(ob, NULL, NULL, NULL, 0);
	
	if(!ob->pd)
	{
		printf("SurfaceModifier deformVerts: Should not happen!\n");
		return;
	}
	
	if(surmd->dm)
	{
		unsigned int numverts = 0, i = 0;
		int init = 0;
		float *vec;
		MVert *x, *v;

		CDDM_apply_vert_coords(surmd->dm, vertexCos);
		CDDM_calc_normals(surmd->dm);
		
		numverts = surmd->dm->getNumVerts ( surmd->dm );

		if(numverts != surmd->numverts || surmd->x == NULL || surmd->v == NULL || md->scene->r.cfra != surmd->cfra+1) {
			if(surmd->x) {
				MEM_freeN(surmd->x);
				surmd->x = NULL;
			}
			if(surmd->v) {
				MEM_freeN(surmd->v);
				surmd->v = NULL;
			}

			surmd->x = MEM_callocN(numverts * sizeof(MVert), "MVert");
			surmd->v = MEM_callocN(numverts * sizeof(MVert), "MVert");

			surmd->numverts = numverts;

			init = 1;
		}

		/* convert to global coordinates and calculate velocity */
		for(i = 0, x = surmd->x, v = surmd->v; i<numverts; i++, x++, v++) {
			vec = CDDM_get_vert(surmd->dm, i)->co;
			mul_m4_v3(ob->obmat, vec);

			if(init)
				v->co[0] = v->co[1] = v->co[2] = 0.0f;
			else
				sub_v3_v3v3(v->co, vec, x->co);
			
			copy_v3_v3(x->co, vec);
		}

		surmd->cfra = md->scene->r.cfra;

		if(surmd->bvhtree)
			free_bvhtree_from_mesh(surmd->bvhtree);
		else
			surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");

		if(surmd->dm->getNumFaces(surmd->dm))
			bvhtree_from_mesh_faces(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
		else
			bvhtree_from_mesh_edges(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
	}
}
/**
 * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
 */
static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
                                   float *dist_v, float *dist_e, float *dist_f,
                                   DerivedMesh *target, const SpaceTransform *loc2trgt)
{
	int i;
	BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh;
	BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh;
	BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh;
	BVHTreeNearest nearest_v   = NULL_BVHTreeNearest;
	BVHTreeNearest nearest_e   = NULL_BVHTreeNearest;
	BVHTreeNearest nearest_f   = NULL_BVHTreeNearest;

	if (dist_v) {
		/* Create a bvh-tree of the given target's verts. */
		bvhtree_from_mesh_verts(&treeData_v, target, 0.0, 2, 6);
		if (treeData_v.tree == NULL) {
			OUT_OF_MEMORY();
			return;
		}
	}
	if (dist_e) {
		/* Create a bvh-tree of the given target's edges. */
		bvhtree_from_mesh_edges(&treeData_e, target, 0.0, 2, 6);
		if (treeData_e.tree == NULL) {
			OUT_OF_MEMORY();
			return;
		}
	}
	if (dist_f) {
		/* Create a bvh-tree of the given target's faces. */
		bvhtree_from_mesh_faces(&treeData_f, target, 0.0, 2, 6);
		if (treeData_f.tree == NULL) {
			OUT_OF_MEMORY();
			return;
		}
	}

	/* Setup nearest. */
	nearest_v.index = nearest_e.index = nearest_f.index = -1;
	/*nearest_v.dist  = nearest_e.dist  = nearest_f.dist  = FLT_MAX;*/
	/* Find the nearest vert/edge/face. */
#ifndef __APPLE__
#pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \
                         shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \
                                dist_f,loc2trgt) \
                         schedule(static)
#endif
	for (i = 0; i < numVerts; i++) {
		float tmp_co[3];

		/* Convert the vertex to tree coordinates. */
		copy_v3_v3(tmp_co, v_cos[i]);
		space_transform_apply(loc2trgt, tmp_co);

		/* Use local proximity heuristics (to reduce the nearest search).
		 *
		 * If we already had an hit before, we assume this vertex is going to have a close hit to
		 * that other vertex, so we can initiate the "nearest.dist" with the expected value to that
		 * last hit.
		 * This will lead in prunning of the search tree.
		 */
		if (dist_v) {
			nearest_v.dist = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX;
			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v);
			dist_v[i] = sqrtf(nearest_v.dist);
		}
		if (dist_e) {
			nearest_e.dist = nearest_e.index != -1 ? len_squared_v3v3(tmp_co, nearest_e.co) : FLT_MAX;
			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e);
			dist_e[i] = sqrtf(nearest_e.dist);
		}
		if (dist_f) {
			nearest_f.dist = nearest_f.index != -1 ? len_squared_v3v3(tmp_co, nearest_f.co) : FLT_MAX;
			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f);
			dist_f[i] = sqrtf(nearest_f.dist);
		}
	}

	if (dist_v)
		free_bvhtree_from_mesh(&treeData_v);
	if (dist_e)
		free_bvhtree_from_mesh(&treeData_e);
	if (dist_f)
		free_bvhtree_from_mesh(&treeData_f);
}
/* from/to_world_space : whether from/to particles are in world or hair space
 * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
 */
static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
                               Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
                               float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
	ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
	ParticleData *pa, *tpa;
	PTCacheEditPoint *edit_point;
	PTCacheEditKey *ekey;
	BVHTreeFromMesh bvhtree= {NULL};
	MFace *mface = NULL, *mf;
	MEdge *medge = NULL, *me;
	MVert *mvert;
	DerivedMesh *dm, *target_dm;
	int numverts;
	int i, k;
	float from_ob_imat[4][4], to_ob_imat[4][4];
	float from_imat[4][4], to_imat[4][4];

	if (!target_psmd->dm)
		return false;
	if (!psys->part || psys->part->type != PART_HAIR)
		return false;
	if (!target_psys->part || target_psys->part->type != PART_HAIR)
		return false;
	
	edit_point = target_edit ? target_edit->points : NULL;
	
	invert_m4_m4(from_ob_imat, ob->obmat);
	invert_m4_m4(to_ob_imat, target_ob->obmat);
	invert_m4_m4(from_imat, from_mat);
	invert_m4_m4(to_imat, to_mat);
	
	if (target_psmd->dm->deformedOnly) {
		/* we don't want to mess up target_psmd->dm when converting to global coordinates below */
		dm = target_psmd->dm;
	}
	else {
		/* warning: this rebuilds target_psmd->dm! */
		dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
	}
	target_dm = target_psmd->dm;
	/* don't modify the original vertices */
	dm = CDDM_copy(dm);

	/* BMESH_ONLY, deform dm may not have tessface */
	DM_ensure_tessface(dm);

	numverts = dm->getNumVerts(dm);
	mvert = dm->getVertArray(dm);

	/* convert to global coordinates */
	for (i=0; i<numverts; i++)
		mul_m4_v3(to_mat, mvert[i].co);

	if (dm->getNumTessFaces(dm) != 0) {
		mface = dm->getTessFaceArray(dm);
		bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
	}
	else if (dm->getNumEdges(dm) != 0) {
		medge = dm->getEdgeArray(dm);
		bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6);
	}
	else {
		dm->release(dm);
		return false;
	}

	for (i = 0, tpa = target_psys->particles, pa = psys->particles;
	     i < target_psys->totpart;
	     i++, tpa++, pa++) {

		float from_co[3];
		BVHTreeNearest nearest;

		if (from_global)
			mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
		else
			mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
		mul_m4_v3(from_mat, from_co);

		nearest.index = -1;
		nearest.dist_sq = FLT_MAX;

		BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);

		if (nearest.index == -1) {
			if (G.debug & G_DEBUG)
				printf("No nearest point found for hair root!");
			continue;
		}

		if (mface) {
			float v[4][3];
			
			mf = &mface[nearest.index];

			copy_v3_v3(v[0], mvert[mf->v1].co);
			copy_v3_v3(v[1], mvert[mf->v2].co);
			copy_v3_v3(v[2], mvert[mf->v3].co);
			if (mf->v4) {
				copy_v3_v3(v[3], mvert[mf->v4].co);
				interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
			}
			else
				interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL);
		}
		else {
			me = &medge[nearest.index];

			tpa->fuv[1] = line_point_factor_v3(nearest.co,
			                                   mvert[me->v1].co,
			                                   mvert[me->v2].co);
			tpa->fuv[0] = 1.0f - tpa->fuv[1];
			tpa->fuv[2] = tpa->fuv[3] = 0.0f;
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = -1;
		}

		/* translate hair keys */
		{
			HairKey *key, *tkey;
			float hairmat[4][4], imat[4][4];
			float offset[3];
			
			if (to_global)
				copy_m4_m4(imat, target_ob->obmat);
			else {
				/* note: using target_dm here, which is in target_ob object space and has full modifiers */
				psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
				invert_m4_m4(imat, hairmat);
			}
			mul_m4_m4m4(imat, imat, to_imat);
			
			/* offset in world space */
			sub_v3_v3v3(offset, nearest.co, from_co);
			
			if (edit_point) {
				for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) {
					float co_orig[3];
					
					if (from_global)
						mul_v3_m4v3(co_orig, from_ob_imat, key->co);
					else
						mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
					mul_m4_v3(from_mat, co_orig);
					
					add_v3_v3v3(tkey->co, co_orig, offset);
					
					mul_m4_v3(imat, tkey->co);
					
					ekey->flag |= PEK_USE_WCO;
				}
				
				edit_point++;
			}
			else {
				for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
					float co_orig[3];
					
					if (from_global)
						mul_v3_m4v3(co_orig, from_ob_imat, key->co);
					else
						mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
					mul_m4_v3(from_mat, co_orig);
					
					add_v3_v3v3(tkey->co, co_orig, offset);
					
					mul_m4_v3(imat, tkey->co);
				}
			}
		}
	}

	free_bvhtree_from_mesh(&bvhtree);
	dm->release(dm);

	psys_free_path_cache(target_psys, target_edit);

	PE_update_object(scene, target_ob, 0);

	return true;
}
Beispiel #10
0
static int connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
{
	ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
	ParticleData *pa;
	PTCacheEdit *edit;
	PTCacheEditPoint *point;
	PTCacheEditKey *ekey = NULL;
	HairKey *key;
	BVHTreeFromMesh bvhtree= {NULL};
	BVHTreeNearest nearest;
	MFace *mface, *mf;
	MVert *mvert;
	DerivedMesh *dm = NULL;
	int numverts;
	int i, k;
	float hairmat[4][4], imat[4][4];
	float v[4][3], vec[3];

	if (!psys || !psys->part || psys->part->type != PART_HAIR || !psmd->dm)
		return FALSE;
	
	edit= psys->edit;
	point=  edit ? edit->points : NULL;
	
	if (psmd->dm->deformedOnly) {
		/* we don't want to mess up psmd->dm when converting to global coordinates below */
		dm = psmd->dm;
	}
	else {
		dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
	}
	/* don't modify the original vertices */
	dm = CDDM_copy(dm);

	/* BMESH_ONLY, deform dm may not have tessface */
	DM_ensure_tessface(dm);

	numverts = dm->getNumVerts(dm);

	mvert = dm->getVertArray(dm);
	mface = dm->getTessFaceArray(dm);

	/* convert to global coordinates */
	for (i=0; i<numverts; i++)
		mul_m4_v3(ob->obmat, mvert[i].co);

	bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);

	for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) {
		key = pa->hair;

		nearest.index = -1;
		nearest.dist = FLT_MAX;

		BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);

		if (nearest.index == -1) {
			if (G.debug & G_DEBUG)
				printf("No nearest point found for hair root!");
			continue;
		}

		mf = &mface[nearest.index];

		copy_v3_v3(v[0], mvert[mf->v1].co);
		copy_v3_v3(v[1], mvert[mf->v2].co);
		copy_v3_v3(v[2], mvert[mf->v3].co);
		if (mf->v4) {
			copy_v3_v3(v[3], mvert[mf->v4].co);
			interp_weights_poly_v3(pa->fuv, v, 4, nearest.co);
		}
		else
			interp_weights_poly_v3(pa->fuv, v, 3, nearest.co);

		pa->num = nearest.index;
		pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL);
		
		psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
		invert_m4_m4(imat, hairmat);

		sub_v3_v3v3(vec, nearest.co, key->co);

		if (point) {
			ekey = point->keys;
			point++;
		}

		for (k=0, key=pa->hair; k<pa->totkey; k++, key++) {
			add_v3_v3(key->co, vec);
			mul_m4_v3(imat, key->co);

			if (ekey) {
				ekey->flag |= PEK_USE_WCO;
				ekey++;
			}
		}
	}

	free_bvhtree_from_mesh(&bvhtree);
	dm->release(dm);

	psys_free_path_cache(psys, psys->edit);

	psys->flag &= ~PSYS_GLOBAL_HAIR;

	PE_update_object(scene, ob, 0);

	return TRUE;
}
Beispiel #11
0
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
{
	int i;

	//Options about projection direction
	const char use_normal	= calc->smd->shrinkOpts;
	float proj_axis[3]		= {0.0f, 0.0f, 0.0f};

	//Raycast and tree stuff
	BVHTreeRayHit hit;
	BVHTreeFromMesh treeData= NULL_BVHTreeFromMesh;

	//auxiliary target
	DerivedMesh *auxMesh	= NULL;
	BVHTreeFromMesh auxData	= NULL_BVHTreeFromMesh;
	SpaceTransform local2aux;

	//If the user doesn't allows to project in any direction of projection axis
	//then theres nothing todo.
	if ((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
		return;


	//Prepare data to retrieve the direction in which we should project each vertex
	if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
		if (calc->vert == NULL) return;
	}
	else {
		//The code supports any axis that is a combination of X,Y,Z
		//although currently UI only allows to set the 3 different axis
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f;
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f;
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f;

		normalize_v3(proj_axis);

		//Invalid projection direction
		if (dot_v3v3(proj_axis, proj_axis) < FLT_EPSILON)
			return; 
	}

	if (calc->smd->auxTarget) {
		auxMesh = object_get_derived_final(calc->smd->auxTarget);
		if (!auxMesh)
			return;
		space_transform_setup(&local2aux, calc->ob, calc->smd->auxTarget);
	}

	//After sucessufuly build the trees, start projection vertexs
	if (bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 4, 6) &&
	    (auxMesh == NULL || bvhtree_from_mesh_faces(&auxData, auxMesh, 0.0, 4, 6)))
	{

#ifndef __APPLE__
#pragma omp parallel for private(i,hit) schedule(static)
#endif
		for (i = 0; i<calc->numVerts; ++i) {
			float *co = calc->vertexCos[i];
			float tmp_co[3], tmp_no[3];
			float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);

			if (weight == 0.0f) continue;

			if (calc->vert) {
				/* calc->vert contains verts from derivedMesh  */
				/* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
				/* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
				if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
					copy_v3_v3(tmp_co, calc->vert[i].co);
					normal_short_to_float_v3(tmp_no, calc->vert[i].no);
				}
				else {
					copy_v3_v3(tmp_co, co);
					copy_v3_v3(tmp_no, proj_axis);
				}
			}
			else {
				copy_v3_v3(tmp_co, co);
				copy_v3_v3(tmp_no, proj_axis);
			}


			hit.index = -1;
			hit.dist = 10000.0f; //TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that

			//Project over positive direction of axis
			if (use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {

				if (auxData.tree)
					normal_projection_project_vertex(0, tmp_co, tmp_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData);

				normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData);
			}

			//Project over negative direction of axis
			if (use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR && hit.index == -1) {
				float inv_no[3];
				negate_v3_v3(inv_no, tmp_no);

				if (auxData.tree)
					normal_projection_project_vertex(0, tmp_co, inv_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData);

				normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData);
			}


			if (hit.index != -1) {
				madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist);
				interp_v3_v3v3(co, co, hit.co, weight);
			}
		}
	}

	//free data structures
	free_bvhtree_from_mesh(&treeData);
	free_bvhtree_from_mesh(&auxData);
}