Cannon.js: 求骰子的边是用四元数

Cannon.js: Finding the side of a dice is using quaternions

Here is a fiddle 使用我正在使用的一些代码。

我正在掷骰子,不是随机的,但稍后会添加。但是现在我很难确定骰子落在了哪一边。

在 JS 的第 352 行,在 tick 函数中我试图找出骰子落在哪一边。我已经尝试了几种查看四元数的方法,但它从来没有给我预期的结果。我敢肯定这是因为我对四元数一无所知。因此,我们将不胜感激。

function tick() {
    world.step(timeStep);

    drawScene();

    if(cubeBody.velocity.norm() < 0.001) {
        var direction = cubeBody.quaternion.toAxisAngle()[0];

        console.log(direction);

        if (direction.x < 0.1 && direction.x > -0.1 &&
            direction.y < 0.1 && direction.y > -0.1) {
            console.log("side 1 or 6");
        } else if (direction.y > 0.1 &&
            direction.z < 0.1 && direction.z > -0.1) {
            console.log("side 2");
        } else if (direction.y < -0.1 &&
            direction.z < 0.1 && direction.z > -0.1) {
            console.log("side 5");
        } else if (direction.x > 0.1 &&
            direction.z < 0.1 && direction.z > -0.1) {
            console.log("side 3");
        } else if (direction.x > 0.1 &&
            direction.z < 0.1 && direction.z > -0.1) {
            console.log("side 4");
        } else {
            console.log("we got trouble");
        }
    } else {
        requestAnimationFrame(tick);
    }

}

此代码稍后可能会使用 switch 或对象键结束,但现在为了帮助我 "visualize" 它,我把它当作一个可怕的 if 语句。抱歉。

我认为最简单的方法是创建 6 个样本点,一个用于骰子的每一面。这些样本点应该恰好位于每个面的中心。例如,如果您的骰子是一个从 (-1,-1,-1) 到 (1,1,1) 的立方体,则 (1,0,0) 是您骰子 "right" 面的中心,并且(-1,0,0) 是骰子 "left" 面的中心。

你的骰子落地后,得到骰子的四元数值。通过四元数变换每个样本点。遍历每个样本点,你的上轴值最大的样本点就是骰子落地的那一侧。

您可以使用立方体的六个局部轴(+x、-x、+y、-y、+z、-z)并使用 [=12= 将它们变换到世界 space ],并检查这些向量中的哪一个是 "pointing up the most".

但是,如果将世界向上矢量转换为局部主体 space,并检查该矢量在局部指向哪个方向,您将获得更好的性能。

在你的游戏循环之前:

var localUp = new CANNON.Vec3();
var inverseBodyOrientation = new CANNON.Quaternion();
var limit = Math.sin(Math.PI/4);

在您的游戏循环中:

// Transform the world up vector to local body space
localUp.set(0,1,0);
body.quaternion.inverse(inverseBodyOrientation);
inverseBodyOrientation.vmult(localUp, localUp);

// Check which side is up
if(localUp.x > limit){
    // Positive x is up
} else if(localUp.x < -limit){
    // Negative x is up
} else if(localUp.y > limit){
    // Positive y is up
} else if(localUp.y < -limit){
    // Negative y is up
} else if(localUp.z > limit){
    // Positive z is up
} else if(localUp.z < -limit){
    // Negative z is up
} else {
    // The box is not resting flat on the ground plane
}

选择limit使得局部向上矢量必须在半径为1的球体的顶部、底部、右、左、前和后切片内。请参见下图中的灰色区域.