I wanted to use shaders to compute Conway’s Game of Life, and I implemented a shader (not a compute shader). However, the shader only applied once, and then it just stopped.
Is there a way to make it run based on the output image of the shader? I have already checked out the official compute shader tutorial, but there seems to be lacking examples about dealing with images. Thanks for your help in advance.
shader_type canvas_item;
void vertex() {
// Called for every vertex the material is visible on.
}
int cell(ivec2 pos, sampler2D t) {
ivec2 s = textureSize(t, 0);
pos = (pos + s) % s;
return (texelFetch(t, pos, 0).r > 0.5) ? 1 : 0;
}
void fragment() {
// Called for every pixel the material is visible on.
ivec2 scaledUV = ivec2(UV * vec2(textureSize(TEXTURE, 0)));
int live = 0;
for(int dx = -1; dx <= 1; dx++) {
for(int dy = -1; dy <= 1; dy++) {
live += cell(scaledUV + ivec2(dx, dy), TEXTURE);
}
}
COLOR = vec4(vec3(float(live)), 1.0);
}
SubViewport has a property called render_target_clear_mode, which is set to never. This means that the screen won’t be cleared before the next frame is drawn.
For the ColorRect I set its anchors_preset to Full Rect, so that it fills the whole SubViewport.
Then I added a simple blur shader to the ColorRect. This shader reads the image on the screen and makes a blurry version of it by taking the average of 5 pixels.
shader_type canvas_item;
uniform sampler2D screen : hint_screen_texture;
void fragment() {
vec3 col = texture(screen, SCREEN_UV).rgb;
col += texture(screen, vec2(SCREEN_UV.x - SCREEN_PIXEL_SIZE.x, SCREEN_UV.y)).rgb;
col += texture(screen, vec2(SCREEN_UV.x + SCREEN_PIXEL_SIZE.x, SCREEN_UV.y)).rgb;
col += texture(screen, vec2(SCREEN_UV.x, SCREEN_UV.y - SCREEN_PIXEL_SIZE.y)).rgb;
col += texture(screen, vec2(SCREEN_UV.x, SCREEN_UV.y + SCREEN_PIXEL_SIZE.y)).rgb;
col *= 0.2;
COLOR = vec4(col, 1.0);
}
Now if I add a texture to the Sprite2D node, the image will be sharp, but when I hide the Sprite2D, the image will persist and get blurrier over time.
For Game of Life you just have to change the shader and maybe figure out a different way to set the initial state.
From my understanding, you used hint_screen_texture to access the already-rendered image on the screen and apply the shader to the result. Is that correct? Additionally, I can’t quite understand the reason why the texture only starts to blur when the Sprite2D is hidden. Shouldn’t the texture start to blur only when it’s visible on the screen? Again, thanks for your kind help. I appreciate everything you have done.
Sorry for the late reply. Your understanding of hint_screen_texture is correct. And the Sprite2D kind of gets blurry even when it’s visible, but you can’t see it, because a new sharp image is drawn on top of the ColorRect every frame. Once the sprite is hidden, you can see the blur effect happening uninterrupted.