blog games developers documentation portfolio gallery

More in this category:

Handy Unity3D C# functions (4. alter textures)

Posted on May 22, 2014, by Richard Knol

A texture in Unity can be accessed through the GetPixels functions if you made sure the import settings in Unity had the "Read/write enabled" flag on and the Texture type is non-compressed (RGBA32, ARGB32 or RGB24). We will use this to manipulate textures and create new copies from them.

The functions below were written for the Unity3D AssetStore package Texture2D+. It adds functions to the Unty API for converting colors to and from Hex, convert colors between RGB and HSB. And allows you to perform basic image manipulation on Textures. Feel free to use this code, but it might be easier to just get the complete package. Here's the link to Texture2D+ in the AssetStore that also includes more advanced stuff like scaling and rotating. And here's the link to the documentation.

Change texture colors


Image editor have toolds tochange the saturation of an image or to make it brighter or darker. Since we made our own Color to HSB functions we can do the same in Unity
public static Texture2D ChangeTextureColor(Texture2D originalTexture, float deltaHue, float deltaSaturation, float deltaBrightness) {
Texture2D newTexture = new Texture2D(originalTexture.width, originalTexture.height, TextureFormat.RGBA32, false);
Color[] originalPixels = originalTexture.GetPixels(0);
Color[] newPixels = newTexture.GetPixels(0);
for (int i = 0; i < originalPixels.Length; i++) {
Vector4 hsba = MakeHSBA(originalPixels[i]);
hsba.x += deltaHue;
hsba.y += deltaSaturation;
hsba.z += deltaBrightness;
newPixels[i] = MakeColor(hsba);
}
newTexture.SetPixels(newPixels, 0);
newTexture.Apply();
return newTexture;
}


Change texture contrast


To change the contrast of a picture properly we first find the average color values for all pixels. Next we apply a power to the delta between this average value and the real color. If the power is smaller than 1 the contrast is stretched, if the power is bigger than 1 the contrast is diminished.
public static Texture2D ChangeTextureContrast(Texture2D originalTexture, float power) {
if(power<0f) power=1f;
Texture2D newTexture = new Texture2D(originalTexture.width, originalTexture.height, TextureFormat.RGBA32, false);
Color[] originalPixels = originalTexture.GetPixels(0);
Color[] newPixels = newTexture.GetPixels(0);
float[] avgColor = new float[3];
for (int i = 0; i < originalPixels.Length; i++) {
Color c = originalPixels[i];
avgColor[0]+=c.r;
avgColor[1]+=c.g;
avgColor[2]+=c.b;
}
avgColor[0] = avgColor[0] / originalPixels.Length;
avgColor[1] = avgColor[1] / originalPixels.Length;
avgColor[2] = avgColor[2] / originalPixels.Length;

for (int i = 0; i < originalPixels.Length; i++) {
Color c = originalPixels[i];
float deltaR = c.r - avgColor[0];
float deltaG = c.g - avgColor[1];
float deltaB = c.b - avgColor[2];
deltaR = Mathf.Pow(Mathf.Abs(deltaR), power) * Mathf.Sign(deltaR);
deltaG = Mathf.Pow(Mathf.Abs(deltaG), power) * Mathf.Sign(deltaG);
deltaB = Mathf.Pow(Mathf.Abs(deltaB), power) * Mathf.Sign(deltaB);
newPixels[i] = new Color(avgColor[0] + deltaR,
avgColor[1] + deltaG,
avgColor[2] + deltaB,
c.a);
}
newTexture.SetPixels(newPixels, 0);
newTexture.Apply();
return newTexture;
}


Change texture contrast linear


If you'd rather use a linear function that doesn't take on the very bright and very dark colors first, the function gets a bit easier.
public static Texture2D ChangeTextureContrastLinear(Texture2D originalTexture, float contrast) {
if(power<0f) power=1f;
Texture2D newTexture = new Texture2D(originalTexture.width, originalTexture.height, TextureFormat.RGBA32, false);
Color[] originalPixels = originalTexture.GetPixels(0);
Color[] newPixels = newTexture.GetPixels(0);
float avgGrey = new float;
for (int i = 0; i < originalPixels.Length; i++) {
Color c = originalPixels[i];
avgGrey+=c.r;
avgGrey+=c.g;
avgGrey+=c.b;
}
avgGrey = avgGrey / (3.0f * originalPixels.Length);

for (int i = 0; i < originalPixels.Length; i++) {
Color c = originalPixels[i];
float deltaR = c.r - avgGrey;
float deltaG = c.g - avgGrey;
float deltaB = c.b - avgGrey;
newPixels[i] = new Color(avgGrey + (deltaR * contrast),
avgGrey + (deltaG * contrast),
avgGrey + (deltaB * contrast),
c.a);
}
newTexture.SetPixels(newPixels, 0);
newTexture.Apply();
return newTexture;
}


Crop textures


When you need only a section of a Texture, you can use the GUI.DrawTextureWithTexCoords function or use the Material.SetTextureOffset function. But what if you just want a new Texture that holds only a section of the original?
public static Texture2D CropTexture(Texture2D originalTexture, Rect cropRect) {
// Make sure the crop rectangle stays within the original Texture dimensions
cropRect.x = Mathf.Clamp(cropRect.x, 0, originalTexture.width);
cropRect.width = Mathf.Clamp(cropRect.width, 0, originalTexture.width - cropRect.x);
cropRect.y = Mathf.Clamp(cropRect.y, 0, originalTexture.height);
cropRect.height = Mathf.Clamp(cropRect.height, 0, originalTexture.height - cropRect.y);
if(cropRect.height<=0 || cropRect.width<=0) return null; // dont create a Texture with size 0

Texture2D newTexture = new Texture2D((int)cropRect.width, (int)cropRect.height, TextureFormat.RGBA32, false);
Color[] pixels = originalTexture.GetPixels((int)cropRect.x, (int)cropRect.y, (int)cropRect.width, (int)cropRect.height, 0);
newTexture.SetPixels(pixels);
newTexture.Apply();
return newTexture;
}


Mirror textures


Sometimes a texture sits backwards on your 3D model. To fix it, you can adjust the model, but you can also simply mirror the texture.
	public static Texture2D MirrorTexture(Texture2D originalTexture, bool horizontal, bool vertical) {
Texture2D newTexture = new Texture2D(originalTexture.width, originalTexture.height, TextureFormat.RGBA32, false);;
Color[] originalPixels = originalTexture.GetPixels(0);
Color[] newPixels = newTexture.GetPixels(0);
for (int y = 0; y < originalTexture.height; y++) {
for (int x = 0; x < originalTexture.width; x++) {
int newX = horizontal ? (newTexture.width-1-x) : x;
int newY = vertical ? (newTexture.height-1-y) : y;
newPixels[(newY * newTexture.width) + newX] = originalPixels[(y * originalTexture.width) + x];
}
}
newTexture.SetPixels(newPixels, 0);
newTexture.Apply();
return newTexture;
}









follow us