您的位置:首页 > 编程语言

最简单的 MRTs(Multi Render Targets)的完整代码示例【OpenGL】

2017-01-09 12:36 399 查看
MRTs 允许应用程序同时渲染多个颜色缓冲区

话不多言,详细代码和注释如下:

// HelloBlitFramebuffer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <GL/glew.h>
#include <gl/freeglut.h>

// -----------------------------------
typedef struct
{
// Handle to a program object
GLuint programObject;

// Handle to a framebuffer object
GLuint fbo;

// Texture handle
GLuint colorTexId[4];

// Texture size
GLsizei textureWidth;
GLsizei textureHeight;

} UserData;

UserData *userData = NULL;

const GLenum attachments[4] =
{
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3
};

#define SCREEN_W 640
#define SCREEN_H 640

///
// 初始化 FBO 和 MRTs
//
int InitFBO()
{
int i;
GLint defaultFramebuffer = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFramebuffer);

// 创建 FBO
glGenFramebuffers(1, &userData->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, userData->fbo);

// 创建4个输出纹理,并绑定到 FBO
userData->textureHeight = userData->textureWidth = 400;
glGenTextures(4, &userData->colorTexId[0]);
for (i = 0; i < 4; ++i)
{
glBindTexture(GL_TEXTURE_2D, userData->colorTexId[i]);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
userData->textureWidth, userData->textureHeight,
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

// 设置过滤模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachments[i],
GL_TEXTURE_2D, userData->colorTexId[i], 0);
}
// 指定待写入的 color buffers
glDrawBuffers(4, attachments);

if (GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER))
{
return FALSE;
}

// 恢复默认的 framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);

return TRUE;
}

// 初始化 Shader Program,返回 Program ID
GLuint InitShaders(const char *vs, const char *fs)
{
GLint vertCompiled, fragCompiled, linked;

// Shaders
GLint v = glCreateShader(GL_VERTEX_SHADER);
GLint f = glCreateShader(GL_FRAGMENT_SHADER);

glShaderSource(v, 1, &vs, NULL);
glShaderSource(f, 1, &fs, NULL);

glCompileShader(v);
glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled); // Debug
if (vertCompiled != GL_TRUE)
{
printf("Vertex Shader compied error! \n");
}

glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);
if (fragCompiled != GL_TRUE)
{
printf("Fragment Shader compied error! \n");
}

//Program:
GLuint p = glCreateProgram();
glAttachShader(p, v);
glAttachShader(p, f);

glLinkProgram(p);
glGetProgramiv(p, GL_LINK_STATUS, &linked); // Debug
if (linked != GL_TRUE)
{
printf("Program linked error! \n");
}

return p;
}

///
// 初始化 shader 和 program
//
int Init()
{
const char vShaderStr[] =
//"#version 300 es \n"
"#version 330 \n"
"layout(location = 0) in vec4 a_position; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
"} \n";

const char fShaderStr[] =
//"#version 300 es \n"
//"precision mediump float; \n"
"#version 330 \n"
"layout(location = 0) out vec4 fragData0; \n"
"layout(location = 1) out vec4 fragData1; \n"
"layout(location = 2) out vec4 fragData2; \n"
"layout(location = 3) out vec4 fragData3; \n"
"void main() \n"
"{ \n"
" // first buffer will contain red color \n"
" fragData0 = vec4 ( 1, 0, 0, 1 ); \n"
" \n"
" // second buffer will contain green color \n"
" fragData1 = vec4 ( 0, 1, 0, 1 ); \n"
" \n"
" // third buffer will contain blue color \n"
" fragData2 = vec4 ( 0, 0, 1, 1 ); \n"
" \n"
" // fourth buffer will contain gray color \n"
" fragData3 = vec4 ( 0.5, 0.5, 0.5, 1 ); \n"
"} \n";

userData->programObject = InitShaders(vShaderStr, fShaderStr);

InitFBO();

glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

return TRUE;
}

///
// 绘制一个 Quad
//
void DrawGeometry()
{
GLfloat vVertices[] = { -1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

glViewport(0, 0, SCREEN_W, SCREEN_H);

glClear(GL_COLOR_BUFFER_BIT);

glUseProgram(userData->programObject);

glVertexAttribPointer(0, 3, GL_FLOAT,
GL_FALSE, 3 * sizeof(GLfloat), vVertices);
glEnableVertexAttribArray(0);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}

///
// ☆ 拷贝 MRTs 的输出到屏幕 ☆
//
void BlitTextures()
{
// 绑定 FBO,用于读取
glBindFramebuffer(GL_READ_FRAMEBUFFER, userData->fbo);

// 选择一块 color buffer 作为源,拷贝输出到屏幕指定位置
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
0, 0,
SCREEN_W / 2, SCREEN_H / 2, // 左下角坐标
GL_COLOR_BUFFER_BIT, GL_LINEAR);

glReadBuffer(GL_COLOR_ATTACHMENT1);
glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
SCREEN_W / 2, 0,
SCREEN_W, SCREEN_H / 2, // 右下角坐标
GL_COLOR_BUFFER_BIT, GL_LINEAR);

glReadBuffer(GL_COLOR_ATTACHMENT2);
glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
0, SCREEN_H / 2,
SCREEN_W / 2, SCREEN_H, // 左上角坐标
GL_COLOR_BUFFER_BIT, GL_LINEAR);

glReadBuffer(GL_COLOR_ATTACHMENT3);
glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
SCREEN_W / 2, SCREEN_H / 2, // 右上角坐标
SCREEN_W, SCREEN_H,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
}

///
// 清理善后
//
void ShutDown()
{
glDeleteTextures(4, userData->colorTexId);

glDeleteFramebuffers(1, &userData->fbo);

glDeleteProgram(userData->programObject);
}

// -----------------------------------

// 键盘响应事件
static void ProcessNormalKeys(unsigned char key, int x, int y)
{
// Esc
if (key == 27)
{
ShutDown();
exit(0);
}
}

static void Display()
{
GLint defaultFramebuffer = 0;

glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFramebuffer);

// 使用 MRTs 输出4种颜色至4块缓冲区
glBindFramebuffer(GL_FRAMEBUFFER, userData->fbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawBuffers(4, attachments);
DrawGeometry();

// 恢复默认 framebuffer
// 从之前的4块缓冲区中拷贝像素到屏幕指定位置
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
BlitTextures();

glutSwapBuffers();
}

int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);
glutInitWindowPosition(100, 100);
glutInitWindowSize(SCREEN_W, SCREEN_H);
glutCreateWindow("Hello BlitFramebuffer !");

GLenum err = glewInit();
if (err != GLEW_OK)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
exit(-2);
}

userData = new UserData;

if (!Init())
{
return GL_FALSE;
}

glutDisplayFunc(Display);
glutIdleFunc(&Display);
glutKeyboardFunc(ProcessNormalKeys);

glutMainLoop();

return 0;
}

结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opengl
相关文章推荐