Sfoglia il codice sorgente

Added IsNaN() to Vector2, Vector3, Vector4, Quaternion. Safeguard against Node::LookAt() misbehaving if target is very close. Closes #231.

Lasse Öörni 11 anni fa
parent
commit
2529f4c51a

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/MathDefs.pkg

@@ -30,6 +30,7 @@ float Sign(float value);
 float Clamp(float value, float min, float max);
 float SmoothStep(float lhs, float rhs, float t);
 bool Equals(float lhs, float rhs);
+bool IsNaN(float value);
 
 float Random();
 float Random(float range);

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/Quaternion.pkg

@@ -39,6 +39,7 @@ class Quaternion
     float LengthSquared() const;
     float DotProduct(const Quaternion& rhs) const;
     bool Equals(const Quaternion& rhs) const;
+    bool IsNaN() const;
     
     Quaternion Conjugate() const;
     Vector3 EulerAngles() const;

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/Vector2.pkg

@@ -25,6 +25,7 @@ class Vector2
     Vector2 Abs() const;
     Vector2 Lerp(const Vector2& rhs, float t) const;
     bool Equals(const Vector2& rhs) const;
+    bool IsNaN() const;
     
     Vector2 Normalized() const;
     

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/Vector3.pkg

@@ -25,6 +25,7 @@ class Vector3
     Vector3 Abs() const;
     Vector3 Lerp(const Vector3& rhs, float t) const;
     bool Equals(const Vector3& rhs) const;
+    bool IsNaN() const;
     float Angle(const Vector3& rhs) const;
     Vector3 Normalized() const;
     

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/Vector4.pkg

@@ -23,6 +23,7 @@ class Vector4
     Vector4 Abs() const;
     Vector4 Lerp(const Vector4& rhs, float t) const;
     bool Equals(const Vector4& rhs) const;
+    bool IsNaN() const;
 
     String ToString() const;
     

+ 2 - 0
Source/Engine/Math/MathDefs.h

@@ -58,6 +58,8 @@ enum Intersection
 
 /// Check whether two floating point values are equal within accuracy.
 inline bool Equals(float lhs, float rhs) { return lhs + M_EPSILON >= rhs && lhs - M_EPSILON <= rhs; }
+/// Check whether a floating point value is NaN.
+inline bool IsNaN(float value) { return value != value; }
 /// Linear interpolation between two float values.
 inline float Lerp(float lhs, float rhs, float t) { return lhs * (1.0f - t) + rhs * t; }
 /// Return the smaller of two floats.

+ 3 - 1
Source/Engine/Math/Quaternion.h

@@ -171,7 +171,7 @@ public:
     void FromAxes(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis);
     /// Define from a rotation matrix.
     void FromRotationMatrix(const Matrix3& matrix);
-    /// Define from a direction to look in and an up direction
+    /// Define from a direction to look in and an up direction.
     void FromLookRotation(const Vector3& direction, const Vector3&up = Vector3::UP);
 
     /// Normalize to unit length.
@@ -219,6 +219,8 @@ public:
     float DotProduct(const Quaternion& rhs) const { return w_ * rhs.w_ + x_ * rhs.x_ + y_ * rhs.y_ + z_ * rhs.z_; }
     /// Test for equality with another quaternion with epsilon.
     bool Equals(const Quaternion& rhs) const { return Urho3D::Equals(w_, rhs.w_) && Urho3D::Equals(x_, rhs.x_) && Urho3D::Equals(y_, rhs.y_) && Urho3D::Equals(z_, rhs.z_); }
+    /// Return whether is NaN.
+    bool IsNaN() const { return Urho3D::IsNaN(w_) || Urho3D::IsNaN(x_) || Urho3D::IsNaN(y_) || Urho3D::IsNaN(z_); }
     /// Return conjugate.
     Quaternion Conjugate() const { return Quaternion(w_, -x_, -y_, -z_); }
     

+ 2 - 0
Source/Engine/Math/Vector2.h

@@ -160,6 +160,8 @@ public:
     Vector2 Lerp(const Vector2& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     /// Test for equality with another vector with epsilon.
     bool Equals(const Vector2& rhs) const { return Urho3D::Equals(x_, rhs.x_) && Urho3D::Equals(y_, rhs.y_); }
+    /// Return whether is NaN.
+    bool IsNaN() const { return Urho3D::IsNaN(x_) || Urho3D::IsNaN(y_); }
     
     /// Return normalized to unit length.
     Vector2 Normalized() const

+ 3 - 1
Source/Engine/Math/Vector3.h

@@ -191,7 +191,9 @@ public:
     bool Equals(const Vector3& rhs) const { return Urho3D::Equals(x_, rhs.x_) && Urho3D::Equals(y_, rhs.y_) && Urho3D::Equals(z_, rhs.z_); }
     /// Returns the angle between this vector and another vector in degrees.
     float Angle(const Vector3& rhs) const { return Urho3D::Acos(DotProduct(rhs) / (Length() * rhs.Length() ) ); }
-
+    /// Return whether is NaN.
+    bool IsNaN() const { return Urho3D::IsNaN(x_) || Urho3D::IsNaN(y_) || Urho3D::IsNaN(z_); }
+    
     /// Return normalized to unit length.
     Vector3 Normalized() const
     {

+ 2 - 0
Source/Engine/Math/Vector4.h

@@ -172,6 +172,8 @@ public:
     Vector4 Lerp(const Vector4& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     /// Test for equality with another vector with epsilon.
     bool Equals(const Vector4& rhs) const { return Urho3D::Equals(x_, rhs.x_) && Urho3D::Equals(y_, rhs.y_) && Urho3D::Equals(z_, rhs.z_) && Urho3D::Equals(w_, rhs.w_); }
+    /// Return whether is NaN.
+    bool IsNaN() const { return Urho3D::IsNaN(x_) || Urho3D::IsNaN(y_) || Urho3D::IsNaN(z_) || Urho3D::IsNaN(w_); }
     
     /// Return float data.
     const float* Data() const { return &x_; }

+ 8 - 1
Source/Engine/Scene/Node.cpp

@@ -400,9 +400,16 @@ void Node::Roll(float angle, bool fixedAxis)
 
 void Node::LookAt(const Vector3& target, const Vector3& upAxis)
 {
-    Vector3 lookDir = (target - GetWorldPosition()).Normalized();
+    Vector3 lookDir = (target - GetWorldPosition());
+    // Check if target is very close, in that case can not reliably calculate lookat direction
+    if (lookDir.Equals(Vector3::ZERO))
+        return;
     Quaternion rotation;
     rotation.FromLookRotation(lookDir, upAxis);
+    // Return doing nothing if rotation became invalid
+    if (rotation.IsNaN())
+        return;
+    
     SetRotation((parent_ == scene_ || !parent_) ? rotation : parent_->GetWorldRotation().Inverse() * rotation);
 }
 

+ 5 - 0
Source/Engine/Script/MathAPI.cpp

@@ -54,6 +54,7 @@ static void RegisterMathFunctions(asIScriptEngine* engine)
     engine->RegisterGlobalProperty("const uint M_MAX_UNSIGNED", (void*)&M_MAX_UNSIGNED);
     
     engine->RegisterGlobalFunction("bool Equals(float, float)", asFUNCTION(Equals), asCALL_CDECL);
+    engine->RegisterGlobalFunction("bool IsNaN(float)", asFUNCTION(IsNaN), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Sin(float)", asFUNCTION(Sin), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Cos(float)", asFUNCTION(Cos), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Tan(float)", asFUNCTION(Tan), asCALL_CDECL);
@@ -237,6 +238,7 @@ static void RegisterVector2(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Vector2", "float AbsDotProduct(const Vector2&in) const", asMETHOD(Vector2, AbsDotProduct), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 Lerp(const Vector2&in, float) const", asMETHOD(Vector2, Lerp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "bool Equals(const Vector2&in) const", asMETHOD(Vector2, Equals), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Vector2", "bool IsNaN() const", asMETHOD(Vector2, IsNaN), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 Normalized() const", asMETHOD(Vector2, Normalized), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "String ToString() const", asMETHOD(Vector2, ToString), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "float get_length() const", asMETHOD(Vector2, Length), asCALL_THISCALL);
@@ -300,6 +302,7 @@ static void RegisterVector3(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Vector3", "Vector3 CrossProduct(const Vector3&in) const", asMETHOD(Vector3, CrossProduct), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 Lerp(const Vector3&in, float) const", asMETHOD(Vector3, Lerp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "bool Equals(const Vector3&in) const", asMETHOD(Vector3, Equals), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Vector3", "bool IsNaN() const", asMETHOD(Vector3, IsNaN), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "float Angle(const Vector3&in) const", asMETHOD(Vector3, Angle), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 Normalized() const", asMETHOD(Vector3, Normalized), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "String ToString() const", asMETHOD(Vector3, ToString), asCALL_THISCALL);
@@ -369,6 +372,7 @@ static void RegisterVector4(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Vector4", "float AbsDotProduct(const Vector4&in) const", asMETHOD(Vector4, AbsDotProduct), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector4", "Vector4 Lerp(const Vector4&in, float) const", asMETHOD(Vector4, Lerp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector4", "bool Equals(const Vector4&in) const", asMETHOD(Vector4, Equals), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Vector4", "bool IsNaN() const", asMETHOD(Vector4, IsNaN), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector4", "String ToString() const", asMETHOD(Vector4, ToString), asCALL_THISCALL);
     engine->RegisterObjectProperty("Vector4", "float x", offsetof(Vector4, x_));
     engine->RegisterObjectProperty("Vector4", "float y", offsetof(Vector4, y_));
@@ -448,6 +452,7 @@ static void RegisterQuaternion(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Quaternion", "Quaternion Slerp(Quaternion, float) const", asMETHOD(Quaternion, Slerp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Quaternion", "Quaternion Nlerp(Quaternion, float, bool) const", asMETHOD(Quaternion, Nlerp), asCALL_THISCALL);
     engine->RegisterObjectMethod("Quaternion", "bool Equals(const Quaternion&in) const", asMETHOD(Quaternion, Equals), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Quaternion", "bool IsNaN() const", asMETHOD(Quaternion, IsNaN), asCALL_THISCALL);
     engine->RegisterObjectMethod("Quaternion", "String ToString() const", asMETHOD(Quaternion, ToString), asCALL_THISCALL);
     engine->RegisterObjectMethod("Quaternion", "Vector3 get_eulerAngles() const", asMETHOD(Quaternion, EulerAngles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Quaternion", "float get_yaw() const", asMETHOD(Quaternion, YawAngle), asCALL_THISCALL);