如何移动 3D 盒子以保持在旋转平面上?
Posted
技术标签:
【中文标题】如何移动 3D 盒子以保持在旋转平面上?【英文标题】:How can I move a 3D box in order to stay on a rotating plane? 【发布时间】: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);
但这些似乎都不起作用。
为了使盒子相应地移动到平面,数学关系是什么?
【问题讨论】:
【参考方案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 & modelMatrix, const glm::vec3 & color)
以上是关于如何移动 3D 盒子以保持在旋转平面上?的主要内容,如果未能解决你的问题,请参考以下文章