如何找到THREE.js中两组3D点之间的旋转矩阵

How to find rotation matrix between two sets of 3D points in THREE.js

我的问题是这个问题的延伸:How to find rotation matrix between two vectors in THREE.js

如果我有一个 Vector3 和一个垂直于它的 Vector3 来描述 3D 对象的方向,我将如何找到这个向量组和我已经可用的这个向量组的转换之间的旋转矩阵已翻译的向量组?

这里有一个视觉效果可以使它更清楚:

Imgur Link

我想使用适当的 THREE.js 实用程序找到四元数,该四元数将 v1 和 v1n 描述的组的旋转旋转为 v1' 和 v1n' 描述的同一组的旋转。这些状态的旋转枢轴由点 p1 和 p1' 描述。

从上面的回答中我知道如何从一个 Vector3 旋转到另一个 Vector3,但是如果我在我的用例中使用该方法,我将不会处理旋转的第 3 个自由度(假设yaw, pitch, roll 用来描述旋转)。

假设 v1 和 v1n 在 group1 中,v2 和 v2n 在 group2 中。 如果我们可以假设两个组都以相同的向量配置开始,比如 (0,1,0) 和 (0,0,1),这似乎是合乎逻辑的:

首先,将 group1 移动到其原始方向。

var qtmp1 = group1.quaternion.clone().conjugate();
group1.applyQuaternion(qtmp1);

然后,将group1移动到group2的方向。

var qtmp2 = group2.quaternion.clone();
group1.applyQuaternion(qtmp2);

一圈:

group1.applyQuaternion(qtmp2.multiply(qtmp1));

假设可能不正确。

编辑:更简单:

group1.quaternion.slerp(group2.quaternion, 1);

我的回答 #2:不依赖于 2 个组的方向。

我们再说一遍,我们要将 v1 和 v1n 轮换为 v2 和 v2n。我们可以使用 .setFromUnitVectors(v1, v2) 来获得四元数 Q1 将 v1 旋转到 v2。 v1n会旋转成v1nrot1,这对v2是正常的,但不是v2n。我们可以再次使用 .setFromUnitVectors(v1nrot1, v2n) 来获得四元数 Q2 将 v1nrot1 旋转到 v2n。第二次旋转不会影响 v1rot (=v2),因为 v1rot 对于 v1nrot1 和 v2n 是正常的。如果这些不正常,将有一个额外的步骤来获得正常。最后,v1rot dot v2 = 1 和 v1nrot2 dot v2n = 1 表明 Q2Q1 旋转有效。代码已注释。

<!doctype html>
<html><!--  -->
  <head>
    <title> SO.html </title>
    <style type="text/css">
* { font-family:monospace; font-size:16px; }
    </style>
    <script src="http://threejs.org/build/three.js"></script>
    <script type="text/javascript">
  "use strict";
  const k57=180/Math.PI;
  var div1elt;
window.onload = function() {
  div1elt = document.getElementById("div1");
  // get v1 and v1n
  print("  --  v1 and v1n");
  var v1 = new THREE.Vector3(1,2,3).normalize();
  var vtmp = new THREE.Quaternion(1,0,0).normalize();
  var v1n = v1.clone().cross(vtmp).normalize(); 
  printv("v1", v1);
  printv("v1n", v1n);
  print("v1 dot v1n", v1.dot(v1n));
  // get v2 and v2n
  print("  --  v2 and v2n");
  var v2 = new THREE.Vector3(4,3,2).normalize();
  var vtmp = new THREE.Quaternion(0,0,1).normalize();
  var v2n = v2.clone().cross(vtmp).normalize(); 
  printv("v2", v2);
  printv("v2n", v2n);
  print("v2 dot v2n", v2.dot(v2n));
  // get Q1 that rotates v1 to v1rot (and v1n to v1nrot1)
  var Q1 = new THREE.Quaternion().setFromUnitVectors(v1, v2);
  // get Q2 that rotates v1nrot1 to v1nrot2
  // Q2 will not rotate v1rot because v1nrot1 and v2n are normal to v1rot
  var v1nrot1 = v1n.clone().applyQuaternion(Q1); // 
  var Q2 = new THREE.Quaternion().setFromUnitVectors(v1nrot1, v2n);
  var Q12 = new THREE.Quaternion().multiplyQuaternions(Q2,Q1);
  // print Q12
  printq("  --  Q12  --",Q12);
  // now see if Q12 works
  print("  --  check results");
  var v1rot = v1.clone().applyQuaternion(Q12);
  print("v1rot dot v2", v1rot.dot(v2).dd(1,5));
  var v1nrot2 = v1n.clone().applyQuaternion(Q12);
  print("v1nrot2 dot v2n", v1nrot2.dot(v2n).dd(1,5));  
};
Number.prototype.dd = function(b4, af) { // formats nn.nnn
  // usage: string = n.dd(2,3) or (2).dd(2,3)
  if (isNaN(parseFloat(this)) || !isFinite(this)) return this;
  var pfx = "", pos, b4s, b4v, afs, afv;
  var s = String(this+.5*Math.pow(10,-af));
  if (s.substring(0,1) == "-") { pfx = "-"; s = s.substring(1); b4-=1; }
  if (s.substring(0,1) == "0") s = s.substring(1);
  if ((pos = s.indexOf("."))==-1) s+=".";
  b4s = s.substring(0,pos); b4v = b4s.length;
  afs = s.substring(pos+1); afv = afs.length;
  if (b4>b4v) pfx+= "0".repeat(b4-b4v);
  if (af>afv) afs +="0".repeat(af-afv);
  if (af<afv) afs = afs.substring(0,af);
  return pfx+b4s+((af!=0)?".":"")+afs;
};
function printq(txt, q) { // print q
  var ang = Math.atan2(Math.sqrt(q.x*q.x+q.y*q.y+q.z*q.z), q.w);
  var len = Math.sqrt(q.w*q.w+q.x*q.x+q.y*q.y+q.z*q.z);
  print(txt, q.w.dd(2,5),q.x.dd(2,5),q.y.dd(2,5),q.z.dd(2,5),
        "[len="+len.dd(2,5)+", ang="+(ang*k57).dd(4,1)+"]");
}
function printv(txt, v) { // print v
  var len = Math.sqrt(v.x*v.x+v.y*v.y+v.z*v.z);
  print(txt, v.x.dd(2,5),v.y.dd(2,5),v.z.dd(2,5),
        "[len="+len.dd(2,5)+"]");
}
function print(what) { // print
  var s="";
  for (var i1=0; i1<arguments.length; i1+=1) {
    if (s != "") s += ", ";
    s+= arguments[i1];
  }
  div1elt.innerHTML += s + "<br />";
}
    </script>
  </head>
  <body>
    <div id="div1"></div>
  </body>
</html>