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();
}
'전공 > 컴퓨터 그래픽스' 카테고리의 다른 글
버퍼 오브젝트 (Buffer Objects) (2) (0) | 2023.05.29 |
---|---|
버퍼 오브젝트 (Buffer Objects) (1) (1) | 2023.05.29 |
텍스처 (3)3D 텍스쳐 (0) | 2023.05.28 |
텍스처 (2)텍스쳐 매핑 기법 (0) | 2023.05.20 |
텍스처 (1)2D 텍스쳐 (0) | 2023.05.07 |
댓글