如何抵消要在局部轴上应用的全局方向力?

joh*_*doe 5 javascript algorithm quaternions

我想对物体的局部轴施加向前力,但我使用的引擎只允许我在全局轴上施加力.

我可以作为四元数访问对象的全局旋转.然而,我不熟悉使用quats(通常未经过高级数学训练).是否有足够的信息来抵消沿所需轴施加的力?怎么样?

例如,为了全球化,我会这样做:

this.entity.rigidbody.applyForce(0, 0, 5);
Run Code Online (Sandbox Code Playgroud)

但为了保持沿物体的局部轴施加力,我需要根据物体的旋转量子以轴的不同方式分配施加的力,例如:

w:0.5785385966300964
x:0
y:-0.815654993057251
z:0
Run Code Online (Sandbox Code Playgroud)

我已经研究了四元数试图解决这个问题,但观看一个关于它们是什么以及为什么它们被使用的视频并没有帮助我弄清楚如何与它们实际合作甚至开始弄清楚如何应用所需的偏移量这里.

到目前为止我尝试过的是对如何做到这一点的猜测,但这是错误的:

Math.degrees = function(radians) {
    return radians * 180 / Math.PI;
};

//converted this from a python func on wikipedia, 
//not sure if it's working properly or not
function convertQuatToEuler(w, x, y, z){ 
    ysqr = y * y;
    t0 = 2 * (w * x + y * z);
    t1 = 1 - 2 * (x * x + ysqr);
    X = Math.degrees(Math.atan2(t0, t1));
    t2 = 2 * (w * y - z * x);
    t2 = (t2 >= 1) ? 1 : t2;
    t2 = (t2 < -1) ? -1 : t2;
    Y = Math.degrees(Math.asin(t2));
    t3 = 2 * (w * z + x * y);
    t4 = 1 - 2 * (ysqr + z * z);
    Z = Math.degrees(Math.atan2(t3, t4));
    console.log('converted', {w, x, y, z}, 'to', {X, Y, Z});
    return {X, Y, Z};
}

function applyGlobalShift(x, y, z, quat) {
    var euler = convertQuatToEuler(quat.w, quat.x, quat.y, quat.z);
    x = x - euler.X; // total guess
    y = y - euler.Y; // total guess
    z = z - euler.Z; // total guess
    console.log('converted', quat, 'to', [x, y, z]);
    return [x, y, z];
}

// represents the entity's current local rotation in space
var quat = {
    w:0.6310858726501465,
    x:0,
    y:-0.7757129669189453,
    z:0
}

console.log(applyGlobalShift(-5, 0, 0, quat));
Run Code Online (Sandbox Code Playgroud)

不要嘲笑我如何计算偏移量的可怕猜测:PI知道它甚至不是很接近,但我在数学上非常糟糕

Evi*_*Tak 7

四元数用于替代欧拉角.因此,你的方法无法实现其目的.而不是试图使用euler角度,征收四元数的属性.

  1. 四元数有4个组件,3个向量组件和一个标量组件.

    q = x*i + y*j + z*k + w
    
    Run Code Online (Sandbox Code Playgroud)

    因此,四元数具有矢量部分x*i + y*j + z*k和标量部分w.因此,向量是具有零标量或实数分量的四元数.

  2. 重要的是要注意,向量乘以四元数是另一个向量.这可以通过使用四元数基元的乘法规则(左侧作为读者的练习)轻松证明.

  3. 四元数的倒数只是它的共轭除以其大小.四元数的共轭w + (x*i + y*j + z*k)是简单的w - (x*i + y*j + z*k),其大小是sqrt(x*x + y*y + z*z + w*w).

矢量的旋转简单地是通过围绕轴旋转该矢量而获得的矢量.四元数旋转表示如图这样的角度轴旋转这里.

载体v可以是围绕轴线并通过旋转四元数表示的角度旋转q通过缀合 v通过q.换一种说法,

v' = q * v * inverse(q)
Run Code Online (Sandbox Code Playgroud)

v'旋转矢量在哪里并且q * v * inverse(q)共轭操作.

由于四元数表示旋转,因此可以合理地假设其幅度为1,使得inverse(q) = q*其中q*的共轭位于何处q.

上分离q成实部s和载体部分u和简化操作的四元数(如所示精美此处),

v' = 2 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2 * s * cross(u, v)
Run Code Online (Sandbox Code Playgroud)

dot返回两个向量的点积和cross返回两个向量的积.

将上面的内容放入(伪)代码中,

function rotate(v: vector3, q: quaternion4) -> vector3 {
    u = vector3(q.x, q.y, q.z)
    s = q.w
    return 2 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2 * s * cross(u, v)
}
Run Code Online (Sandbox Code Playgroud)

现在我们知道如何使用四元数旋转矢量,我们可以使用世界(全局)旋转四元数来通过将局部方向与旋转四元数相结合来找到局部方向的相应世界方向(或轴).

本地前向轴始终由0*i + 0*j + 1*k.给出.因此,要找到对象的世界前向轴,必须将向量(0, 0, 1)与世界旋转四元数共轭.

使用上面定义的函数,前进轴变为

forward = rotate(vector3(0, 0, 1), rotationQuaternion)
Run Code Online (Sandbox Code Playgroud)

现在您拥有世界前进轴,沿着它施加的力将仅仅是世界前轴的标量倍数.