Hi all,

this is what I am trying to do, all in 2D: - Draw an object with _draw commands on a CanvasItem - take the drawn stuff from a texture, apply a shader to it - take that as a texture/image and do image processing with it (e.g. erosion on a height map, and blend more noise in), - and finally blend that through another image/color filter (possibly a shader), where the user gets to see it as the end result.

So ideally, I need all of that to happen without the user seeing any of that on screen, only the last step as end result.

I understand that I can use _draw commands on an image when its data is locked; I understand how to program simple shaders as well both in code and with the visual shader. But I have a hard time wrapping my head around how to combine this. How do I get the drawn result of a CanvasItem shaded, and that Texture2D live back into a shader where it can be processed further? On the visual shader I can not for the life of me use a Viewport Texture as the Editor claims the Resource is "not local".

I've looked around a bit, but the whole thing seems rather convoluted as a concept if you need to do multi-step image processing. So, a long rant short -- what is the best workflow for getting these steps done:

  1. getting canvas draw operation onto a buffered texture,
  2. getting that as input texture into a shader and produce a shaded output texture, 3 getting that output texture back onto a CanvasItem or ImageRect or somesuch, which can draw in a blend/mix/add mode?

Also, how big is the speed difference between shader operations and draw commands on images? I know the latter must be slower for certain tasks, but are there any where the speed is compatible, or is the use of shaders always faster than any canvas _draw operations?

Thank you for your suggestions.

You can use a Viewport to get the finished result from a CanvasItem (Node2D or Control) into a single texture. Then you can pass the Viewport texture to the shader like a normal texture (sample2D viewport_texture - I think) and use it in Godot's shading language. For getting the output back out, I believe you can just attach the shader that takes the Viewport input to a TextureRect node, you just need to set the rendering flags to the canvas mode you want.

I'm not sure if it will achieve what you are looking for, but that is how I would approach it. The hardest part is just getting the drawn result from the CanvasItem into a texture, as Godot doesn't (that I know of) offer an easy way to get the resulting texture from the draw function.

@TwistedTwigleg said: The hardest part is just getting the drawn result from the CanvasItem into a texture, as Godot doesn't (that I know of) offer an easy way to get the resulting texture from the draw function.

Thanks @TwistedTwigleg !

I'll look into it.

So it seems this setup works only partially. - Create a TextureRect, do all necessary draw calls in a particular step in its draw function - If any drawing data changes, make sure the TextureRect's update() routine gets called in code (or draw it permanently by adding an update() in its process() function.) - Add that TextureRect to a Viewport, so the user does not see that drawing happening. - Elsewhere in your scene, add, for example a Sprite, and add any shaders to it you want to be used. Set that Sprite's texture to be a ViewportTexture of the previously created viewport. (This only works if its resource is set to "local to scene". - The Shader will now be applied to what you code-drew in the TextureRect.

However: - You will only be able to see any of your TextureRect drawing once the program runs, as it is in a separate viewport. - The resulting, shaded Sprite texture cannot be written to a buffer anywhere to create an image from that.

@TwistedTwigleg : Does anyone have a solution for this? Or will Shading-to-buffer only come in Vulkan/4.0?

2 years later