Пример #1
0
static void
quaternion_matrix_to_from (mutest_spec_t *spec)
{
  graphene_quaternion_t *q1, *q2;
  graphene_matrix_t *m;

  m = graphene_matrix_init_identity (graphene_matrix_alloc ());

  q1 = graphene_quaternion_init_from_matrix (graphene_quaternion_alloc (), m);
  q2 = graphene_quaternion_init_identity (graphene_quaternion_alloc ());
  mutest_expect ("initializing from an identity matrix yields an identity quaternion",
                 mutest_bool_value (graphene_quaternion_equal (q1, q2)),
                 mutest_to_be_true,
                 NULL);

  graphene_matrix_rotate_x (m, 30.f);
  graphene_matrix_rotate_y (m, 45.f);
  graphene_matrix_rotate_z (m, -135.f);
  graphene_quaternion_init_from_matrix (q1, m);
  mutest_expect ("initializing from a rotation matrix does not yield an identity quaternion",
                 mutest_bool_value (graphene_quaternion_equal (q1, q2)),
                 mutest_to_be_false,
                 NULL);

  graphene_matrix_init_identity (m);
  graphene_matrix_rotate_quaternion (m, q1);
  graphene_quaternion_init_from_matrix (q2, m);
  mutest_expect ("rotating a matrix with a quaternion yields the same quaternion",
                 mutest_bool_value (graphene_quaternion_equal (q1, q2)),
                 mutest_to_be_true,
                 NULL);

  graphene_quaternion_free (q2);
  graphene_quaternion_free (q1);

  graphene_matrix_free (m);
}
Пример #2
0
static gboolean
matrix_decompose_3d (const graphene_matrix_t *m,
                     graphene_point3d_t      *scale_r,
                     float                    shear_r[3],
                     graphene_quaternion_t   *rotate_r,
                     graphene_point3d_t      *translate_r,
                     graphene_vec4_t         *perspective_r)
{
  graphene_matrix_t local, perspective;
  float shear_xy, shear_xz, shear_yz;
  float scale_x, scale_y, scale_z;
  graphene_simd4f_t dot, cross;

  if (graphene_matrix_get_value (m, 3, 3) == 0.f)
    return FALSE;

  local = *m;

  /* normalize the matrix */
  graphene_matrix_normalize (&local, &local);

  /* perspective is used to solve for the perspective component,
   * but it also provides an easy way to test for singularity of
   * the upper 3x3 component
   */
  perspective = local;
  perspective.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f);

  if (graphene_matrix_determinant (&perspective) == 0.f)
    return FALSE;

  /* isolate the perspective */
  if (graphene_simd4f_is_zero3 (local.value.w))
    {
      graphene_matrix_t tmp;

      /* perspective_r is the right hand side of the equation */
      perspective_r->value = local.value.w;

      /* solve the equation by inverting perspective and multiplying
       * the inverse with the perspective vector
       */
      graphene_matrix_inverse (&perspective, &tmp);
      graphene_matrix_transpose_transform_vec4 (&tmp, perspective_r, perspective_r);

      /* clear the perspective partition */
      local.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f);
    }
  else
    graphene_vec4_init (perspective_r, 0.f, 0.f, 0.f, 1.f);

  /* next, take care of the translation partition */
  translate_r->x = graphene_simd4f_get_x (local.value.w);
  translate_r->y = graphene_simd4f_get_y (local.value.w);
  translate_r->z = graphene_simd4f_get_z (local.value.w);
  local.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, graphene_simd4f_get_w (local.value.w));

  /* now get scale and shear */

  /* compute the X scale factor and normalize the first row */
  scale_x = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.x));
  local.value.x = graphene_simd4f_div (local.value.x, graphene_simd4f_splat (scale_x));

  /* compute XY shear factor and the second row orthogonal to the first */
  shear_xy = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.x, local.value.y));
  local.value.y = graphene_simd4f_sub (local.value.y, graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (shear_xy)));

  /* now, compute the Y scale factor and normalize the second row */
  scale_y = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.y));
  local.value.y = graphene_simd4f_div (local.value.y, graphene_simd4f_splat (scale_y));
  shear_xy /= scale_y;

  /* compute XZ and YZ shears, make the third row orthogonal */
  shear_xz = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.x, local.value.z));
  local.value.z = graphene_simd4f_sub (local.value.z, graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (shear_xz)));
  shear_yz = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.y, local.value.z));
  local.value.z = graphene_simd4f_sub (local.value.z, graphene_simd4f_mul (local.value.y, graphene_simd4f_splat (shear_yz)));

  /* next, get the Z scale and normalize the third row */
  scale_z = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.z));
  local.value.z = graphene_simd4f_div (local.value.z, graphene_simd4f_splat (scale_z));

  shear_xz /= scale_z;
  shear_yz /= scale_z;

  shear_r[XY_SHEAR] = shear_xy;
  shear_r[XZ_SHEAR] = shear_xz;
  shear_r[YZ_SHEAR] = shear_yz;

  /* at this point, the matrix is orthonormal. we check for a
   * coordinate system flip. if the determinant is -1, then
   * negate the matrix and the scaling factors
   */
  dot = graphene_simd4f_cross3 (local.value.y, local.value.z);
  cross = graphene_simd4f_dot4 (local.value.x, dot);
  if (graphene_simd4f_get_x (cross) < 0.f)
    {
      scale_x *= -1.f;
      scale_y *= -1.f;
      scale_z *= -1.f;

      graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (-1.f));
      graphene_simd4f_mul (local.value.y, graphene_simd4f_splat (-1.f));
      graphene_simd4f_mul (local.value.z, graphene_simd4f_splat (-1.f));
    }

  graphene_point3d_init (scale_r, scale_x, scale_y, scale_z);

  /* get the rotations out */
  graphene_quaternion_init_from_matrix (rotate_r, &local);

  return TRUE;
}