예제 #1
0
/**
 * Same as #interp_v3_v3v3_slerp buy uses fallback values
 * for opposite vectors.
 */
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t)
{
	if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, b, t))) {
		/* axis are aligned so any otho vector is acceptable */
		float ab_ortho[3];
		ortho_v3_v3(ab_ortho, a);
		normalize_v3(ab_ortho);
		if (t < 0.5f) {
			if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, ab_ortho, t * 2.0f))) {
				BLI_assert(0);
				copy_v3_v3(target, a);
			}
		}
		else {
			if (UNLIKELY(!interp_v3_v3v3_slerp(target, ab_ortho, b, (t - 0.5f) * 2.0f))) {
				BLI_assert(0);
				copy_v3_v3(target, b);
			}
		}
	}
}
/**
 * Specialized slerp that uses a sphere defined by each points normal.
 */
static void interp_slerp_co_no_v3(
        const float co_a[3], const float no_a[3],
        const float co_b[3], const float no_b[3],
        const float no_dir[3],  /* caller already knows, avoid normalize */
        float fac,
        float r_co[3])
{
	/* center of the sphere defined by both normals */
	float center[3];

	BLI_assert(len_squared_v3v3(no_a, no_b) != 0);

	/* calculate sphere 'center' */
	{
		/* use point on plane to */
		float plane_a[4], plane_b[4], plane_c[4];
		float no_mid[3], no_ortho[3];
		/* pass this as an arg instead */
#if 0
		float no_dir[3];
#endif

		float v_a_no_ortho[3], v_b_no_ortho[3];

		add_v3_v3v3(no_mid, no_a, no_b);
		normalize_v3(no_mid);

#if 0
		sub_v3_v3v3(no_dir, co_a, co_b);
		normalize_v3(no_dir);
#endif

		/* axis of slerp */
		cross_v3_v3v3(no_ortho, no_mid, no_dir);
		normalize_v3(no_ortho);

		/* create planes */
		cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
		cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
		project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
		project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);

		plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
		plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
		plane_from_point_normal_v3(plane_c, co_b, no_ortho);

		/* find the sphere center from 3 planes */
		if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
			/* pass */
		}
		else {
			mid_v3_v3v3(center, co_a, co_b);
		}
	}

	/* calculate the final output 'r_co' */
	{
		float ofs_a[3], ofs_b[3], ofs_slerp[3];
		float dist_a, dist_b;

		sub_v3_v3v3(ofs_a, co_a, center);
		sub_v3_v3v3(ofs_b, co_b, center);

		dist_a = normalize_v3(ofs_a);
		dist_b = normalize_v3(ofs_b);

		if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
			madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
		}
		else {
			interp_v3_v3v3(r_co, co_a, co_b, fac);
		}
	}
}