Home > Blockchain >  Comparing two pixels and setting a texture to black depending on outcome
Comparing two pixels and setting a texture to black depending on outcome

Time:02-05

I am trying to compare two pixels of the same texture and then if they are different (For Unity BTW), then for it to take the X and Y and plug that into another texture to set the pixel. My first thought was this simple script

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

public class MapDisplay : MonoBehaviour
{
    [SerializeField]
    Texture2D provinceMap;

    [SerializeField]
    GameObject mapObject;

    Color borderColor = new Color(255, 0, 0);

    private void Awake()
    {

        int provinceMapSizeX = provinceMap.width;
        int provinceMapSizeY = provinceMap.height;

        Texture2D mapDisplayBorders = new Texture2D(provinceMapSizeX, provinceMapSizeY);

        for (int x = 0; x < provinceMapSizeX; x  )
        {
            for (int y = 0; y < provinceMapSizeY; y  )
            {
                Color previousPixel = provinceMap.GetPixel(x - 1, y - 1);
                Color currentPixel = provinceMap.GetPixel(x, y);

                if (previousPixel != currentPixel)
                {
                    mapDisplayBorders.SetPixel(x - 1, y - 1, borderColor);
                }
            }
        }

        mapObject.GetComponent<Renderer>().material.mainTexture = mapDisplayBorders;

    }

}

And at first I thought this would work, and on pressing play, the plane turned darker but nothing else. then I tried messing with borderColor (Hence 255), but nothing happened. The Texture2D provinceMap is a simple image that is 64x64 pixels, about half white and half black. I am trying to get it to add a pixel of black for every color change in this example (Its supposed to be on both pixels which can be fixed in one line of code but trying to test this right now). I don't understand why this wouldn't work though. Thanks for any help!

CodePudding user response:

First of all some general notes

  • For being able to use GetPixel or GetPixels at all your source texture needs to be set to Read/Write enabled in the Texture Import Settings

  • Color uses float values between 0 and 1. If you want to use RGB values in bytes between 0 and 255 rather use Color32 instead.

    In your case it doesn't matter of course since the value will just get clamped to 1 but something you should have in mind.

  • Your current value will not be Black but rather Red. If you wanted black it should rather be

    Color borderColor = new Color(0, 0, 0);
    
  • Using GetPixel and SetPixel repeatedly is slow!

    Rather use GetPixels and SetPixels in order to access/write all pixels in one go.

  • However - and this brings us back to Color32 - using GetPixels32 and SetPixels32 is again faster than GetPixels and SetPixels and uses less memory since it doesn't have to do the calculating between byte and float of course which brings some overhead.

    So I would rather go with Color32 in your case.

  • Then you are iterating the X and Y coordinates starting both with 0 but then you try to access x - 1 and y - 1 which are out of bounds coordinates!

    You would probably rather start with x = 1 and y = 1 in order to avoid that.

  • And finally either way you have to also call Apply once you are done

    Actually apply all previous SetPixel and SetPixels changes.

So you should rather do something like e.g.

// Use a Color32 instead with all bytes 0 for black
Color32 borderColor = new Color32(0, 0, 0);

...

var mapDisplayBorders = new Texture2D(provinceMapSizeX, provinceMapSizeY);

// Get the entire arrays of pixels at once for both textures
var borderPixels = mapDisplayBorders.GetPixels32();
var mapPixels = provinceMap.GetPixels32();

// Start iterating from 1 to prevent out of bounds coordinates
for (int x = 1; x < provinceMapSizeX; x  )
{
    for (int 1 = 0; y < provinceMapSizeY; y  )
    {
        // The pixels in the array are laid out row by row
        var previousPixel = mapPixels[(x - 1)   (y - 1) * provinceMapSizeX];
        var currentPixel = mapPixels[x   y * provinceMapSizeX];

        if (AreEqual(previousPixel, currentPixel))
        {
            borderPixels[(x - 1)   (y - 1) * provinceMapSizeX] = borderColor;
        }
    }
}

mapDisplayBorders.SetPixels32(borderPixels);
mapDisplayBorders.Apply();

mapObject.GetComponent<Renderer>().material.mainTexture = mapDisplayBorders;

...

// Afaik this is not implemented for some reason so have to do it ourselves
private bool AreEqual(Color32 a, Color32 b)
{
    return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
  •  Tags:  
  • Related