본문 바로가기
전공/컴퓨터 그래픽스

프레임 버퍼(Frame Buffer Object)

by 임 낭 만 2023. 5. 28.

Frame Buffer Objects

  • OpenGL allows to read off the pixel data from the framebuffer, for example, to use them as an input for a second rendering pass
  • To this end, in addition to the original frame buffer (which is typically controlled by the window manager) a custom framebuffer object (FBO) is created and defined as a new render target (off-screen rendering)
  • An FBO may include the following 2D raster graphics: several color buffer, depth buffer, stencil buffer, and accumulation buffer
더보기

OpenGL을 사용하면 프레임 버퍼에서 픽셀 데이터를 읽어내어 두 번째 렌더링 경로의 입력으로 사용할 수 있음.

이를 위해 원래 프레임 버퍼(일반적으로 윈도우 매니저에 의해 제어됨) 외에도 사용자 정의 프레임 버퍼 객체(FBO)가 생성되어 새로운 렌더 대상(화면 밖 렌더링)으로 정의됨.

FBO는 다음의 2D 래스터 그래픽을 포함할 수 있음: 여러 색상 버퍼, 깊이 버퍼, 스텐실 버퍼 및 축적 버퍼

Creating FrameBuffer Objects

  • An FBO can be generated with
glGenFramebuffers(1, &fboID);
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
  • The commands only produce an empty container that has no memory assigned for storing the pixel data
  • Pixel data storage can be provided by either textures or so-called "renderbuffer objects"
더보기

명령어는 픽셀 데이터를 저장하기 위한 메모리가 할당되지 않은 빈 컨테이너만 생성함.

픽셀 데이터 스토리지는 텍스처 또는 소위 "렌더 버퍼 객체"에 의해 제공될 수 있음.

2D Texture as a Data Storage

  • To use a texture as a pixel data memory, it must be generated and then passed to the FBO with glFramebuffer Texture2D( … )
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, texLevel, texFormat,
		inWidth, inHeight, inBorder, inFormat, inType, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, texLevel);
  • The second argument indicates for which buffer the texture should be used. Possible parameters are:
    GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHEMNT1, …,
    GL_DEPTH_ATTACHMENT or GL_STENCIL_ATTACHMENT
더보기

텍스처를 픽셀 데이터 메모리로 사용하려면 텍스처를 생성한 후 glFramebufferTexture2D(...)를 사용하여 FBO에 전달해야 함.

두 번째 인수는 텍스처를 사용할 버퍼를 나타냄. 가능한 매개 변수는 다음과 같음 ...

Renderbuffer Objects as a Data Storage

  • To use a renderbuffer object as a pixel data memory, it must be generated with glFramebufferRenderbuffer(..) and then passed with glFramebufferRenderbuffer(..) to the FBO
glGenRenderbuffers(1, &depthID);
glBindRenderbuffer(GL_RENDERBUFFER, depthID);
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, depthID);
  • The internal storage format format should be chosen such that it fits the purpose, that is:
    GL_RGBA or GL_COLOR_ATTACHMENT0 or GL_DEPTH_COMPONENT or GL_DEPTH_ATTACHMENT, etc.

Example: Rendering the Scene to a Texture

// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.
#include <GL/glew.h>
#include <GL/freeglut.h> // we use glut here as window manager
#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
class Renderer {
public:
    float t;
    int mode;
private:
    GLuint fboID;
    GLuint texID;
    GLuint depthID;
    int fboTexSize;
    int width;
    int height;
public:
    // constructor
    Renderer() : t(0.0), mode(1),
        fboID(0), texID(0), depthID(0),
        fboTexSize(512), width(0), height(0) {}
    // destructor
    ~Renderer() {
        if (texID != 0) glDeleteTextures(1, &texID);
        if (fboID != 0) glDeleteFramebuffers(1, &fboID);
        if (depthID != 0) glDeleteRenderbuffers(1, &depthID);
    }
public:
    void init() {
        glEnable(GL_DEPTH_TEST);
        // create a frame buffer object
        glGenFramebuffers(1, &fboID);
        // bind the frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, fboID);
        // Generate render texture
        glGenTextures(1, &texID);
        glBindTexture(GL_TEXTURE_2D, texID);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        int level = 0;
        glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, fboTexSize, fboTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        // Attach the texture to the fbo
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, level);
        if (!checkFramebufferStatus()) exit(1);
        // generate a renderbuffer for the depth buffer
        glGenRenderbuffers(1, &depthID);
        glBindRenderbuffer(GL_RENDERBUFFER, depthID);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fboTexSize, fboTexSize);
        // Attach the depth buffer to the fbo
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
            GL_RENDERBUFFER, depthID);
        if (!checkFramebufferStatus()) exit(1);
        // unbind texture
        glBindTexture(GL_TEXTURE_2D, 0);
        //unbind fbo
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    void resize(int w, int h) {
        width = w;
        height = h;
        changeViewport(w, h);
    }
    void display() {
        if (mode == 1) {
            // bind the fbo
            glBindFramebuffer(GL_FRAMEBUFFER, fboID);
            changeViewport(fboTexSize, fboTexSize);
        }
        glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        // render to attached fbo
        drawScene();

        if (mode == 1) {
            // unbind frame buffer
            glBindFramebuffer(GL_FRAMEBUFFER, 0);

            changeViewport(width, height);
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            // using first render pass result as texture
            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, texID);
            // second render pass
            drawScene();
            glDisable(GL_TEXTURE_2D);
        }
    }
private:
    void changeViewport(int w, int h) {
        glViewport(0, 0, w, h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(30.0, (float)w / (float)h, 0.1, 50.0);
    }
    void drawScene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        // set camera
        gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
        // draw scene
        glRotatef(t, 0.0f, 0.0f, 1.0f);
        drawTexturedCube();
    }
    bool checkFramebufferStatus() {
        GLenum status;
        status = (GLenum)glCheckFramebufferStatus(GL_FRAMEBUFFER);
        switch (status) {
        case GL_FRAMEBUFFER_COMPLETE:
            return true;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            printf("Framebuffer incomplete, incomplete attachment\n");
            return false;
        case GL_FRAMEBUFFER_UNSUPPORTED:
            printf("Unsupported framebuffer format\n");
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            printf("Framebuffer incomplete, missing attachment\n");
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
            printf("Framebuffer incomplete, missing draw buffer\n");
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
            printf("Framebuffer incomplete, missing read buffer\n");
            return false;
        }
        return false;
    }
    void drawTexturedCube() {
        glColor3f(1.0f, 0.0f, 0.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, -1.0f, 1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, 1.0f, 1.0f);
        glEnd();
        glColor3f(1.0f, 1.0f, 0.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, 1.0f, -1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
        glEnd();
        glColor3f(0.0f, 0.0f, 1.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(1.0f, 1.0f, 1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(1.0f, -1.0f, 1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, -1.0f, -1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, 1.0f, -1.0f);
        glEnd();
        glColor3f(1.0f, 1.0f, 1.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, 1.0f, -1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, 1.0f, 1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, 1.0f, -1.0f);
        glEnd();
        glColor3f(0.0f, 1.0f, 1.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, -1.0f, -1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, -1.0f, 1.0f);
        glEnd();
        glColor3f(0.0f, 1.0f, 0.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(1.0f, 1.0f, -1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(1.0f, -1.0f, -1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(-1.0f, 1.0f, -1.0f);
        glEnd();
    }
};
//this is a static pointer to a Renderer used in the glut callback functions
static Renderer* renderer;
//glut static callbacks start
static void glutResize(int w, int h)
{
    renderer->resize(w, h);
}
static void glutDisplay()
{
    renderer->display();
    glutSwapBuffers();
    glutReportErrors();
}
static void timer(int v)
{
    float offset = 0.25f;
    renderer->t += offset;
    glutDisplay();
    glutTimerFunc(unsigned(20), timer, ++v);
}
static void glutKeyboard(unsigned char key, int x, int y) {
    bool redraw = false;
    std::string modeStr;
    switch (key) {
    case '1':
        if (renderer->mode == 1) {
            renderer->mode = 0;
            modeStr = "first render pass result";
        }
        else {
            renderer->mode = 1;
            modeStr = "second render pass result";
        }
        redraw = true;
        break;
    }
    if (redraw) {
        glutDisplay();
        cout << modeStr << endl;
        glutSetWindowTitle(modeStr.c_str());
    }
}
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(320, 320);
    glutCreateWindow("Press 1 to toggle between first/second render pass");
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "Glew error: %s\n", glewGetErrorString(err));
    }
    glutDisplayFunc(glutDisplay);
    //glutIdleFunc(glutDisplay);
    glutReshapeFunc(glutResize);
    glutKeyboardFunc(glutKeyboard);

    renderer = new Renderer;
    renderer->init();

    glutTimerFunc(unsigned(20), timer, 0);
    glutMainLoop();
}

Example: Rendering the Depth Buffer into a Texture

// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.
#include <GL/glew.h>
#include <GL/freeglut.h> // we use glut here as window manager
#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
class Renderer {
public:
    float t;
    int mode;
private:
    GLuint fboID;
    GLuint depthID;
    int fboTexSize;
    int width;
    int height;
public:
    // constructor
    Renderer() : t(0.0), mode(1),
        fboID(0), depthID(0),
        fboTexSize(512), width(0), height(0) {}
    // destructor
    ~Renderer() {
        if (fboID != 0) glDeleteFramebuffers(1, &fboID);
        if (depthID != 0) glDeleteTextures(1, &depthID);
    }
public:
    void init() {
        glEnable(GL_DEPTH_TEST);
        // create a frame buffer object
        glGenFramebuffers(1, &fboID);
        // bind the frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, fboID);
        // Generate render texture
        // this is not used (but some drivers require it)
        GLuint texID;
        glGenTextures(1, &texID);
        glBindTexture(GL_TEXTURE_2D, texID);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        int level = 0;
        glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, fboTexSize, fboTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        // Attach the texture to the fbo
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, level);
        if (!checkFramebufferStatus()) exit(1);
        // Generate depth render texture
        glGenTextures(1, &depthID);
        glBindTexture(GL_TEXTURE_2D, depthID);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D, level, GL_DEPTH_COMPONENT, fboTexSize, fboTexSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        // Attach the texture to the fbo
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthID, level);
        if (!checkFramebufferStatus()) exit(1);
        // unbind texture
        glBindTexture(GL_TEXTURE_2D, 0);
        //unbind fbo
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    void resize(int w, int h) {
        width = w;
        height = h;
        changeViewport(w, h);
    }
    void display() {
        if (mode > 0) {
            // bind the fbo
            glBindFramebuffer(GL_FRAMEBUFFER, fboID);
            changeViewport(fboTexSize, fboTexSize);
        }
        else {
            changeViewport(width, height);
        }
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        // render to attached fbo
        drawScene();

        if (mode == 1) {
            // unbind frame buffer
            glBindFramebuffer(GL_FRAMEBUFFER, 0);

            changeViewportOrtho(width, height);

            // using first render pass result as texture
            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, depthID);
            //draw quad with depth texture
            glColor3f(1.0f, 0.0f, 0.0f);
            glBegin(GL_POLYGON);
            glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, -1.0f, 0.0f);
            glTexCoord2f(1.00f, 0.00f); glVertex3f(1.0f, -1.0f, 0.0f);
            glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, 1.0f, 0.0f);
            glTexCoord2f(0.00f, 1.00f); glVertex3f(-1.0f, 1.0f, 0.0f);
            glEnd();

            glDisable(GL_TEXTURE_2D);
        }
    }
private:
    void changeViewport(int w, int h) {
        glViewport(0, 0, w, h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(30.0, (float)w / (float)h, 7.0, 12.0);
    }
    void changeViewportOrtho(int w, int h) {
        float aspect = (float)w / (float)h;
        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0, -1.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }
    void drawScene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        // set camera
        gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
        // draw scene
        glRotatef(t, 0.0f, 0.0f, 1.0f);
        drawTexturedCube();
    }
    bool checkFramebufferStatus() {
        GLenum status;
        status = (GLenum)glCheckFramebufferStatus(GL_FRAMEBUFFER);
        switch (status) {
        case GL_FRAMEBUFFER_COMPLETE:
            return true;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            printf("Framebuffer incomplete, incomplete attachment\n");
            return false;
        case GL_FRAMEBUFFER_UNSUPPORTED:
            printf("Unsupported framebuffer format\n");
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            printf("Framebuffer incomplete, missing attachment\n");
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
            printf("Framebuffer incomplete, missing draw buffer\n");
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
            printf("Framebuffer incomplete, missing read buffer\n");
            return false;
        }
        return false;
    }
    void drawTexturedCube() {
        glColor3f(1.0f, 0.0f, 0.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, -1.0f, 1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, 1.0f, 1.0f);
        glEnd();
        glColor3f(1.0f, 1.0f, 0.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, 1.0f, -1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
        glEnd();
        glColor3f(0.0f, 0.0f, 1.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(1.0f, 1.0f, 1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(1.0f, -1.0f, 1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, -1.0f, -1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, 1.0f, -1.0f);
        glEnd();
        glColor3f(1.0f, 0.0f, 1.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, 1.0f, -1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, 1.0f, 1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, 1.0f, -1.0f);
        glEnd();
        glColor3f(0.0f, 1.0f, 1.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(1.0f, -1.0f, -1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(1.0f, -1.0f, 1.0f);
        glEnd();
        glColor3f(0.0f, 1.0f, 0.0f);
        glBegin(GL_POLYGON);
        glTexCoord2f(0.00f, 0.00f); glVertex3f(1.0f, 1.0f, -1.0f);
        glTexCoord2f(1.00f, 0.00f); glVertex3f(1.0f, -1.0f, -1.0f);
        glTexCoord2f(1.00f, 1.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
        glTexCoord2f(0.00f, 1.00f); glVertex3f(-1.0f, 1.0f, -1.0f);
        glEnd();
    }
};
//this is a static pointer to a Renderer used in the glut callback functions
static Renderer* renderer;
//glut static callbacks start
static void glutResize(int w, int h)
{
    renderer->resize(w, h);
}
static void glutDisplay()
{
    renderer->display();
    glutSwapBuffers();
    glutReportErrors();
}
static void timer(int v)
{
    float offset = 0.25f;
    renderer->t += offset;
    glutDisplay();
    glutTimerFunc(unsigned(20), timer, ++v);
}
static void glutKeyboard(unsigned char key, int x, int y) {
    bool redraw = false;
    std::string modeStr;
    switch (key) {
    case '1':
        if (renderer->mode == 1) {
            renderer->mode = 0;
            modeStr = "first render pass result";
        }
        else {
            renderer->mode = 1;
            modeStr = "second render pass result";
        }
        redraw = true;
        break;
    }
    if (redraw) {
        glutDisplay();
        cout << modeStr << endl;
        glutSetWindowTitle(modeStr.c_str());
    }
}
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(320, 320);

    glutCreateWindow("Press 1 to toggle between first/second render pass");
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "Glew error: %s\n", glewGetErrorString(err));
    }
    glutDisplayFunc(glutDisplay);
    //glutIdleFunc(glutDisplay);
    glutReshapeFunc(glutResize);
    glutKeyboardFunc(glutKeyboard);

    renderer = new Renderer;
    renderer->init();

    glutTimerFunc(unsigned(20), timer, 0);
    glutMainLoop();
}

 

댓글