Ejemplo n.º 1
0
/**
 * Callback used by BLI_task 'for loop' helper.
 */
static void vert2geom_task_cb(void *userdata, void *userdata_chunk, int iter)
{
	Vert2GeomData *data = userdata;
	Vert2GeomDataChunk *data_chunk = userdata_chunk;

	float tmp_co[3];
	int i;

	/* Convert the vertex to tree coordinates. */
	copy_v3_v3(tmp_co, data->v_cos[iter]);
	BLI_space_transform_apply(data->loc2trgt, tmp_co);

	for (i = 0; i < ARRAY_SIZE(data->dist); i++) {
		if (data->dist[i]) {
			BVHTreeNearest nearest = {0};

			/* Note that we use local proximity heuristics (to reduce the nearest search).
			 *
			 * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index),
			 * 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.
			 */
			nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX;
			nearest.index = -1;

			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest,
			                         data->treeData[i]->nearest_callback, data->treeData[i]);
			data->dist[i][iter] = sqrtf(nearest.dist_sq);

			if (nearest.index != -1) {
				copy_v3_v3(data_chunk->last_hit_co[i], nearest.co);
				data_chunk->is_init[i] = true;
			}
		}
	}
}
Ejemplo n.º 2
0
/* simple deform modifier */
static void SimpleDeformModifier_do(
        SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	const float base_limit[2] = {0.0f, 0.0f};

	int i;
	float smd_limit[2], smd_factor;
	SpaceTransform *transf = NULL, tmp_transf;
	void (*simpleDeform_callback)(const float factor, const int axis, const float dcut[3], float co[3]) = NULL;  /* Mode callback */
	int vgroup;
	MDeformVert *dvert;

	/* This is historically the lock axis, _not_ the deform axis as the name would imply */
	const int deform_axis = smd->deform_axis;
	int lock_axis = smd->axis;
	if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouldn't have any lock axis */
		lock_axis = 0;
	}
	else {
		/* Don't lock axis if it is the chosen deform axis, as this flattens
		 * the geometry */
		if (deform_axis == 0) {
			lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X;
		}
		if (deform_axis == 1) {
			lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y;
		}
		if (deform_axis == 2) {
			lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z;
		}
	}


	/* Safe-check */
	if (smd->origin == ob) smd->origin = NULL;  /* No self references */

	if (smd->limit[0] < 0.0f) smd->limit[0] = 0.0f;
	if (smd->limit[0] > 1.0f) smd->limit[0] = 1.0f;

	smd->limit[0] = min_ff(smd->limit[0], smd->limit[1]);  /* Upper limit >= than lower limit */

	/* Calculate matrixs do convert between coordinate spaces */
	if (smd->origin) {
		transf = &tmp_transf;
		BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin);
	}

	/* Update limits if needed */
	int limit_axis = deform_axis;
	if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
		/* Bend is a special case. */
		switch (deform_axis) {
			case 0:
				ATTR_FALLTHROUGH;
			case 1:
				limit_axis = 2;
				break;
			default:
				limit_axis = 0;
		}
	}

	{
		float lower =  FLT_MAX;
		float upper = -FLT_MAX;

		for (i = 0; i < numVerts; i++) {
			float tmp[3];
			copy_v3_v3(tmp, vertexCos[i]);

			if (transf) {
				BLI_space_transform_apply(transf, tmp);
			}

			lower = min_ff(lower, tmp[limit_axis]);
			upper = max_ff(upper, tmp[limit_axis]);
		}


		/* SMD values are normalized to the BV, calculate the absolute values */
		smd_limit[1] = lower + (upper - lower) * smd->limit[1];
		smd_limit[0] = lower + (upper - lower) * smd->limit[0];

		smd_factor   = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]);
	}

	switch (smd->mode) {
		case MOD_SIMPLEDEFORM_MODE_TWIST:   simpleDeform_callback = simpleDeform_twist;     break;
		case MOD_SIMPLEDEFORM_MODE_BEND:    simpleDeform_callback = simpleDeform_bend;      break;
		case MOD_SIMPLEDEFORM_MODE_TAPER:   simpleDeform_callback = simpleDeform_taper;     break;
		case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch;   break;
		default:
			return; /* No simpledeform mode? */
	}

	if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
		if (fabsf(smd_factor) < BEND_EPS) {
			return;
		}
	}

	modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup);
	const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
	const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2];

	for (i = 0; i < numVerts; i++) {
		float weight = defvert_array_find_weight_safe(dvert, i, vgroup);

		if (invert_vgroup) {
			weight = 1.0f - weight;
		}

		if (weight != 0.0f) {
			float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};

			if (transf) {
				BLI_space_transform_apply(transf, vertexCos[i]);
			}

			copy_v3_v3(co, vertexCos[i]);

			/* Apply axis limits, and axis mappings */
			if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
				axis_limit(0, base_limit, co, dcut);
			}
			if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
				axis_limit(1, base_limit, co, dcut);
			}
			if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
				axis_limit(2, base_limit, co, dcut);
			}
			axis_limit(limit_axis, smd_limit, co, dcut);

			/* apply the deform to a mapped copy of the vertex, and then re-map it back. */
			float co_remap[3];
			float dcut_remap[3];
			copy_v3_v3_map(co_remap, co, axis_map);
			copy_v3_v3_map(dcut_remap, dcut, axis_map);
			simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap);  /* apply deform */
			copy_v3_v3_unmap(co, co_remap, axis_map);

			interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight);  /* Use vertex weight has coef of linear interpolation */

			if (transf) {
				BLI_space_transform_invert(transf, vertexCos[i]);
			}
		}
	}
}
Ejemplo n.º 3
0
/* simple deform modifier */
static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
                                    float (*vertexCos)[3], int numVerts)
{
	static const float lock_axis[2] = {0.0f, 0.0f};

	int i;
	int limit_axis = 0;
	float smd_limit[2], smd_factor;
	SpaceTransform *transf = NULL, tmp_transf;
	void (*simpleDeform_callback)(const float factor, const float dcut[3], float co[3]) = NULL;  /* Mode callback */
	int vgroup;
	MDeformVert *dvert;

	/* Safe-check */
	if (smd->origin == ob) smd->origin = NULL;  /* No self references */

	if (smd->limit[0] < 0.0f) smd->limit[0] = 0.0f;
	if (smd->limit[0] > 1.0f) smd->limit[0] = 1.0f;

	smd->limit[0] = min_ff(smd->limit[0], smd->limit[1]);  /* Upper limit >= than lower limit */

	/* Calculate matrixs do convert between coordinate spaces */
	if (smd->origin) {
		transf = &tmp_transf;
		BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin);
	}

	/* Setup vars,
	 * Bend limits on X.. all other modes limit on Z */
	limit_axis  = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2;

	/* Update limits if needed */
	{
		float lower =  FLT_MAX;
		float upper = -FLT_MAX;

		for (i = 0; i < numVerts; i++) {
			float tmp[3];
			copy_v3_v3(tmp, vertexCos[i]);

			if (transf) {
				BLI_space_transform_apply(transf, tmp);
			}

			lower = min_ff(lower, tmp[limit_axis]);
			upper = max_ff(upper, tmp[limit_axis]);
		}


		/* SMD values are normalized to the BV, calculate the absolut values */
		smd_limit[1] = lower + (upper - lower) * smd->limit[1];
		smd_limit[0] = lower + (upper - lower) * smd->limit[0];

		smd_factor   = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]);
	}

	switch (smd->mode) {
		case MOD_SIMPLEDEFORM_MODE_TWIST:   simpleDeform_callback = simpleDeform_twist;     break;
		case MOD_SIMPLEDEFORM_MODE_BEND:    simpleDeform_callback = simpleDeform_bend;      break;
		case MOD_SIMPLEDEFORM_MODE_TAPER:   simpleDeform_callback = simpleDeform_taper;     break;
		case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch;   break;
		default:
			return; /* No simpledeform mode? */
	}

	if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
		if (fabsf(smd_factor) < BEND_EPS) {
			return;
		}
	}

	modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup);

	for (i = 0; i < numVerts; i++) {
		float weight = defvert_array_find_weight_safe(dvert, i, vgroup);

		if (weight != 0.0f) {
			float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};

			if (transf) {
				BLI_space_transform_apply(transf, vertexCos[i]);
			}

			copy_v3_v3(co, vertexCos[i]);

			/* Apply axis limits */
			if (smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shoulnt have any lock axis */
				if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut);
				if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut);
			}
			axis_limit(limit_axis, smd_limit, co, dcut);

			simpleDeform_callback(smd_factor, dcut, co);  /* apply deform */
			interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight);  /* Use vertex weight has coef of linear interpolation */

			if (transf) {
				BLI_space_transform_invert(transf, vertexCos[i]);
			}
		}
	}
}
Ejemplo n.º 4
0
/**
 * 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 treeData_e = {NULL};
	BVHTreeFromMesh treeData_f = {NULL};
	BVHTreeNearest nearest_v   = {0};
	BVHTreeNearest nearest_e   = {0};
	BVHTreeNearest nearest_f   = {0};

	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. */
#pragma omp parallel for default(shared) private(i) firstprivate(nearest_v, nearest_e, nearest_f) \
                         schedule(static) if (numVerts > 10000)
	for (i = 0; i < numVerts; i++) {
		float tmp_co[3];

		/* Convert the vertex to tree coordinates. */
		copy_v3_v3(tmp_co, v_cos[i]);
		BLI_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_sq = 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_sq);
		}
		if (dist_e) {
			nearest_e.dist_sq = 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_sq);
		}
		if (dist_f) {
			nearest_f.dist_sq = 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_sq);
		}
	}

	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);
}