diff --git a/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Matrix.kt b/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Matrix.kt index ad6ab85..9aa5d4a 100644 --- a/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Matrix.kt +++ b/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Matrix.kt @@ -16,8 +16,6 @@ package com.curiouscreature.kotlin.math -import kotlin.math.asin -import kotlin.math.atan2 import kotlin.math.cos import kotlin.math.sin import kotlin.math.tan @@ -320,16 +318,8 @@ data class Mat4( get() = w.xyz val rotation: Float3 get() { - val x = normalize(right) - val y = normalize(up) - val z = normalize(forward) - - return when { - z.y <= -1.0f -> Float3(degrees(-HALF_PI), 0.0f, degrees(atan2(x.z, y.z))) - z.y >= 1.0f -> Float3(degrees(HALF_PI), 0.0f, degrees(atan2(-x.z, -y.z))) - else -> Float3( - degrees(-asin(z.y)), degrees(-atan2(z.x, z.z)), degrees(atan2(x.y, y.y))) - } + val toEulerAngles = Quaternion.from(this).toEulerAngles() + return Float3(degrees(toEulerAngles.x), degrees(toEulerAngles.y), degrees(toEulerAngles.z)) } inline val upperLeft: Mat3 diff --git a/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Quaternion.kt b/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Quaternion.kt index f5ad38b..81a9a4e 100644 --- a/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Quaternion.kt +++ b/src/commonMain/kotlin/com/curiouscreature/kotlin/math/Quaternion.kt @@ -14,8 +14,12 @@ data class Quaternion(val x: Float, val y: Float, val z: Float, val w: Float) { return floatArrayOf(x, y, z, w) } - // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Source_Code_2 + /** + * Transform a quaternion in Euler angles. + * Angles are in degrees. + */ fun toEulerAngles(): Float3 { + // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Source_Code_2 // roll (x-axis rotation) val sinrCosp = 2f * (w * x + y * z) val cosrCosp = 1f - 2f * (x * x + y * y) @@ -23,7 +27,7 @@ data class Quaternion(val x: Float, val y: Float, val z: Float, val w: Float) { // pitch (y-axis rotation) val sinp = 2f * (w * y - z * x) - val pitch = if (abs(sinp) >= 1) + val pitch = if (abs(sinp) >= 1f) PI / 2f * sign(sinp) // use 90 degrees if out of range else asin(sinp) diff --git a/src/commonTest/kotlin/com/curiouscreature/kotlin/math/MatrixTest.kt b/src/commonTest/kotlin/com/curiouscreature/kotlin/math/MatrixTest.kt index 8552b9a..d119747 100644 --- a/src/commonTest/kotlin/com/curiouscreature/kotlin/math/MatrixTest.kt +++ b/src/commonTest/kotlin/com/curiouscreature/kotlin/math/MatrixTest.kt @@ -243,6 +243,24 @@ class MatrixTest { ) } + @Test + fun Mat4_rotation_by_axis_x() { + val x = rotation(Float3(1f, 0f, 0f), 90f).rotation.x + assertEquals(-90f, x, delta = 0.1f) + } + + @Test + fun Mat4_rotation_by_axis_y() { + val y = rotation(Float3(0f, 1f, 0f), 90f).rotation.y + assertEquals(-90f, y, delta = 0.1f) + } + + @Test + fun Mat4_rotation_by_axis_z() { + val z = rotation(Float3(0f, 0f, 1f), 90f).rotation.z + assertEquals(-90f, z, delta = 0.1f) + } + @Test fun normal() { assertArrayEquals(