diff --git a/Source/Editor/SceneGraph/Actors/SpriteRenderNode.cs b/Source/Editor/SceneGraph/Actors/SpriteRenderNode.cs index d0566b9a3..2c07c53be 100644 --- a/Source/Editor/SceneGraph/Actors/SpriteRenderNode.cs +++ b/Source/Editor/SceneGraph/Actors/SpriteRenderNode.cs @@ -50,7 +50,7 @@ namespace FlaxEditor.SceneGraph.Actors OrientedBoundingBox bounds; bounds.Extents = Vector3.Half; - bounds.Transformation = world; + world.Decompose(out bounds.Transformation); normal = -ray.Ray.Direction; return bounds.Intersects(ref ray.Ray, out distance); diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index 0f77d5c5f..0dbbf721b 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -774,9 +774,10 @@ namespace FlaxEditor.Utilities else orientation = Quaternion.LookRotation(dir, Vector3.Cross(Vector3.Cross(dir, Vector3.Up), dir)); Vector3 up = Vector3.Up * orientation; - box.Transformation = Matrix.CreateWorld(min + vec * 0.5f, dir, up); - Matrix.Invert(ref box.Transformation, out Matrix inv); - Vector3 vecLocal = Vector3.TransformNormal(vec * 0.5f, inv); + Matrix world = Matrix.CreateWorld(min + vec * 0.5f, dir, up); + world.Decompose(out box.Transformation); + Matrix.Invert(ref world, out Matrix invWorld); + Vector3 vecLocal = Vector3.TransformNormal(vec * 0.5f, invWorld); box.Extents.X = margin; box.Extents.Y = margin; box.Extents.Z = vecLocal.Z; diff --git a/Source/Engine/Core/Math/OrientedBoundingBox.cpp b/Source/Engine/Core/Math/OrientedBoundingBox.cpp index 819fa1268..803cdf73a 100644 --- a/Source/Engine/Core/Math/OrientedBoundingBox.cpp +++ b/Source/Engine/Core/Math/OrientedBoundingBox.cpp @@ -3,6 +3,7 @@ #include "OrientedBoundingBox.h" #include "BoundingSphere.h" #include "BoundingBox.h" +#include "Matrix.h" #include "Ray.h" #include "../Types/String.h" @@ -10,32 +11,41 @@ OrientedBoundingBox::OrientedBoundingBox(const BoundingBox& bb) { const Vector3 center = bb.Minimum + (bb.Maximum - bb.Minimum) * 0.5f; Extents = bb.Maximum - center; - Matrix::Translation(center, Transformation); + Transformation = ::Transform(center); +} + +OrientedBoundingBox::OrientedBoundingBox(const Vector3& extents, const Matrix& transformation) + : Extents(extents) +{ + transformation.Decompose(Transformation); } OrientedBoundingBox::OrientedBoundingBox(const Vector3& extents, const Matrix3x3& rotationScale, const Vector3& translation) : Extents(extents) - , Transformation(rotationScale) + , Transformation(translation, rotationScale) { - Transformation.SetTranslation(translation); +} + +OrientedBoundingBox::OrientedBoundingBox(const Vector3& minimum, const Vector3& maximum) +{ + const Vector3 center = minimum + (maximum - minimum) * 0.5f; + Extents = maximum - center; + Transformation = ::Transform(center); } OrientedBoundingBox::OrientedBoundingBox(Vector3 points[], int32 pointCount) { ASSERT(points && pointCount > 0); - Vector3 minimum = points[0]; Vector3 maximum = points[0]; - for (int32 i = 1; i < pointCount; i++) { Vector3::Min(minimum, points[i], minimum); Vector3::Max(maximum, points[i], maximum); } - - const Vector3 center = minimum + (maximum - minimum) / 2.0f; + const Vector3 center = minimum + (maximum - minimum) * 0.5f; Extents = maximum - center; - Matrix::Translation(center, Transformation); + Transformation = ::Transform(center); } String OrientedBoundingBox::ToString() const @@ -45,15 +55,11 @@ String OrientedBoundingBox::ToString() const void OrientedBoundingBox::GetCorners(Float3 corners[8]) const { - Float3 xv((float)Extents.X, 0, 0); - Float3 yv(0, (float)Extents.Y, 0); - Float3 zv(0, 0, (float)Extents.Z); + const Float3 xv = Transformation.LocalToWorldVector(Vector3((float)Extents.X, 0, 0)); + const Float3 yv = Transformation.LocalToWorldVector(Vector3(0, (float)Extents.Y, 0)); + const Float3 zv = Transformation.LocalToWorldVector(Vector3(0, 0, (float)Extents.Z)); - Float3::TransformNormal(xv, Transformation, xv); - Float3::TransformNormal(yv, Transformation, yv); - Float3::TransformNormal(zv, Transformation, zv); - - const Float3 center = Transformation.GetTranslation(); + const Float3 center = Transformation.Translation; corners[0] = center + xv + yv + zv; corners[1] = center + xv + yv - zv; @@ -67,15 +73,11 @@ void OrientedBoundingBox::GetCorners(Float3 corners[8]) const void OrientedBoundingBox::GetCorners(Double3 corners[8]) const { - Double3 xv(Extents.X, 0, 0); - Double3 yv(0, Extents.Y, 0); - Double3 zv(0, 0, Extents.Z); + const Double3 xv = Transformation.LocalToWorldVector(Vector3((float)Extents.X, 0, 0)); + const Double3 yv = Transformation.LocalToWorldVector(Vector3(0, (float)Extents.Y, 0)); + const Double3 zv = Transformation.LocalToWorldVector(Vector3(0, 0, (float)Extents.Z)); - Double3::TransformNormal(xv, Transformation, xv); - Double3::TransformNormal(yv, Transformation, yv); - Double3::TransformNormal(zv, Transformation, zv); - - const Double3 center = Transformation.GetTranslation(); + const Double3 center = Transformation.Translation; corners[0] = center + xv + yv + zv; corners[1] = center + xv + yv - zv; @@ -89,39 +91,26 @@ void OrientedBoundingBox::GetCorners(Double3 corners[8]) const Vector3 OrientedBoundingBox::GetSize() const { - Vector3 xv = Vector3(Extents.X * 2, 0, 0); - Vector3 yv = Vector3(0, Extents.Y * 2, 0); - Vector3 zv = Vector3(0, 0, Extents.Z * 2); - - Vector3::TransformNormal(xv, Transformation, xv); - Vector3::TransformNormal(yv, Transformation, yv); - Vector3::TransformNormal(zv, Transformation, zv); - + const Vector3 xv = Transformation.LocalToWorldVector(Vector3(Extents.X * 2, 0, 0)); + const Vector3 yv = Transformation.LocalToWorldVector(Vector3(0, Extents.Y * 2, 0)); + const Vector3 zv = Transformation.LocalToWorldVector(Vector3(0, 0, Extents.Z * 2)); return Vector3(xv.Length(), yv.Length(), zv.Length()); } Vector3 OrientedBoundingBox::GetSizeSquared() const { - Vector3 xv = Vector3(Extents.X * 2, 0, 0); - Vector3 yv = Vector3(0, Extents.Y * 2, 0); - Vector3 zv = Vector3(0, 0, Extents.Z * 2); - - Vector3::TransformNormal(xv, Transformation, xv); - Vector3::TransformNormal(yv, Transformation, yv); - Vector3::TransformNormal(zv, Transformation, zv); - + const Vector3 xv = Transformation.LocalToWorldVector(Vector3(Extents.X * 2, 0, 0)); + const Vector3 yv = Transformation.LocalToWorldVector(Vector3(0, Extents.Y * 2, 0)); + const Vector3 zv = Transformation.LocalToWorldVector(Vector3(0, 0, Extents.Z * 2)); return Vector3(xv.LengthSquared(), yv.LengthSquared(), zv.LengthSquared()); } BoundingBox OrientedBoundingBox::GetBoundingBox() const { BoundingBox result; - Vector3 corners[8]; GetCorners(corners); - BoundingBox::FromPoints(corners, 8, result); - return result; } @@ -135,19 +124,21 @@ void OrientedBoundingBox::GetBoundingBox(BoundingBox& result) const void OrientedBoundingBox::Transform(const Matrix& matrix) { - const Matrix tmp = Transformation; - Matrix::Multiply(tmp, matrix, Transformation); + ::Transform transform; + matrix.Decompose(transform); + Transformation = transform.LocalToWorld(Transformation); +} + +void OrientedBoundingBox::Transform(const ::Transform& transform) +{ + Transformation = transform.LocalToWorld(Transformation); } ContainmentType OrientedBoundingBox::Contains(const Vector3& point, Real* distance) const { // Transform the point into the obb coordinates - Matrix invTrans; - Matrix::Invert(Transformation, invTrans); - Vector3 locPoint; - Vector3::TransformCoordinate(point, invTrans, locPoint); - + Transformation.WorldToLocal(point, locPoint); locPoint.X = Math::Abs(locPoint.X); locPoint.Y = Math::Abs(locPoint.Y); locPoint.Z = Math::Abs(locPoint.Z); @@ -161,7 +152,7 @@ ContainmentType OrientedBoundingBox::Contains(const Vector3& point, Real* distan // Transform distance to world space Vector3 dstVec = Vector3::UnitX * minDstToEdgeLocal; - Vector3::TransformNormal(dstVec, Transformation, dstVec); + Transformation.LocalToWorldVector(dstVec, dstVec); *distance = dstVec.Length(); } @@ -173,49 +164,11 @@ ContainmentType OrientedBoundingBox::Contains(const Vector3& point, Real* distan return ContainmentType::Disjoint; } -ContainmentType OrientedBoundingBox::Contains(int32 pointsCnt, Vector3 points[]) const -{ - ASSERT(pointsCnt > 0); - - Matrix invTrans; - Matrix::Invert(Transformation, invTrans); - - bool containsAll = true; - bool containsAny = false; - - for (int32 i = 0; i < pointsCnt; i++) - { - Vector3 locPoint; - Vector3::TransformCoordinate(points[i], invTrans, locPoint); - - locPoint.X = Math::Abs(locPoint.X); - locPoint.Y = Math::Abs(locPoint.Y); - locPoint.Z = Math::Abs(locPoint.Z); - - // Simple axes-aligned BB check - if (Vector3::NearEqual(locPoint, Extents)) - containsAny = true; - if (locPoint.X < Extents.X && locPoint.Y < Extents.Y && locPoint.Z < Extents.Z) - containsAny = true; - else - containsAll = false; - } - - if (containsAll) - return ContainmentType::Contains; - if (containsAny) - return ContainmentType::Intersects; - return ContainmentType::Disjoint; -} - ContainmentType OrientedBoundingBox::Contains(const BoundingSphere& sphere, bool ignoreScale) const { - Matrix invTrans; - Matrix::Invert(Transformation, invTrans); - // Transform sphere center into the obb coordinates Vector3 locCenter; - Vector3::TransformCoordinate(sphere.Center, invTrans, locCenter); + Transformation.WorldToLocal(sphere.Center, locCenter); Real locRadius; if (ignoreScale) @@ -226,7 +179,7 @@ ContainmentType OrientedBoundingBox::Contains(const BoundingSphere& sphere, bool { // Transform sphere radius into the obb coordinates Vector3 vRadius = Vector3::UnitX * sphere.Radius; - Vector3::TransformNormal(vRadius, invTrans, vRadius); + Transformation.LocalToWorldVector(vRadius, vRadius); locRadius = vRadius.Length(); } @@ -238,119 +191,25 @@ ContainmentType OrientedBoundingBox::Contains(const BoundingSphere& sphere, bool if (distance > locRadius * locRadius) return ContainmentType::Disjoint; - - if (minusExtents.X + locRadius <= locCenter.X - && locCenter.X <= Extents.X - locRadius - && (Extents.X - minusExtents.X > locRadius - && minusExtents.Y + locRadius <= locCenter.Y) - && (locCenter.Y <= Extents.Y - locRadius - && Extents.Y - minusExtents.Y > locRadius - && (minusExtents.Z + locRadius <= locCenter.Z - && locCenter.Z <= Extents.Z - locRadius - && Extents.Z - minusExtents.Z > locRadius))) - { + if (minusExtents.X + locRadius <= locCenter.X && locCenter.X <= Extents.X - locRadius && (Extents.X - minusExtents.X > locRadius && minusExtents.Y + locRadius <= locCenter.Y) && (locCenter.Y <= Extents.Y - locRadius && Extents.Y - minusExtents.Y > locRadius && (minusExtents.Z + locRadius <= locCenter.Z && locCenter.Z <= Extents.Z - locRadius && Extents.Z - minusExtents.Z > locRadius))) return ContainmentType::Contains; - } - return ContainmentType::Intersects; } -/*ContainmentType OrientedBoundingBox::Contains(const OrientedBoundingBox& obb) -{ - Vector3 obbCorners[8]; - obb.GetCorners(obbCorners); - auto cornersCheck = Contains(8, obbCorners); - if (cornersCheck != ContainmentType::Disjoint) - return cornersCheck; - - // http://www.3dkingdoms.com/weekly/bbox.cpp - Vector3 SizeA = Extents; - Vector3 SizeB = obb.Extents; - Vector3 RotA[3]; - Vector3 RotB[3]; - GetRows(Transformation, RotA); - GetRows(obb.Transformation, RotB); - - Matrix R = Matrix::Identity; // Rotation from B to A - Matrix AR = Matrix::Identity; // absolute values of R matrix, to use with box extents - - Real ExtentA, ExtentB, Separation; - int i, k; - - // Calculate B to A rotation matrix - for (i = 0; i < 3; i++) - { - for (k = 0; k < 3; k++) - { - R[i, k] = Vector3::Dot(RotA[i], RotB[k]); - AR[i, k] = Math::Abs(R[i, k]); - } - } - - // Vector separating the centers of Box B and of Box A - Vector3 vSepWS = obb.GetCenter() - GetCenter(); - - // Rotated into Box A's coordinates - Vector3 vSepA = Vector3(Vector3::Dot(vSepWS, RotA[0]), Vector3::Dot(vSepWS, RotA[1]), Vector3::Dot(vSepWS, RotA[2])); - - // Test if any of A's basis vectors separate the box - for (i = 0; i < 3; i++) - { - ExtentA = SizeA[i]; - ExtentB = Vector3::Dot(SizeB, Vector3(AR[i, 0], AR[i, 1], AR[i, 2])); - Separation = Math::Abs(vSepA[i]); - - if (Separation > ExtentA + ExtentB) - return ContainmentType::Disjoint; - } - - // Test if any of B's basis vectors separate the box - for (k = 0; k < 3; k++) - { - ExtentA = Vector3::Dot(SizeA, Vector3(AR[0, k], AR[1, k], AR[2, k])); - ExtentB = SizeB[k]; - Separation = Math::Abs(Vector3::Dot(vSepA, Vector3(R[0, k], R[1, k], R[2, k]))); - - if (Separation > ExtentA + ExtentB) - return ContainmentType::Disjoint; - } - - // Now test Cross Products of each basis vector combination ( A[i], B[k] ) - for (i = 0; i < 3; i++) - { - for (k = 0; k < 3; k++) - { - int i1 = (i + 1) % 3, i2 = (i + 2) % 3; - int k1 = (k + 1) % 3, k2 = (k + 2) % 3; - ExtentA = SizeA[i1] * AR[i2, k] + SizeA[i2] * AR[i1, k]; - ExtentB = SizeB[k1] * AR[i, k2] + SizeB[k2] * AR[i, k1]; - Separation = Math::Abs(vSepA[i2] * R[i1, k] - vSepA[i1] * R[i2, k]); - if (Separation > ExtentA + ExtentB) - return ContainmentType::Disjoint; - } - } - - // No separating axis found, the boxes overlap - return ContainmentType::Intersects; -}*/ - bool OrientedBoundingBox::Intersects(const Ray& ray, Vector3& point) const { // Put ray in box space - Matrix invTrans; - Matrix::Invert(Transformation, invTrans); - Ray bRay; - Vector3::TransformNormal(ray.Direction, invTrans, bRay.Direction); - Vector3::TransformCoordinate(ray.Position, invTrans, bRay.Position); + Transformation.WorldToLocalVector(ray.Direction, bRay.Direction); + Transformation.WorldToLocal(ray.Position, bRay.Position); // Perform a regular ray to BoundingBox check - const BoundingBox bb = BoundingBox(-Extents, Extents); + const BoundingBox bb(-Extents, Extents); const bool intersects = CollisionsHelper::RayIntersectsBox(bRay, bb, point); // Put the result intersection back to world if (intersects) - Vector3::TransformCoordinate(point, Transformation, point); + Transformation.LocalToWorld(point, point); return intersects; } @@ -366,19 +225,16 @@ bool OrientedBoundingBox::Intersects(const Ray& ray, Real& distance) const bool OrientedBoundingBox::Intersects(const Ray& ray, Real& distance, Vector3& normal) const { // Put ray in box space - Matrix invTrans; - Matrix::Invert(Transformation, invTrans); - Ray bRay; - Vector3::TransformNormal(ray.Direction, invTrans, bRay.Direction); - Vector3::TransformCoordinate(ray.Position, invTrans, bRay.Position); + Transformation.WorldToLocalVector(ray.Direction, bRay.Direction); + Transformation.WorldToLocal(ray.Position, bRay.Position); // Perform a regular ray to BoundingBox check const BoundingBox bb(-Extents, Extents); if (CollisionsHelper::RayIntersectsBox(bRay, bb, distance, normal)) { // Put the result intersection back to world - Vector3::TransformNormal(normal, Transformation, normal); + Transformation.LocalToWorldVector(normal, normal); normal.Normalize(); return true; } diff --git a/Source/Engine/Core/Math/OrientedBoundingBox.cs b/Source/Engine/Core/Math/OrientedBoundingBox.cs index 46c927c21..47c46f3cf 100644 --- a/Source/Engine/Core/Math/OrientedBoundingBox.cs +++ b/Source/Engine/Core/Math/OrientedBoundingBox.cs @@ -29,32 +29,16 @@ using Real = System.Single; // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. - using System; using System.Collections.Generic; using System.Globalization; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace FlaxEngine { - /// - /// OrientedBoundingBox (OBB) is a rectangular block, much like an AABB (BoundingBox) but with an arbitrary orientation. - /// [Serializable] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct OrientedBoundingBox : IEquatable, IFormattable + partial struct OrientedBoundingBox : IEquatable, IFormattable { - /// - /// Half lengths of the box along each axis. - /// - public Vector3 Extents; - - /// - /// The matrix which aligns and scales the box, and its translation vector represents the center of the box. - /// - public Matrix Transformation; - /// /// Creates an from a BoundingBox. /// @@ -62,9 +46,9 @@ namespace FlaxEngine /// Initially, the OBB is axis-aligned box, but it can be rotated and transformed later. public OrientedBoundingBox(BoundingBox bb) { - Vector3 center = bb.Minimum + (bb.Maximum - bb.Minimum) / 2f; + Vector3 center = bb.Minimum + (bb.Maximum - bb.Minimum) * 0.5f; Extents = bb.Maximum - center; - Transformation = Matrix.Translation(center); + Transformation = new Transform(center); } /// @@ -75,7 +59,7 @@ namespace FlaxEngine public OrientedBoundingBox(Vector3 extents, Matrix transformation) { Extents = extents; - Transformation = transformation; + transformation.Decompose(out Transformation); } /// @@ -86,9 +70,9 @@ namespace FlaxEngine /// Initially, the OrientedBoundingBox is axis-aligned box, but it can be rotated and transformed later. public OrientedBoundingBox(Vector3 minimum, Vector3 maximum) { - Vector3 center = minimum + (maximum - minimum) / 2f; + Vector3 center = minimum + (maximum - minimum) * 0.5f; Extents = maximum - center; - Transformation = Matrix.Translation(center); + Transformation = new Transform(center); } /// @@ -100,19 +84,16 @@ namespace FlaxEngine { if ((points == null) || (points.Length == 0)) throw new ArgumentNullException(nameof(points)); - - var minimum = Vector3.Maximum; - var maximum = Vector3.Minimum; - - for (var i = 0; i < points.Length; ++i) + var minimum = points[0]; + var maximum = points[0]; + for (var i = 1; i < points.Length; ++i) { Vector3.Min(ref minimum, ref points[i], out minimum); Vector3.Max(ref maximum, ref points[i], out maximum); } - - Vector3 center = minimum + (maximum - minimum) / 2f; + Vector3 center = minimum + (maximum - minimum) * 0.5f; Extents = maximum - center; - Transformation = Matrix.Translation(center); + Transformation = new Transform(center); } /// @@ -121,25 +102,8 @@ namespace FlaxEngine /// An array of points representing the eight corners of the bounding box. public Vector3[] GetCorners() { - var xv = new Vector3(Extents.X, 0, 0); - var yv = new Vector3(0, Extents.Y, 0); - var zv = new Vector3(0, 0, Extents.Z); - Vector3.TransformNormal(ref xv, ref Transformation, out xv); - Vector3.TransformNormal(ref yv, ref Transformation, out yv); - Vector3.TransformNormal(ref zv, ref Transformation, out zv); - - Vector3 center = Transformation.TranslationVector; - var corners = new Vector3[8]; - corners[0] = center + xv + yv + zv; - corners[1] = center + xv + yv - zv; - corners[2] = center - xv + yv - zv; - corners[3] = center - xv + yv + zv; - corners[4] = center + xv - yv + zv; - corners[5] = center + xv - yv - zv; - corners[6] = center - xv - yv - zv; - corners[7] = center - xv - yv + zv; - + GetCorners(corners); return corners; } @@ -147,28 +111,12 @@ namespace FlaxEngine /// Retrieves the eight corners of the bounding box. /// /// An array of points representing the eight corners of the bounding box. - public void GetCorners(Vector3[] corners) + public unsafe void GetCorners(Vector3[] corners) { if (corners == null || corners.Length != 8) throw new ArgumentException(); - - var xv = new Vector3(Extents.X, 0, 0); - var yv = new Vector3(0, Extents.Y, 0); - var zv = new Vector3(0, 0, Extents.Z); - Vector3.TransformNormal(ref xv, ref Transformation, out xv); - Vector3.TransformNormal(ref yv, ref Transformation, out yv); - Vector3.TransformNormal(ref zv, ref Transformation, out zv); - - Vector3 center = Transformation.TranslationVector; - - corners[0] = center + xv + yv + zv; - corners[1] = center + xv + yv - zv; - corners[2] = center - xv + yv - zv; - corners[3] = center - xv + yv + zv; - corners[4] = center + xv - yv + zv; - corners[5] = center + xv - yv - zv; - corners[6] = center - xv - yv - zv; - corners[7] = center - xv - yv + zv; + fixed (Vector3* ptr = corners) + GetCorners(ptr); } /// @@ -177,14 +125,10 @@ namespace FlaxEngine /// An array of points representing the eight corners of the bounding box. public unsafe void GetCorners(Vector3* corners) { - var xv = new Vector3(Extents.X, 0, 0); - var yv = new Vector3(0, Extents.Y, 0); - var zv = new Vector3(0, 0, Extents.Z); - Vector3.TransformNormal(ref xv, ref Transformation, out xv); - Vector3.TransformNormal(ref yv, ref Transformation, out yv); - Vector3.TransformNormal(ref zv, ref Transformation, out zv); - - Vector3 center = Transformation.TranslationVector; + Vector3 xv = Transformation.LocalToWorldVector(new Vector3(Extents.X, 0, 0)); + Vector3 yv = Transformation.LocalToWorldVector(new Vector3(0, Extents.Y, 0)); + Vector3 zv = Transformation.LocalToWorldVector(new Vector3(0, 0, Extents.Z)); + Vector3 center = Transformation.Translation; corners[0] = center + xv + yv + zv; corners[1] = center + xv + yv - zv; @@ -204,55 +148,32 @@ namespace FlaxEngine { if (corners == null) throw new ArgumentNullException(); - - var xv = new Vector3(Extents.X, 0, 0); - var yv = new Vector3(0, Extents.Y, 0); - var zv = new Vector3(0, 0, Extents.Z); - Vector3.TransformNormal(ref xv, ref Transformation, out xv); - Vector3.TransformNormal(ref yv, ref Transformation, out yv); - Vector3.TransformNormal(ref zv, ref Transformation, out zv); - - Vector3 center = Transformation.TranslationVector; - - corners.Add(center + xv + yv + zv); - corners.Add(center + xv + yv - zv); - corners.Add(center - xv + yv - zv); - corners.Add(center - xv + yv + zv); - corners.Add(center + xv - yv + zv); - corners.Add(center + xv - yv - zv); - corners.Add(center - xv - yv - zv); - corners.Add(center - xv - yv + zv); + corners.AddRange(GetCorners()); } /// /// Transforms this box using a transformation matrix. /// /// The transformation matrix. - /// - /// While any kind of transformation can be applied, it is recommended to apply scaling using scale method instead, which - /// scales the Extents and keeps the Transformation matrix for rotation only, and that preserves collision detection accuracy. - /// + /// While any kind of transformation can be applied, it is recommended to apply scaling using scale method instead, which scales the Extents and keeps the Transformation matrix for rotation only, and that preserves collision detection accuracy. public void Transform(ref Matrix mat) { - Transformation *= mat; + mat.Decompose(out var transform); + Transformation = transform.LocalToWorld(Transformation); } /// /// Transforms this box using a transformation matrix. /// /// The transformation matrix. - /// - /// While any kind of transformation can be applied, it is recommended to apply scaling using scale method instead, which - /// scales the Extents and keeps the Transformation matrix for rotation only, and that preserves collision detection accuracy. - /// + /// While any kind of transformation can be applied, it is recommended to apply scaling using scale method instead, which scales the Extents and keeps the Transformation matrix for rotation only, and that preserves collision detection accuracy. public void Transform(Matrix mat) { - Transformation *= mat; + Transform(ref mat); } /// - /// Scales the by scaling its Extents without affecting the Transformation matrix, - /// By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. + /// Scales the by scaling its Extents without affecting the Transformation matrix, By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. /// /// public void Scale(ref Vector3 scaling) @@ -261,8 +182,7 @@ namespace FlaxEngine } /// - /// Scales the by scaling its Extents without affecting the Transformation matrix, - /// By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. + /// Scales the by scaling its Extents without affecting the Transformation matrix, By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. /// /// public void Scale(Vector3 scaling) @@ -271,8 +191,7 @@ namespace FlaxEngine } /// - /// Scales the by scaling its Extents without affecting the Transformation matrix, - /// By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. + /// Scales the by scaling its Extents without affecting the Transformation matrix, By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. /// /// public void Scale(Real scaling) @@ -286,7 +205,7 @@ namespace FlaxEngine /// the translation vector. public void Translate(ref Vector3 translation) { - Transformation.TranslationVector += translation; + Transformation.Translation += translation; } /// @@ -295,14 +214,13 @@ namespace FlaxEngine /// the translation vector. public void Translate(Vector3 translation) { - Transformation.TranslationVector += translation; + Transformation.Translation += translation; } /// /// The size of the if no scaling is applied to the transformation matrix. /// - /// The property will return the actual size even if the scaling is applied using Scale method, but if the scaling is applied to transformation matrix, use GetSize Function instead. - /// + /// The property will return the actual size even if the scaling is applied using Scale method, but if the scaling is applied to transformation matrix, use GetSize Function instead. public Vector3 Size => Extents * 2; /// @@ -312,13 +230,9 @@ namespace FlaxEngine /// This method is computationally expensive, so if no scale is applied to the transformation matrix use property instead. public Vector3 GetSize() { - var xv = new Vector3(Extents.X * 2, 0, 0); - var yv = new Vector3(0, Extents.Y * 2, 0); - var zv = new Vector3(0, 0, Extents.Z * 2); - Vector3.TransformNormal(ref xv, ref Transformation, out xv); - Vector3.TransformNormal(ref yv, ref Transformation, out yv); - Vector3.TransformNormal(ref zv, ref Transformation, out zv); - + Vector3 xv = Transformation.LocalToWorldVector(new Vector3(Extents.X * 2, 0, 0)); + Vector3 yv = Transformation.LocalToWorldVector(new Vector3(0, Extents.Y * 2, 0)); + Vector3 zv = Transformation.LocalToWorldVector(new Vector3(0, 0, Extents.Z * 2)); return new Vector3(xv.Length, yv.Length, zv.Length); } @@ -328,20 +242,16 @@ namespace FlaxEngine /// The size of the consideration public Vector3 GetSizeSquared() { - var xv = new Vector3(Extents.X * 2, 0, 0); - var yv = new Vector3(0, Extents.Y * 2, 0); - var zv = new Vector3(0, 0, Extents.Z * 2); - Vector3.TransformNormal(ref xv, ref Transformation, out xv); - Vector3.TransformNormal(ref yv, ref Transformation, out yv); - Vector3.TransformNormal(ref zv, ref Transformation, out zv); - + Vector3 xv = Transformation.LocalToWorldVector(new Vector3(Extents.X * 2, 0, 0)); + Vector3 yv = Transformation.LocalToWorldVector(new Vector3(0, Extents.Y * 2, 0)); + Vector3 zv = Transformation.LocalToWorldVector(new Vector3(0, 0, Extents.Z * 2)); return new Vector3(xv.LengthSquared, yv.LengthSquared, zv.LengthSquared); } /// /// Returns the center of the . /// - public Vector3 Center => Transformation.TranslationVector; + public Vector3 Center => Transformation.Translation; /// /// Determines whether a contains a point. @@ -351,10 +261,7 @@ namespace FlaxEngine public ContainmentType Contains(ref Vector3 point) { // Transform the point into the obb coordinates - Matrix.Invert(ref Transformation, out Matrix invTrans); - - Vector3.TransformCoordinate(ref point, ref invTrans, out Vector3 locPoint); - + Transformation.WorldToLocal(ref point, out Vector3 locPoint); locPoint.X = Math.Abs(locPoint.X); locPoint.Y = Math.Abs(locPoint.Y); locPoint.Z = Math.Abs(locPoint.Z); @@ -377,47 +284,6 @@ namespace FlaxEngine return Contains(ref point); } - /// - /// Determines whether a contains an array of points>. - /// - /// The points array to test. - /// The type of containment. - public ContainmentType Contains(Vector3[] points) - { - Matrix.Invert(ref Transformation, out Matrix invTrans); - - var containsAll = true; - var containsAny = false; - - for (var i = 0; i < points.Length; i++) - { - Vector3.TransformCoordinate(ref points[i], ref invTrans, out Vector3 locPoint); - - locPoint.X = Math.Abs(locPoint.X); - locPoint.Y = Math.Abs(locPoint.Y); - locPoint.Z = Math.Abs(locPoint.Z); - - // Simple axes-aligned BB check - if (Mathf.NearEqual(locPoint.X, Extents.X) && - Mathf.NearEqual(locPoint.Y, Extents.Y) && - Mathf.NearEqual(locPoint.Z, Extents.Z)) - containsAny = true; - - if ((locPoint.X < Extents.X) && (locPoint.Y < Extents.Y) && (locPoint.Z < Extents.Z)) - containsAny = true; - else - containsAll = false; - } - - if (containsAll) - return ContainmentType.Contains; - - if (containsAny) - return ContainmentType.Intersects; - - return ContainmentType.Disjoint; - } - /// /// Determines whether a contains a . /// @@ -427,10 +293,8 @@ namespace FlaxEngine /// This method is not designed for which has a non-uniform scaling applied to its transformation matrix. But any type of scaling applied using Scale method will keep this method accurate. public ContainmentType Contains(BoundingSphere sphere, bool ignoreScale = false) { - Matrix.Invert(ref Transformation, out Matrix invTrans); - // Transform sphere center into the obb coordinates - Vector3.TransformCoordinate(ref sphere.Center, ref invTrans, out Vector3 locCenter); + Transformation.WorldToLocal(ref sphere.Center, out Vector3 locCenter); Real locRadius; if (ignoreScale) @@ -439,235 +303,19 @@ namespace FlaxEngine { // Transform sphere radius into the obb coordinates Vector3 vRadius = Vector3.UnitX * sphere.Radius; - Vector3.TransformNormal(ref vRadius, ref invTrans, out vRadius); + Transformation.LocalToWorldVector(ref vRadius, out vRadius); locRadius = vRadius.Length; } - //Perform regular BoundingBox to BoundingSphere containment check + // Perform regular BoundingBox to BoundingSphere containment check Vector3 minusExtens = -Extents; Vector3.Clamp(ref locCenter, ref minusExtens, ref Extents, out Vector3 vector); Real distance = Vector3.DistanceSquared(ref locCenter, ref vector); if (distance > locRadius * locRadius) return ContainmentType.Disjoint; - if ((minusExtens.X + locRadius <= locCenter.X) && (locCenter.X <= Extents.X - locRadius) && (Extents.X - minusExtens.X > locRadius) && (minusExtens.Y + locRadius <= locCenter.Y) && (locCenter.Y <= Extents.Y - locRadius) && (Extents.Y - minusExtens.Y > locRadius) && (minusExtens.Z + locRadius <= locCenter.Z) && (locCenter.Z <= Extents.Z - locRadius) && (Extents.Z - minusExtens.Z > locRadius)) return ContainmentType.Contains; - - return ContainmentType.Intersects; - } - - private static Float3[] GetRows(ref Matrix mat) - { - return new[] - { - new Float3(mat.M11, mat.M12, mat.M13), - new Float3(mat.M21, mat.M22, mat.M23), - new Float3(mat.M31, mat.M32, mat.M33) - }; - } - - /// - /// Check the intersection between two - /// - /// The OrientedBoundingBox to test. - /// The type of containment the two objects have. - /// For accuracy, The transformation matrix for both must not have any scaling applied to it. Anyway, scaling using Scale method will keep this method accurate. - public ContainmentType Contains(ref OrientedBoundingBox obb) - { - ContainmentType cornersCheck = Contains(obb.GetCorners()); - if (cornersCheck != ContainmentType.Disjoint) - return cornersCheck; - - //http://www.3dkingdoms.com/weekly/bbox.cpp - Vector3 SizeA = Extents; - Vector3 SizeB = obb.Extents; - var RotA = GetRows(ref Transformation); - var RotB = GetRows(ref obb.Transformation); - - var R = new Matrix(); // Rotation from B to A - var AR = new Matrix(); // absolute values of R matrix, to use with box extents - - Real ExtentA, ExtentB, Separation; - int i, k; - - // Calculate B to A rotation matrix - for (i = 0; i < 3; i++) - for (k = 0; k < 3; k++) - { - R[i, k] = Float3.Dot(RotA[i], RotB[k]); - AR[i, k] = Math.Abs(R[i, k]); - } - - // Vector separating the centers of Box B and of Box A - Vector3 vSepWS = obb.Center - Center; - // Rotated into Box A's coordinates - var vSepA = new Vector3(Vector3.Dot(vSepWS, RotA[0]), Vector3.Dot(vSepWS, RotA[1]), Vector3.Dot(vSepWS, RotA[2])); - - // Test if any of A's basis vectors separate the box - for (i = 0; i < 3; i++) - { - ExtentA = SizeA[i]; - ExtentB = Vector3.Dot(SizeB, new Vector3(AR[i, 0], AR[i, 1], AR[i, 2])); - Separation = Math.Abs(vSepA[i]); - - if (Separation > ExtentA + ExtentB) - return ContainmentType.Disjoint; - } - - // Test if any of B's basis vectors separate the box - for (k = 0; k < 3; k++) - { - ExtentA = Vector3.Dot(SizeA, new Vector3(AR[0, k], AR[1, k], AR[2, k])); - ExtentB = SizeB[k]; - Separation = Math.Abs(Vector3.Dot(vSepA, new Vector3(R[0, k], R[1, k], R[2, k]))); - - if (Separation > ExtentA + ExtentB) - return ContainmentType.Disjoint; - } - - // Now test Cross Products of each basis vector combination ( A[i], B[k] ) - for (i = 0; i < 3; i++) - for (k = 0; k < 3; k++) - { - int i1 = (i + 1) % 3, i2 = (i + 2) % 3; - int k1 = (k + 1) % 3, k2 = (k + 2) % 3; - ExtentA = SizeA[i1] * AR[i2, k] + SizeA[i2] * AR[i1, k]; - ExtentB = SizeB[k1] * AR[i, k2] + SizeB[k2] * AR[i, k1]; - Separation = Math.Abs(vSepA[i2] * R[i1, k] - vSepA[i1] * R[i2, k]); - if (Separation > ExtentA + ExtentB) - return ContainmentType.Disjoint; - } - - // No separating axis found, the boxes overlap - return ContainmentType.Intersects; - } - - /// - /// Check the intersection between an and a line defined by two points - /// - /// The first point in the line. - /// The second point in the line. - /// The type of containment the two objects have. - /// For accuracy, The transformation matrix for the must not have any scaling applied to it. Anyway, scaling using Scale method will keep this method accurate. - public ContainmentType ContainsLine(ref Vector3 L1, ref Vector3 L2) - { - ContainmentType cornersCheck = Contains(new[] - { - L1, - L2 - }); - if (cornersCheck != ContainmentType.Disjoint) - return cornersCheck; - - //http://www.3dkingdoms.com/weekly/bbox.cpp - // Put line in box space - Matrix.Invert(ref Transformation, out Matrix invTrans); - - Vector3.TransformCoordinate(ref L1, ref invTrans, out Vector3 LB1); - Vector3.TransformCoordinate(ref L1, ref invTrans, out Vector3 LB2); - - // Get line midpoint and extent - Vector3 LMid = (LB1 + LB2) * 0.5f; - Vector3 L = LB1 - LMid; - var LExt = new Vector3(Math.Abs(L.X), Math.Abs(L.Y), Math.Abs(L.Z)); - - // Use Separating Axis Test - // Separation vector from box center to line center is LMid, since the line is in box space - if (Math.Abs(LMid.X) > Extents.X + LExt.X) - return ContainmentType.Disjoint; - - if (Math.Abs(LMid.Y) > Extents.Y + LExt.Y) - return ContainmentType.Disjoint; - - if (Math.Abs(LMid.Z) > Extents.Z + LExt.Z) - return ContainmentType.Disjoint; - - // Cross products of line and each axis - if (Math.Abs(LMid.Y * L.Z - LMid.Z * L.Y) > Extents.Y * LExt.Z + Extents.Z * LExt.Y) - return ContainmentType.Disjoint; - - if (Math.Abs(LMid.X * L.Z - LMid.Z * L.X) > Extents.X * LExt.Z + Extents.Z * LExt.X) - return ContainmentType.Disjoint; - - if (Math.Abs(LMid.X * L.Y - LMid.Y * L.X) > Extents.X * LExt.Y + Extents.Y * LExt.X) - return ContainmentType.Disjoint; - - // No separating axis, the line intersects - return ContainmentType.Intersects; - } - - /// - /// Check the intersection between an and - /// - /// The BoundingBox to test. - /// The type of containment the two objects have. - /// For accuracy, The transformation matrix for the must not have any scaling applied to it. Anyway, scaling using Scale method will keep this method accurate. - public ContainmentType Contains(ref BoundingBox box) - { - ContainmentType cornersCheck = Contains(box.GetCorners()); - if (cornersCheck != ContainmentType.Disjoint) - return cornersCheck; - - Vector3 boxCenter = box.Minimum + (box.Maximum - box.Minimum) / 2f; - Vector3 boxExtents = box.Maximum - boxCenter; - - Vector3 SizeA = Extents; - Vector3 SizeB = boxExtents; - var RotA = GetRows(ref Transformation); - - Real ExtentA, ExtentB, Separation; - int i, k; - - // Rotation from B to A - Matrix.Invert(ref Transformation, out Matrix R); - var AR = new Matrix(); // absolute values of R matrix, to use with box extents - - for (i = 0; i < 3; i++) - for (k = 0; k < 3; k++) - AR[i, k] = Math.Abs(R[i, k]); - - // Vector separating the centers of Box B and of Box A - Vector3 vSepWS = boxCenter - Center; - // Rotated into Box A's coordinates - var vSepA = new Vector3(Vector3.Dot(vSepWS, RotA[0]), Vector3.Dot(vSepWS, RotA[1]), Vector3.Dot(vSepWS, RotA[2])); - - // Test if any of A's basis vectors separate the box - for (i = 0; i < 3; i++) - { - ExtentA = SizeA[i]; - ExtentB = Vector3.Dot(SizeB, new Vector3(AR[i, 0], AR[i, 1], AR[i, 2])); - Separation = Math.Abs(vSepA[i]); - - if (Separation > ExtentA + ExtentB) - return ContainmentType.Disjoint; - } - - // Test if any of B's basis vectors separate the box - for (k = 0; k < 3; k++) - { - ExtentA = Vector3.Dot(SizeA, new Vector3(AR[0, k], AR[1, k], AR[2, k])); - ExtentB = SizeB[k]; - Separation = Math.Abs(Vector3.Dot(vSepA, new Vector3(R[0, k], R[1, k], R[2, k]))); - - if (Separation > ExtentA + ExtentB) - return ContainmentType.Disjoint; - } - - // Now test Cross Products of each basis vector combination ( A[i], B[k] ) - for (i = 0; i < 3; i++) - for (k = 0; k < 3; k++) - { - int i1 = (i + 1) % 3, i2 = (i + 2) % 3; - int k1 = (k + 1) % 3, k2 = (k + 2) % 3; - ExtentA = SizeA[i1] * AR[i2, k] + SizeA[i2] * AR[i1, k]; - ExtentB = SizeB[k1] * AR[i, k2] + SizeB[k2] * AR[i, k1]; - Separation = Math.Abs(vSepA[i2] * R[i1, k] - vSepA[i1] * R[i2, k]); - if (Separation > ExtentA + ExtentB) - return ContainmentType.Disjoint; - } - - // No separating axis found, the boxes overlap return ContainmentType.Intersects; } @@ -680,11 +328,9 @@ namespace FlaxEngine public bool Intersects(ref Ray ray, out Vector3 point) { // Put ray in box space - Matrix.Invert(ref Transformation, out Matrix invTrans); - Ray bRay; - Vector3.TransformNormal(ref ray.Direction, ref invTrans, out bRay.Direction); - Vector3.TransformCoordinate(ref ray.Position, ref invTrans, out bRay.Position); + Transformation.WorldToLocalVector(ref ray.Direction, out bRay.Direction); + Transformation.WorldToLocal(ref ray.Position, out bRay.Position); // Perform a regular ray to BoundingBox check var bb = new BoundingBox(-Extents, Extents); @@ -692,7 +338,7 @@ namespace FlaxEngine // Put the result intersection back to world if (intersects) - Vector3.TransformCoordinate(ref point, ref Transformation, out point); + Transformation.LocalToWorld(ref point, out point); return intersects; } @@ -724,25 +370,6 @@ namespace FlaxEngine return Intersects(ref ray, out Vector3 _); } - private Vector3[] GetLocalCorners() - { - var xv = new Vector3(Extents.X, 0, 0); - var yv = new Vector3(0, Extents.Y, 0); - var zv = new Vector3(0, 0, Extents.Z); - - var corners = new Vector3[8]; - corners[0] = +xv + yv + zv; - corners[1] = +xv + yv - zv; - corners[2] = -xv + yv - zv; - corners[3] = -xv + yv + zv; - corners[4] = +xv - yv + zv; - corners[5] = +xv - yv - zv; - corners[6] = -xv - yv - zv; - corners[7] = -xv - yv + zv; - - return corners; - } - /// /// Get the axis-aligned which contains all corners. /// @@ -752,94 +379,6 @@ namespace FlaxEngine return BoundingBox.FromPoints(GetCorners()); } - /// - /// Calculates the matrix required to transfer any point from one local coordinates to another. - /// - /// The source OrientedBoundingBox. - /// The target OrientedBoundingBox. - /// If true, the method will use a fast algorithm which is inapplicable if a scale is applied to the transformation matrix of the OrientedBoundingBox. - /// The matrix. - public static Matrix GetBoxToBoxMatrix(ref OrientedBoundingBox a, ref OrientedBoundingBox b, bool noMatrixScaleApplied = false) - { - Matrix AtoB_Matrix; - - // Calculate B to A transformation matrix - if (noMatrixScaleApplied) - { - var RotA = GetRows(ref a.Transformation); - var RotB = GetRows(ref b.Transformation); - AtoB_Matrix = new Matrix(); - int i, k; - for (i = 0; i < 3; i++) - for (k = 0; k < 3; k++) - AtoB_Matrix[i, k] = Float3.Dot(RotB[i], RotA[k]); - Vector3 v = b.Center - a.Center; - AtoB_Matrix.M41 = Float3.Dot(v, RotA[0]); - AtoB_Matrix.M42 = Float3.Dot(v, RotA[1]); - AtoB_Matrix.M43 = Float3.Dot(v, RotA[2]); - AtoB_Matrix.M44 = 1; - } - else - { - Matrix.Invert(ref a.Transformation, out Matrix AInvMat); - AtoB_Matrix = b.Transformation * AInvMat; - } - - return AtoB_Matrix; - } - - /// - /// Merge an OrientedBoundingBox B into another OrientedBoundingBox A, by expanding A to contain B and keeping A orientation. - /// - /// The to merge into it. - /// The to be merged - /// If true, the method will use a fast algorithm which is inapplicable if a scale is applied to the transformation matrix of the OrientedBoundingBox. - /// Unlike merging axis aligned boxes, The operation is not interchangeable, because it keeps A orientation and merge B into it. - public static void Merge(ref OrientedBoundingBox a, ref OrientedBoundingBox b, bool noMatrixScaleApplied = false) - { - Matrix AtoB_Matrix = GetBoxToBoxMatrix(ref a, ref b, noMatrixScaleApplied); - - //Get B corners in A Space - Vector3[] bCorners = b.GetLocalCorners(); - for (int i = 0; i < bCorners.Length; i++) - Vector3.TransformCoordinate(ref bCorners[i], ref AtoB_Matrix, out bCorners[i]); - - //Get A local Bounding Box - var A_LocalBB = new BoundingBox(-a.Extents, a.Extents); - - //Find B BoundingBox in A Space - BoundingBox B_LocalBB = BoundingBox.FromPoints(bCorners); - - //Merger A and B local Bounding Boxes - BoundingBox.Merge(ref B_LocalBB, ref A_LocalBB, out BoundingBox mergedBB); - - //Find the new Extents and Center, Transform Center back to world - Vector3 newCenter = mergedBB.Minimum + (mergedBB.Maximum - mergedBB.Minimum) / 2f; - a.Extents = mergedBB.Maximum - newCenter; - Vector3.TransformCoordinate(ref newCenter, ref a.Transformation, out newCenter); - a.Transformation.TranslationVector = newCenter; - } - - /// - /// Merge this OrientedBoundingBox into another OrientedBoundingBox, keeping the other OrientedBoundingBox orientation. - /// - /// The other to merge into. - /// If true, the method will use a fast algorithm which is inapplicable if a scale is applied to the transformation matrix of the OrientedBoundingBox. - public void MergeInto(ref OrientedBoundingBox oob, bool noMatrixScaleApplied = false) - { - Merge(ref oob, ref this, noMatrixScaleApplied); - } - - /// - /// Merge another OrientedBoundingBox into this OrientedBoundingBox. - /// - /// The other to merge into this OrientedBoundingBox. - /// If true, the method will use a fast algorithm which is inapplicable if a scale is applied to the transformation matrix of the OrientedBoundingBox. - public void Add(ref OrientedBoundingBox oob, bool noMatrixScaleApplied = false) - { - Merge(ref this, ref oob, noMatrixScaleApplied); - } - /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/OrientedBoundingBox.h b/Source/Engine/Core/Math/OrientedBoundingBox.h index 7835de971..dbdba67a4 100644 --- a/Source/Engine/Core/Math/OrientedBoundingBox.h +++ b/Source/Engine/Core/Math/OrientedBoundingBox.h @@ -3,19 +3,26 @@ #pragma once -#include "Vector3.h" -#include "Matrix.h" -#include "CollisionsHelper.h" +#include "Transform.h" -// Oriented Bounding Box (OBB) is a rectangular block, much like an AABB (Bounding Box) but with an arbitrary orientation in 3D space. -API_STRUCT(InBuild) struct FLAXENGINE_API OrientedBoundingBox +enum class ContainmentType; + +/// +/// Oriented Bounding Box (OBB) is a rectangular block, much like an AABB (Bounding Box) but with an arbitrary orientation in 3D space. +/// +API_STRUCT() struct FLAXENGINE_API OrientedBoundingBox { -public: - // Half lengths of the box along each axis. - Vector3 Extents; + DECLARE_SCRIPTING_TYPE_MINIMAL(Rectangle); - // The matrix which aligns and scales the box, and its translation vector represents the center of the box. - Matrix Transformation; + /// + /// Half lengths of the box along each axis. + /// + API_FIELD() Vector3 Extents; + + /// + /// The transformation which aligns and scales the box, and its translation vector represents the center of the box. + /// + API_FIELD() Transform Transformation; public: /// @@ -25,34 +32,16 @@ public: { } - // Init - // @param bb The BoundingBox to create from - OrientedBoundingBox(const BoundingBox& bb); - - // Init - // @param extents The half lengths of the box along each axis. - // @param transformation The matrix which aligns and scales the box, and its translation vector represents the center of the box. - OrientedBoundingBox(const Vector3& extents, const Matrix& transformation) + OrientedBoundingBox(const Vector3& extents, const Transform& transformation) { Extents = extents; Transformation = transformation; } + OrientedBoundingBox(const BoundingBox& bb); + OrientedBoundingBox(const Vector3& extents, const Matrix& transformation); OrientedBoundingBox(const Vector3& extents, const Matrix3x3& rotationScale, const Vector3& translation); - - // Init - // @param minimum The minimum vertex of the bounding box. - // @param maximum The maximum vertex of the bounding box. - OrientedBoundingBox(const Vector3& minimum, const Vector3& maximum) - { - const Vector3 center = minimum + (maximum - minimum) / 2.0f; - Extents = maximum - center; - Matrix::Translation(center, Transformation); - } - - // Init - // @param points The points that will be contained by the box. - // @param pointCount Amount of the points in th array. + OrientedBoundingBox(const Vector3& minimum, const Vector3& maximum); OrientedBoundingBox(Vector3 points[], int32 pointCount); public: @@ -77,9 +66,9 @@ public: Vector3 GetSizeSquared() const; // Gets the center of the OBB. - Vector3 GetCenter() const + FORCE_INLINE Vector3 GetCenter() const { - return Transformation.GetTranslation(); + return Transformation.Translation; } /// @@ -98,6 +87,7 @@ public: // Transforms this box using a transformation matrix. // @param mat The transformation matrix. void Transform(const Matrix& matrix); + void Transform(const ::Transform& transform); // Scales the OBB by scaling its Extents without affecting the Transformation matrix. // By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate. @@ -119,7 +109,7 @@ public: // @param translation the translation vector. void Translate(const Vector3& translation) { - Transformation.SetTranslation(Transformation.GetTranslation() + translation); + Transformation.Translation += translation; } public: @@ -140,12 +130,11 @@ public: return result; } -private: - static void GetRows(const Matrix& mat, Vector3 rows[3]) + FORCE_INLINE OrientedBoundingBox operator*(const ::Transform& matrix) const { - rows[0] = Vector3(mat.M11, mat.M12, mat.M13); - rows[1] = Vector3(mat.M21, mat.M22, mat.M23); - rows[2] = Vector3(mat.M31, mat.M32, mat.M33); + OrientedBoundingBox result = *this; + result.Transform(matrix); + return result; } public: @@ -157,8 +146,8 @@ public: /// The result. static void CreateCentered(const Vector3& center, const Vector3& size, OrientedBoundingBox& result) { - result.Extents = size / 2.0f; - Matrix::Translation(center, result.Transformation); + result.Extents = size * 0.5f; + result.Transformation = ::Transform(center); } /// @@ -170,8 +159,7 @@ public: static OrientedBoundingBox CreateCentered(const Vector3& center, const Vector3& size) { OrientedBoundingBox result; - result.Extents = size / 2.0f; - Matrix::Translation(center, result.Transformation); + CreateCentered(center, size, result); return result; } @@ -181,12 +169,6 @@ public: // @returns The type of containment the two objects have. ContainmentType Contains(const Vector3& point, Real* distance = nullptr) const; - // Determines whether a OBB contains an array of points. - // @param pointsCnt Amount of points to test. - // @param points The points array to test. - // @returns The type of containment. - ContainmentType Contains(int32 pointsCnt, Vector3 points[]) const; - // Determines whether a OBB contains a BoundingSphere. // @param sphere The sphere to test. // @param ignoreScale Optimize the check operation by assuming that OBB has no scaling applied. diff --git a/Source/Engine/Level/Actors/BoxBrush.cpp b/Source/Engine/Level/Actors/BoxBrush.cpp index 0f8e2d791..02e2a3973 100644 --- a/Source/Engine/Level/Actors/BoxBrush.cpp +++ b/Source/Engine/Level/Actors/BoxBrush.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #include "BoxBrush.h" +#include "Engine/Core/Math/Matrix.h" #include "Engine/Content/Content.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Level/Scene/Scene.h" diff --git a/Source/Engine/Level/Actors/BoxBrush.h b/Source/Engine/Level/Actors/BoxBrush.h index 718fd5d55..fc30aedc2 100644 --- a/Source/Engine/Level/Actors/BoxBrush.h +++ b/Source/Engine/Level/Actors/BoxBrush.h @@ -190,7 +190,7 @@ private: FORCE_INLINE void UpdateBounds() { OrientedBoundingBox::CreateCentered(_center, _size, _bounds); - _bounds.Transform(_transform.GetWorld()); + _bounds.Transform(_transform); _bounds.GetBoundingBox(_box); BoundingSphere::FromBox(_box, _sphere); } diff --git a/Source/Engine/Level/Actors/BoxVolume.cpp b/Source/Engine/Level/Actors/BoxVolume.cpp index 278b0bf0d..824745fd5 100644 --- a/Source/Engine/Level/Actors/BoxVolume.cpp +++ b/Source/Engine/Level/Actors/BoxVolume.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #include "BoxVolume.h" +#include "Engine/Core/Math/Matrix.h" #include "Engine/Serialization/Serialization.h" BoxVolume::BoxVolume(const SpawnParams& params) @@ -54,11 +55,13 @@ namespace else Quaternion::LookRotation(dir, Vector3::Cross(Vector3::Cross(dir, Vector3::Up), dir), orientation); const Vector3 up = orientation * Vector3::Up; - Matrix::CreateWorld(min + vec * 0.5f, dir, up, box.Transformation); - Matrix inv; - Matrix::Invert(box.Transformation, inv); + Matrix world; + Matrix::CreateWorld(min + vec * 0.5f, dir, up, world); + world.Decompose(box.Transformation); + Matrix invWorld; + Matrix::Invert(world, invWorld); Vector3 vecLocal; - Vector3::TransformNormal(vec * 0.5f, inv, vecLocal); + Vector3::TransformNormal(vec * 0.5f, invWorld, vecLocal); box.Extents.X = margin; box.Extents.Y = margin; box.Extents.Z = vecLocal.Z; diff --git a/Source/Engine/Level/Actors/Decal.cpp b/Source/Engine/Level/Actors/Decal.cpp index f39d081bf..fb78110a1 100644 --- a/Source/Engine/Level/Actors/Decal.cpp +++ b/Source/Engine/Level/Actors/Decal.cpp @@ -15,7 +15,7 @@ Decal::Decal(const SpawnParams& params) { _world = Matrix::Scaling(_size); _bounds.Extents = Vector3::Half; - _bounds.Transformation = _world; + _world.Decompose(_bounds.Transformation); _bounds.GetBoundingBox(_box); BoundingSphere::FromBox(_box, _sphere); } @@ -30,8 +30,8 @@ void Decal::SetSize(const Vector3& value) Transform t = _transform; t.Scale *= _size; t.GetWorld(_world); - _bounds.Extents = Vector3::Half; - _bounds.Transformation = _world; + + _bounds.Transformation = t; _bounds.GetBoundingBox(_box); BoundingSphere::FromBox(_box, _sphere); } @@ -152,7 +152,7 @@ void Decal::OnTransformChanged() t.GetWorld(_world); _bounds.Extents = Vector3::Half; - _bounds.Transformation = _world; + _bounds.Transformation = t; _bounds.GetBoundingBox(_box); BoundingSphere::FromBox(_box, _sphere); diff --git a/Source/Engine/Level/Actors/Decal.h b/Source/Engine/Level/Actors/Decal.h index 3e2d6a18c..d6e608f6e 100644 --- a/Source/Engine/Level/Actors/Decal.h +++ b/Source/Engine/Level/Actors/Decal.h @@ -3,6 +3,7 @@ #pragma once #include "../Actor.h" +#include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Content/Assets/MaterialBase.h" #include "Engine/Content/AssetReference.h" diff --git a/Source/Engine/Physics/Colliders/BoxCollider.cpp b/Source/Engine/Physics/Colliders/BoxCollider.cpp index efcb89ade..d3dcc2295 100644 --- a/Source/Engine/Physics/Colliders/BoxCollider.cpp +++ b/Source/Engine/Physics/Colliders/BoxCollider.cpp @@ -60,11 +60,13 @@ namespace else Quaternion::LookRotation(dir, Float3::Cross(Float3::Cross(dir, Float3::Up), dir), orientation); const Vector3 up = orientation * Vector3::Up; - Matrix::CreateWorld(min + vec * 0.5f, dir, up, box.Transformation); - Matrix inv; - Matrix::Invert(box.Transformation, inv); + Matrix world; + Matrix::CreateWorld(min + vec * 0.5f, dir, up, world); + world.Decompose(box.Transformation); + Matrix invWorld; + Matrix::Invert(world, invWorld); Vector3 vecLocal; - Vector3::TransformNormal(vec * 0.5f, inv, vecLocal); + Vector3::TransformNormal(vec * 0.5f, invWorld, vecLocal); box.Extents.X = margin; box.Extents.Y = margin; box.Extents.Z = vecLocal.Z; diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 42b984247..d3d25c133 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -1074,8 +1074,10 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con } // Write to objects buffer (this must match unpacking logic in HLSL) + Matrix localToWorldBounds; + object->Bounds.Transformation.GetWorld(localToWorldBounds); Matrix worldToLocalBounds; - Matrix::Invert(object->Bounds.Transformation, worldToLocalBounds); + Matrix::Invert(localToWorldBounds, worldToLocalBounds); uint32 objectAddress = _objectsBuffer->Data.Count() / sizeof(Float4); auto* objectData = _objectsBuffer->WriteReserve(GLOBAL_SURFACE_ATLAS_OBJECT_DATA_STRIDE); objectData[0] = *(Float4*)&actorObjectBounds; @@ -1103,13 +1105,13 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con yAxis = tileIndex == 2 || tileIndex == 3 ? Float3::Right : Float3::Up; Float3::Cross(yAxis, zAxis, xAxis); Float3 localSpaceOffset = -zAxis * object->Bounds.Extents; - Float3::TransformNormal(xAxis, object->Bounds.Transformation, xAxis); - Float3::TransformNormal(yAxis, object->Bounds.Transformation, yAxis); - Float3::TransformNormal(zAxis, object->Bounds.Transformation, zAxis); + xAxis = object->Bounds.Transformation.LocalToWorldVector(xAxis); + yAxis = object->Bounds.Transformation.LocalToWorldVector(yAxis); + zAxis = object->Bounds.Transformation.LocalToWorldVector(zAxis); xAxis.NormalizeFast(); yAxis.NormalizeFast(); zAxis.NormalizeFast(); - Float3::Transform(localSpaceOffset, object->Bounds.Transformation, tile->ViewPosition); + object->Bounds.Transformation.LocalToWorld(localSpaceOffset, tile->ViewPosition); tile->ViewDirection = zAxis; // Create view matrix @@ -1122,7 +1124,7 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con OrientedBoundingBox viewBounds(object->Bounds); viewBounds.Transform(tile->ViewMatrix); Float3 viewExtent; - Float3::TransformNormal(viewBounds.Extents, viewBounds.Transformation, viewExtent); + viewExtent = viewBounds.Transformation.LocalToWorldVector(viewBounds.Extents); tile->ViewBoundsSize = viewExtent.GetAbsolute() * 2.0f; // Per-tile data diff --git a/Source/Engine/Serialization/JsonWriter.h b/Source/Engine/Serialization/JsonWriter.h index 94130cbe7..6e5e07250 100644 --- a/Source/Engine/Serialization/JsonWriter.h +++ b/Source/Engine/Serialization/JsonWriter.h @@ -7,8 +7,6 @@ #include "Engine/Utilities/StringConverter.h" struct CommonValue; -struct Matrix; -struct Transform; class ISerializable; // Helper macro for JSON serialization keys (reduces allocations count) diff --git a/Source/Engine/UI/GUI/CanvasContainer.cs b/Source/Engine/UI/GUI/CanvasContainer.cs index 60cfa2a78..88e844a1d 100644 --- a/Source/Engine/UI/GUI/CanvasContainer.cs +++ b/Source/Engine/UI/GUI/CanvasContainer.cs @@ -39,7 +39,8 @@ namespace FlaxEngine.GUI child.Canvas.GetWorldMatrix(out var world); Matrix.Translation((float)bounds.Extents.X, (float)bounds.Extents.Y, 0, out var offset); - Matrix.Multiply(ref offset, ref world, out bounds.Transformation); + Matrix.Multiply(ref offset, ref world, out var boxWorld); + boxWorld.Decompose(out bounds.Transformation); // Hit test if (bounds.Intersects(ref ray, out Vector3 hitPoint)) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 65d521bf9..1dc150399 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -330,7 +330,8 @@ namespace FlaxEngine }; GetWorldMatrix(out Matrix world); Matrix.Translation((float)bounds.Extents.X, (float)bounds.Extents.Y, 0, out Matrix offset); - Matrix.Multiply(ref offset, ref world, out bounds.Transformation); + Matrix.Multiply(ref offset, ref world, out var boxWorld); + boxWorld.Decompose(out bounds.Transformation); return bounds; } } diff --git a/Source/Engine/UI/UIControl.cs b/Source/Engine/UI/UIControl.cs index 0fe96f3cc..bd1d2e795 100644 --- a/Source/Engine/UI/UIControl.cs +++ b/Source/Engine/UI/UIControl.cs @@ -122,7 +122,8 @@ namespace FlaxEngine canvasRoot.Canvas.GetWorldMatrix(out Matrix world); Matrix.Translation(min.X + size.X * 0.5f, min.Y + size.Y * 0.5f, 0, out Matrix offset); - Matrix.Multiply(ref offset, ref world, out bounds.Transformation); + Matrix.Multiply(ref offset, ref world, out var boxWorld); + boxWorld.Decompose(out bounds.Transformation); return bounds; } }