create readable colour map

Hi =]

I want to output my 2D array to a texture, then read that texture back later to populate that array with the same information

So (thanks to Unity Answers) I have the save part of the script (The chunk of script at the end of the question). Now that part seems to be working excellently, the console returns nice values that are multiples of 0.02

Here is an output for a simple 4x4 map (scaled of course!) :

5441-samplemap.png

ok, so now for my reader. It does not return nice friendly values that are multiples of 0.02 at all :

// me =]

function ReadFromTexture()
{
	// reset lists
	tileHeight = new int[ heightTexture.width, heightTexture.height ];
	
	Debug.Log( "gridSize H " + heightTexture.width + "," + heightTexture.height + " : T " + typeTexture.width + "," + typeTexture.height );
	
	// populate list with pixel info
	
	for ( var y : int = 0; y < heightTexture.height; y ++ ) 
    {
        for ( var x : int = 0; x < heightTexture.width; x ++ ) 
        {
			// -- HEIGHT --
			
			var heightPxlColour : Color = heightTexture.GetPixel( x, y );
			
			//var tempHeight : float = ( heightPxlColour.r + heightPxlColour.g + heightPxlColour.b ) / 3.0;
			var tempHeight : float = heightPxlColour.r;
			Debug.Log( "tempHeight = " + tempHeight );
			
			tempHeight = tempHeight * 50.0; // 1/0.02;
			Debug.Log( "tempHeight * 50 = " + tempHeight ); 
			
			tempHeight -= 10.0; // from +
			Debug.Log( "tempHeight - 10 = " + tempHeight ); 
			
			//  			
			Debug.Log( " " + x + " " + y + " : tileHeight = " + tempHeight );            
			
			tileHeight[ x, y ] = parseInt( tempHeight );
		}
	}
	
	// assign all to TileManager ....
}

I have set the Texture Import settings to :

Advanced
(power of 2 is greyed out, otherwise would be set to none/single)
Read/Write enabled = true
mode = Clamp
max size = 32
format = automatic truecolor

How can I generate a ‘heightmap’ from a 2 dimensinal array, then read that texture to return the exact same values.

The 2D array is an array of integers.

Thanks.


Write Texture Script :

function GenerateMap() 
{
	// Create a new texture and assign it to the renderer's material
    var texHeight = new Texture2D( tileManager.gridSize.x, tileManager.gridSize.y ); // height texture
    
    // Fill the texture information from tileHeight array
    for ( var y : int = 0; y < texHeight.height; y ++ ) 
    {
        for ( var x : int = 0; x < texHeight.width; x ++ ) 
        {
            // -- height texture --
            
            var hColor : Color;
            
            // - set the colour range -
            
            // range is based on tiles being between
            // -10 and 40 on the Y_axis
            
            var tempColour : float = 0.0;
            
            tempColour = ( parseFloat( tileHeight[ x, y ] ) + 10.0 ); // +10 makes range = 0 to 50
            
            Debug.Log( "tempColour at   height + 10 = " + tempColour );
            
            tempColour = tempColour * 0.02; // 1/50 of the position
            
            Debug.Log( "tempColour at   tempColour * 0.02 = " + tempColour );
            
            tempColour = Mathf.Clamp( tempColour, 0.0, 1.0 ); // clamp 
            
            Debug.Log( "tileHeight " + (x+(x*y)) + " " + tileHeight[ x, y ] + " : tempColour " + tempColour );
            
            hColor = Color( tempColour, 0.0, 0.0 );
            
            texHeight.SetPixel( x, y, hColor );
        }
    }
    
    // Apply all SetPixel calls
    texHeight.Apply();
	
	// save to system
	var timeStamp : String = GetSystemDateTime();
	
	SaveTextureToFile( texHeight, timeStamp + "_heightmap.png" ); // height texture
}

// http://answers.unity3d.com/questions/245600/saving-a-png-image-to-hdd-in-standalone-build.html

function SaveTextureToFile( texture : Texture2D, fileName )
{
	var bytes = texture.EncodeToPNG();
	var file = new File.Open( Application.dataPath + "/" + fileName, FileMode.Create );
	var binary = new BinaryWriter(file);
	binary.Write(bytes);
	file.Close();
}

Edit :

Here is the test code I wrote using Set/GetPixels32. It stores ints between 0 and 255, and returns correct values from the texture :

#pragma strict

private var myArray : int[ , ];

public var inputTexture : Texture2D;
private var readArray : int[ , ];

function Start() 
{
	PopulateArray();
}

function Update() 
{
	if ( Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.F1) )
	{
		GenerateTexture();
	}
	else if ( Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.F2) )
	{
		ReadTexture();
	}
}

// ----

function PopulateArray() 
{
	myArray = new int[ 4, 4 ];
	
	for ( var i:int = 0; i < 4; i ++ )
	{
		myArray[ 0, i ] = i;
		myArray[ 1, i ] = i * 20;
		myArray[ 2, i ] = i * 50;
		myArray[ 3, i ] = i * 62;
	}
}

// ----

function GenerateTexture() 
{
	var tempTexture : Texture2D = new Texture2D( 4, 4 );
	var tempColourArray : Color32[] = new Color32[ 16 ];
	var index : int = 0;
	
	for ( var y : int = 0; y < tempTexture.height; y ++ ) 
	{
		for ( var x : int = 0; x < tempTexture.width; x ++ ) 
		{
			tempColourArray[ index ++ ] = Color( myArray[ x, y ] / 255.0, 0.0, 0.0 );
		}
	}
	
	tempTexture.SetPixels32( tempColourArray, 0 );
	tempTexture.Apply( false );
	
	// save to system
	var timeStamp : String = GetSystemDateTime();
	SaveTextureToFile( tempTexture, timeStamp + "_colourmaptest.png" );
}

// ----

function ReadTexture() 
{
	var tempArray : Color32[] = inputTexture.GetPixels32( 0 );
	readArray = new int[ 4, 4 ];
	
	var success : boolean = true;
	var index : int = 0;
	
	for ( var y:int = 0; y < 4; y ++ )
	{
		for ( var x:int = 0; x < 4; x ++ )
		{
			readArray[ x, y ] = parseInt( tempArray[ index ].r * 1.0 );
			
			if ( readArray[ x, y ] != myArray[ x, y ] )
			{
				Debug.Log( "index " + index + " mismatch at ( " + x + ", " + y + " ) : read = " + readArray[ x, y ] + " : write = " + myArray[ x, y ] );
				success = false;
			}
			
			index ++;
		}
	}
	
	Debug.Log( "success = " + success );
}

// ----

// http://answers.unity3d.com/questions/245600/saving-a-png-image-to-hdd-in-standalone-build.html

function SaveTextureToFile( texture : Texture2D, fileName )
{
	var bytes = texture.EncodeToPNG();
	var file = new File.Open( Application.dataPath + "/" + fileName, FileMode.Create );
	var binary = new BinaryWriter(file);
	binary.Write(bytes);
	file.Close();
}

// ----

// Me

function GetSystemDateTime() : String
{
	// get the date time
	var tempStamp : String = System.DateTime.Now.ToString();
	// remove "/"
	var dateStampSplit : String[] = tempStamp.Split( "/"[0] );
	// remove ":"
	var timeStampSplit : String[] = dateStampSplit[2].Split( ":"[0] );
	// remove " "
	var space1split : String[] = timeStampSplit[0].Split( " "[0] );
	var space2split : String[] = timeStampSplit[2].Split( " "[0] );
	// put timeStamp together
	var timeStamp : String = "";
	timeStamp = dateStampSplit[0] + dateStampSplit[1] + space1split[0] + space1split[1] + timeStampSplit[1] + space2split[0] + space2split[1];
	return timeStamp;
}

// ----

So images are not stored using floating points - they are stored using bytes :slight_smile: Your code is therefore:

  • Converting an int to a float
  • Messing with it
  • Converting back into an int (with only 255 discrete values) by writing it to an image!

You really want to be using the GetPixels32 to return the whole image as an array and then you can actually access the integers stored in the file :slight_smile: