- Home /
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.
8 bit per colour channel is exactly what I need. I'm not getting it. Despite the texture file containing this accuracy, I'm getting values between 2 and 253 and (as an example) values of 4, 5 and 6 are all being read as 5.
Answer by andrew-lukasik · Dec 26, 2021 at 08:10 PM
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[i] = 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
Not exactly what I needed but It sent me down the right path. I simply set Compression to "None" in the import settings. I've not encountered AssetDatabase before. Is there any advantage to using this over just importing through the editor from the assets folder?
Changing Compression
to None
in the import settings is one way of doing exactly what i wrote there in bold letters - it disables lossy compression. Line 29 did that from code and there is no difference with doing so manually.
There are ways of achieving lossless compression (best option) for heightmaps (binary files compressed with LZMA) but those are far more technical to implement and maintain than this.