I am currently trying to create a tiny pixelart tool for godot, but it's not possible to use the draw_line() method for erasing pixels. There seems to be no way in replacing the alpha value of a pixel with another alpha value at the moment - in the way you can draw with another color on top of old lines.
As @Zylann said
@blurymind you could overwrite alpha pixels as if they were a normal color component, I believe there are blending modes in OpenGL to do that, but Godot doesn't expose them. This is a precision I added at the beginning of the thread, no need to repost the entire code :)
this use case concerns blending mode when rendering on texture, not on screen (which wouldn't make much sense because screen has no alpha)
I think there is a workaround but it's impractical, you would need to do your own blending with a shader by drawing transparent pixels as a red color on a separate texture, and then blends your image + the red texture together with a shader that erases pixels that come in contact with red pixels, to render it on the final render target which you can then save... but an appropriate control on blending mode would be much more simpler.
Currently it is possible, but very impractical.
Here is an example code for drawing freehand lines:
extends Container
var _pen = null
var _prev_mouse_pos = Vector2()
var viewport = Viewport.new()
func _ready():
set_process_input(true)
# Make it so it renders on a texture
viewport.set_as_render_target(true)
# Set the size of it
viewport.set_rect(get_parent().get_rect())
viewport.set_transparent_background(true)
# I tried to set the background color, but none of this worked...
_pen = Node2D.new()
viewport.add_child(_pen)
_pen.connect("draw", self, "_on_draw")
# Don't clear the frame when it gets updated so it will accumulate drawings
viewport.set_render_target_clear_on_new_frame(false)
add_child(viewport)
# Use a sprite to display the result texture
var rt = viewport.get_render_target_texture()
var board = Sprite.new()
board.set_texture(rt)
board.set_centered(false)
add_child(board)
set_process(true)
func _process(delta):
_pen.update()
var color = Color(1, 1, 0,1)
func _on_draw():
var mouse_pos = _pen.get_global_mouse_pos()
_pen.draw_line(mouse_pos, _prev_mouse_pos,color,5 )
_prev_mouse_pos = mouse_pos
func _input(event):
if event.is_action_pressed("eraser"):
print('using eraser now')
color = Color(VisualServer.get_default_clear_color()) #<-- this approach to setting the brush to be an eraser doesnt work!
if event.is_action_pressed("save"):
viewport.queue_screen_capture()
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
var captured = viewport.get_screen_capture()
captured.save_png("res://screenshot.png") #<-- capture and you will see why
color = Color(VisualServer.get_default_clear_color())
Will fail to erase the yellow pixels in the example.
Instead it simply writes the background color and you get this ugly grey color when you export the image with viewport.get_screen_capture():
The ideal solution for me personally is if I could set the color value to (0,0,0,0) and have that act as an eraser.
If we could have Godot actually have VisualServer.get_default_clear_color() be a color that erases pixels whenever set_transparent_background is true- that would make more sense too.
Or perhaps the best approach to this is to have a new blending mode that supports it.
I am assuming that something has to be done to the way godot's draw_line method works when writing to a texture. Any solution to this is very much welcome.
Making it possible will allow people to implement a freehand eraser tool and possibly other very useful things using the draw_line method
I would precise that this use case concerns blending mode when rendering on texture, not on screen (which wouldn't make much sense because screen has no alpha)
@Zylann we can still screen capture with alpha though
The viewport has
set_transparent_background ( true )
http://docs.godotengine.org/en/stable/classes/class_viewport.html?highlight=screenshot#class-viewport-queue-screen-capture
has anyone figured out a way to erase pixels using the draw_line method?
@blurymind it's about adding a new blend mode I think, that will use alpha like a regular color, to replace the alpha already in the target buffer. Maybe @reduz knows how to do it?
@reduz is there a way to erase pixels or overwrite pixels using the draw_line method?
I need it to implement a simple freehand eraser tool
@Tvs-Frank you can't write the background color to "erase" pixels if your background is not a solid color (or worse, animated)
I was wondering, is there a way to overwrite pixels? If so, we could over write the pixels with 1 for alpha with pixels with 0 alpha.
How do you do that in godot?
@blurymind you could overwrite alpha pixels as if they were a normal color component, I believe there are blending modes in OpenGL to do that, but Godot doesn't expose them. This is a precision I added at the beginning of the thread, no need to repost the entire code :)
I think there is a workaround but it's impractical, you would need to do your own blending with a shader by drawing transparent pixels as a red color on a separate texture, and then blends your image + the red texture together with a shader that erases pixels that come in contact with red pixels, to render it on the final render target which you can then save... but an appropriate control on blending mode would be much more simpler.
Can we please tag this as a feature request or should I create another
issue for a request?
On 31 Aug 2017 10:42, "Marc" notifications@github.com wrote:
@blurymind https://github.com/blurymind you could overwrite alpha
pixels as if they were a normal color component, I believe there are
blending modes in OpenGL to do that, but Godot doesn't expose them. This is
a precision I added at the beginning of the thread, no need to repost the
entire code :)I think there is a workaround but it's impractical, you would need to do
your own blending with a shader by drawing transparent pixels as a red
color on a separate texture, and then blends your image + the red texture
together with a shader that erases pixels that come in contact with red
pixels, to render it on the final render target which you can then save...
but an appropriate blending mode would be much more simpler.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/10255#issuecomment-326245277,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AGMbVYssoQc0hQ7umU3SVdntrVf5ksvOks5sdoAYgaJpZM4O0ygy
.
Sounds like a good feature request. If you can edit the original post for clarity based on the follow-up discussion, that would be great.
@akien-mga Thank you :)
I updated the title and the first post to more accurately reflect the request
Please let me know if it needs more amendments
@Zylann another approach could be to have VisualServer.get_default_clear_color() be a color that erases pixels whenever set_transparent_background is true? Not sure what design would be most elegant here
a color that erases pixels whenever set_transparent_background is true
A Color cannot hold such info beyond having an alpha of zero. What you mean is again a blend mode (say, instead of mixing alpha, OpenGL will replace alpha with a different calculation)
@Zylann A new blending mode would be awesome to get. Is there anyone interested in implementing it?
Which node will acquire the new blending mode and how would an example gdscript that enables and uses it to freehand erase pixel look like?
I updated the title and description in the first post again to reflect that
I think it would be an option in the material (or shader?) that let you choose how the result is blended, and it would work on anything that currently can have a blend mode (so anything that the engine can draw, basically).
Currently we have these:
Mix is the most commonly used blend mode.
I'm not sure what Premult Alpha does though, and not sure how add, sub and mul treat it either.
In Unity shaders, blending is specified as two keywords instead of one, so there might be combination of things at play.
@Zylann would we still be using gdscript and draw_line method though? Or are we writing a shader?
You would still draw anything you want like the engine allows you to. I mentionned shaders just for the "replace alpha" part, but it's not really about coding the shader, mostly specifying a blending mode the Godot way so that OpenGL does what you need in the renderer. Like, blend mode "Add" adds color to the image. "Sub" subtracts it. "Mul" multiplies it. It sounds logical to have a way to say "Replace alpha" then, or something close to what OpenGL needs.
This SO threads is a similar problem to yours https://stackoverflow.com/questions/4074955/blending-a-texture-to-erase-alpha-values-softly-with-opengl
Same "easy" solutions are being discussed too in case your background is a solid color, but the general blending mode option is also mentionned.
They mention this:
...If so, instead of "erasing", you could simply paint background over it. That would be somewhat simpler, as you would only change the color and not the blending mod.
Which is pretty much one of the suggestions we came up with here.. Notably:
color = Color(VisualServer.get_default_clear_color())
Unfortunately godot doesnt treat that color as a color with 0 alpha that erases other colors - which would the expected behaviour be.
That said, I would take the option of a new blending mode too. Either would solve it. The question now is which one is a lower hanging fruit and does it fit best with the current design?
Do we need to have both another blending mode and VisualServer.get_default_clear_color() do what it's supposed to, instead of this:
https://user-images.githubusercontent.com/6495061/29914660-45be9be4-8e31-11e7-8ee6-7d014da28662.png
What would the most elegant gdscript method be to set the masking color that erases pixels?
What part of the source code is in charge of blending modes. I wish I knew as much c++ as I do python 🖌
I think the best way to do this would be:
1) To add a draw_line function to Image
2) To upload the image when it changes
3) To use it as either light or mask for the framebuffer
@blurymind VisualServer.get_default_clear_color()
will never help you draw on the alpha channel, at best it will give you which color to draw in order to "fake" transparency by drawing the same background, but then the image won't be transparent if you want to save it afterwards.
@reduz why not exposing the blend options? They exactly do what an app involving painting would need, and work faster than painting on the CPU and uploading the image every frame (also would miss all features the renderer let us draw).
Sure, having a 1px-wide breisenham on CPU would fit this very specific request a bit better than GDScript, but I feel like it would miss a awesome quick win for using the renderer.
Also maintaining a secondary texture as mask would work, but you would need to redraw on it the same things that you draw on the main texture, when not using the eraser, in order to refill alpha to 1. And when it comes to save as image another rendering would occur to flatten those two textures into one. It would maybe work, but in an impractical way.
@Zylann there is not much of a blend option to expose, GPU blending is very very limited, not near as complex as what something like Photoshop can do.
He can also do this using GPU by drawing to another viewport and use it to blend..
Are you sure it's not supported? The SO thread mentionned this:
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
Also the same kind of options are available to write in Unity shaders.
@Zylann Exposing higher level blending options will not happen, because Godot tweaks the shader and changes the blend function according to what it's doing internally.
In Unity you can do this, but you have to write your own shader passes for forward base, forward add, deferred, shadow, etc. That's not the idea in Godot, as It's meant to be more user friendly.
That said, given this is 2D only, adding color replace and alpha replace models should be possible to the list of 2D blend modes.
@reduz you're right, having a color replace and alpha replace models would be only useful for 2d drawing anyway.
@Zylann makes a good point that it would be beneficial to have it, since getting this sort of functionality in a game or an app would be both much more straightforward and more performant.
I would be very thankful if somebody looks into it and will help in any way possible with testing/examples :)
A drawing app is not the only use case for this I can think of either. There are many interesting things that can be done. Cool editor addons can come out of it
Even a simple pixel editing app addon could help rapid prototyping without leaving the editor. A dirty mockup used to design gameplay can be made by the designer and later used by an artist for sprite dimensions
While thinking about implementing GPU-based terrain painting and sculpting, I figured out I needed alpha override blend modes (among other things). Indeed, the case is similar to general texture painting, while in this case the texture is used as a "data" rather than forcibly something to draw as is.
What I would need would basically treat the alpha channel like any other channel (R, G, B), which gives the ability to paint on full splatmaps or various other maps that use 4 channels at once. That use case needs a 2D viewport though.
Edit: I realized one problem with this, though... if those blend modes are available in 2D only, but those textures are then used in 3D, that means it could create a constant reimport loop due to the fact VisualServer auto-reimport color space of such textures when used for 3D :x
I second the option to add a blend mode which simply says "replace" or simply "off". Basically just turn off blending when rendering with that shader. The alpha (along with the RGB value) will just be written into the frame buffer as is without blending it with the current value.
I'm running into this issue as well when working on my texture painter. There seems to be no way to decreate alpha by drawing something, aka erasing. So if the alpha of a pixel is 1, there's no way to get it back down to 0. The painting shader is 2D, so a "alpha replace" 2D blend mode would be perfect and solve all my issues.
I added this to master a week or so ago, check the render_modes, there
should be a blend_disabled there. If you use SCREEN_TEXTURE you can read
the current pixel value, do your own modifications, and write back whatever
value you want
On Tue, 22 May 2018 at 1:58 am, Bauxitedev notifications@github.com wrote:
I'm running into this issue as well when working on my texture painter
https://github.com/Bauxitedev/godot-texture-painter. There seems to be
no way to decreate alpha by drawing something, aka erasing. So if the alpha
of a pixel is 1, there's no way to get it back down to 0. The painting
shader is 2D, so a "alpha replace" 2D blend mode would be perfect and solve
all my issues.—
You are receiving this because you commented.Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/10255#issuecomment-390698250,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AB2vacvhG9_Lo4fKDJX0gxMzQWybms5Iks5t0uQ9gaJpZM4O0ygy
.>
Kindest regards,
Bastiaan Olij
https://www.facebook.com/bastiaan.olij
https://twitter.com/mux213
https://www.youtube.com/channel/UCrbLJYzJjDf2p-vJC011lYw
https://github.com/BastiaanOlij
Oh look, my PR is even referenced up above :) #18462 :) Couldn't see that on my poor mobile phone
@BastiaanOlij can you share a simple code snippet demonstrating how this could be applied on a draw operation such as draw_line for example
I kind of already posted a minimal example where it doesnt work because of the feature missing. :) I wanna test it out in the weekend and was wondering what to alter in my little example to make it erase pixels
@blurymind check out the shaders in my terrain editor:
https://github.com/BastiaanOlij/godot-terrain-edit/blob/master/Shaders/Splatmap-brush.shader
Keep in mind, you need a fresh master build for this, it was only added a week or so ago so this is not in any of the official builds and won't be till 3.1 comes out.
(and also keep in mind that if you do use SCREEN_TEXTURE, it creates a copy of your viewport texture for the first shader that uses it, so you can't do any overlapping logic)
@BastiaanOlij so it can only be done via a shader? Is there no way to use a simple draw() method?
Seems like taking a long route just to be able to erase pixels you painted in a simple pixel editor.
It does make a lot more sense in the context of a 3d terrain editor though
@blurymind thing is, when you're using viewports you're dealing with a texture that lives in GPU memory (whatever the correct term for that is:)). Shaders are the most effective way to write into that but I do see that in the use case you sketch it feels like overkill :)
However you don't have simple direct access to it.
I guess we could add some sort of interface that allows you to call glTexSubImage2D to overwrite a small part of a texture with a subimage.
In my usecase, the main problem was that we cant use any of the draw methods to erase pixels - which is required if one is to create a pixel editing tool with a simple eraser brush.
The original idea for the addon was to enable editing pixel art inside godot without leaving it- just the ability to draw lines and erase them with a brush. We got the first part down.
So in order to be able to also delete pixels, I have to now completely abandon the draw_line method - which is really what is expected to be used in the api for such a thing.
I was hoping that one would be able to simply set the color of a line to a specific value - with any alpha value - and that alpha value should be able to overwrite any pixels that the line is drawn ontop of.
So to make an eraser - it could be as simple as setting the alpha to 0 and putting the line on an overwrite pixels below instead of composit blend mode.
I think that is what was suggested as another blending mode - surely there is some complexity to achieve it - exposing that functionality to draw methods would make them much more powerful imo. Without it they feel kind of limited to only be able to draw new lines, erase specific lines, or erase the entire canvas. We cant directly erase pixels by drawing lines ontop of them at all
In my usecase, the main problem was that we cant use any of the draw methods to erase pixels - which is required if one is to create a pixel editing tool with a simple eraser brush.
You can if the viewport in which you draw has a render-target. Any draw method will work, with the appropriate material or shader, nothing complex. This is the actual solution to being able to erase pixels, that's how I prototyped a drawing tool :)
I managed to delete drawn pixels following @Zylann suggestion.
I have the next Node structure (Control Node --> Viewport, Sprite)
The viewport has this properties:
The board node is a Sprite with a CanvasItemMaterial on the Material property:
On the CanvasItemMaterial the Blend Mode is set to add:
Then I can use the method draw_line with an HEX ARGB color to erase previously drawn pixels.
I use next color to delete drawn pixels:
Color("#ff000000")
Can you share your example project?
On Sun, Mar 10, 2019, 11:12 PM AlvaroAV notifications@github.com wrote:
I managed to delete drawn pixels following @Zylann
https://github.com/Zylann suggestion.I have the next Node structure (Control Node --> Viewport, Sprite)
[image: image]
https://user-images.githubusercontent.com/5870043/54092784-9a06cf80-4390-11e9-8ed5-2ca50a0e8cc7.pngThe viewport has this properties:
- Transparent BG = True
- Clear Mode = Next Frame
The board node is a Sprite with a CanvasItemMaterial on the Material
property:
[image: image]
https://user-images.githubusercontent.com/5870043/54092840-7001dd00-4391-11e9-9a6b-041772880b3a.png[image: image]
https://user-images.githubusercontent.com/5870043/54092799-cfabb880-4390-11e9-927e-2d9947e1ffc5.pngThe Blend Mode set to add on the CanvasItemMaterial
Then I can use the method draw_line with an HEX ARGB color to erase
previously drawn pixels.I use next color to delete drawn pixels:
Color("#ff000000")
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/10255#issuecomment-471364039,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AGMbVS9xDpQSnLGPAT8t0II3Igf0C6XZks5vVZF3gaJpZM4O0ygy
.
@blurymind I'll try to upload an example project with this working on Godot 3.1
I'm quite busy until weekend, I'll let you know when it's ready
Any update on this? I've tried @AlvaroAV method but having the texture in add blend mode is problematic if I intend to have multiple textures stacked, need them on normal mode to be able to paint them properly.
I also managed to clear pixels using what is suggested above: Using a Viewport
and draw inside that Viewport
. However I'm using Line2D
to implement both draw and eraser.
The drawing Line2D
has material blend mode BLEND_MODE_MIX
, while the eraser Line2D
has material blend mode BLEND_MODE_SUB
.
Very simple demo project:
https://github.com/starryalley/godot-draw-eraser-demo
Feature and improvement proposals for the Godot Engine are now being discussed and reviewed in a dedicated Godot Improvement Proposals (GIP) (godotengine/godot-proposals) issue tracker. The GIP tracker has a detailed issue template designed so that proposals include all the relevant information to start a productive discussion and help the community assess the validity of the proposal for the engine.
The main (godotengine/godot) tracker is now solely dedicated to bug reports and Pull Requests, enabling contributors to have a better focus on bug fixing work. Therefore, we are now closing all older feature proposals on the main issue tracker.
If you are interested in this feature proposal, please open a new proposal on the GIP tracker following the given issue template (after checking that it doesn't exist already). Be sure to reference this closed issue if it includes any relevant discussion (which you are also encouraged to summarize in the new proposal). Thanks in advance!
Most helpful comment
I added this to master a week or so ago, check the render_modes, there
should be a blend_disabled there. If you use SCREEN_TEXTURE you can read
the current pixel value, do your own modifications, and write back whatever
value you want
On Tue, 22 May 2018 at 1:58 am, Bauxitedev notifications@github.com wrote:
Kindest regards,
Bastiaan Olij
https://www.facebook.com/bastiaan.olij
https://twitter.com/mux213
https://www.youtube.com/channel/UCrbLJYzJjDf2p-vJC011lYw
https://github.com/BastiaanOlij