计算旋转以将对象与 3D 空间中的两点对齐

Bra*_* H. 4 math processing euler-angles

我正在处理动作捕捉数据,我想在处理中进行“蒙皮”。因此,基本上,我从数据中获得的每两个点都必须在其间添加一个 3D 对象(我现在将使用一个盒子,放置和旋转坐标是 3D 对象的中心)并旋转它,以便它在所有三个维度上与连接两点的向量对齐。

在这里,我们可以在左侧看到两点之间最初放置的框,在右侧看到现在正确旋转的框: 白色平行六面体的分割图像,未与图像左侧的红色对角线(左上到右下)对齐,并且白色平行六面体与图像右侧的红线对齐

我知道在处理中旋转对象的唯一方法是使用rotateX()、rotateY()、rotateZ()函数,它们使用欧拉角围绕全局(?)轴旋转对象。

现在我正在努力寻找一种正确计算这种旋转的方法。

我已经编写了一个用于计算两个向量之间的角度的函数:

float calcVectorAngle(PVector p1, PVector p2) {
    return acos((p1.dot(p2)) / (mag(p1.x, p1.y, p1.z) * mag(p2.x, p2.y, p2.z)));
}
Run Code Online (Sandbox Code Playgroud)

然后我尝试将向量(两点之间)与每个旋转轴之一的单位向量结合起来:

float x = calcVectorAngle(vector, new PVector(1,0,0));
float y = calcVectorAngle(vector, new PVector(0,1,0));
float z = calcVectorAngle(vector, new PVector(0,0,1));
Run Code Online (Sandbox Code Playgroud)

但是当我使用这些值旋转对象时,旋转完全关闭。

代码示例:

PVector p1;
PVector p2;
PVector boxSize = new PVector(500, 100, 100);

void setup() {
    size(1000,1000,P3D);
    p1 = new PVector(100, 100, 0);
    p2 = new PVector(900, 900, -1000);
}

void draw() {
    background(125);
    strokeWeight(2);
    stroke(255, 0, 0);

    pushMatrix();
    
    line(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);

    PVector midPoint = calcMidPoint(p1, p2);
    translate(midPoint.x, midPoint.y, midPoint.z);

    PVector rotation = calcRotation(p1, p2);
    rotateX(rotation.x);
    rotateY(rotation.y);
    rotateZ(rotation.z);

    box(boxSize.x, boxSize.y, boxSize.z);
    popMatrix();
    
}


PVector calcMidPoint(PVector p1, PVector p2) {
    return new PVector((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, (p1.z + p2.z) / 2);
}

PVector calcRotation(PVector p1, PVector p2) {
    PVector vector = new PVector();
    vector.sub(p2, p1, vector);
    float x = calcVectorAngle(vector, new PVector(1,0,0));
    float y = calcVectorAngle(vector, new PVector(0,1,0));
    float z = calcVectorAngle(vector, new PVector(0,0,1));
    return new PVector(x, y, z);
}

float calcVectorAngle(PVector p1, PVector p2) {
    return acos((p1.dot(p2)) / (mag(p1.x, p1.y, p1.z) * mag(p2.x, p2.y, p2.z)));
}
Run Code Online (Sandbox Code Playgroud)

现在我有点失落了。

Rab*_*d76 5

旋转轴是框的默认方向 (1, 0, 0) 与沿线方向 ( ) 的叉积p2 - p1
旋转角度是归一化方向向量的点积acos

PVector currentDirection = new PVector(1, 0, 0);
PVector newDirection = p2.copy().sub(p1).normalize(); 
    
PVector rotationAxis = currentDirection.cross(newDirection).normalize();
float rotationAngle = acos(currentDirection.dot(newDirection));
Run Code Online (Sandbox Code Playgroud)

将盒子绕轴旋转一定角度:

rotate(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
Run Code Online (Sandbox Code Playgroud)

完整示例:

PVector p1, p2;
PVector boxSize = new PVector(500, 100, 100);

void setup() {
    size(1000,1000,P3D);
    p1 = new PVector(100, 100, 0);
    p2 = new PVector(900, 900, -1000);
}

void draw() {
    background(125);
    strokeWeight(2);
    stroke(255, 0, 0);

    line(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);

    PVector midPoint = PVector.lerp(p1, p2, 0.5);
    PVector currentDirection = new PVector(1, 0, 0);
    PVector newDirection = p2.copy().sub(p1).normalize(); 
    PVector rotationAxis = currentDirection.cross(newDirection).normalize();
    float rotationAngle = acos(currentDirection.dot(newDirection));

    pushMatrix();
    translate(midPoint.x, midPoint.y, midPoint.z);
    rotate(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
    box(boxSize.x, boxSize.y, boxSize.z);
    popMatrix();
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案!(+1)。希望小修改没问题。遗憾的是 [`rotate()` 处理参考](https://processing.org/reference/rotate_.html) 没有列出角度轴覆盖,但它是[那里](https://github.com/processing/ processing/blob/a6e0e227a948e7e2dc042c04504d6f5b8cf0c1a6/core/src/processing/opengl/PGraphicsOpenGL.java#L3846) 并通过 [PMatrix3D](https://processing.github.io/processing-javadocs/core/processing/core 在较低级别上提供支持/PMatrix3D.html#rotate-float-float-float-float-) ([src](https://github.com/processing/processing/blob/master/core/src/processing/core/PMatrix3D.java#L244 )) (2认同)