Skip to content

Instantly share code, notes, and snippets.

@blackslate
Created November 27, 2015 15:20

Revisions

  1. blackslate created this gist Nov 27, 2015.
    87 changes: 87 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,87 @@
    THREE.Ray.prototype.closestPointToRay = function (that, details) {
    // that: THREE.Ray()
    // details: (optional) object
    // { pointOnThisRay: <THREE.Vector3>
    // , pointOnThatRay: <THREE.Vector3>
    // , midPoint: <THREE.Vector3>
    // , distanceBetweenClosestPoints: <float>
    // }
    // For an explanation of the vector mathematics, see:
    // http://morroworks.com/Content/Docs/Rays%20closest%20point.pdf

    // @return undefined if rays are invalid or parallel
    // or THREE.Vector3() point on this ray which is closest
    // to that ray.

    if (!(that instanceof THREE.Ray)) {
    return
    }

    var thisDirection = this.direction
    var thatDirection = that.direction

    if (!thisDirection.clone().cross(thatDirection).length()) {
    // Rays are parallel
    return
    }

    if ( !thisDirection.dot(thisDirection)
    || !thatDirection.dot(thatDirection)) {
    // At least one of the rays is just a point with no direction
    return
    }

    var closestPoint = new THREE.Vector3()
    var thisOrigin = this.origin
    var thatOrigin = that.origin
    var sameOrigin = thisOrigin.equals(thatOrigin)

    if (sameOrigin) {
    // Simple case
    closestPoint.copy(thisOrigin)
    } else {
    var a = thisDirection.clone().normalize()
    var b = thatDirection.clone().normalize()
    var c = thatOrigin.clone().sub(thisOrigin)

    var p = a.dot(b)
    var q = a.dot(c)
    var r = b.dot(c)
    var s = a.dot(a) // already known to be non-zero
    var t = b.dot(b) // already known to be non-zero

    var divisor = (s * t - p * p)

    if (!divisor) {
    // The two rays are colinear. They are "closest" at all points
    // This case should already have been excluded by the .cross()
    // check made at the start.
    return
    }

    var d = (q * t - p * r) / divisor
    closestPoint.copy(thisOrigin).add(a.multiplyScalar(d))
    }

    if ( typeof details === "object" ) {
    details.pointOnThisRay = closestPoint

    if (sameOrigin) {
    // Should all points be the same object or clones?
    details.pointOnThatRay = closestPoint
    details.midPoint = closestPoint
    details.distanceBetweenClosestPoints = 0
    } else {
    // TODO: Add other details
    d = (p * q - r * s) / divisor
    var thatPoint = new THREE.Vector3().copy(thatOrigin).add(b.multiplyScalar(d))
    details.pointOnThatRay = thatPoint
    details.midPoint = closestPoint.clone()
    .add(thatPoint)
    .divideScalar(2)
    details.distanceBetweenClosestPoints = closestPoint.distanceTo(thatPoint)
    }
    }

    return closestPoint
    }