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

举报
ShaderJoy 发表于 2021/12/30 00:50:05 2021/12/30
【摘要】 MRTs 允许应用程序同时渲染多个颜色缓冲区 话不多言,详细代码和注释如下: // HelloBlitFramebuffer.cpp : 定义控制台应用程序的入口点。// #include "stdafx.h"#include <iostream>#include <GL/glew.h>#include ...


MRTs 允许应用程序同时渲染多个颜色缓冲区


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



  
  1. // HelloBlitFramebuffer.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <GL/glew.h>
  6. #include <gl/freeglut.h>
  7. // -----------------------------------
  8. typedef struct
  9. {
  10. // Handle to a program object
  11. GLuint programObject;
  12. // Handle to a framebuffer object
  13. GLuint fbo;
  14. // Texture handle
  15. GLuint colorTexId[4];
  16. // Texture size
  17. GLsizei textureWidth;
  18. GLsizei textureHeight;
  19. } UserData;
  20. UserData *userData = NULL;
  21. const GLenum attachments[4] =
  22. {
  23. GL_COLOR_ATTACHMENT0,
  24. GL_COLOR_ATTACHMENT1,
  25. GL_COLOR_ATTACHMENT2,
  26. GL_COLOR_ATTACHMENT3
  27. };
  28. #define SCREEN_W 640
  29. #define SCREEN_H 640
  30. ///
  31. // 初始化 FBO 和 MRTs
  32. //
  33. int InitFBO()
  34. {
  35. int i;
  36. GLint defaultFramebuffer = 0;
  37. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFramebuffer);
  38. // 创建 FBO
  39. glGenFramebuffers(1, &userData->fbo);
  40. glBindFramebuffer(GL_FRAMEBUFFER, userData->fbo);
  41. // 创建4个输出纹理,并绑定到 FBO
  42. userData->textureHeight = userData->textureWidth = 400;
  43. glGenTextures(4, &userData->colorTexId[0]);
  44. for (i = 0; i < 4; ++i)
  45. {
  46. glBindTexture(GL_TEXTURE_2D, userData->colorTexId[i]);
  47. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  48. userData->textureWidth, userData->textureHeight,
  49. 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  50. // 设置过滤模式
  51. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  52. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  53. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachments[i],
  54. GL_TEXTURE_2D, userData->colorTexId[i], 0);
  55. }
  56. // 指定待写入的 color buffers
  57. glDrawBuffers(4, attachments);
  58. if (GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER))
  59. {
  60. return FALSE;
  61. }
  62. // 恢复默认的 framebuffer
  63. glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
  64. return TRUE;
  65. }
  66. // 初始化 Shader Program,返回 Program ID
  67. GLuint InitShaders(const char *vs, const char *fs)
  68. {
  69. GLint vertCompiled, fragCompiled, linked;
  70. // Shaders
  71. GLint v = glCreateShader(GL_VERTEX_SHADER);
  72. GLint f = glCreateShader(GL_FRAGMENT_SHADER);
  73. glShaderSource(v, 1, &vs, NULL);
  74. glShaderSource(f, 1, &fs, NULL);
  75. glCompileShader(v);
  76. glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled); // Debug
  77. if (vertCompiled != GL_TRUE)
  78. {
  79. printf("Vertex Shader compied error! \n");
  80. }
  81. glCompileShader(f);
  82. glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);
  83. if (fragCompiled != GL_TRUE)
  84. {
  85. printf("Fragment Shader compied error! \n");
  86. }
  87. //Program:
  88. GLuint p = glCreateProgram();
  89. glAttachShader(p, v);
  90. glAttachShader(p, f);
  91. glLinkProgram(p);
  92. glGetProgramiv(p, GL_LINK_STATUS, &linked); // Debug
  93. if (linked != GL_TRUE)
  94. {
  95. printf("Program linked error! \n");
  96. }
  97. return p;
  98. }
  99. ///
  100. // 初始化 shader 和 program
  101. //
  102. int Init()
  103. {
  104. const char vShaderStr[] =
  105. //"#version 300 es \n"
  106. "#version 330 \n"
  107. "layout(location = 0) in vec4 a_position; \n"
  108. "void main() \n"
  109. "{ \n"
  110. " gl_Position = a_position; \n"
  111. "} \n";
  112. const char fShaderStr[] =
  113. //"#version 300 es \n"
  114. //"precision mediump float; \n"
  115. "#version 330 \n"
  116. "layout(location = 0) out vec4 fragData0; \n"
  117. "layout(location = 1) out vec4 fragData1; \n"
  118. "layout(location = 2) out vec4 fragData2; \n"
  119. "layout(location = 3) out vec4 fragData3; \n"
  120. "void main() \n"
  121. "{ \n"
  122. " // first buffer will contain red color \n"
  123. " fragData0 = vec4 ( 1, 0, 0, 1 ); \n"
  124. " \n"
  125. " // second buffer will contain green color \n"
  126. " fragData1 = vec4 ( 0, 1, 0, 1 ); \n"
  127. " \n"
  128. " // third buffer will contain blue color \n"
  129. " fragData2 = vec4 ( 0, 0, 1, 1 ); \n"
  130. " \n"
  131. " // fourth buffer will contain gray color \n"
  132. " fragData3 = vec4 ( 0.5, 0.5, 0.5, 1 ); \n"
  133. "} \n";
  134. userData->programObject = InitShaders(vShaderStr, fShaderStr);
  135. InitFBO();
  136. glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
  137. return TRUE;
  138. }
  139. ///
  140. // 绘制一个 Quad
  141. //
  142. void DrawGeometry()
  143. {
  144. GLfloat vVertices[] = { -1.0f, 1.0f, 0.0f,
  145. -1.0f, -1.0f, 0.0f,
  146. 1.0f, -1.0f, 0.0f,
  147. 1.0f, 1.0f, 0.0f,
  148. };
  149. GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
  150. glViewport(0, 0, SCREEN_W, SCREEN_H);
  151. glClear(GL_COLOR_BUFFER_BIT);
  152. glUseProgram(userData->programObject);
  153. glVertexAttribPointer(0, 3, GL_FLOAT,
  154. GL_FALSE, 3 * sizeof(GLfloat), vVertices);
  155. glEnableVertexAttribArray(0);
  156. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
  157. }
  158. ///
  159. // ☆ 拷贝 MRTs 的输出到屏幕 ☆
  160. //
  161. void BlitTextures()
  162. {
  163. // 绑定 FBO,用于读取
  164. glBindFramebuffer(GL_READ_FRAMEBUFFER, userData->fbo);
  165. // 选择一块 color buffer 作为源,拷贝输出到屏幕指定位置
  166. glReadBuffer(GL_COLOR_ATTACHMENT0);
  167. glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
  168. 0, 0,
  169. SCREEN_W / 2, SCREEN_H / 2, // 左下角坐标
  170. GL_COLOR_BUFFER_BIT, GL_LINEAR);
  171. glReadBuffer(GL_COLOR_ATTACHMENT1);
  172. glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
  173. SCREEN_W / 2, 0,
  174. SCREEN_W, SCREEN_H / 2, // 右下角坐标
  175. GL_COLOR_BUFFER_BIT, GL_LINEAR);
  176. glReadBuffer(GL_COLOR_ATTACHMENT2);
  177. glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
  178. 0, SCREEN_H / 2,
  179. SCREEN_W / 2, SCREEN_H, // 左上角坐标
  180. GL_COLOR_BUFFER_BIT, GL_LINEAR);
  181. glReadBuffer(GL_COLOR_ATTACHMENT3);
  182. glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight,
  183. SCREEN_W / 2, SCREEN_H / 2, // 右上角坐标
  184. SCREEN_W, SCREEN_H,
  185. GL_COLOR_BUFFER_BIT, GL_LINEAR);
  186. }
  187. ///
  188. // 清理善后
  189. //
  190. void ShutDown()
  191. {
  192. glDeleteTextures(4, userData->colorTexId);
  193. glDeleteFramebuffers(1, &userData->fbo);
  194. glDeleteProgram(userData->programObject);
  195. }
  196. // -----------------------------------
  197. // 键盘响应事件
  198. static void ProcessNormalKeys(unsigned char key, int x, int y)
  199. {
  200. // Esc
  201. if (key == 27)
  202. {
  203. ShutDown();
  204. exit(0);
  205. }
  206. }
  207. static void Display()
  208. {
  209. GLint defaultFramebuffer = 0;
  210. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFramebuffer);
  211. // 使用 MRTs 输出4种颜色至4块缓冲区
  212. glBindFramebuffer(GL_FRAMEBUFFER, userData->fbo);
  213. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  214. glDrawBuffers(4, attachments);
  215. DrawGeometry();
  216. // 恢复默认 framebuffer
  217. // 从之前的4块缓冲区中拷贝像素到屏幕指定位置
  218. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
  219. BlitTextures();
  220. glutSwapBuffers();
  221. }
  222. int main(int argc, char* argv[])
  223. {
  224. glutInit(&argc, argv);
  225. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);
  226. glutInitWindowPosition(100, 100);
  227. glutInitWindowSize(SCREEN_W, SCREEN_H);
  228. glutCreateWindow("Hello BlitFramebuffer !");
  229. GLenum err = glewInit();
  230. if (err != GLEW_OK)
  231. {
  232. fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
  233. exit(-2);
  234. }
  235. userData = new UserData;
  236. if (!Init())
  237. {
  238. return GL_FALSE;
  239. }
  240. glutDisplayFunc(Display);
  241. glutIdleFunc(&Display);
  242. glutKeyboardFunc(ProcessNormalKeys);
  243. glutMainLoop();
  244. return 0;
  245. }

结果:


文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/54287825

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。