首页 > 解决方案 > 如何正确旋转这些房屋?

问题描述

我正在使用 C++、OpenGL 和 glut。我正在尝试制作 5 个像这样正确旋转的房屋:

在此处输入图像描述

但是,每当我尝试实现该glRotatef功能时,我似乎都无法获得正确的坐标,或者我的代码中某处出现了问题。另外,我把背景色设置为白色,但还是全黑,怎么回事?现在我将房屋设置为白色以应对这种情况。这是我的代码:

#include <GL/glut.h>

typedef int vert2D[2]; 

void initialize()
{
    glClearColor(1.0, 1.0, 1.0, 0); 
    glMatrixMode(GL_PROJECTION); 

    glLoadIdentity(); 
    gluOrtho2D(10.0, 215.0, 0.0, 250.0);  

    glMatrixMode(GL_MODELVIEW);
}

void drawHouse(vert2D* sq, vert2D* tri)
{
    glColor3f(1.0, 1.0, 1.0); 

    glBegin(GL_LINE_LOOP);
    glVertex2iv(sq[0]);
    glVertex2iv(sq[1]);
    glVertex2iv(sq[2]);
    glVertex2iv(sq[3]);
    glEnd();

    glBegin(GL_LINE_LOOP);
    glVertex2iv(tri[0]);
    glVertex2iv(tri[1]);
    glVertex2iv(tri[2]);
    glEnd();
}

void render()
{
    vert2D sqPts[4] = { {115, 150}, {115, 125}, {100,125}, {100,150} };
    vert2D triPts[3] = { {120, 150}, {95,150}, {108,160} };

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glMatrixMode(GL_MODELVIEW);

    drawHouse(sqPts, triPts);
    glPushMatrix();
    glTranslatef(1.0, 0.0, 0.0);

    glRotatef(-10.0, 0.0, 0.0, 1.0); 
    drawHouse(sqPts, triPts); 
    glTranslatef(1.0, 0.0, 0.0); 

    glRotatef(-10.0, 0.0, 0.0, -1.0);
    drawHouse(sqPts, triPts);
    glPopMatrix();
    glPushMatrix();
    glTranslatef(-1.0, 0.0, 0.0);

    glRotatef(10.0, 0.0, 0.0, 1.0); 
    drawHouse(sqPts, triPts); 
    glTranslatef(-1.0, 0.0, 0.0); 

    glRotatef(10.0, 0.0, 0.0, 1.0); 
    drawHouse(sqPts, triPts); 
    glPopMatrix(); 

    glFlush(); 
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);           
    glutInitWindowPosition(100, 100); 
    glutInitWindowSize(640, 480); 
    glutCreateWindow("TestMeOut"); 

    initialize();
    glutDisplayFunc(render); 

    glutMainLoop();
}

标签: c++openglglut

解决方案


让我们首先回答为什么你的背景仍然是黑色的更简单的问题:你根本就没有glClear(GL_COLOR_BUFFER_BIT)颜色缓冲。你告诉 OpenGL “嘿,下次我用(至少)GL_COLOR_BUFFER_BIT 调用 glClear 时,我希望将颜色缓冲区清除为白色。” 但您从未真正清除缓冲区。

现在,我们如何绘制具有正确位置和方向的房屋:

您应该首先在适合在进一步步骤中转换它们的合理局部坐标系/框架中定义房屋的顶点。目前,根据您定义房屋顶点的方式,很难对它们进行任何变换(主要是因为像旋转这样的线性变换总是相对于坐标系的原点)。

所以,让我们改变它。让我们将房屋的原点 (0, 0) 定义为房屋底部/基线的中心。我们还定义你房子的四边形的边长为 10 个“单位”:

vert2D sqPts[4] = {
    {-5, 0}, // <- bottom left
    { 5, 0}, // <- bottom right
    { 5,10}, // <- top right
    {-5,10}  // <- top left
};

现在,对于房子的屋顶,我们假设相同的坐标系((0, 0) 是房子底线/底线的中心),所以我们从 Y=10 开始:

vert2D triPts[3] = {
    {-6, 10}, // <- left
    { 6, 10}, // <- right
    { 0, 12}  // <- top
};

接下来,我们需要定义 (0, 0) 在我们的“世界”中的位置,可以这么说。一种定义可能是: (0, 0) 应该是视口/屏幕底部的中心,并且视口应该有 100 个“单位”的长度。现在,当视口的宽度不等于视口的高度时,我们并不关心正确的纵横比。这可以稍后添加。

从剪辑空间坐标系开始,我们可以通过使用这些变换将这个剪辑空间转换为我们自己的“世界空间”:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(0.0, -1.0, 0.0); // <- move the origin down to the bottom of the viewport
glScalef(1.0 / 50.0, 1.0 / 50.0, 1.0); // <- "scale down" the clip space to cover more space in the viewport

现在,上面的部分基本上gluOrtho2D()也是如此,但在这里突出显示实际的坐标系转换步骤很有用。

现在我们定义了房屋的局部坐标系和“世界”坐标系,我们可以旋转和平移世界坐标系,使房屋出现在我们世界中正确的位置和方向。

为了画出 5 个房子,我们只需要一个 for 循环:

glMatrixMode(GL_MODELVIEW);
for (int i = -2; i <= 2; i++) { // <- 5 steps
  glPushMatrix();
  glRotatef(i * 20.0, 0.0, 0.0, 1.0);
  glTranslatef(0.0, 50.0, 0.0);
  drawHouse(sqPts, triPts);
  glPopMatrix();
}

因此,从我们的世界坐标系开始,我们通过围绕其原点 (0, 0) 旋转适当的量来转换它,以使带有索引的房屋具有i正确的旋转,然后将坐标系沿其平移 50 个单位(现在已旋转) Y 轴。

这两个转换现在将导致在所需位置绘制房屋。因此,以不同的旋转角度总共重复 5 次,就完成了。


推荐阅读