【问题标题】:How can I move a 3D box in order to stay on a rotating plane?如何移动 3D 盒子以保持在旋转平面上?
【发布时间】:2019-01-13 10:33:08
【问题描述】:

我有一个旋转平面和一个盒子。当飞机旋转并倾斜一个角度时,我希望盒子保持在飞机上的相同位置。

Here平面没有倾斜,

here 飞机倾斜时,

但盒子不跟随平面向下。

在每次更新时,我都会渲染该框,并通过glm::translate 中的给定vec3 对其进行翻译:

{
    glm::mat4 modelMatrix = glm::mat4(1);
    modelMatrix = glm::translate(modelMatrix, glm::vec3(boxOX, boxOY, boxOZ));
    modelMatrix = glm::rotate(modelMatrix, RADIANS(anglePlaneOX), glm::vec3(1, 0, 0));
    modelMatrix = glm::rotate(modelMatrix, RADIANS(anglePlaneOY), glm::vec3(0, 1, 0));
    modelMatrix = glm::rotate(modelMatrix, RADIANS(anglePlaneOZ), glm::vec3(0, 0, 1));
    modelMatrix = glm::scale(modelMatrix, glm::vec3(0.2f));
    RenderSimpleMesh(meshes["box"], shaders["ShaderLab8"], modelMatrix, glm::vec3(1, 0, 0));
}

飞机通过按WASD键移动:

    if (window->KeyHold(GLFW_KEY_W) && (anglePlaneOX > -90.0f)) {
        anglePlaneOX -= deltaTime * DELTA_SLOPE;
    }
    if (window->KeyHold(GLFW_KEY_S) && (anglePlaneOX < 90.0f)) {
        anglePlaneOX += deltaTime * DELTA_SLOPE;
    }
    if (window->KeyHold(GLFW_KEY_D) && (anglePlaneOZ > -90.0f)) {
        anglePlaneOZ -= deltaTime * DELTA_SLOPE;
    }
    if (window->KeyHold(GLFW_KEY_A) && (anglePlaneOZ < 90.0f)) {
        anglePlaneOZ += deltaTime * DELTA_SLOPE;
    }

我尝试了以下

按A键时:

boxOY += deltaTime * (1 - (float)cos((double)anglePlaneOZ * PI / 180));

当按下 W 键时:

boxOX -= deltaTime * sinf(anglePlaneOX * PI / 180);

但这些似乎都不起作用。

为了使盒子相应地移动到平面,数学关系是什么?

【问题讨论】:

    标签: c++ opengl glm-math coordinate-transformation


    【解决方案1】:

    您必须在旋转“之前”进行翻译:

    glm::mat4 modelMatrix = glm::mat4(1);  
    

    modelMatrix = glm::translate(modelMatrix, glm::vec3(boxOX, boxOY, boxOZ));

    modelMatrix = glm::rotate(modelMatrix, RADIANS(anglePlaneOX), glm::vec3(1, 0, 0));  
    modelMatrix = glm::rotate(modelMatrix, RADIANS(anglePlaneOY), glm::vec3(0, 1, 0));  
    modelMatrix = glm::rotate(modelMatrix, RADIANS(anglePlaneOZ), glm::vec3(0, 0, 1));
    
    modelMatrix = glm::translate(modelMatrix, glm::vec3(boxOX, boxOY, boxOZ)); //  translate here
    
    modelMatrix = glm::scale(modelMatrix, glm::vec3(0.2f));
    RenderSimpleMesh(meshes["box"], shaders["ShaderLab8"], modelMatrix, glm::vec3(1, 0, 0));  
    

    解释:

    翻译矩阵如下所示:

    glm::mat4 translate;
    
    translate[0] : ( 1,  0,  0,  0 )
    translate[1] : ( 0,  1,  0,  0 )
    translate[2] : ( 0,  0,  1,  0 )
    translate[3] : ( tx, ty, tz, 1 )
    

    围绕 Y 轴的旋转矩阵如下所示:

    mat4  rotate;
    float angle;
    
    rotate[0] : ( cos(angle),  0, sin(angle), 0 )
    rotate[1] : ( 0,           1, 0,          0 )
    rotate[2] : ( -sin(angle), 0, cos(angle), 0 )
    rotate[3] : ( 0,           0, 0,          1 ) 
    

    translate * rotate 的结果是这样的:

    model[0] : ( cos(angle),  0,  sin(angle), 0 )
    model[1] : ( 0,           1,  0,          0 )
    model[2] : ( -sin(angle), 0,  cos(angle), 0 )
    model[3] : ( tx,          ty, tz,         1 )
    

    注意,rotate * translate 的结果是:

    model[0] : ( cos(angle),                     0,   sin(angle),                     0 )
    model[1] : ( 0,                              1,   0,                              0 )
    model[2] : ( -sin(angle),                    0,   cos(angle),                     0 )
    model[3] : ( cos(angle)*tx - sin(angle)*tx,  ty,  sin(angle)*tz + cos(angle)*tz,  1 )
    

    【讨论】:

    • 这真的很有帮助,谢谢。但是,当飞机向下倾斜超过 45 度时(imgur.com/a/uydhjIy),盒子似乎落在了飞机上,并且在向上倾斜超过 45 度时保持在“上方”。 (imgur.com/a/3921x0U)。按A键时使用的公式为:boxOX -= deltaTime * (float)sinf(anglePlaneOZ * PI / 180);boxOY += deltaTime * (1 - (float)cos((double)anglePlaneOZ * PI / 180));
    • 立方体网格的中心必须在 (0, 0, 0) 并且立方体的位置必须完全由 (boxOX, boxOY, boxOZ) 定义
    • @DanBrezeanu 最后一个参数是RenderSimpleMesh的盒子位置吗?将其更改为 0,0,0,并使用矩阵平移来调整位置。
    • @immibis 不,最后一个参数是颜色。语法如下void RenderSimpleMesh(Mesh *mesh, Shader *shader, const glm::mat4 &amp; modelMatrix, const glm::vec3 &amp; color)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 2013-07-29
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多