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

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

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

结果:

image.png

目录
相关文章
Pyinstaller:moviepy打包报错AttributeError: module ‘moviepy.audio.fx.all‘ has no attribute ‘audio_fadein‘
该文章分享了使用Pyinstaller打包moviepy库时遇到的`AttributeError: module 'moviepy.audio.fx.all' has no attribute 'audio_fadein'`错误,分析了问题原因,并提供了修改moviepy子包中的`__init__.py`文件来解决动态加载模块问题的详细步骤和最终打包成功的结果。
|
6月前
|
JavaScript
【Vue Error】 error Component name “product“ should always be multi-word vue/multi-word-compone……
【Vue Error】 error Component name “product“ should always be multi-word vue/multi-word-compone……
【Simulink】Three-Phase V-I Measurement 使用方法
【Simulink】Three-Phase V-I Measurement 使用方法
|
TensorFlow 算法框架/工具
TensorFlow修改图像尺寸:AttributeError: module ‘tensorflow._api.v2.image‘ has no attribute ‘image‘
TensorFlow修改图像尺寸:AttributeError: module ‘tensorflow._api.v2.image‘ has no attribute ‘image‘
130 0
TensorFlow修改图像尺寸:AttributeError: module ‘tensorflow._api.v2.image‘ has no attribute ‘image‘
react+hook+ts项目总结-Ts中[propName: string]: any;
react+hook+ts项目总结-Ts中[propName: string]: any;
122 0
|
iOS开发
cocos2dx-bullet物理引擎编译的一个问题: Argument value 10880 is outside the valid range
cocos2dx-bullet物理引擎编译的一个问题: Argument value 10880 is outside the valid range
366 0
|
TensorFlow 算法框架/工具
tensorflow报错:AttributeError: module ‘tensorflow._api.v2.compat.v1‘ has no attribute ‘Sessions‘,亲测有效
tensorflow报错:AttributeError: module ‘tensorflow._api.v2.compat.v1‘ has no attribute ‘Sessions‘,
1482 0
tensorflow报错:AttributeError: module ‘tensorflow._api.v2.compat.v1‘ has no attribute ‘Sessions‘,亲测有效
|
TensorFlow 算法框架/工具
成功解决AttributeError: module tensorflow.image has no attribute resize
成功解决AttributeError: module tensorflow.image has no attribute resize
Libra教程之:运行自定义move modules
Libra教程之:运行自定义move modules
|
API Python Windows
成功解决Scrapy框架的问题ModuleNotFoundError: No module named 'win32api'
成功解决Scrapy框架的问题ModuleNotFoundError: No module named 'win32api'
成功解决Scrapy框架的问题ModuleNotFoundError: No module named 'win32api'