* Calculates a new heading and magnitude that are between two vectors. * * The `amt` parameter is the amount to interpolate between the old vector and * the new vector. 0.0 keeps the heading and magnitude equal to the old * vector's, 0.5 sets them halfway between, and 1.0 sets the headin
(v, amt)
| 2558 | * } |
| 2559 | */ |
| 2560 | slerp(v, amt) { |
| 2561 | // edge cases. |
| 2562 | if (amt === 0) { |
| 2563 | return this; |
| 2564 | } |
| 2565 | if (amt === 1) { |
| 2566 | return this.set(v); |
| 2567 | } |
| 2568 | |
| 2569 | // calculate magnitudes |
| 2570 | const selfMag = this.mag(); |
| 2571 | const vMag = v.mag(); |
| 2572 | const magmag = selfMag * vMag; |
| 2573 | // if either is a zero vector, linearly interpolate by these vectors |
| 2574 | if (magmag === 0) { |
| 2575 | this.mult(1 - amt).add(v.x * amt, v.y * amt, v.z * amt); |
| 2576 | return this; |
| 2577 | } |
| 2578 | // the cross product of 'this' and 'v' is the axis of rotation |
| 2579 | const axis = this.cross(v); |
| 2580 | const axisMag = axis.mag(); |
| 2581 | // Calculates the angle between 'this' and 'v' |
| 2582 | const theta = Math.atan2(axisMag, this.dot(v)); |
| 2583 | |
| 2584 | // However, if the norm of axis is 0, normalization cannot be performed, |
| 2585 | // so we will divide the cases |
| 2586 | if (axisMag > 0) { |
| 2587 | axis.x /= axisMag; |
| 2588 | axis.y /= axisMag; |
| 2589 | axis.z /= axisMag; |
| 2590 | } else if (theta < Math.PI * 0.5) { |
| 2591 | // if the norm is 0 and the angle is less than PI/2, |
| 2592 | // the angle is very close to 0, so do linear interpolation. |
| 2593 | this.mult(1 - amt).add(v.x * amt, v.y * amt, v.z * amt); |
| 2594 | return this; |
| 2595 | } else { |
| 2596 | // If the norm is 0 and the angle is more than PI/2, the angle is |
| 2597 | // very close to PI. |
| 2598 | // In this case v can be regarded as '-this', so take any vector |
| 2599 | // that is orthogonal to 'this' and use that as the axis. |
| 2600 | if (this.z === 0 && v.z === 0) { |
| 2601 | // if both this and v are 2D vectors, use (0,0,1) |
| 2602 | // this makes the result also a 2D vector. |
| 2603 | axis.set(0, 0, 1); |
| 2604 | } else if (this.x !== 0) { |
| 2605 | // if the x components is not 0, use (y, -x, 0) |
| 2606 | axis.set(this.y, -this.x, 0).normalize(); |
| 2607 | } else { |
| 2608 | // if the x components is 0, use (1,0,0) |
| 2609 | axis.set(1, 0, 0); |
| 2610 | } |
| 2611 | } |
| 2612 | |
| 2613 | // Since 'axis' is a unit vector, ey is a vector of the same length as 'this'. |
| 2614 | const ey = axis.cross(this); |
| 2615 | // interpolate the length with 'this' and 'v'. |
| 2616 | const lerpedMagFactor = 1 - amt + (amt * vMag) / selfMag; |
| 2617 | // imagine a situation where 'axis', 'this', and 'ey' are pointing |