+1 vote

Let's say i have a 100x100px sprite in a very simple scene.

I want to manually modify the sprite colors. For example i want to make all of its pixels green.

Right now, the sprite has an ImageTexture. I am procedurally assigning an Image object to the ImageTexture.

    Image i = new Image();
    i.Create(100, 100, false, Image.Format.Rgb8);

    ImageTexture t = this.Texture as ImageTexture;

    i.Lock();
    i.SetPixel(0, 0, new Color(1f, 1f, 1f)); 

    t.SetData(i);

This causes godot to throw an error:

Condition ' !texture->active ' is true.
 ImageTexture.cs:127 @ void Godot.ImageTexture.SetData(Godot.Image )

How do i go about doing this properly?

in Engine by (28 points)

1 Answer

+3 votes
Best answer

There are a few issues with your code:
- You are locking the image but never unlocking it
- You are calling SetData() on an ImageTexture but it was never initialized. It's not the right function to create it from an image (honestly I'm not sure what are the true behavior of SetData, the doc is missing some details).

Try this instead:

i.Lock();
i.SetPixel(0, 0, new Color(1f, 1f, 1f)); 
i.Unlock();

t.CreateFromImage(i, 0)
by (27,897 points)
selected by

I had set the texture property of the sprite to an ImageTexture via the inspector but i guess that was the wrong approach.

I tried this and it works:

    Image i = new Image();
    i.Create(1920, 1080, false, Image.Format.Rgb8);
    i.Lock();

    ImageTexture t = new ImageTexture();

    Random r = new Random();

    for (int y = 0; y < i.GetHeight(); y++)
    {
        for (int x = 0; x < i.GetWidth(); x++)
        {
            int rand = r.Next(0, 100);
            float f = rand / 100f;

            i.SetPixel(x, y, new Color(f, f, f));
        }
    }

    i.Unlock();
    t.CreateFromImage(i);

    this.Texture = t;       

Though i'm not sure if this is the most efficient way to do it. I want to run this code as fast as possible so perhaps creating a new imagetexture and image every time it runs is a bad idea.

There are a few ways to go, depending on what you are doing. If you want to actually edit the image, either reupload it entirely like you are doing, or use VisualServer.texture_set_data_partial to upload only a modified sub-rectangle (but might not be worth it if your sprite is small like 100x100).

But if your use case is only about tinting the image, generating or replacing colors at runtime, a shader could do this effect much more efficiently.

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 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 webmaster@godotengine.org with your username.