diff --git a/packages/dev/core/src/Maths/math.vector.ts b/packages/dev/core/src/Maths/math.vector.ts index 1964e92f2b6..38495091a10 100644 --- a/packages/dev/core/src/Maths/math.vector.ts +++ b/packages/dev/core/src/Maths/math.vector.ts @@ -1130,7 +1130,7 @@ export class Vector3 { } /** - * Projects the current vector3 to a plane along a ray starting from a specified origin and directed towards the point. + * Projects the current point Vector3 to a plane along a ray starting from a specified origin and passing through the current point Vector3. * @param plane defines the plane to project to * @param origin defines the origin of the projection ray * @returns the projected vector3 @@ -1144,48 +1144,34 @@ export class Vector3 { } /** - * Projects the current vector3 to a plane along a ray starting from a specified origin and directed towards the point. + * Projects the current point Vector3 to a plane along a ray starting from a specified origin and passing through the current point Vector3. * @param plane defines the plane to project to * @param origin defines the origin of the projection ray * @param result defines the Vector3 where to store the result */ public projectOnPlaneToRef(plane: Plane, origin: Vector3, result: Vector3): void { - // Use the normal scaled to the plane offset as the origin for the formula - const planeOrigin = MathTmp.Vector3[0]; - plane.normal.scaleToRef(-plane.d, planeOrigin); - - // Since the normal in Babylon should point toward the viewer, invert it for the dot product - const inverseNormal = MathTmp.Vector3[1]; - plane.normal.negateToRef(inverseNormal); - - // This vector is the direction - const { x, y, z } = this; - - // Calculate how close the direction is to the normal of the plane - const dotProduct = Vector3.Dot(inverseNormal, this); - - /* - * Early out in case the direction will never hit the plane. - * - * Epsilon is used to avoid issues with rays very near to parallel with the - * plane, and squared because as of writing the value is not sufficiently - * small for this use case. - */ - if (dotProduct <= Epsilon * Epsilon) { - // No good option for setting the result vector here, so just take the origin of the ray - result.copyFrom(origin); - return; - } + const n = plane.normal; + const d = plane.d; + + const V = MathTmp.Vector3[0]; + + // ray direction + this.subtractToRef(origin, V); - // Calculate the offset - const relativeOrigin = MathTmp.Vector3[2]; - planeOrigin.subtractToRef(origin, relativeOrigin); + V.normalize(); - // Calculate the length along the direction vector to the hit point - const hitDistance = Vector3.Dot(relativeOrigin, inverseNormal) / dotProduct; + const denom = Vector3.Dot(V, n); - // Apply the hit point by adding the direction scaled by the distance to the origin - result.set(origin.x + x * hitDistance, origin.y + y * hitDistance, origin.z + z * hitDistance); + //When the ray is close to parallel to the plane return infinity vector + if (Math.abs(denom) < Math.pow(10, -10)) { + origin.addToRef(new Vector3(Infinity, Infinity, Infinity), result); + } else { + const t = -(Vector3.Dot(origin, n) + d) / denom; + + // P = P0 + t*V + const scaledV = V.scaleInPlace(t); + origin.addToRef(scaledV, result); + } } /** diff --git a/packages/dev/core/test/unit/Math/babylon.math.vector.test.ts b/packages/dev/core/test/unit/Math/babylon.math.vector.test.ts index ee2c45869db..bd047f16819 100644 --- a/packages/dev/core/test/unit/Math/babylon.math.vector.test.ts +++ b/packages/dev/core/test/unit/Math/babylon.math.vector.test.ts @@ -1,43 +1,34 @@ -import { Plane, Vector3 } from 'core/Maths' +import { Plane, Vector3 } from "core/Maths"; /** * Describes the test suite. */ describe("Babylon Vectors", () => { describe("#Vector3", () => { - it("can project a direction vector onto a plane", () => { + it("can project from an origin onto a plane", () => { // A ground plane at origin - const simplePlane = Plane.FromPositionAndNormal( - Vector3.Zero(), - Vector3.Up(), - ); + const simplePlane = Plane.FromPositionAndNormal(Vector3.Zero(), Vector3.Up()); const rayOrigin = new Vector3(0, 10, 0); - const rayAngle = new Vector3(0.5, -0.5, 0); + const rayGoingThrough = new Vector3(1, 8, 0); - /* - * At 45 degrees this should form a perfect right triangle, - * so the result should be the same as the distance to the origin. - */ - const expected = new Vector3(10, 0, 0); + // Going left 1 unit for each 2 units downs + const expected = new Vector3(5, 0, 0); - expect(rayAngle.projectOnPlane(simplePlane, rayOrigin)).toEqual(expected) - }) + expect(rayGoingThrough.projectOnPlane(simplePlane, rayOrigin)).toEqual(expected); + }); - it("can project a direction vector onto an offset plane", () => { + it("can project from an origin onto an offset plane", () => { // A ground plane 10 units below origin - const simplePlane = Plane.FromPositionAndNormal( - new Vector3(0, -10, 0), - Vector3.Up(), - ); + const simplePlane = Plane.FromPositionAndNormal(new Vector3(0, -10, 0), Vector3.Up()); const rayOrigin = new Vector3(0, 10, 0); - const rayAngle = new Vector3(0.5, -0.5, 0); + const rayGoingThrough = new Vector3(1, 8, 0); - // This is also a right triangle, but the plane is offset so the hit point is offset and the distance increases - const expected = new Vector3(20, -10, 0); + // Going left 1 unit for each 2 units downs + const expected = new Vector3(10, -10, 0); - expect(rayAngle.projectOnPlane(simplePlane, rayOrigin)).toEqual(expected) - }) - }) -}) \ No newline at end of file + expect(rayGoingThrough.projectOnPlane(simplePlane, rayOrigin)).toEqual(expected); + }); + }); +});