如何在openGL中正确显示球体

How to display a sphere correctly in openGL

本文关键字:显示 openGL      更新时间:2023-10-16

我对openGL/glust了解不多,但我以前曾成功地将其用于2D中一些非常简单的事情。现在我想能够在三维中绘制球体。我正在尝试模拟粒子碰撞,所以在图形端我真正需要做的就是绘制球体。这是我失败的尝试

void renderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
            // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);
    glutSwapBuffers();
}
void timerProc(int arg)
{
    glutTimerFunc(50,timerProc,0);
    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glColor3f(0.0,0.0,0.0);  //color = black
    glPushMatrix();
        glTranslated(0,0,0);
        glutSolidSphere(.74, 500, 500);
    glPopMatrix();
    glutSwapBuffers();
}
int main(int argc, char **argv)
{
    srand(time(NULL));
    init();
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50,30);
    glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)-80,glutGet(GLUT_SCREEN_HEIGHT)-60);
    mainWindow=glutCreateWindow("New Window"); //global variable
    WIDTH=glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT=glutGet(GLUT_WINDOW_HEIGHT); //global variable
    glutDisplayFunc(renderScene);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glutTimerFunc(50,timerProc,0);
    glutMainLoop();
    return 0;
}

希望我所有的问题都源于一个非常基本的错误。。。出于某种原因,这会创建一个椭圆形。而且,尽管椭圆很大(可能是屏幕的八分之一宽和高),但如果我把半径降低到.73,它就会消失,我猜是因为它太小了,看不见。我该如何制作它,使这个球体像你所期望的那样呈现圆形,这样我就可以看到给定体积中发生的一切,比如一个10x10x10的盒子,就像你站在一个四处飞行的粒子盒子旁边凝视它一样,或者一个合理的近似值。现在很难说我到底在看什么(我知道我站在1,1,1,看着原点,但很难准确把握我看到的是什么)此外,偶尔当我运行它时,整个屏幕都是黑色的。然后,当我清理、构建并再次运行时,一切都很好。这不是一个很大的问题,但很烦人,我很想了解发生了什么。此外,当切片和堆栈的数量较低时,如果半径较大,它看起来会很好,但当半径较小时,它会变得非常扭曲,我认为这很奇怪。。。

这里的主要问题是Z剪裁。场景的初始Z范围为(-1,1),因此您只能看到实际球体的一部分,通过更改其大小,您将超出Z范围。

图像

我在代码中看到了几个问题。掌握GLUT工作流程的实际工作方式是很好的。

让我们看看代码做错了什么。

Main

int main(int argc, char **argv)
{
    srand(time(NULL));
    init();
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 30);
    glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH) - 80, 
                       glutGet(GLUT_SCREEN_HEIGHT) - 60);
    mainWindow = glutCreateWindow("New Window"); //global variable
    WIDTH = glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT = glutGet(GLUT_WINDOW_HEIGHT); //global variable
    glutDisplayFunc(renderScene);

在这里定义显示功能。每当窗口内容必须无效时,都会调用它。在这种情况下,它只在开始时无效。renderScene函数并没有做任何了不起的事情,只是清除屏幕。所以一开始你会看到一个黑屏。

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

目前无需混合。你可以完全跳过那部分。

    glutTimerFunc(50, timerProc, 0);

现在,您将timerProc函数设置为在50毫秒内调用。

    glutMainLoop();

正如文档所述:glutMainLoop进入GLUT事件处理循环。在GLUT程序中,此例程最多应调用一次。一旦调用,此例程将永远不会返回。它将根据需要调用任何已注册的回调。

    return 0;
}

渲染场景

void renderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

这是唯一可以清除屏幕的地方。Timer Func不执行此操作。

    glLoadIdentity();

你正在重新设定矩阵。

    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);

设置矩阵。(精确地说是一个矩阵)

    glutSwapBuffers();

在不绘制任何内容的情况下,可以交换缓冲区。

}

每次必须重新绘制窗口帧时,都会调用场景渲染函数。

计时器

此功能确实依赖于renderScene首先清除的屏幕。void timerProc(int arg){glutTimerFunc(50,timerProc,0);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

这次没有清除。仅设置颜色。

    glColor3f(0.0, 0.0, 0.0);  //color = black
    glPushMatrix();
    glTranslated(0, 0, 0);
    glutSolidSphere(.74, 500, 500);
    glPopMatrix();
    glutSwapBuffers();
}

如何修复

只需设置矩阵即可。具有适当的Z范围。

void resetTransformations() {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1, 1, -1, 1, -1000, 1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);
}
void renderScene()
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Reset transformations
    resetTransformations();
    // Just to see some triangles
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glColor3f(0.0, 0.0, 0.0);  //color = black
    glPushMatrix();
    glTranslated(0, 0, 0);
    glutSolidSphere(0.74, 500, 500);
    glPopMatrix();
    glutSwapBuffers();
}
int main(int argc, char **argv)
{
    srand(time(NULL));
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 30);
    glutInitWindowSize(256, 256);
    mainWindow = glutCreateWindow("New Window"); //global variable
    WIDTH = glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT = glutGet(GLUT_WINDOW_HEIGHT); //global variable
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutMainLoop();
    return 0;
}