GetPixels32 returning color values different from source image file

I’m using Texture2D.GetPixels32 to use as a height map for a terrain.

My problem is that the colour data is not accurate. It seems to jump by 2 or 3.

I’ve tried using different file formats to store the texture but nothing helps. The data in the file is correct when I load it back into photoshop or paint.

Try Texture2D.GetPixels instead as Texture2D.GetPixels32 uses low-precision (8-bit greyscale range) Color32 struct.

Disable lossy compression

TL;DR: Set Compression to None

proof:

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using IO = System.IO;
public static class Color32Test
{
    const string k_test_file_name = "8-bit grayscale bar.png";
    const string k_asset_path = "Assets/"+k_test_file_name;
    [MenuItem("Color32/Run a test")]
    static void RunTest ()
    {
        CreateTestTexture();
        InspectTestTexture();
    }
    static void CreateTestTexture ()
    {
        var texture = new Texture2D( 256 , 4 , TextureFormat.RGBA32 , 0 , true );
        Color32[] pixels = new Color32[ texture.width * texture.height ];
        for( int i=0 ; i<256 ; i++ ) pixels *= new Color32{ r=(byte)i , g=(byte)i , b=(byte)i , a=255 };
		texture.SetPixels32( pixels );
		texture.Apply();
		var pngBytes = texture.EncodeToPNG();
		Object.DestroyImmediate( texture );
		string absolutePath = IO.Path.Combine( Application.dataPath , k_test_file_name );
		IO.File.WriteAllBytes( absolutePath , pngBytes );
		AssetDatabase.ImportAsset( k_asset_path );
		var importer = AssetImporter.GetAtPath( k_asset_path ) as TextureImporter;
		importer.isReadable = true;
		importer.textureCompression = TextureImporterCompression.Uncompressed;// THIS FIXES THE ISSUE
		AssetDatabase.ImportAsset( k_asset_path );
		Debug.Log($"file saved: {absolutePath}");
	}
	static void InspectTestTexture ()
	{
		var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(k_asset_path);
		var pixels = texture.GetPixels32();
		bool passed = true;
		for( int x=0 ; x<256 ; x++ )
		{
			var color = pixels[x];
			if( color.r!=x ) { Debug.LogWarning($"test failed at index {x}, R value: {color.r}"); passed=false; }
			if( color.g!=x ) { Debug.LogWarning($"test failed at index {x}, G value: {color.g}"); passed=false; }
			if( color.b!=x ) { Debug.LogWarning($"test failed at index {x}, B value: {color.b}"); passed=false; }
		}
		if( passed ) Debug.Log("<b>test PASSED</b>");
		else Debug.LogWarning("<b>test FAILED</b>");
	}
}
#endif