From 7662d07fa36eca01d9518d1ea620905f64bf2584 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 5 Mar 2019 16:44:25 +0100 Subject: [PATCH] matrix: Fix interpolation of perspective matrices The code was extracting the 3rd row as perspective, not the 3rd column. A new test interpolate-perspective has been added. --- src/graphene-matrix.c | 27 ++++++++++++--------------- src/tests/matrix.c | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/graphene-matrix.c b/src/graphene-matrix.c index 334719ee..818af2c5 100644 --- a/src/graphene-matrix.c +++ b/src/graphene-matrix.c @@ -1844,7 +1844,7 @@ matrix_decompose_3d (const graphene_matrix_t *m, graphene_point3d_t *translate_r, graphene_vec4_t *perspective_r) { - graphene_matrix_t local, perspective; + graphene_matrix_t local; float shear_xy, shear_xz, shear_yz; float scale_x, scale_y, scale_z; graphene_simd4f_t perspective_v; @@ -1862,17 +1862,20 @@ matrix_decompose_3d (const graphene_matrix_t *m, * 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_approx_val (graphene_matrix_determinant (&perspective), 0.f)) - return false; - perspective_v = graphene_simd4f_init (graphene_simd4f_get_w (local.value.x), graphene_simd4f_get_w (local.value.y), graphene_simd4f_get_w (local.value.z), graphene_simd4f_get_w (local.value.w)); + /* Clear the perspective component */ + local.value.x = graphene_simd4f_merge_w (local.value.x, 0.f); + local.value.y = graphene_simd4f_merge_w (local.value.y, 0.f); + local.value.z = graphene_simd4f_merge_w (local.value.z, 0.f); + local.value.w = graphene_simd4f_merge_w (local.value.w, 1.f); + + if (graphene_approx_val (graphene_matrix_determinant (&local), 0.f)) + return false; + /* isolate the perspective */ if (!graphene_simd4f_is_zero3 (perspective_v)) { @@ -1886,14 +1889,8 @@ matrix_decompose_3d (const graphene_matrix_t *m, * check if the matrix is invertible here because we just checked * whether the determinant is not zero. */ - graphene_matrix_inverse (&perspective, &tmp); - graphene_matrix_transpose_transform_vec4 (&tmp, perspective_r, perspective_r); - - /* Clear the perspective component */ - local.value.x = graphene_simd4f_merge_w (local.value.x, 0.f); - local.value.y = graphene_simd4f_merge_w (local.value.y, 0.f); - local.value.z = graphene_simd4f_merge_w (local.value.z, 0.f); - local.value.w = graphene_simd4f_merge_w (local.value.w, 1.f); + graphene_matrix_inverse (&local, &tmp); + graphene_matrix_transform_vec4 (&tmp, perspective_r, perspective_r); } else graphene_vec4_init (perspective_r, 0.f, 0.f, 0.f, 1.f); diff --git a/src/tests/matrix.c b/src/tests/matrix.c index e2ac8838..7140b767 100644 --- a/src/tests/matrix.c +++ b/src/tests/matrix.c @@ -455,6 +455,28 @@ GRAPHENE_TEST_UNIT_BEGIN (matrix_interpolate) } GRAPHENE_TEST_UNIT_END +GRAPHENE_TEST_UNIT_BEGIN (matrix_interpolate_perspective) +{ + graphene_matrix_t m1, m2, m3, mr; + + graphene_matrix_init_identity (&m1); + graphene_matrix_perspective (&m1, 200, &m1); + graphene_matrix_init_identity (&m2); + graphene_matrix_perspective (&m2, 800, &m2); + + graphene_matrix_interpolate (&m1, &m2, 0.0, &mr); + graphene_assert_fuzzy_matrix_equal (&mr, &m1, 0.1); + + graphene_matrix_interpolate (&m1, &m2, 1.0, &mr); + graphene_assert_fuzzy_matrix_equal (&mr, &m2, 0.1); + + graphene_matrix_init_identity (&m3); + graphene_matrix_perspective (&m3, 400, &m3); + graphene_matrix_interpolate (&m1, &m2, 0.5, &mr); + graphene_assert_fuzzy_matrix_equal (&mr, &m3, 0.1); +} +GRAPHENE_TEST_UNIT_END + GRAPHENE_TEST_UNIT_BEGIN (matrix_multiply_self) { graphene_matrix_t a, b, res, test; @@ -584,6 +606,7 @@ GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/matrix/look_at", matrix_look_at) GRAPHENE_TEST_UNIT ("/matrix/invert", matrix_invert) GRAPHENE_TEST_UNIT ("/matrix/interpolate", matrix_interpolate) + GRAPHENE_TEST_UNIT ("/matrix/interpolate-perspective", matrix_interpolate_perspective) GRAPHENE_TEST_UNIT ("/matrix/multiply_self", matrix_multiply_self) GRAPHENE_TEST_UNIT ("/matrix/to-2d", matrix_to_2d) GRAPHENE_TEST_UNIT ("/matrix/2d/identity", matrix_2d_identity)