如何在openGL中正确显示球体

时间:2014-04-15 18:54:07

标签: c++ opengl glut

我不太了解openGL / glut,但我在成功之前已经使用它来处理2D中的一些非常简单的事情。 现在我希望能够在3D中绘制球体。我正在尝试模拟粒子碰撞,所以我真正需要在图形端做的就是绘制球体。 这是我的失败尝试

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;
}

希望我的所有问题都源于一个非常基本的错误...... 出于某种原因,这会产生一个椭圆形。而且,虽然椭圆形相当大(可能大约是屏幕宽度和高度的1/8),但如果我将半径降低到0.73它会消失,我猜测它因为它太小而无法看到。 我怎么能这样做,这个球体会像你期望的那样显示圆形,所以我可以看到在给定体积中发生的所有事情,例如一个10x10x10的盒子,就像你站在旁边一样一盒飞来飞去并窥视它的粒子,或者是一个合理的近似值。现在很难说出我到底在看什么(我知道我站在1,1,1看着原点,但很难准确掌握我所看到的) 此外,偶尔当我运行它时,整个屏幕只是黑色。然后,当我清理并建立并再次运行时,它很好。这不是一个非常令人担忧的问题,但令人讨厌,我很想知道发生了什么。 此外,当切片和堆叠的数量较少时,如果半径很大,它看起来会很好,但是当半径很小时会变得非常扭曲,我觉得这很奇怪......

1 个答案:

答案 0 :(得分:1)

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

Image

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

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

主要

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);

现在设置要在50毫秒内调用的timerProc函数。

    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;
}