Hey,

I'm trying to use a shader to create a brush system. The shader would need the previous texture as a uniform sampler2D.

In Unity (without compute shaders...) I would use Graphics.Blit in order to achieve this. Any idea on how I can do this using Godot ? I'm trying to do this using viewport something like that:

Image img = parentViewport.GetTexture().GetData();
ImageTexture imgTex = new ImageTexture();
imgTex.CreateFromImage(img);
material.Set("shader_param/tex", imgTex);

But unfortunately I'm getting artifacts...

Ideally I would be able to apply the shader on the Sprite, blitt the result in another texture for setting the new "prev texture" for the next iteration.

Thank you in advance !

@panicq said:

But unfortunately I'm getting artifacts...

Care to show the artifacts? Perhaps someone can share a solution or an idea towards solving it.

According to https://lazyfoo.net/tutorials/OpenGL/22_texture_blitting_and_texture_padding/index.php theres some manual padding work that needs to be done, but this tutorial is doing texture blitting in straight-up OpenGL/C program. Can't say I've tried to do something in the subset of GLSL/OpenGL that is the godot ShaderLang... But using a viewport for this is a good call I recon.

I'm getting artifacts because the sprite inside the viewport (on which I'm drawing) is smaller than the viewport, therefore when capturing the data of the viewport I have more than needed and the image scales down until nothing lefts. Anyway I don't think this is the right way of doing this in the sense that I have a canvas (with panning and zooming navigation) and getting the texture of the viewport will only give me parts that are visible from the viewport... What I really need is a blit, exactly like unity does with Graphics.Blit passing a source and a destination render texture using a material.

Ah, so you are literally creating a painting/drawing application in godot? Perhaps this might be of interest: Pixelorama - Your Free & Open Source Sprite Editor

An open source pixel drawing tool developed in godot. :) Since it's open source you can probably look through it's sources for some ideas and direction. And if @Overloaded has the time perhaps the author can offer some advice as well.

Thanks but this is not what I need. He's not using the GPU in order to draw and right now I'm using the CPU for my brush using SetPixel but this is extremely slow when reaching big texture sizes (2048 for instance). I want to take advantage of the GPU as calculating the brush is not that hard in a shader providing the fact that I have the previous state of the texture as an input so brush strokes can accumulate.

@panicq said: Anyway I don't think this is the right way of doing this in the sense that I have a canvas (with panning and zooming navigation) and getting the texture of the viewport will only give me parts that are visible from the viewport...

It might be as simple as having multiple viewports, one just for end-user facing display, and others for the processing purposes. Note that you can have multiple 'viewports' - it's essentially just a glorified rendertarget.

@Megalomaniak I created a fresh project to do a simple test:

I have a simple viewport containing a sprite both have a 512k size.

I have a shader doing a simple thing in the frag:

vec4 sample =   texture(prevTex, UV.xy);

if(distance(UV.xy, mousePos) < 0.1)
	 sample = mix(sample, vec4(1,0,0,1), 0.1f - distance(UV.xy, mousePos));
	
COLOR = sample;

I've attached a script on the viewport that sets the shaders uniforms in the process like this:

public override void _Process(float delta)
{
	Vector2 mousePos = GetMousePosition() / 512.0f;

	mousePos.y = 1.0f - mousePos.y;
	
	sprite.Material.Set("shader_param/mousePos", mousePos);
	sprite.Material.Set("shader_param/prevTex", GetTexture());
}

How can I be sure that rendering of the frame is finished at the point where I set the uniforms in the process. Is there a OnPostRender callback (like in Unity) ?

Here is my issue visually:

Thanks in advance.

There is no post render callback like in Unity, at least not that I am aware of, but you can use a yield so code is not called until a frame has been rendered. Going off memory, I believe the syntax is something like: yield(get_tree(), "idle_frame").

@TwistedTwigleg said: There is no post render callback like in Unity, at least not that I am aware of, but you can use a yield so code is not called until a frame has been rendered. Going off memory, I believe the syntax is something like: yield(get_tree(), "idle_frame").

I've found that:

	VisualServer.Singleton.Connect("frame_post_draw", this, "on_post_render");

But anyway it is not resolving my issue...

YEAH !! I finally found a solution to my issue and created the base of GPU brush system :D

void _on_post_render()
{
	if (canDraw)
	{
		sprite.Material.Set("shader_param/mousePos", mousePos);

		//I needed to create a copy here :D
		ImageTexture imgTex = new ImageTexture();
	        Image img = GetTexture().GetData();
	       imgTex.CreateFromImage(img);
		imgTex.SetData(img);
        
		sprite.Material.Set("shader_param/prevTex", imgTex);
	}
}

I though Texture would return a copy of the texture

Yeah, another thing I was considering mentioning was that you might want to look at dealing with the visual server directly, but that's a lower level thing that I've never ventured into myself, so wasn't confident enough to recommend.

Glad to see you've found your solution.

Oh man! It looks so responsive, even though you are copying image data around. I'd like to experiment with that. :)

Nice work. I tried to make a drawing program years ago in GDI but it was too slow to be usable. Never finished that project but it was a lot of fun messing around with.

3 years later