【问题标题】:Listen to keyboard input in GLFW and modify objects accordingly?聆听 GLFW 中的键盘输入并相应地修改对象?
【发布时间】:2021-06-03 06:14:52
【问题描述】:

我正在尝试在 cpp 中绘制一个金字塔。我已经设法实现了输入处理程序和渲染功能,但似乎我的金字塔上的任何更改都被初始状态覆盖了。 (也就是说,尽管能够接受输入并移动对象,但对象总是“跳回”到它的初始位置和角度)

我的代码是这样的:

void listenToKeyboard(GLFWwindow* w) {
    if (glfwGetKey(w, GLFW_KEY_F) == GLFW_PRESS) {
        glTranslatef(0.0f, 0.1f, 0.0f); // move forward
        posArr1[2] -= 0.1f;
    }

void drawPyramid(GLfloat p[][3]) {
    glBegin(GL_TRIANGLES);
    // some drawing functions like glVertex3f
    ...codes...
    glEnd();
}

void renderPyramidWithInput(GLFWwindow* w, GLfloat p[][3]) {
    glPushMatrix();
    listenToKeyboard(w);
    drawPyramid(p);
    glPopMatrix();
}

int main() {
    // some initialization
    ...codes...

    while (!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);

        renderPyramidWithInput(window, p);

        glfwSwapBuffers(window);                      
        glfwPollEvents();
    }

    // other useful functions
    ...codes...
}

(我需要使用glPushMatrixglPopMatrix来拥有多个可控对象,所以在这里)

【问题讨论】:

  • OpenGL 不是场景图,OpenGL 不知道对象,OpenGL 一次只绘制一个点、线或三角形。 glTranslate / glRotate 等(旧固定函数管道的一部分)不操作对象,它们只是改变控制屏幕上最终位置的转换矩阵。 glPushMatrix / glPopMatrix 允许构建转换层次结构。任何应该持久的东西,你都需要自己存储。固定功能管道也已过时。
  • @datenwolf 是的,我明白这一点,但问题是我对层次结构或管道等这些概念知之甚少。我试着看一些khronos的文档,比如glRotate,但是它们的描述太复杂了,而我的知识太少了。无论如何,如果我应该谷歌这个问题可以开始吗?
  • 谷歌搜索“场景图”。并尝试改变你的心智模式。自己回答:只给一支铅笔和一叠纸,如果您逐帧手动绘制动画,您将如何跟踪事物。因为归根结底,这就是 OpenGL 的全部内容:用于在数字画布上绘图的非常复杂的铅笔。
  • @datenwolf 谢谢你的帮助,我会检查一下:)

标签: c++ opengl glfw opengl-compat


【解决方案1】:

我自己设法解决了这个问题。基本上我的代码......很好,但它们确实需要一些改进。 listenToKeyboard 可以修改为:

void listenToKeyboard(GLFWwindow* w) {
    if (glfwGetKey(w, GLFW_KEY_F) == GLFW_PRESS) {
        posArr[0] -= 0.1f;
    }

   ...other useful codes...

结合全局数组posArr

// {deltaX, deltaY, deltaZ}
GLfloat posArr[3] = {0.0f, 0.0f, 0.0f};

可以在renderPyramidWithInput访问

void renderPyramidWithInput(GLFWwindow* w, GLfloat p[][3]) {
    glPushMatrix();
    listenToKeyboard(w);
    glTranslatef(posArr[0], posArr[1], posArr[2]); // move in three directions;
    drawPyramid(p);
    glPopMatrix();
}

正如@datenwolf 和@user253751 所提到的,OpenGL“什么都不记得”,因此可以合理地将位置和其他所需数据保存在某处(此处为posArr)。

同样,可以定义另一个数组angleArr 以类似的方式存储角度:

// {xAngle, yAngle, zAngle}
GLfloat angleArr[3] = {0.0f, 0.0f, 0.0f};

然后使用

访问它
glRotatef(angleArr[0], 1.0f, 0.0f, 0.0f);
glRotatef(angleArr[1], 0.0f, 1.0f, 0.0f);
glRotatef(angleArr[2], 0.0f, 0.0f, 1.0f);

这些代码可能不是最好的解决方案(很有可能不是),但至少它们以我期望的方式工作。

这实际上是非常基本的,但如果一个人不满足先决条件,可能会非常令人沮丧,所以...我把它留在这里,以防其他学习者发现它有用。

【讨论】:

    【解决方案2】:

    OpenGL 不记得从一帧到另一帧的任何内容。

    glPushMatrix 保存当前的渲染位置(基本上),glPopMatrix 回到保存的位置。它不记得“哦,我上次调用drawPyramid时位置在那边,我最好再次使用那个位置”。不,它只记住当前位置。

    glTranslatef 更新当前渲染位置,但每帧都从头开始。

    所有这些“渲染位置”(也称为矩阵堆栈)都是为了帮助您管理绘制对象的位置,但它不会为下一帧存储任何内容。

    如果要存储金字塔的位置,请创建一个变量。然后,使 F 键更新变量。当您渲染金字塔时,您会从变量中获取位置,并将该位置传递给 glTranslatef。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-05
      • 2011-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-08
      相关资源
      最近更新 更多