diff --git a/Source/Engine/Core/Math/Quaternion.cpp b/Source/Engine/Core/Math/Quaternion.cpp
index ab92426d7..46240d4b8 100644
--- a/Source/Engine/Core/Math/Quaternion.cpp
+++ b/Source/Engine/Core/Math/Quaternion.cpp
@@ -7,6 +7,7 @@
#include "Matrix3x3.h"
#include "Math.h"
#include "../Types/String.h"
+#include "Engine/Core/Math/Transform.h"
Quaternion Quaternion::Zero(0, 0, 0, 0);
Quaternion Quaternion::One(1, 1, 1, 1);
@@ -537,3 +538,14 @@ void Quaternion::RotationYawPitchRoll(float yaw, float pitch, float roll, Quater
result.Y = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2;
result.Z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2;
}
+
+Quaternion Quaternion::GetRotationFromNormal(const Vector3& normal, const Transform& reference)
+{
+ Float3 up = reference.GetUp();
+ const float dot = Vector3::Dot(normal, up);
+ if (Math::NearEqual(Math::Abs(dot), 1))
+ {
+ up = reference.GetRight();
+ }
+ return Quaternion::LookRotation(normal, up);
+}
diff --git a/Source/Engine/Core/Math/Quaternion.cs b/Source/Engine/Core/Math/Quaternion.cs
index e50795221..b6b9518c3 100644
--- a/Source/Engine/Core/Math/Quaternion.cs
+++ b/Source/Engine/Core/Math/Quaternion.cs
@@ -1483,6 +1483,45 @@ namespace FlaxEngine
return results;
}
+ ///
+ /// Gets rotation from a normal in relation to a transform.
+ /// This function is especially useful for axis aligned faces,
+ /// and with .
+ ///
+ /// Example code:
+ ///
+ /// GetRotationFromNormalExample :
+ /// RayOrigin;
+ /// SomeObject;
+ ///
+ /// {
+ /// (.RayCast(RayOrigin.Position, RayOrigin.Transform.Forward, out hit)
+ /// {
+ /// position = hit.Collider.Position;
+ /// transform = hit.Collider.Transform;
+ /// point = hit.Point;
+ /// normal = hit.Normal;
+ /// rot = .GetRotationFromNormal(normal,transform);
+ /// SomeObject.Position = point;
+ /// SomeObject.Orientation = rot;
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ /// The normal vector.
+ /// The reference transform.
+ /// The rotation from the normal vector.
+ public static Quaternion GetRotationFromNormal(Vector3 normal, Transform reference)
+ {
+ Float3 up = reference.Up;
+ var dot = Vector3.Dot(normal, up);
+ if (Mathf.NearEqual(Math.Abs(dot), 1))
+ up = reference.Right;
+ return LookRotation(normal, up);
+ }
+
///
/// Adds two quaternions.
///
diff --git a/Source/Engine/Core/Math/Quaternion.h b/Source/Engine/Core/Math/Quaternion.h
index 45605a674..b2b57886f 100644
--- a/Source/Engine/Core/Math/Quaternion.h
+++ b/Source/Engine/Core/Math/Quaternion.h
@@ -660,6 +660,14 @@ public:
// @param roll The roll of rotation (in radians)
// @param result When the method completes, contains the newly created quaternion
static void RotationYawPitchRoll(float yaw, float pitch, float roll, Quaternion& result);
+
+ ///
+ /// Gets rotation from a normal in relation to a transform. This function is especially useful for axis aligned faces, and with .
+ ///
+ /// The normal vector.
+ /// The reference transform.
+ /// The rotation from the normal vector.
+ static Quaternion GetRotationFromNormal(const Vector3& normal, const Transform& reference);
};
///
diff --git a/Source/Engine/Core/Math/Transform.cpp b/Source/Engine/Core/Math/Transform.cpp
index 6195dad04..0106be2f9 100644
--- a/Source/Engine/Core/Math/Transform.cpp
+++ b/Source/Engine/Core/Math/Transform.cpp
@@ -252,3 +252,9 @@ void Transform::Lerp(const Transform& t1, const Transform& t2, float amount, Tra
Quaternion::Slerp(t1.Orientation, t2.Orientation, amount, result.Orientation);
Float3::Lerp(t1.Scale, t2.Scale, amount, result.Scale);
}
+
+Transform Transform::AlignRotationToNormalAndSnapToGrid(const Vector3& point, const Vector3& normal, const Vector3& normalOffset, const Transform& relativeTo, const Vector3& gridSize, const Float3& scale)
+{
+ Quaternion rot = Quaternion::GetRotationFromNormal(normal, relativeTo);
+ return Transform(Vector3::SnapToGrid(point, gridSize, rot, relativeTo.Translation, normalOffset), rot, scale);
+}
diff --git a/Source/Engine/Core/Math/Transform.cs b/Source/Engine/Core/Math/Transform.cs
index e00265f6d..7387bab83 100644
--- a/Source/Engine/Core/Math/Transform.cs
+++ b/Source/Engine/Core/Math/Transform.cs
@@ -478,6 +478,96 @@ namespace FlaxEngine
Float3.Lerp(ref start.Scale, ref end.Scale, amount, out result.Scale);
}
+ ///
+ /// Combines the functions:
+ /// ,
+ /// .
+ /// Example code:
+ ///
+ /// AlignRotationToObjectAndSnapToGridExample :
+ /// Offset = new Vector3(0, 0, 50f);
+ /// GridSize = * 20.0f;
+ /// RayOrigin;
+ /// SomeObject;
+ ///
+ /// {
+ /// (.RayCast(RayOrigin.Position, RayOrigin.Transform.Forward, out hit)
+ /// {
+ /// transform = hit.Collider.Transform;
+ /// point = hit.Point;
+ /// normal = hit.Normal;
+ /// SomeObject.Transform = .AlignRotationToNormalAndSnapToGrid
+ /// (
+ /// point,
+ /// normal,
+ /// Offset,
+ /// transform,
+ /// SomeObject.Scale,
+ /// GridSize,
+ /// Float3.One
+ /// );
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ /// The position to snap.
+ /// The size of the grid.
+ /// The local grid offset to apply after snapping.
+ /// The normal vector.
+ /// The relative transform.
+ /// The scale to apply to the transform.
+ /// The rotated and snapped transform.
+ public static Transform AlignRotationToNormalAndSnapToGrid(Vector3 point, Vector3 normal, Vector3 normalOffset, Transform relativeTo, Vector3 gridSize, Float3 scale)
+ {
+ Quaternion rot = Quaternion.GetRotationFromNormal(normal, relativeTo);
+ return new Transform(Vector3.SnapToGrid(point, gridSize, rot, relativeTo.Translation, normalOffset), rot, scale);
+ }
+
+ ///
+ /// Combines the functions:
+ /// ,
+ /// .
+ /// Example code:
+ ///
+ /// AlignRotationToObjectAndSnapToGridExample :
+ /// Offset = new Vector3(0, 0, 50f);
+ /// GridSize = * 20.0f;
+ /// RayOrigin;
+ /// SomeObject;
+ ///
+ /// {
+ /// (.RayCast(RayOrigin.Position, RayOrigin.Transform.Forward, out hit)
+ /// {
+ /// transform = hit.Collider.Transform;
+ /// point = hit.Point;
+ /// normal = hit.Normal;
+ /// SomeObject.Transform = .AlignRotationToNormalAndSnapToGrid
+ /// (
+ /// point,
+ /// normal,
+ /// Offset,
+ /// transform,
+ /// GridSize
+ /// );
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ /// The position to snap.
+ /// The size of the grid.
+ /// The local grid offset to apply after snapping.
+ /// The normal vector.
+ /// The relative transform.
+ /// The rotated and snapped transform with scale .
+ public static Transform AlignRotationToNormalAndSnapToGrid(Vector3 point, Vector3 normal, Vector3 normalOffset, Transform relativeTo, Vector3 gridSize)
+ {
+ return AlignRotationToNormalAndSnapToGrid(point, normal, normalOffset, relativeTo, gridSize, Float3.One);
+ }
+
///
/// Tests for equality between two objects.
///
diff --git a/Source/Engine/Core/Math/Transform.h b/Source/Engine/Core/Math/Transform.h
index 2c51bfa4a..8e9e07e0a 100644
--- a/Source/Engine/Core/Math/Transform.h
+++ b/Source/Engine/Core/Math/Transform.h
@@ -291,6 +291,20 @@ public:
return result;
}
+ ///
+ /// Combines the functions:
+ /// ,
+ /// .
+ ///
+ /// The position to snap.
+ /// The size of the grid.
+ /// The local grid offset to apply after snapping.
+ /// The normal vector.
+ /// The relative transform.
+ /// The scale to apply to the transform.
+ /// The rotated and snapped transform.
+ static Transform AlignRotationToNormalAndSnapToGrid(const Vector3& point, const Vector3& normal, const Vector3& normalOffset, const Transform& relativeTo, const Vector3& gridSize, const Float3& scale = Float3::One);
+
public:
FORCE_INLINE Transform operator*(const Transform& other) const
{
diff --git a/Source/Engine/Core/Math/Vector3.cpp b/Source/Engine/Core/Math/Vector3.cpp
index 3ffb2cdc9..5a26f2309 100644
--- a/Source/Engine/Core/Math/Vector3.cpp
+++ b/Source/Engine/Core/Math/Vector3.cpp
@@ -324,6 +324,20 @@ float Float3::Angle(const Float3& from, const Float3& to)
return Math::Acos(dot);
}
+template<>
+Float3 Float3::SnapToGrid(const Float3& pos, const Float3& gridSize)
+{
+ return Float3(Math::Ceil((pos.X - (gridSize.X * 0.5f)) / gridSize.X) * gridSize.X,
+ Math::Ceil((pos.Y - (gridSize.Y * 0.5f)) / gridSize.Y) * gridSize.Y,
+ Math::Ceil((pos.Z - (gridSize.Z * 0.5f)) / gridSize.Z) * gridSize.Z);
+}
+
+template<>
+Float3 Float3::SnapToGrid(const Float3& point, const Float3& gridSize, const Quaternion& gridOrientation, const Float3& gridOrigin, const Float3& offset)
+{
+ return (gridOrientation * (gridOrientation.Conjugated() * SnapToGrid(point - gridOrigin, gridSize) + offset)) + gridOrigin;
+}
+
// Double
static_assert(sizeof(Double3) == 24, "Invalid Double3 type size.");
@@ -638,6 +652,20 @@ double Double3::Angle(const Double3& from, const Double3& to)
return Math::Acos(dot);
}
+template<>
+Double3 Double3::SnapToGrid(const Double3& pos, const Double3& gridSize)
+{
+ return Double3(Math::Ceil((pos.X - (gridSize.X * 0.5)) / gridSize.X) * gridSize.X,
+ Math::Ceil((pos.Y - (gridSize.Y * 0.5)) / gridSize.Y) * gridSize.Y,
+ Math::Ceil((pos.Z - (gridSize.Z * 0.5)) / gridSize.Z) * gridSize.Z);
+}
+
+template<>
+Double3 Double3::SnapToGrid(const Double3& point, const Double3& gridSize, const Quaternion& gridOrientation, const Double3& gridOrigin, const Double3& offset)
+{
+ return (gridOrientation * (gridOrientation.Conjugated() * SnapToGrid(point - gridOrigin, gridSize) + offset)) + gridOrigin;
+}
+
// Int
static_assert(sizeof(Int3) == 12, "Invalid Int3 type size.");
@@ -852,3 +880,17 @@ int32 Int3::Angle(const Int3& from, const Int3& to)
{
return 0;
}
+
+template<>
+Int3 Int3::SnapToGrid(const Int3& pos, const Int3& gridSize)
+{
+ return Int3(((pos.X - (gridSize.X / 2)) / gridSize.X) * gridSize.X,
+ ((pos.Y - (gridSize.Y / 2)) / gridSize.Y) * gridSize.Y,
+ ((pos.Z - (gridSize.Z / 2)) / gridSize.Z) * gridSize.Z);
+}
+
+template<>
+Int3 Int3::SnapToGrid(const Int3& point, const Int3& gridSize, const Quaternion& gridOrientation, const Int3& gridOrigin, const Int3& offset)
+{
+ return (gridOrientation * (gridOrientation.Conjugated() * SnapToGrid(point - gridOrigin, gridSize) + offset)) + gridOrigin;
+}
diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs
index 738a9bad8..5505c5053 100644
--- a/Source/Engine/Core/Math/Vector3.cs
+++ b/Source/Engine/Core/Math/Vector3.cs
@@ -1672,7 +1672,7 @@ namespace FlaxEngine
}
///
- /// Snaps the input position into the grid.
+ /// Snaps the input position onto the grid.
///
/// The position to snap.
/// The size of the grid.
@@ -1685,6 +1685,44 @@ namespace FlaxEngine
return pos;
}
+ ///
+ /// Snaps the onto the rotated grid.
+ /// For world aligned grid snapping use instead.
+ /// Example code:
+ ///
+ /// SnapToGridExample :
+ /// GridSize = * 20.0f;
+ /// RayOrigin;
+ /// SomeObject;
+ ///
+ /// {
+ /// (.RayCast(RayOrigin.Position, RayOrigin.Transform.Forward, out hit)
+ /// {
+ /// position = hit.Collider.Position;
+ /// transform = hit.Collider.Transform;
+ /// point = hit.Point;
+ /// normal = hit.Normal;
+ /// //Get rotation from normal relative to collider transform
+ /// rot = .GetRotationFromNormal(normal, transform);
+ /// point = .SnapToGrid(point, GridSize, rot, position);
+ /// SomeObject.Position = point;
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ /// The position to snap.
+ /// The size of the grid.
+ /// The rotation of the grid.
+ /// The center point of the grid.
+ /// The local position offset applied to the snapped position before grid rotation.
+ /// The position snapped to the grid.
+ public static Vector3 SnapToGrid(Vector3 point, Vector3 gridSize, Quaternion gridOrientation, Vector3 gridOrigin, Vector3 offset)
+ {
+ return ((SnapToGrid(point - gridOrigin, gridSize) * gridOrientation.Conjugated() + offset) * gridOrientation) + gridOrigin;
+ }
+
///
/// Adds two vectors.
///
diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h
index 619fcfc12..2e5d3d478 100644
--- a/Source/Engine/Core/Math/Vector3.h
+++ b/Source/Engine/Core/Math/Vector3.h
@@ -927,6 +927,25 @@ public:
/// The second vector.
/// The angle (in radians).
static FLAXENGINE_API T Angle(const Vector3Base& from, const Vector3Base& to);
+
+ ///
+ /// Snaps the input position onto the grid.
+ ///
+ /// The position to snap.
+ /// The size of the grid.
+ /// The position snapped to the grid.
+ static FLAXENGINE_API Vector3Base SnapToGrid(const Vector3Base& pos, const Vector3Base& gridSize);
+
+ ///
+ /// Snaps the onto the rotated grid. For world aligned grid snapping use instead.
+ ///
+ /// The position to snap.
+ /// The size of the grid.
+ /// The center point of the grid.
+ /// The rotation of the grid.
+ /// The local position offset applied to the snapped position before grid rotation.
+ /// The position snapped to the grid.
+ static FLAXENGINE_API Vector3Base SnapToGrid(const Vector3Base& point, const Vector3Base& gridSize, const Quaternion& gridOrientation, const Vector3Base& gridOrigin = Zero, const Vector3Base& offset = Zero);
};
template