为什么在尝试旋转这个立方体时我的屏幕会闪烁?

Why does my screen flicker when trying to rotate this cube?

#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <stdio.h>
#include <OpenGL/gl.h>
#include <string.h>
using namespace std;


    //Screen dimension constants
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;


bool SetOpenGLAttributes()
{

    // SDL_GL_CONTEXT_CORE gives us only the newer version, deprecated functions are disabled
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);


    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    return true;
}



    int main( int argc, char* args[] )
    {

        SDL_Window* window = NULL;

        //Initialize SDL
        if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
        {
            printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        }
        else
        {
            //Create window
            window = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL );
            if( window == NULL )
            {
                printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
            }
            else
            {



                //creating new context
                SDL_GL_CreateContext(window);

                SetOpenGLAttributes();
                SDL_GL_SetSwapInterval(1);

                //cube front
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5, .5, -.5);
                glVertex3f(.5, .5, -.5);
                glVertex3f(.5, -.5, -.5);
                glVertex3f(-.5, -.5, -.5);
                glEnd();

                //cube top
                glBegin(GL_POLYGON);
                glColor3f(1.0,0.0,0.0);
                glVertex3f(-.5,.5,-.5);
                glVertex3f(.5, .5, -.5);
                glVertex3f(.5, .5, .5);
                glVertex3f(-.5, .5, .5);
                glEnd();

                //cube bottom
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5,-.5,-.5);
                glVertex3f(.5, -.5, -.5);
                glVertex3f(.5, -.5, .5);
                glVertex3f(-.5, -.5, .5);
                glEnd();

                //cube right
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(.5, -.5, -.5);
                glVertex3f(.5, -.5, .5);
                glVertex3f(.5, .5, .5);
                glVertex3f(.5, .5, -.5);
                glEnd();

                //cube left
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5, -.5, -.5);
                glVertex3f(-.5, .5, -.5);
                glVertex3f(-.5, .5, .5);
                glVertex3f(-.5, -.5, .5);
                glEnd();

                //cube back
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5, .5, .5);
                glVertex3f(-.5, -.5, .5);
                glVertex3f(.5, -.5, .5);
                glVertex3f(.5, .5, .5);
                glEnd();

                glFlush();

                SDL_GL_SwapWindow(window);

                bool running = true;
                while(running){
                    glRotatef(1, 1, 0, 0);
                    glFlush();
                    SDL_GL_SwapWindow(window);
                    SDL_Delay(100);

                }


            }
        }


        //Destroy window
        //SDL_DestroyWindow( window );

        //Quit SDL subsystems
        //SDL_Quit();

        return 0;
}

我正在学习openGL和SDL。我设法让 "cube" 显示出来,但它看起来只是一个红色矩形。我想旋转立方体以确保我的代码实际上是在制作立方体,但是当我旋转然后交换 windows 时,立方体只会闪烁。好像第二个buffer window只是黑色,但是再次切换的时候,还是一样的红色矩形。为什么我不能旋转我的立方体,为什么我的第二个缓冲区 window 是黑色的?

  • 每次通过 while(running) 循环清除帧缓冲区并重新绘制立方体。 现在,您只是在包含立方体的帧缓冲区和空白帧缓冲区之间交替。
  • OpenGL isn't a scenegraph
  • 如果您要使用 glBegin() 等已删除的功能,请不要请求 Core context。行不通了。
  • 使用 SDL_PollEvent()/SDL_WaitEvent() 启动事件循环以保持 OS 快乐

总计:

#include <cstdio>
#include <cstdlib>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main( int argc, char* args[] )
{
    SDL_Window* window = NULL;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        return EXIT_FAILURE;
    }

    //Create window
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    window = SDL_CreateWindow
        (
        "SDL Tutorial",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        SCREEN_WIDTH, SCREEN_HEIGHT,
        SDL_WINDOW_OPENGL
        );
    if( window == NULL )
    {
        printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        return EXIT_FAILURE;
    }

    //creating new context
    SDL_GLContext ctx = SDL_GL_CreateContext(window);
    SDL_GL_SetSwapInterval(1);

    bool running = true;
    while( running )
    {
        SDL_Event ev;
        while( SDL_PollEvent( &ev ) )
        {
            if( ( SDL_QUIT == ev.type ) ||
                ( SDL_KEYDOWN == ev.type && SDLK_ESCAPE == ev.key.keysym.sym ) )
            {
                running = false;
                break;
            }
        }

        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();

        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();

        static float angle = 0.0f;
        angle += 1;
        glRotatef( angle, 0.2, 0.3, 0.1 );

        //cube front
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5, .5, -.5);
        glVertex3f(.5, .5, -.5);
        glVertex3f(.5, -.5, -.5);
        glVertex3f(-.5, -.5, -.5);
        glEnd();

        //cube top
        glBegin(GL_POLYGON);
        glColor3f(1.0,0.0,0.0);
        glVertex3f(-.5,.5,-.5);
        glVertex3f(.5, .5, -.5);
        glVertex3f(.5, .5, .5);
        glVertex3f(-.5, .5, .5);
        glEnd();

        //cube bottom
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5,-.5,-.5);
        glVertex3f(.5, -.5, -.5);
        glVertex3f(.5, -.5, .5);
        glVertex3f(-.5, -.5, .5);
        glEnd();

        //cube right
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(.5, -.5, -.5);
        glVertex3f(.5, -.5, .5);
        glVertex3f(.5, .5, .5);
        glVertex3f(.5, .5, -.5);
        glEnd();

        //cube left
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5, -.5, -.5);
        glVertex3f(-.5, .5, -.5);
        glVertex3f(-.5, .5, .5);
        glVertex3f(-.5, -.5, .5);
        glEnd();

        //cube back
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5, .5, .5);
        glVertex3f(-.5, -.5, .5);
        glVertex3f(.5, -.5, .5);
        glVertex3f(.5, .5, .5);
        glEnd();

        SDL_GL_SwapWindow(window);
        SDL_Delay( 16 );
    }

    SDL_GL_DeleteContext(ctx);
    SDL_DestroyWindow( window );
    SDL_Quit();

    return 0;
}

您不能只绘制图像然后继续调用旋转并期望它旋转您之前渲染的所有内容。这不是它的工作原理。 OpenGL 本来可以按照这种方式工作,但事实并非如此。

您需要在渲染当前正在绘制的部分之前调用变换函数(旋转、缩放、平移);对于多对象场景(想想 2 个以上的立方体都在不同的位置并且 moving/spinning 彼此独立)你会重置-变换-绘制-变换-绘制-等等。把它想象成你在移动画笔,而不是你用来拍照的相机。

所以你应该在每一帧(在你的循环内)继续重新绘制那个形状,并且通常你应该在渲染之前每帧继续将视图重置为单位矩阵(或者 push/pop 矩阵,如果你是对此很满意)。

main loop:
    reset view
    render
    swap buffers

至于双缓冲...

无论何时绘制,您都在绘制缓冲区。您不会绘制到两个缓冲区,而是一次绘制到一个缓冲区。如果您使用双倍(或更多)缓冲,则在完全渲染完图像后交换缓冲区。您正在绘制的图像被交换到管道中以显示在您的显示器上,之前显示在您显示器上的图像现在是您的图像下一帧的绘图 space。现在在那个上画(可能在你画之前先擦掉它上面的所有东西,这就是 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 的目的),当你画完下一帧时,你再次交换它们。这就是你在循环中正在做的(或应该做的)。您一次只能在其中一张图像上绘图,但您会一直绘图、交换(在另一幅图像上绘图)、绘图、交换、绘图、交换等。

至于重置矩阵,请尝试 glLoadIdentity();。查看有关 glLoadIdentity 和矩阵模式 here 的问题以进一步阅读。在此处的特定实例中,只需在每个循环开始时调用 glLoadIdentity 就足够了,但是如果您打算进一步研究该主题,则应该掌握投影模式。

至于在你的情况下使用 glLoadIdentity,还记得我说过你应该继续旋转循环的每个实例,每一帧吗?请记住,循环的每次迭代通常都是按照您希望它在动画帧中的外观来绘制图像。在帧之间,您实际上是在重置以绘制新图片,即下一帧。想想 glLoadIdentity 就像艺术家将他的手拉回自己重新开始。如果你继续每帧旋转一次,它就会旋转得越来越多。与缩放和平移相同。现在我考虑一下,对于您的具体情况,您可能实际上想要它,但通常您不需要。例如,如果你继续平移到 (1,2,0) 并旋转 (0.5,0.5,0),"brush" 将在每一帧继续移动和旋转,你很少能得到结果你在期待那个。

关于 "resetting" 事情的另一说明:有时您可能需要 "reset" 当您还在画画的中间时。例如,绘制两个彼此无关的对象,您可能 glLoadIdentity 在绘制第一个对象后重置内容,以便在同一缓冲区上绘制第二个对象之前 "got your brush back in your hand in front of you" 。或者,如果您需要一种效果,无论距离如何,一个对象始终绘制在另一个对象之上,您可以 glClear 重置深度缓冲区。

查看这个旋转立方体的具体示例 here

下面那个例子的片段 - 注意它是如何从一些 "reset view" 类型代码开始的(有时你需要更多,这取决于你在做什么),然后转换(包括几次旋转) ,然后渲染,然后增加一个变量,该变量保存用于绘制旋转中使用的立方体的角度。

另请注意,在示例中,代码段只是一个函数体,但它可以是在主循环中调用的函数,或者函数体可以直接用作循环。

// Clear Screen And Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glLoadIdentity();

glTranslatef(0.0f, 0.0f,-7.0f); // Translate Into The Screen 7.0 Units
glRotatef(rotqube,0.0f,1.0f,0.0f);  // Rotate The cube around the Y axis
glRotatef(rotqube,1.0f,1.0f,1.0f);
glBegin(GL_QUADS);      // Draw The Cube Using quads
glColor3f(0.0f,1.0f,0.0f);  // Color Blue
glVertex3f( 1.0f, 1.0f,-1.0f);  // Top Right Of The Quad (Top)
glVertex3f(-1.0f, 1.0f,-1.0f);  // Top Left Of The Quad (Top)
glVertex3f(-1.0f, 1.0f, 1.0f);  // Bottom Left Of The Quad (Top)
glVertex3f( 1.0f, 1.0f, 1.0f);  // Bottom Right Of The Quad (Top)
glColor3f(1.0f,0.5f,0.0f);  // Color Orange
glVertex3f( 1.0f,-1.0f, 1.0f);  // Top Right Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f, 1.0f);  // Top Left Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f,-1.0f);  // Bottom Left Of The Quad (Bottom)
glVertex3f( 1.0f,-1.0f,-1.0f);  // Bottom Right Of The Quad (Bottom)
glColor3f(1.0f,0.0f,0.0f);  // Color Red    
glVertex3f( 1.0f, 1.0f, 1.0f);  // Top Right Of The Quad (Front)
glVertex3f(-1.0f, 1.0f, 1.0f);  // Top Left Of The Quad (Front)
glVertex3f(-1.0f,-1.0f, 1.0f);  // Bottom Left Of The Quad (Front)
glVertex3f( 1.0f,-1.0f, 1.0f);  // Bottom Right Of The Quad (Front)
glColor3f(1.0f,1.0f,0.0f);  // Color Yellow
glVertex3f( 1.0f,-1.0f,-1.0f);  // Top Right Of The Quad (Back)
glVertex3f(-1.0f,-1.0f,-1.0f);  // Top Left Of The Quad (Back)
glVertex3f(-1.0f, 1.0f,-1.0f);  // Bottom Left Of The Quad (Back)
glVertex3f( 1.0f, 1.0f,-1.0f);  // Bottom Right Of The Quad (Back)
glColor3f(0.0f,0.0f,1.0f);  // Color Blue
glVertex3f(-1.0f, 1.0f, 1.0f);  // Top Right Of The Quad (Left)
glVertex3f(-1.0f, 1.0f,-1.0f);  // Top Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f,-1.0f);  // Bottom Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f, 1.0f);  // Bottom Right Of The Quad (Left)
glColor3f(1.0f,0.0f,1.0f);  // Color Violet
glVertex3f( 1.0f, 1.0f,-1.0f);  // Top Right Of The Quad (Right)
glVertex3f( 1.0f, 1.0f, 1.0f);  // Top Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f, 1.0f);  // Bottom Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f,-1.0f);  // Bottom Right Of The Quad (Right)
glEnd();            // End Drawing The Cube

rotqube +=0.9f;         // Increase Angle