c++ - 如何正确旋转这些房屋?
问题描述
我正在使用 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();
}
解决方案
让我们首先回答为什么你的背景仍然是黑色的更简单的问题:你根本就没有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 次,就完成了。
推荐阅读
- c++ - C++ 模板不识别数据类型
- android - 如何收听导航组件中的片段变化?
- java - 优化图片的显示
- regex - 正则表达式从字符串中提取名称
- python - 使用 lxml 解析文章内容时缺少一些文本,这是什么问题?
- java - 尝试制作 Java Web Scraper
- javascript - 通过 Id 和 Xpath 进行点击的 Javascript 代码执行速度非常快
- c# - 如何从 AutomationElement 获取原始元素
- javascript - 在打字稿中,如何使用 es6 语法导入具有默认导出的纯 javascript 文件?
- cucumber - 如何从 Cucumber Scenario 文件中访问 TestNg 参数(动态更改场景名称)