0 votes

Hi everyone!
I'm struggling with a problem that's driving me crazy. Basically, I've got a Sprite3D, and what I want to do is to modify the texture image when I hit a few keys (for instance, by pressing a key you can change the image colors, by pressing another you can draw a line, etc.).
I tried to find a solution on the shaders documentation, but I've not found what I needed.
Can someone help me? Thank you so much!

Godot version 3.3.4
in Engine by (96 points)

You just want to do it with "Shader"? Have you looked at other solutions?

What do you mean when you say you want to modify the image? You mean drawing pixel-by-pixel on it directly? (instead of just changing the texture to another one)

Yes, I looked at other solutions, but I didn't find anything.

Yes, I mean any single pixel I want (or, precisely, drawing on it).

1 Answer

+1 vote
Best answer

Surprising you could not find anything about the topic, I thought that would be covered somewhere on the internet as it doesnt seem so uncommon.

There are two ways you can achieve this.

First one is to use the Image and ImageTexture classes.
Image stores pixels and can be modified directly from GDScript.
ImageTexture is a texture that can be created from an Image, which then you can apply to your Sprite3D to render it.

extends Sprite3D

var _image := Image.new()
var _texture := ImageTexture.new()

func load_image_from_file(path: String):
    var err = _image.load(path)
    if err != OK:
        push_error(str("Could not load image ", path, ", error ", err))

    # Update texture
    _texture.create_from_image(_image, 0)
    texture = _texture

func modify_pixels():

    # Change whichever pixel you want
    # ...
    _image.set_pixel(x, y, color)
    # ...

    # Update texture
    _texture.create_from_image(_image, _texture.flags)

It is however quite slow if you plan having high-resolution images.

Another option is to draw with the graphics engine using your GPU.
The idea of this one is to use a Viewport node, and render the output of this viewport on your sprite.
You can put any regular 2D node under the viewport and Godot will render that as usual. And you can also configure the viewport to not clear itself every frame so drawings can accumulate.
This solution is preferable if your images can be large and your paintings use complex algorithms like blurring or brush systems etc.
See also this older question: https://godotengine.org/qa/24621/painting-game-persist-drawing?show=24633#a24633

by (29,090 points)
selected by

Thank you so much, you saved my life! :-)

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.