Mask a sprite with a dynamic mask

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By sleepprogger
:warning: Old Version Published before Godot 3 was released.

I am trying to mask a sprite with a dynamic mask updated from code.
This should be possible, or am i wrong ?

I know i can do the masking part via shader, but how do i manipulate (draw/remove circles, rectangles and polygons) the mask from code ?
Is there a way to create a texture from the current content of a CanvasItem ?

Alternatively if someone knows of a better way to reach my goal please share.
Thanks a bunch.

Do you want to make a Sprite or a Texture Button with a dynamic mask? because if I’m not mistaken a Sprite got no mask, only a picture which it displays

rustyStriker | 2016-10-23 14:54

I want to mask a sprite. This works via Shader/Light2D. But my problem is to generate dynamic masks at runtime.

sleepprogger | 2016-10-24 02:26

:bust_in_silhouette: Reply From: volzhs

You can make a mask with Light2D
See demo for it.

There is similar question and answer about making dynamic mask.

Thanks, i found that post (after submitting this question tho).
Manipulating the mask with brush_transfer should work for some things but is really suboptimal.

All that is needed is some way to render a CanvasItem to a texture or some other way to use the draw_* methods to create images/textures.
One could manipulate the image data pixel by pixel ofc. but i guess that would be slow as hell.
If there is no other way would this be something for a feature request ?

sleepprogger | 2016-10-24 02:24

:bust_in_silhouette: Reply From: sleepprogger

While volzhs answer is valid for static brushes i needed a way to draw like one is able to in the canvasItem draw method (draw_circle, draw_rect, draw_polygon…)
So here is what i ended up with:

Disclaimer: While this is working i am sure there are more efficient solutions

Create the mask renderer

1. Create a Viewport and set Render Target to enabled
2. Add a Node2D (or any CanvasItem) as child and use the _draw method to draw your mask. Paint everything which should be visible with white.

Use the mask
In GDScript use my_viewport.get_render_target_texture() to get your texture.
If you want to only show masked areas just plug that texture into a LightMask2D (See link posted by volzhs). In this case you are done and can stop reading.

If you want the reverse case (hide everything masked) you need to write a shader (at least that was the easiest way i could think of). Don’t fret, its easy.
Create a material and set the shader to new CanvasItemShaderGraph.
In the fragment shader wire it up like seen below:
enter image description here
In the shader we defined two parameter (Uniforms): One is the Texture we want to mask and the other our mask texture.
In GDScript you can provide them to the shader like:

sprite.get_material.set_shader_param("Tex", sprite.get_texture())
sprite.get_material.set_shader_param("Mask", mask_viewport.get_render_target_texture())

Thats it.
This approach is using a 4 channel (r,g,b,a) image for our mask and only uses 1, tho.
If it is somehow possible to use only one chanel images that should improve efficiency.

Hi, can you post a demo with source, i really don’t understand how to use your code :(, thanks!!

0nepixel | 2017-04-12 18:56
I didn’t check out godot since some time so no clue if it is still working.
Also the code isn’t really cleaned up but should be enough to get you going.

sleepprogger | 2017-04-12 23:18

Delite it please.

max3312 | 2019-09-11 07:36