Ping-pong rendering between two FBOs fails after the first frame.

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... } } 
+4
source share
3 answers

Do I understand your code correctly so that you display the result in the texture in the first if-else block and display the result for display in the second if-else block? If so, then it looks like you have a mistake in how you organize input and output for starters. This is what happens in your first pass (I reduced your code):

 if(counter%2==0) { glBindFramebuffer(GL_FRAMEBUFFER, fboA); // will render to textureA glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureB); // textureB is our input } else { ... } if (counter % 2 == 0) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureB); // textureB still as input? not textureA? } else { ... } 

... and this is what happens in the second pass:

 if(counter%2==0) { ... } else { glBindFramebuffer(GL_FRAMEBUFFER, fboB); // will render to textureB glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureA); // textureA as input } if (counter % 2 == 0) { ... } else { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureA); // textureA as input again? } 

The reason you see something in the first frame is because you are really visualizing your input, but not the result of your first pass. And the reason you have a black screen in the second pass may be because your fragment shader is not working properly. Judging by your shader code, an error in accessing neighboring texels seems to be the most plausible reason for this. Can you provide du and dv values?

Also, I don’t think that using only one unit of texture should create problems, as Brad previously noted. I am not sure about that.

On the side of the note: for ping-ponging you should consider creating FBOs as an array to make the code more understandable.

EDIT:

I'm having trouble setting du and dv glUniform1f() to glUniform1f() , try glUniform1i() (you need to use float() in your shader) or glUniform1fv() . I once had the same problem with PowerVR GLES2 drivers, where this function did nothing, and it was equal to 0.0 .

+1
source

You have two textures that you would like to deal with, but I see only one texture here. Perhaps if you linked your FBO texture to a texture block using the following code:

 glBindFramebuffer(GL_FRAMEBUFFER, fboA); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureA); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureB); 

or

 glBindFramebuffer(GL_FRAMEBUFFER, fboB); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureB); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureA); 

before you create each frame, it will correctly read from one texture bound to unit 0, and output through FBO to another texture by unit 1.

Alternatively, you can permanently bind one texture to one device and another to another device, as well as alternative values ​​for your AUTOMATE_TEXT form to indicate which device to pull from. This will be a little more efficient because it avoids the overhead of linking textures to each render.

0
source

If you want to get the color plane of the frame, you need to bind the texture to the buffer of the frame you are writing to. If the texture attached to the frame buffer needs to be read in the shader, then the text should be attached to the texture block, and the index of the text block should be set to the shader unit of the shader texture.

Since you cannot read from the frame buffer and write to the same frame buffer at once (this will cause undefined behavior), you must draw to read from one frame buffer and write to the second frame buffer.

After each frame, frame buffers must change their place. The buffer that has been read will become the buffer that will be written, and the buffer that has been written will become the buffer that will be read.

Create textures for frame buffer attachments:

 GLuint colorTexture[2]; glGenTextures( 2, &colorTexture[0] ); glBindTexture( GL_TEXTURE_2D, colorTexture[0] ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glBindTexture( GL_TEXTURE_2D, colorTexture[1] ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); 

Create frame buffers:

 GLuint frameBuffer[2]; glGenFramebuffers( 2, &frameBuffer[0] ); glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer[0] ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[0], 0 ); glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer[1] ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[1], 0 ); 

Note that if a depth buffer or even a stencil buffer is required, then GL_DEPTH_ATTACHMENT , GL_STENCIL_ATTACHMENT or GL_DEPTH_STENCIL_ATTACHMENT must be attached to the frame buffer.

Since each frame accesses the frame buffer, you need to implement a post-process that brings the color plane from the frame buffer to the drawing buffer.
This can be done with glBlitFramebuffer , which transfer a rectangle of pixel values ​​from one area of ​​the framebuffer being read to another region of the framebuffer.

  glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer[ ... ] ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); glBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST ); 

Your main rendering cycle should look something like this:

 int drawFB = 0; while ( /* ... */ ) { int readFB = 1 - drawFB; glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer[drawFB]); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, colorTexture[readFB]); glProgramUse( /* shader program object */ ); glUniform1i( /* texture sampler 2D location */, 1 ); // do the drawing // ... // post processing glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer[drawFB] ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); glBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST ); drawFB = 1 - drawFB; } 

Alternatively, you can also use 1 frame buffer with 2 color planes and 2 textures. Activate the first or second color plane in turn:

 GLuint frameBuffer; glGenFramebuffers( 1, &frameBuffer ); glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[0], 0 ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorTexture[1], 0 ); int drawFB = 0; while ( /* ... */ ) { int readFB = 1 - drawFB; glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glDrawBuffer( drawFB == 0 ? GL_COLOR_ATTACHMENT0 : GL_COLOR_ATTACHMENT1 ); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, colorTexture[readFB]); glProgramUse( /* shader program object */ ); glUniform1i( /* texture sampler 2D location */, 1 ); // do the drawing // ... // post processing glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer[drawFB] ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); glBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST ); drawFB = 1 - drawFB; } 

To demonstrate the process, see the following simple WebGL example:

 var ShaderProgram = {}; ShaderProgram.Create = function( shaderList, uniformNames ) { var shaderObjs = []; for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) { var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage ); if ( shderObj == 0 ) return 0; shaderObjs.push( shderObj ); } var progObj = this.LinkProgram( shaderObjs ) if ( progObj != 0 ) { progObj.unifomLocation = {}; for ( var i_n = 0; i_n < uniformNames.length; ++ i_n ) { var name = uniformNames[i_n]; progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name ); } } return progObj; } ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } ShaderProgram.SetUniformInt = function( progObj, name, val ) { gl.uniform1i( progObj.unifomLocation[name], val ); } ShaderProgram.SetUniform2i = function( progObj, name, arr ) { gl.uniform2iv( progObj.unifomLocation[name], arr ); } ShaderProgram.SetUniformFloat = function( progObj, name, val ) { gl.uniform1f( progObj.unifomLocation[name], val ); } ShaderProgram.SetUniform2f = function( progObj, name, arr ) { gl.uniform2fv( progObj.unifomLocation[name], arr ); } ShaderProgram.SetUniform3f = function( progObj, name, arr ) { gl.uniform3fv( progObj.unifomLocation[name], arr ); } ShaderProgram.SetUniformMat44 = function( progObj, name, mat ) { gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); } ShaderProgram.CompileShader = function( source, shaderStage ) { var shaderScript = document.getElementById(source); if (shaderScript) { source = ""; var node = shaderScript.firstChild; while (node) { if (node.nodeType == 3) source += node.textContent; node = node.nextSibling; } } var shaderObj = gl.createShader( shaderStage ); gl.shaderSource( shaderObj, source ); gl.compileShader( shaderObj ); var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS ); if ( !status ) alert(gl.getShaderInfoLog(shaderObj)); return status ? shaderObj : 0; } ShaderProgram.LinkProgram = function( shaderObjs ) { var prog = gl.createProgram(); for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh ) gl.attachShader( prog, shaderObjs[i_sh] ); gl.linkProgram( prog ); status = gl.getProgramParameter( prog, gl.LINK_STATUS ); if ( !status ) alert("Could not initialise shaders"); gl.useProgram( null ); return status ? prog : 0; } var FrameBuffer = {}; FrameBuffer.Create = function( vp, texturePlan ) { var texPlan = texturePlan ? new Uint8Array( texturePlan ) : null; var fb = gl.createFramebuffer(); fb.width = vp[0]; fb.height = vp[1]; gl.bindFramebuffer( gl.FRAMEBUFFER, fb ); fb.color0_texture = gl.createTexture(); gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, texPlan ); fb.renderbuffer = gl.createRenderbuffer(); gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer ); gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height ); gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 ); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer ); gl.bindTexture( gl.TEXTURE_2D, null ); gl.bindRenderbuffer( gl.RENDERBUFFER, null ); gl.bindFramebuffer( gl.FRAMEBUFFER, null ); fb.Bind = function( clear ) { gl.bindFramebuffer( gl.FRAMEBUFFER, this ); if ( clear ) { gl.clearColor( 0.0, 0.0, 0.0, 1.0 ); //gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); gl.clear( gl.DEPTH_BUFFER_BIT ); } }; fb.Release = function( clear ) { gl.bindFramebuffer( gl.FRAMEBUFFER, null ); if ( clear ) { gl.clearColor( 0.0, 0.0, 0.0, 1.0 ); //gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); gl.clear( gl.DEPTH_BUFFER_BIT ); } }; fb.BindTexture = function( textureUnit ) { gl.activeTexture( gl.TEXTURE0 + textureUnit ); gl.bindTexture( gl.TEXTURE_2D, this.color0_texture ); }; return fb; } var curBufInx = 0; var tick = 0; var signal = 0; function drawScene(){ var canvas = document.getElementById( "glow-canvas" ); var vp = [canvas.width, canvas.height]; var currentTime = Date.now(); var deltaMS = currentTime - startTime testTick = Tick( currentTime, 0.05 ) signal = testTick > tick ? 1 : 0; tick = testTick var srcBufInx = curBufInx == 0 ? 1 : 0; gl.viewport( 0, 0, drawFB[curBufInx].width, drawFB[curBufInx].height ); gl.enable( gl.DEPTH_TEST ); drawFB[curBufInx].Bind( true ); // set up draw shader ShaderProgram.Use( progDraw ); var texUnitSource = 2; drawFB[srcBufInx].BindTexture( texUnitSource ); ShaderProgram.SetUniformInt( progDraw, "u_colorAttachment0", texUnitSource ); ShaderProgram.SetUniform2i( progDraw, "u_textureSize", [drawFB[curBufInx].width, drawFB[curBufInx].height] ); ShaderProgram.SetUniformInt( progDraw, "u_signal", signal ); gl.enableVertexAttribArray( progDraw.inPos ); gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos ); gl.vertexAttribPointer( progDraw.inPos, 2, gl.FLOAT, false, 0, 0 ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx ); gl.drawElements( gl.TRIANGLES, bufQuad.inxLen, gl.UNSIGNED_SHORT, 0 ); gl.disableVertexAttribArray( progDraw.inPos ); drawFB[curBufInx].Release( true ); gl.viewport( 0, 0, canvas.width, canvas.height ); var texUnitDraw = 2; drawFB[curBufInx].BindTexture( texUnitDraw ); ShaderProgram.Use( progScreenSpace ); ShaderProgram.SetUniformInt( progScreenSpace, "u_colorAttachment0", texUnitDraw ); gl.enableVertexAttribArray( progScreenSpace.inPos ); gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos ); gl.vertexAttribPointer( progScreenSpace.inPos, 2, gl.FLOAT, false, 0, 0 ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx ); gl.drawElements( gl.TRIANGLES, bufQuad.inxLen, gl.UNSIGNED_SHORT, 0 ); gl.disableVertexAttribArray( progScreenSpace.inPos ); curBufInx = curBufInx == 0 ? 1 : 0; } function Tick( currentTime, intervall ) { return Math.trunc( (currentTime - startTime) / intervall ); } var plot_download_request = false; var drawFB; var sliderScale = 100.0 var gl; var progDraw; var progScreenSpace; var bufCube = {}; var bufQuad = {}; function sceneStart() { var canvas = document.getElementById( "glow-canvas"); var vp = [canvas.width, canvas.height]; gl = canvas.getContext( "experimental-webgl" ); if ( !gl ) return; progDraw = ShaderProgram.Create( [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER }, { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER } ], [ "u_colorAttachment0", "u_textureSize", "u_signal" ] ); progDraw.inPos = gl.getAttribLocation( progDraw, "inPos" ); if ( progDraw == 0 ) return; progScreenSpace = ShaderProgram.Create( [ { source : "screen-shader-vs", stage : gl.VERTEX_SHADER }, { source : "screen-shader-fs", stage : gl.FRAGMENT_SHADER } ], [ "u_colorAttachment0" ] ); progScreenSpace.inPos = gl.getAttribLocation( progDraw, "inPos" ); if ( progDraw == 0 ) return; // create frame buffers var texCX = Math.floor(vp[0] / 4); var texCY = Math.floor(vp[1] / 4); var texPlan = []; for (ix = 0; ix < texCX; ++ix) { for (iy = 0; iy < texCY; ++iy) { texPlan.push( 0, 0, 0, 0 ); } } for (ip = 0; ip < texCX * texCY / 20; ++ip) { var inx_tex = Math.floor( Math.random() * texCY ) * texCX + Math.floor( Math.random() * texCX ); texPlan[inx_tex * 4 + 0] = 255 * Math.random(); texPlan[inx_tex * 4 + 1] = 255 * Math.random(); texPlan[inx_tex * 4 + 2] = 127; texPlan[inx_tex * 4 + 3] = 255; } drawFB = [ FrameBuffer.Create( [texCX, texCY], texPlan ), FrameBuffer.Create( [texCX, texCY], texPlan ) ]; bufQuad.pos = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos ); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW ); bufQuad.inx = gl.createBuffer(); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx ); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW ); bufQuad.inxLen = 6; startTime = Date.now(); setInterval(drawScene, 50); } 
 <script id="draw-shader-vs" type="x-shader/x-vertex"> precision mediump float; attribute vec2 inPos; varying vec2 vertPos; void main() { vertPos.xy = inPos.xy; gl_Position = vec4( inPos, 0.0, 1.0 ); } </script> <script id="draw-shader-fs" type="x-shader/x-fragment"> precision mediump float; varying vec2 vertPos; uniform sampler2D u_colorAttachment0; uniform ivec2 u_textureSize; uniform int u_signal; vec3 Merge( in vec2 texC, in vec2 dir ) { vec2 testC = texC + dir; vec2 rangeTest = step( vec2(0.0), testC ) * step( testC, vec2(1.0) ); vec3 texCol = texture2D( u_colorAttachment0, testC ).rgb; vec2 tempDir = texCol.xy * 2.0 - 1.0; vec2 pDir = tempDir; pDir.x *= step( abs(tempDir.y * 0.7), abs( tempDir.x ) ); pDir.y *= step( abs(tempDir.x * 0.7), abs( tempDir.y ) ); pDir = sign( pDir ); vec2 tDir = sign( dir ); //vec2 dirTestTemp = step( vec2(0.5), -tDir * pDir ); //float dirTest = dirTestTemp.x * dirTestTemp.y; vec2 dirTestTemp = tDir + pDir; float dirTest = 1.0 - step( 0.5, abs( dirTestTemp.x ) + abs( dirTestTemp.y ) ); return rangeTest.x * rangeTest.y * dirTest * texCol; } void main() { ivec2 texSize = u_textureSize; vec2 texStep = vec2( 1.0 / float( texSize.x ), 1.0 / float( texSize.y ) ); vec2 texC = vertPos.st * 0.5 + 0.5; vec3 texCol = vec3(0.0); if ( u_signal == 0 ) { texCol = texture2D( u_colorAttachment0, texC ).rgb; } else { texCol += Merge( texC, -texStep ); texCol += Merge( texC, vec2( -texStep.x, 0.0 ) ); texCol += Merge( texC, vec2( -texStep.x, texStep.y ) ); texCol += Merge( texC, vec2( 0.0, -texStep.y ) ); texCol += Merge( texC, vec2( 0.0, texStep.y ) ); texCol += Merge( texC, vec2( texStep.x, -texStep.y ) ); texCol += Merge( texC, vec2( texStep.x, 0.0 ) ); texCol += Merge( texC, texStep ); } if ( texCol.b > 0.0 ) { vec2 colDir = texCol.rg * 2.0 - 1.0; vec2 pDir = sign( colDir ); vec2 nextTexC = texC + pDir * texStep; if ( nextTexC.x <= texStep.x/2.0 || nextTexC.x >= 1.0-texStep.x/2.0 ) colDir.x = -colDir.x; if ( nextTexC.y <= texStep.y/2.0 || nextTexC.y >= 1.0-texStep.y/2.0 ) colDir.y *= -1.0; texCol.rg = colDir * 0.5 + 0.5; } vec3 col = texCol.rgb; gl_FragColor = vec4( col, 1.0 ); } </script> <script id="screen-shader-vs" type="x-shader/x-vertex"> precision mediump float; attribute vec2 inPos; varying vec2 vertPos; void main() { vertPos.xy = inPos.xy; gl_Position = vec4( inPos, 0.0, 1.0 ); } </script> <script id="screen-shader-fs" type="x-shader/x-fragment"> precision mediump float; varying vec2 vertPos; uniform sampler2D u_colorAttachment0; void main() { vec4 texCol = texture2D( u_colorAttachment0, vertPos.st * 0.5 + 0.5 ); gl_FragColor = vec4( texCol.rgb, 1.0 ); } </script> <body onload="sceneStart();"> <canvas id="glow-canvas" style="border: none;" width="256" height="256"></canvas> </body> 
0
source

Source: https://habr.com/ru/post/1383456/


All Articles