stevensona/shader-toy

bug report on self-input-buffer and solution to it

duwangthefirst opened this issue · 1 comments

I'm running this shadertoy demo: https://www.shadertoy.com/view/4ddSz4

it has two buffer: bufferA and mainImage, and the final result is not right and the console log shows some warning about "Framebuffer is incomplete: Attachment has zero size.".

In vs code, after edit the html file generated by this plugin (right click -> Shader Toy: create portable GLSL preview), I managed to solve this problem:
just change the declaration of the "resolution" variable from:

  let renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true,
    context: gl,
    preserveDrawingBuffer: true,
  });

  let resolution = new THREE.Vector3();

to:

  let renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true,
    context: gl,
    preserveDrawingBuffer: true,
  });
  let resolution = new THREE.Vector3(
    window.innerWidth,
    window.innerHeight,
    0.0
  );

BTW, the two glsl files are pasted below: (with "#iChannel0" definition added)
a.glsl:

#iChannel0 "self"

vec4 readMemory(vec2 coords) {
    return texture(iChannel0, (coords + 0.5) / iChannelResolution[0].xy);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    //Read data
    vec4 data1 = readMemory(vec2(0, 0));
    vec2 pos1 = data1.xy;
    vec2 vel1 = data1.zw;

    vec4 data2 = readMemory(vec2(1, 1));
    vec2 pos2 = data2.xy;
    vec2 vel2 = data2.zw;

    //Set initial values
    if(pos1.x == 0.0 && pos1.y == 0.0) {
        pos1 = vec2(20, 30);
    }

    if(pos2.x == 0.0 && pos2.y == 0.0) {
        pos2 = vec2(iChannelResolution[0].x - 20.0, 30);
    }

    if(vel1.x == 0.0 && vel1.y == 0.0) {
        vel1 = vec2(1, 1);
    }

    if(vel2.x == 0.0 && vel2.y == 0.0) {
        vel2 = vec2(-1, 1);
    }

    //Update positions
    pos1 += vel1;
    pos2 += vel2;

    //Check boundaries and bounce
    if(pos1.x > iResolution.x) {
        vel1.x = -1.0;
    }
    if(pos1.x < 0.0) {
        vel1.x = 1.0;
    }
    if(pos1.y > iResolution.y) {
        vel1.y = -1.0;
    }
    if(pos1.y < 0.0) {
        vel1.y = 1.0;
    }

    if(pos2.x > iResolution.x) {
        vel2.x = -1.0;
    }
    if(pos2.x < 0.0) {
        vel2.x = 1.0;
    }
    if(pos2.y > iResolution.y) {
        vel2.y = -1.0;
    }
    if(pos2.y < 0.0) {
        vel2.y = 1.0;
    }

    //Write data
    if(fragCoord.x < 1.0 && fragCoord.y < 1.0) {
        fragColor = vec4(pos1.x, pos1.y, vel1.x, vel1.y);
    } else if(fragCoord.x < 2.0 && fragCoord.y < 2.0) {
        fragColor = vec4(pos2.x, pos2.y, vel2.x, vel2.y);
    } else {
        discard;
    }

}

main.glsl:

#iChannel0 "file://a.glsl"

vec4 readMemory(vec2 coords) {
    return texture(iChannel0, (coords + 0.5) / iChannelResolution[0].xy);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec4 data1 = readMemory(vec2(0, 0));
    vec4 data2 = readMemory(vec2(1, 1));

    vec2 pos1 = data1.xy;
    vec2 pos2 = data2.xy;

    vec4 col = vec4(0, 0, 0, 1);
    if(distance(pos1, fragCoord.xy) < 20.0) {
        col = vec4(1, 0, 0, 1);
    } else if(distance(pos2, fragCoord.xy) < 15.0) {
        col = vec4(1, 1, 0, 1);
    }

    fragColor = col;
}

Sorry @duwangthefirst I have very little time to work on hobby projects these days and my other projects consumes all of that. Since you have a solution here can you perhaps just make a PR for it? Sounds like a simple solution.