patriciogonzalezvivo/glslCanvas

How to use backbuffer?

yvan-sraka opened this issue · 15 comments

Hello,

Is it possible to use a kind of uniform sampler2D backbuffer to get the pixels color of previous screen frame?

Thank you in advance,

Not now. But WOULD be GREAT, specially because that code is already implemented on glslViewer as u_backbuffer.

To be implemented probable all the shader compilation need to be encapsulated on a "Shader" class and a FBO need to be implemented from the ground up. The rest is pretty much like glslViewer.

The main shader when it compiles search for uniform sampler2D u_backbuffer if it's there... creates a FBO where it renders the scene. (having that ON for all cases would be a performance hit).

I'm writing a wrapper on glsl-canvas that helps write buffers. demo here , repo here. would be great to have it built in. The idea is to write a single .glsl with // u_buffer tokens that get splitted into programs. example here. This way you can handle as many buffers as you need.

Wow @actarian this is great! Thanks so much!

One thing that worries me is that in case of using this outside glslCanvas will need some edition and modification. Reusing the code as is on other environments I think is important because GlslEditor, GlslCanvas and GlslViewer are designed mostly as prototyping tools. So I was thinking in another way to parse the code for the different buffers that is 100% compatible with any other enviroment based on GLSL #defines

Here is an example:

#ifdef GL_ES
    precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

uniform sampler2D u_buffer_0;
uniform sampler2D u_buffer_1;

vec2 coord(in vec2 p) {
    p = p / u_resolution.xy;
    if (u_resolution.x > u_resolution.y) {
        p.x *= u_resolution.x / u_resolution.y;
        p.x += (u_resolution.y - u_resolution.x) / u_resolution.y / 2.0;
    } else {
        p.y *= u_resolution.y / u_resolution.x;
        p.y += (u_resolution.x - u_resolution.y) / u_resolution.x / 2.0;
    }
    p -= 0.5;
    p *= vec2(-1.0, 1.0);
    return p;
}

#define uv gl_FragCoord.xy / u_resolution.xy
#define st coord(gl_FragCoord.xy)
#define mx coord(u_mouse)
#define rx 1.0 / min(u_resolution.x, u_resolution.y)
#define ts abs(sin(u_time))

float fill(in float d) { return 1.0 - smoothstep(0.0, rx * 2.0, d); }
float stroke(in float d, in float t) { return 1.0 - smoothstep(t - rx * 1.5, t + rx * 1.5, abs(d)); }
float sCircle(in vec2 p, in float w) { return length(p) * 2.0 - w; }

void main() {

#if defined(BUFFER_0)

    // u_buffer_0
    float v = fill(sCircle(st - 0.1 * ts, 0.1));
    gl_FragColor = vec4(v, 0.0, 0.0, 1.0);

#elif defined(BUFFER_1)

    // u_buffer_1 
    float v = fill(sCircle(st + 0.1 * ts, 0.1));
    vec3 color = texture2D(u_buffer_0, uv).rgb;
    color = mix(color, vec3(0.0, v, 0.0), v); 
    gl_FragColor = vec4(color, 1.0);

#else

    // Main
    vec3 color = texture2D(u_buffer_1, uv).rgb;    
    gl_FragColor = vec4(color, 1.0);
#endif

}

From the perspective of the parsing is not necessary to search for comments, just if the #define BUFFER_XX is present. then on compilation the shader needs to be compiled 3 times using adding the BUFFER_0 the first time, BUFFER_1 the second time and nothing the third time. This hopefully will help keeping things consistent and more robust.

What do you think?

@patriciogonzalezvivo Your option is more elegant and 100% compatible (and we could strip the comment token away), but in this way buffers and main have to share the same outer functions (not a big problem, but there could be some use cases where separation is needed). On the other hand glslCanvas plugin itself has all the code to make buffers workable and I think will be the most common case. I've planned to add an export functionality on the vsCode plugin that could split the codes or export a production ready version. It could be added to glslEditor too.

I think both ways have good points, so you decide. As for now the code compile every program submitting all the textures and buffers, this way you can read / write from all the sources. I think shadertoy let you do this way.

Just to clarify, the #if and #ifdef will work outside the main() too. : )

I'm just trying to keep the ecosystem of glslViewer, glslEditor and glslCanvas consistent all across. Keeping that coherent will empower other projects like your awesome vsCode plugin : )

Right, I totally agree. So I will check it out and do another pull request! : )

Thanks @actarian!! REALLY EXCITED FOR THIS thanks for contributing to the project!

Wow! Just came here on a whim to see if you had considered this feature. Glad to hear its already on its way.

Commits added. Thank you @patriciogonzalezvivo for inspiring us all! : )

@actarian thanks a lot! I have push a new commit (and new release). I love the fact that now we have this feature! Thanks a lot.

I made a small change, texture are in u_buffer0, u_buffer1, u_buffer2, etc... just to keep it coherent with the automatic name for uploaded textures which is u_tex0, u_tex1, u_tex2, etc..

I hope you don't mind that I change the buffer example to make it a little more simple and coherent with the other one.

Hope you don't mind

@patriciogonzalezvivo no problem. I was just writing that there's a missing line here:

this.BUFFER_COUNT = 0;
const buffers = this.getBuffers(this.fragmentString);

I forgot to reset the buffer counter on every update.

@patriciogonzalezvivo sure, could you commit last changes?

Already did. I didn't start w expanding to #ifdef yet... unless you want to take it

@patriciogonzalezvivo check src/glslCanvas.jsand buffers.htmlon master branch are dated last week.