Using keys to modify Sprite3D image

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Rob1980

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!

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

ramazan | 2022-02-04 09:27

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)

Zylann | 2022-02-04 13:41

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

Rob1980 | 2022-02-04 15:11

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

Rob1980 | 2022-02-04 15:13

:bust_in_silhouette: Reply From: Zylann

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))
		return

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


func modify_pixels():
	_image.lock()

	# 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://forum.godotengine.org/24621/painting-game-persist-drawing?show=24633#a24633

Thank you so much, you saved my life! :slight_smile:

Rob1980 | 2022-02-05 07:15