diff --git a/source/graphics/Decal.cpp b/source/graphics/Decal.cpp index 30e6fc5fb8..93132467ca 100644 --- a/source/graphics/Decal.cpp +++ b/source/graphics/Decal.cpp @@ -98,9 +98,11 @@ void CModelDecal::ValidatePosition() void CModelDecal::SetTransform(const CMatrix3D& transform) { - CMatrix3D newTransform = transform; - newTransform.SetYRotation(m_Decal.m_Angle); - newTransform.Concatenate(transform); + // Since decals are assumed to be horizontal and projected downwards + // onto the terrain, use just the Y-axis rotation and the translation + CMatrix3D newTransform; + newTransform.SetYRotation(transform.GetYRotation() + m_Decal.m_Angle); + newTransform.Translate(transform.GetTranslation()); CRenderableObject::SetTransform(newTransform); InvalidatePosition(); diff --git a/source/maths/Matrix3D.cpp b/source/maths/Matrix3D.cpp index dc4af5dede..eae659c6dd 100644 --- a/source/maths/Matrix3D.cpp +++ b/source/maths/Matrix3D.cpp @@ -503,3 +503,20 @@ void CMatrix3D::SetRotation(const CQuaternion& quat) { quat.ToMatrix(*this); } + +float CMatrix3D::GetYRotation() const +{ + // Project the X axis vector onto the XZ plane + CVector3D axis = -GetLeft(); + axis.Y = 0; + + // Normalise projected vector + + float len = axis.Length(); + if (len < 0.0001f) + return 0.f; + axis *= 1.0f/len; + + // Negate the return angle to match the SetYRotation convention + return -atan2(axis.Z, axis.X); +} diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h index 3d23262c7c..f4bd26bc0d 100644 --- a/source/maths/Matrix3D.h +++ b/source/maths/Matrix3D.h @@ -139,6 +139,9 @@ public: CVector3D GetIn() const; // return a quaternion representing the matrix's rotation CQuaternion GetRotation() const; + // return the angle of rotation around the Y axis in range [-pi,pi] + // (based on projecting the X axis onto the XZ plane) + float GetYRotation() const; // transform a 3D vector by this matrix CVector3D Transform (const CVector3D &vector) const diff --git a/source/maths/tests/test_Matrix3d.h b/source/maths/tests/test_Matrix3d.h index f21fd37cd6..acca381185 100644 --- a/source/maths/tests/test_Matrix3d.h +++ b/source/maths/tests/test_Matrix3d.h @@ -122,6 +122,25 @@ public: TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f); } + void test_getRotation() + { + CMatrix3D m; + srand(0); + + m.SetZero(); + TS_ASSERT_EQUALS(m.GetYRotation(), 0.f); + + m.SetIdentity(); + TS_ASSERT_EQUALS(m.GetYRotation(), 0.f); + + for (int j = 0; j < 16; ++j) + { + float a = 2*M_PI*rand()/(float)RAND_MAX - M_PI; + m.SetYRotation(a); + TS_ASSERT_DELTA(m.GetYRotation(), a, 0.001f); + } + } + void test_scale() { CMatrix3D m;