modeling/src/maths/mat4/fromVectorRotation.js

  1. const vec3 = require('../vec3')
  2. const fromRotation = require('./fromRotation')
  3. /**
  4. * Create a matrix that rotates the given source to the given target vector.
  5. *
  6. * Each vector must be a directional vector with a length greater than zero.
  7. * @see https://gist.github.com/kevinmoran/b45980723e53edeb8a5a43c49f134724
  8. * @param {mat4} out - receiving matrix
  9. * @param {vec3} source - source vector
  10. * @param {vec3} target - target vector
  11. * @returns {mat4} a new matrix
  12. * @alias module:modeling/maths/mat4.fromVectorRotation
  13. * @example
  14. * let matrix = fromVectorRotation(mat4.create(), [1, 2, 2], [-3, 3, 12])
  15. */
  16. const fromVectorRotation = (out, source, target) => {
  17. const sourceNormal = vec3.normalize(vec3.create(), source)
  18. const targetNormal = vec3.normalize(vec3.create(), target)
  19. const axis = vec3.cross(vec3.create(), targetNormal, sourceNormal)
  20. const cosA = vec3.dot(targetNormal, sourceNormal)
  21. if (cosA === -1.0) return fromRotation(out, Math.PI, vec3.orthogonal(axis, sourceNormal))
  22. const k = 1 / (1 + cosA)
  23. out[0] = (axis[0] * axis[0] * k) + cosA
  24. out[1] = (axis[1] * axis[0] * k) - axis[2]
  25. out[2] = (axis[2] * axis[0] * k) + axis[1]
  26. out[3] = 0
  27. out[4] = (axis[0] * axis[1] * k) + axis[2]
  28. out[5] = (axis[1] * axis[1] * k) + cosA
  29. out[6] = (axis[2] * axis[1] * k) - axis[0]
  30. out[7] = 0
  31. out[8] = (axis[0] * axis[2] * k) - axis[1]
  32. out[9] = (axis[1] * axis[2] * k) + axis[0]
  33. out[10] = (axis[2] * axis[2] * k) + cosA
  34. out[11] = 0
  35. out[12] = 0
  36. out[13] = 0
  37. out[14] = 0
  38. out[15] = 1
  39. return out
  40. }
  41. module.exports = fromVectorRotation