Set all pixels to be red (255,0,0) using Texture2D.SetPixelData, but the pixels change to a multicolour assortment

Advertisements

I have the following code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextureScript : MonoBehaviour
{

    Texture2D texture;

    // Start is called before the first frame update
    void Start()
    {
        texture = new Texture2D(256,256, TextureFormat.RGB24, true);

        var rectTransform = transform.GetComponent<RectTransform>();
        rectTransform.sizeDelta = new Vector2(texture.width, texture.height);

        int pixelCount = texture.width * texture.height;

        Queue<Color> queue = new Queue<Color>();

        for(int i = 0; i < pixelCount; i++)
        {
            queue.Enqueue(new Color(255,0,0));
        }

        Color[] colorArray = queue.ToArray();

        texture.SetPixelData(colorArray, 0, 0);
        texture.filterMode = FilterMode.Point;
        texture.Apply(updateMipmaps: false);

        GetComponent<RawImage>().material.mainTexture = texture;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

Which produces this:

I am unsure as to what could be producing it. Previously I was using a byte array for tests which worked, but my work now requires a queue, and to then convert this queue into an array (which I have done using .ToArray()).

I also used RGBA32 rather than RGB24 with varying alpha values of 255, 128, 1, & 0; however, this produced a nearly see-through image each time.

Thank-you for your help.

>Solution :

  • Why use a Queue instead of simply an array?
  • Why use SetPixelData instead of simply SetPixels?

I would simply do e.g.

//var pixels = texture.GetPixels();
// or even simply
var pixels = new Color[texture.width * texture.height];
for(var i = 0; i < pixels.Length; i++)
{
    pixels[i] = color.Red;
}
texture.SetPixels(pixels);
texture.Apply();

SetPixelData is rather

useful if you want to load compressed or other non-color texture format data into a texture.

What happens in your case is: Color has a byte size of 4 float (=16 byte) since it also has an alpha value! Your texture is using RGB24 and therefore only expecting 3 bytes (=24 bit) per pixel.

So in case you really want to stick to that (might be faster – or not ^^) you would rather have to do e.g.

var pixels = new byte[texture.width * texture.height * 3];
for(var i = 0; i < pixels.Length; i+=3)
{
    pixels[i] = 255; // R
    pixels[i+1] = 0; // G
    pixels[i+2] = 0; // B
}
texture.SetPixelData(pixels, 0, 0);
texture.Apply();

also regarding

new Color(255,0,0)

note that Color takes float arguments from 0 to 1. If you are looking for a byte based input rather go for Color32 and SetPixels32


Further note that RawImage is actually quite expensive – you could stick to an Image component and simply create a Sprite from your Texture2D

GetComponent<Image>().sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 0.5f);

Leave a ReplyCancel reply