OpenGL ES中MRT应用
Demo涵盖了OpenGL ES 3.0 的一系列新特性:
1、VAO和VBO
2、帧缓冲对象
3、MRT
效果:
代码:
1 //yf's version 2 #define STB_IMAGE_IMPLEMENTATION 3 #include <stdlib.h> 4 #include "esUtil.h" 5 #include "stb_image.h" 6 7 typedef struct 8 { 9 // Handle to a program object 10 GLuint programObject; 11 GLuint programObjectQuad; 12 13 GLuint cubeVAO, cubeVBO; 14 GLuint floorVAO, floorVBO; 15 GLuint quadVAO, quadVBO; 16 GLuint framebuffer; 17 18 ESMatrix mvMatrix; 19 ESMatrix mvpMatrix; 20 21 GLuint mvLoc; 22 GLuint mvpLoc; 23 24 GLuint cubeTexture; 25 GLuint floorTexture; 26 27 // Rotation angle 28 GLfloat angle; 29 30 GLuint texIDfloor; 31 GLuint texIDcube; 32 33 GLuint texColorbuffer; 34 GLuint texColorArray[4]; 35 36 GLuint textureWidth; 37 GLuint textureHeight; 38 } UserData; 39 40 GLfloat cubeVertices[] = { 41 // Positions // Texture Coords 42 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 43 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 44 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 45 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 46 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 47 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 48 49 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 50 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 51 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 52 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 53 -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 54 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 55 56 -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 57 -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 58 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 59 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 60 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 61 -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 62 63 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 64 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 65 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 66 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 67 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 68 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 69 70 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 71 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 72 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 73 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 74 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 75 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 76 77 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 78 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 79 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 80 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 81 -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 82 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f 83 }; 84 GLfloat floorVertices[] = { 85 // Positions // Texture Coords (note we set these higher than 1 that together with GL_REPEAT as texture wrapping mode will cause the floor texture to repeat) 86 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 87 -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, 88 -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 89 90 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 91 -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 92 5.0f, -0.5f, -5.0f, 2.0f, 2.0f 93 }; 94 //渲染到这个四边形 95 GLfloat quadVertices[] = { // Vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. 96 // Positions // TexCoords 97 -1.0f, 1.0f, 0.0f, 1.0f, 98 -1.0f, -1.0f, 0.0f, 0.0f, 99 1.0f, -1.0f, 1.0f, 0.0f, 100 101 -1.0f, 1.0f, 0.0f, 1.0f, 102 1.0f, -1.0f, 1.0f, 0.0f, 103 1.0f, 1.0f, 1.0f, 1.0f 104 }; 105 106 GLuint screenWidth = 600; 107 GLuint screenHeight = 400; 108 109 GLuint LoadTextureFile(const char* filename) 110 { 111 GLuint texID; 112 glGenTextures(1, &texID); 113 glBindTexture(GL_TEXTURE_2D, texID); 114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 118 int width, height, nrChannels; 119 unsigned char *data = stbi_load(filename, &width, &height, &nrChannels, 0); 120 if (data) 121 { 122 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 123 glGenerateMipmap(GL_TEXTURE_2D); 124 } 125 else 126 printf("Failed to load texture\n"); 127 stbi_image_free(data); 128 return texID; 129 } 130 131 char vShaderStr[] = 132 "#version 300 es \n" 133 "layout(location = 0) in vec4 a_position; \n" 134 "layout(location = 1) in vec2 a_texCoord; \n" 135 "uniform mat4 u_mvpMatrix; \n" 136 "out vec2 v_texCoord; \n" 137 "void main() \n" 138 "{ \n" 139 " gl_Position = u_mvpMatrix * a_position; \n" 140 " v_texCoord=a_texCoord; \n" 141 "} \n"; 142 143 char fShaderStr[] = 144 "#version 300 es \n" 145 "precision mediump float; \n" 146 "in vec2 v_texCoord; \n" 147 "uniform sampler2D screenTexture; \n" 148 "out vec4 outColor; \n" 149 "void main() \n" 150 "{ \n" 151 " outColor = texture(screenTexture,v_texCoord); \n" 152 "} \n"; 153 154 //填充quad面片的VS 155 char vScreenShaderStr[] = 156 "#version 300 es \n" 157 "layout(location = 0) in vec2 a_position; \n" 158 "layout(location = 1) in vec2 texCoord; \n" 159 "out vec2 v_texCoord; \n" 160 "void main() \n" 161 "{ \n" 162 " gl_Position = vec4(a_position.x,a_position.y,0.0,1.0); \n" 163 " v_texCoord=texCoord; \n" 164 "} \n"; 165 166 ////正常:outColor=texture(Texture,v_texCoord); 167 char fScreenShaderStr[] = //正常Shader 168 "#version 300 es \n" 169 "precision mediump float; \n" 170 "out vec4 outColor; \n" 171 "in vec2 v_texCoord; \n" 172 "uniform sampler2D Texture; \n" 173 "void main() \n" 174 "{ \n" 175 //" outColor=texture(Texture,v_texCoord); \n"//正常色 176 " outColor=vec4(vec3(1.0-texture(Texture,v_texCoord)),1.0); \n"//反色 177 "} \n"; 178 179 char fScreenShaderStrKernel[] =//核效果着色器 180 "#version 300 es \n" 181 "precision mediump float; \n" 182 "const float offset=1.0/300.0; \n" 183 "layout(location = 0) out vec4 outColor0; \n" 184 "layout(location = 1) out vec4 outColor1; \n" 185 "layout(location = 2) out vec4 outColor2; \n" 186 "layout(location = 3) out vec4 outColor3; \n" 187 "in vec2 v_texCoord; \n" 188 "uniform sampler2D Texture; \n" 189 "void main() \n" 190 "{ \n" 191 " vec2 offsets[9] = vec2[]( \n" 192 " vec2(-offset, offset), \n" 193 " vec2(0.0f, offset), \n" 194 " vec2(offset, offset), \n" 195 " vec2(-offset, 0.0f), \n" 196 " vec2(0.0f, 0.0f), \n" 197 " vec2(offset, 0.0f), \n" 198 " vec2(-offset, -offset), \n" 199 " vec2(0.0f, -offset), \n" 200 " vec2(offset, -offset) \n" 201 " ); \n" 202 203 " float kernel[9] = float[]( \n"//模糊核0 204 " 1.0/16.0, 2.0/16.0, 1.0/16.0, \n" 205 " 2.0/16.0, 4.0/16.0, 2.0/16.0, \n" 206 " 1.0/16.0, 2.0/16.0, 1.0/16.0 \n" 207 " ); \n" 208 " vec3 sampleTex[9]; \n" 209 " for (int i = 0; i < 9; i++) \n" 210 " { \n" 211 " sampleTex[i] = vec3(texture(Texture, v_texCoord.st + offsets[i])); \n" 212 " } \n" 213 " vec3 col = vec3(0.0); \n" 214 " for (int i = 0; i < 9; i++) \n" 215 " col += sampleTex[i] * kernel[i]; \n" 216 " outColor0 = vec4(col, 1.0); \n" 217 218 " kernel = float[]( \n"//锐化核1 219 " -1, -1, -1, \n" 220 " -1, 9, -1, \n" 221 " -1, -1, -1 \n" 222 " ); \n" 223 " for (int i = 0; i < 9; i++) \n" 224 " { \n" 225 " sampleTex[i] = vec3(texture(Texture, v_texCoord.st + offsets[i])); \n" 226 " } \n" 227 " col = vec3(0.0); \n" 228 " for (int i = 0; i < 9; i++) \n" 229 " col += sampleTex[i] * kernel[i]; \n" 230 " outColor1 = vec4(col, 1.0); \n" 231 " outColor2 = texture(Texture,v_texCoord); \n"//正常色2 232 " outColor3 = vec4(vec3(1.0-texture(Texture,v_texCoord)),1.0); \n"//反色3 233 "} \n"; 234 235 int Init(ESContext *esContext) 236 { 237 UserData *userData = esContext->userData; 238 userData->textureWidth = 600; 239 userData->textureHeight = 400; 240 // Load the shaders and get a linked program object 241 userData->programObject = esLoadProgram(vShaderStr, fShaderStr);//载入文件、附件、编译、判错、删除Shader 242 userData->programObjectQuad = esLoadProgram(vScreenShaderStr, fScreenShaderStrKernel); 243 244 userData->angle = 0.0f; 245 userData->mvLoc = glGetUniformLocation(userData->programObject, "u_mvMatrix"); 246 userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix"); 247 //cube 248 glGenVertexArrays(1, &userData->cubeVAO);//初始化cube的vao 249 glGenBuffers(1, &userData->cubeVBO);//初始化装载cube属性的vbo 250 glBindVertexArray(userData->cubeVAO);//以下操作对cubeVAO负责 251 glBindBuffer(GL_ARRAY_BUFFER, userData->cubeVBO);//以下操作对cubeVBO负责 252 glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);//复制数据到当前vbo 253 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLvoid*)0);//设置顶点位置 254 glEnableVertexAttribArray(0); 255 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLvoid*)(sizeof(GLfloat) * 3)); 256 glEnableVertexAttribArray(1); 257 userData->texIDcube = LoadTextureFile("container.jpg"); 258 glBindVertexArray(0);//完成cubeVAO的设置 259 //floor 260 glGenVertexArrays(1, &userData->floorVAO);//初始化地板vao 261 glGenBuffers(1, &userData->floorVBO); 262 glBindVertexArray(userData->floorVAO); 263 glBindBuffer(GL_ARRAY_BUFFER, userData->floorVBO); 264 glBufferData(GL_ARRAY_BUFFER, sizeof(floorVertices), floorVertices, GL_STATIC_DRAW); 265 glEnableVertexAttribArray(0); 266 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLvoid*)0); 267 glEnableVertexAttribArray(1); 268 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLvoid*)(sizeof(GLfloat) * 3)); 269 userData->texIDfloor = LoadTextureFile("brick_DIFF.bmp"); 270 glBindVertexArray(0);//完成floorVAO的设置 271 //quad 272 glGenVertexArrays(1, &userData->quadVAO); 273 glGenBuffers(1, &userData->quadVBO); 274 glBindVertexArray(userData->quadVAO); 275 glBindBuffer(GL_ARRAY_BUFFER, userData->quadVBO); 276 glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW); 277 glEnableVertexAttribArray(0); 278 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (GLvoid*)0); 279 glEnableVertexAttribArray(1); 280 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (GLvoid*)(sizeof(GLfloat) * 2)); 281 glBindVertexArray(0); 282 283 //GLuint defaultFramebuffer = 0; 284 const GLenum attachments[4] = { 285 GL_COLOR_ATTACHMENT0, 286 GL_COLOR_ATTACHMENT1, 287 GL_COLOR_ATTACHMENT2, 288 GL_COLOR_ATTACHMENT3 289 }; 290 //glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFramebuffer); 291 292 //设置FBO 293 glGenFramebuffers(1, &userData->framebuffer);//初始化帧缓冲framebuffer 294 glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer);//以下代码对framebuffer负责,包括纹理附件设置和rbo附件设置 295 glGenTextures(4, &userData->texColorArray); 296 for (int i = 0; i < 4; i++){ 297 //userData->texColorArray[i] = generateAttachmentTexture(GL_FALSE, GL_FALSE);//纹理附件 298 glBindTexture(GL_TEXTURE_2D, userData->texColorArray[i]); 299 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 300 userData->textureWidth, userData->textureHeight, 301 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);//设置宽高但不赋予纹理文件的数据 302 // Set the filtering mode 303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 305 glBindTexture(GL_TEXTURE_2D, 0); 306 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, userData->texColorArray[i], 0);//完成FBO的纹理附件挂载 307 } 308 glDrawBuffers(4, attachments); 309 if (GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER)) 310 return FALSE; 311 312 //设置渲染缓冲对象附件 313 GLuint rbo; 314 glGenRenderbuffers(1, &rbo);//初始化rbo附件 315 glBindRenderbuffer(GL_RENDERBUFFER, rbo);//以下操作对rbo负责 316 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); 317 glBindRenderbuffer(GL_RENDERBUFFER, 0);//完成对rbo的设置 318 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);//完成FBO的rbo附件挂载 319 320 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 321 printf("ERROR::FRAMEBUFFER:: Framebuffer is not complete!"); 322 323 glBindFramebuffer(GL_FRAMEBUFFER, 0);//完成纹理附件和rbo附件的设置,解绑fbo 324 325 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//初始刷新一下 326 glEnable(GL_DEPTH_TEST); 327 return TRUE; 328 } 329 330 void Update(ESContext *esContext, float deltaTime) 331 { 332 UserData *userData = esContext->userData; 333 334 userData->angle += (deltaTime * 50.0f);//转动 335 if (userData->angle >= 360.0f) 336 userData->angle -= 360.0f; 337 338 esMatrixLoadIdentity(&userData->mvMatrix); 339 esTranslate(&userData->mvMatrix, 0.0f, 0.0f, -3.0f); 340 esRotate(&userData->mvMatrix, userData->angle, 0.0f, 1.0f, 0.0f); 341 342 ESMatrix perspective; 343 esMatrixLoadIdentity(&perspective);//单位化一个矩阵作为透视投影矩阵 344 float aspect = (GLfloat)esContext->width / ((GLfloat)esContext->height); 345 esPerspective(&perspective, 60.f, aspect, 0.2f, 20.f); 346 347 esMatrixMultiply(&userData->mvpMatrix, &userData->mvMatrix, &perspective); 348 } 349 350 void DrawQuad(ESContext *esContext) 351 { 352 UserData *userData = esContext->userData; 353 glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer); 354 glViewport(0, 0, esContext->width, esContext->height); 355 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 356 glEnable(GL_DEPTH_TEST); 357 glUseProgram(userData->programObject);//启用programObject 358 glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix);//mvpMatrix在Update里更新 359 360 glBindVertexArray(userData->cubeVAO); 361 glBindTexture(GL_TEXTURE_2D, userData->texIDcube); 362 glDrawArrays(GL_TRIANGLES, 0, 36); 363 glBindVertexArray(0); 364 365 glBindVertexArray(userData->floorVAO); 366 glBindTexture(GL_TEXTURE_2D, userData->texIDfloor); 367 glDrawArrays(GL_TRIANGLES, 0, 6); 368 glBindVertexArray(0); 369 glBindFramebuffer(GL_FRAMEBUFFER, 0); 370 371 // Bind to default framebuffer again and draw the quad plane with attched screen texture. 372 glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer);//闪烁是因为重复渲染了三维图像和QUAD 373 glUseProgram(userData->programObjectQuad);//启用programObjectQuad 374 glBindVertexArray(userData->quadVAO); 375 glBindTexture(GL_TEXTURE_2D, userData->texColorArray[0]);//texColorArray在Init里绑定到了fbo的纹理Attachment 376 glDrawArrays(GL_TRIANGLES, 0, 6); 377 glBindVertexArray(0); 378 glBindFramebuffer(GL_FRAMEBUFFER, 0); 379 //ID号为0表示缺省帧缓存,即默认的window提供的帧缓存。因此,在glBindFramebuffer()中将ID号设置为0可以解绑定当前FBO。 380 } 381 382 void BlitTextures(ESContext *esContext)//区位块传送 383 { 384 UserData *userData = esContext->userData; 385 386 // set the fbo for reading 387 glBindFramebuffer(GL_READ_FRAMEBUFFER, userData->framebuffer); 388 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 389 // Copy the output red buffer to lower left quadrant 390 glReadBuffer(GL_COLOR_ATTACHMENT0); 391 glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight, 392 0, 0, esContext->width / 2, esContext->height / 2, 393 GL_COLOR_BUFFER_BIT, GL_LINEAR); 394 //(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 395 // GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) 396 397 // Copy the output green buffer to lower right quadrant 398 glReadBuffer(GL_COLOR_ATTACHMENT1); 399 glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight, 400 esContext->width / 2, 0, esContext->width, esContext->height / 2, 401 GL_COLOR_BUFFER_BIT, GL_LINEAR); 402 403 // Copy the output blue buffer to upper left quadrant 404 glReadBuffer(GL_COLOR_ATTACHMENT2); 405 glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight, 406 0, esContext->height / 2, esContext->width / 2, esContext->height, 407 GL_COLOR_BUFFER_BIT, GL_LINEAR); 408 409 // Copy the output gray buffer to upper right quadrant 410 glReadBuffer(GL_COLOR_ATTACHMENT3); 411 glBlitFramebuffer(0, 0, userData->textureWidth, userData->textureHeight, 412 esContext->width / 2, esContext->height / 2, esContext->width, esContext->height, 413 GL_COLOR_BUFFER_BIT, GL_LINEAR); 414 } 415 416 void Draw(ESContext *esContext) 417 { 418 DrawQuad(esContext); 419 BlitTextures(esContext); 420 } 421 422 void ShutDown(ESContext *esContext) 423 { 424 UserData *userData = esContext->userData; 425 426 glDeleteVertexArrays(1, &userData->cubeVAO); 427 glDeleteBuffers(1, &userData->cubeVBO); 428 glDeleteVertexArrays(1, &userData->floorVAO); 429 glDeleteBuffers(1, &userData->floorVBO); 430 glDeleteVertexArrays(1, &userData->quadVAO); 431 glDeleteBuffers(1, &userData->quadVBO); 432 433 glDeleteBuffers(4, userData->texColorArray); 434 glDeleteFramebuffers(1, &userData->framebuffer); 435 436 glDeleteProgram(userData->programObject); 437 glDeleteProgram(userData->programObjectQuad); 438 } 439 440 int esMain(ESContext *esContext) 441 { 442 esContext->userData = malloc(sizeof(UserData)); 443 444 esCreateWindow(esContext, "正常,反色,模糊,锐化", screenWidth, screenHeight, ES_WINDOW_RGB | ES_WINDOW_ALPHA | ES_WINDOW_DEPTH); 445 446 if (!Init(esContext)) 447 { 448 return GL_FALSE; 449 } 450 esRegisterShutdownFunc(esContext, ShutDown); 451 esRegisterUpdateFunc(esContext, Update); 452 esRegisterDrawFunc(esContext, Draw); 453 454 return GL_TRUE; 455 }