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
GetPixelorGetPixelsat all your source texture needs to be set toRead/Write enabledin the Texture Import SettingsColoruses float values between0and1. If you want to use RGB values in bytes between0and255rather useColor32instead.In your case it doesn't matter of course since the value will just get clamped to
1but 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
GetPixelandSetPixelrepeatedly is slow!Rather use
GetPixelsandSetPixelsin order to access/write all pixels in one go.However - and this brings us back to
Color32- usingGetPixels32andSetPixels32is again faster thanGetPixelsandSetPixelsand 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
Color32in your case.Then you are iterating the X and Y coordinates starting both with
0but then you try to accessx - 1andy - 1which are out of bounds coordinates!You would probably rather start with
x = 1andy = 1in order to avoid that.And finally either way you have to also call
Applyonce you are doneActually 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;
}
