How to implement Shadertoy buffers in WebGL Javascript when trying to convert to JS?
Asked Answered
H

1

10

I'm attempting to convert a Shadertoy to Javascript and WebGL so that it can run independently from Shadertoy. Shadertoy has the concept of a buffer, in this example it re-cycles the buffer and improves the output image. It does this on the Buf A tab.

https://www.shadertoy.com/view/MdyGDW

It does this by writing its output to buffer A which is bound to iChannel0 and then it reads from the same iChannel0 on each draw cycle. How can I implement this concept of buffers in WebGL Javascript fragment shaders, WebGL uses the GLSL language. Specifically in this case it is able to write to the buffer and then read from the same buffer on the next render cycle.

Heinie answered 7/1, 2017 at 9:29 Comment(2)
FYI, There's this: #36984269 To add to what Kirill said you make 2 textures with 2 framebuffers, draw to the first, then next frame use the first as input and draw to the 2nd, the net frame use the 2nd as input and draw the the first. There's another example of drawing to framebuffers hereChinook
Yes as it seems I cannot write to the buffer I read from.Heinie
W
13

Shadertoy uses technique called rendering to texture. Suppose gl is our WebGL context. First we need to create a texture first pass will draw to:

// desired size of the texture
const W = 800, H = 600;
const textureA = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, textureA);
// allocate texture data.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, W, H, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// may be change texture parameters (at least magnification and
// minification filters since we won't render mip levels.

Then we create framebuffer object so we can draw to our texture:

const framebufferA = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferA);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureA, 0);

Now we can draw:

gl.bindBuffer(gl.FRAMEBUFFER, framebufferA);
gl.viewport(0, 0, W, H);

// draw first pass, the one which supposed to write data for the channel 0
// it'll use fragment shader for bufferA

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

// pass textureA as channel 0
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textureA);
gl.uniform1i(channel0Uniform, 0);

// draw second pass, the one with uses channel 0

There're a lot of materials about rendering to texture, for example here or here.

Washstand answered 7/1, 2017 at 14:25 Comment(2)
thanks for the answer, the link is broken thoughSanfred
rendering to a texture? here is the best and most recent link: webglfundamentals.org/webgl/lessons/…Dvandva

© 2022 - 2024 — McMap. All rights reserved.