Hello, I am trying to optimise one of my shaders by grabbing the shaders previous result, from the viewport, and putting it back into a sampler2D on the shader. The shader will then simply return pixels from this sampler2D for most of the texture and just has to re-calculate where something has changed (eg the screen edge when it scrolls).

I cannot get the viewport texture to show up in the shader, I tried simply pointing the sampler2D uniform on the shader at the viewport, which resulted in garbage (didn't expect this to work anyway), then I tried grabbing the texture in GDScript (same), then grabbing the texture with duplicate() and duplicate(true) which does nothing (texture is null).

Here is a small example - proceduralshader

Here the shader (shader is on the Sprite) is grabbing the next right (x+1) pixel from the sampler and also drawing a small blue area on the right of the viewport. If it were working correctly it would "drag" the blue area across the whole viewport.

I can save the viewports texture, using .get_data.save_png, which proves it looks as expected, and is obtainable. I feel I have missed something simple.

I did find this https://github.com/godotengine/godot/issues/17593 which might be related, but I tried the suggested work arounds without any joy.

Any idea what I am doing wrong here? Is this even possible?

Edited the opening post to fix the link, had a formatting error.

Hi #cyberreality - Thanks for trying to help but your code more or less matches what I am already doing. It did help me come up with a solution (workaround?) though - I found that grabbing the image (like you do with get_data()), then turning it back into an ImageTexture and passing that to the shader does seem to work. The GDScript code (in _Process) looks like this:

	var previousimage = $ViewportContainer/Viewport.get_texture().get_data()
	var previoustextureimage := ImageTexture.new()
	previoustextureimage.create_from_image(previousimage)
	$ViewportContainer/Viewport/Sprite.material.set_shader_param("previous_texture", previoustextureimage)

Hopefully this will help anyone else who lands here, though the lack of response suggests not many people doing this?

The above works, except that, as this is copying data from the GPU memory, to normal memory, then back to GPU memory again it is incredibly expensive, not something you want to do each frame, and eats up any time saved from the optimisation. Back to the drawing board :/

8 months later

Wouldn't it be just perfect to be able to limit the FPS of the Camera? Then it could all stay in the GPU and we could avoid duplicating the texture in order to control the simulation speed.

a year later