I am trying to create two FBOs and implement ping pong rendering. But I only get the first frame to work properly. I try to simulate a game in life, and, after the first frame, I get only a black screen. could you help me? I spent hours on this question.
Edit
Perhaps I did not describe clearly. Actually, I want to use a texture as a texture and render it texture, then use the texture to render on the screen, and then vice versa.
Edit I see the first frame, which is texture B. After it passes through the fragment shader, it will turn black. At first I suspect that the fragment shader, I change it to only cancel black to white and from white to black. He is still turning black.
Customize fbo and texture
glEnable(GL_TEXTURE_2D); glGenTextures(1, &textureA); glBindTexture(GL_TEXTURE_2D, textureA); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glGenTextures(1, &textureB); glBindTexture(GL_TEXTURE_2D, textureB); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); data=(GLubyte*)malloc(256*256*4*sizeof(GLubyte)); GLubyte val; for (int i = 0; i < 256 * 256 * 4; i+=4) { if (rand()%10 ==1) { val = 0; } else { val = 255; } data[i] = data[i+1] = data[i+2] = val; data[i+3] = 255; } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenFramebuffers(1, &fboA); glBindFramebuffer(GL_FRAMEBUFFER, fboA); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureA, 0); glGenFramebuffers(1, &fboB); glBindFramebuffer(GL_FRAMEBUFFER, fboB); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureB, 0);
Render loop
if ([context API] == kEAGLRenderingAPIOpenGLES2) { if(counter%2==0) { glUseProgram(automateProg); glBindFramebuffer(GL_FRAMEBUFFER, fboA); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureB); glUniform1i(AUTOMATE_TEXT, 0); glUniform1f(DU, 1.0/256); glUniform1f(DV, 1.0/256); // Update attribute values. glVertexAttribPointer(ATTRIB_VERTEX_2, 2, GL_FLOAT, 0, 0, squareVertices); glEnableVertexAttribArray(ATTRIB_VERTEX_2); glVertexAttribPointer(ATTRIB_TEXCOORD_2, 2, GL_FLOAT, GL_FALSE, 0, texCoord); //glEnableVertexAttribArray(ATTRIB_TEXCOORD_2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (![self validateProgram:automateProg]) { NSLog(@"Failed to validate program: %d", automateProg); return; } glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(0); } else { glUseProgram(automateProg); glBindFramebuffer(GL_FRAMEBUFFER, fboB); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureA); glUniform1i(AUTOMATE_TEXT, 0); glUniform1f(DU, 1.0/256); glUniform1f(DV, 1.0/256); // Update attribute values. glVertexAttribPointer(ATTRIB_VERTEX_2, 2, GL_FLOAT, 0, 0, squareVertices); glEnableVertexAttribArray(ATTRIB_VERTEX_2); glVertexAttribPointer(ATTRIB_TEXCOORD_2, 2, GL_FLOAT, GL_FALSE, 0, texCoord); //glEnableVertexAttribArray(ATTRIB_TEXCOORD_2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (![self validateProgram:automateProg]) { NSLog(@"Failed to validate program: %d", automateProg); return; } glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(0); } [(EAGLView *)self.view setFramebuffer]; glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); if (counter % 2 == 0) { glUseProgram(normalProg); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureB); glUniform1i(NORMAL_TEXT, 0); glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices); glEnableVertexAttribArray(ATTRIB_VERTEX); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoord); glEnableVertexAttribArray(ATTRIB_TEXCOORD); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (![self validateProgram:normalProg]) { NSLog(@"Failed to validate program: %d", normalProg); return; } glUseProgram(0); } else { glUseProgram(normalProg); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureA); glUniform1i(NORMAL_TEXT, 0); glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices); glEnableVertexAttribArray(ATTRIB_VERTEX); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoord); glEnableVertexAttribArray(ATTRIB_TEXCOORD); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (![self validateProgram:normalProg]) { NSLog(@"Failed to validate program: %d", normalProg); return; } glUseProgram(0); } counter++; [(EAGLView *)self.view presentFramebuffer];
Fragment shader
precision mediump float; varying vec2 v_texCoord; uniform sampler2D tex; //the input texture uniform float du; //the width of the cells uniform float dv; //the height of the cells void main() { int count = 0; vec4 C = texture2D( tex, v_texCoord ); vec4 E = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y) ); vec4 N = texture2D( tex, vec2(v_texCoord.x, v_texCoord.y + dv) ); vec4 W = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y) ); vec4 S = texture2D( tex, vec2(v_texCoord.x, v_texCoord.y - dv) ); vec4 NE = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y + dv) ); vec4 NW = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y + dv) ); vec4 SE = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y - dv) ); vec4 SW = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y - dv) ); if (Er == 1.0) { count++; } if (Nr == 1.0) { count++; } if (Wr == 1.0) { count++; } if (Sr == 1.0) { count++; } if (NE.r == 1.0) { count++; } if (NW.r == 1.0) { count++; } if (SE.r == 1.0) { count++; } if (SW.r == 1.0) { count++; } if ( (count == 2 || count == 3)) { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); //cell lives... } else { gl_FragColor = vec4(0.0,0.0,0.0, 1.0); //cell dies... } }