• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by AlucardJay · Dec 02, 2012 at 08:23 AM · colortexture2dgetpixelsetpixel

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!) :

alt text

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;
 }
 
 // ----

samplemap.png (1.1 kB)
Comment

People who like this

0 Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image whydoidoit · Dec 02, 2012 at 11:41 AM 0
Share

What does it return? On first reading it looks ok - with the caveat that I'm not 100% on the parseInt being necessary (but JS isn't my language).

avatar image AlucardJay · Dec 02, 2012 at 11:55 AM 0
Share
 tempHeight = 0.2
 tempHeight * 50 = 10
 tempHeight - 10 = 0
  0,0 : tileHeight = 0

 tempHeight = 0.2196078
 tempHeight * 50 = 10.98039
 tempHeight - 10 = 0.9803925
  1,0 : tileHeight = 0.9803925

 tempHeight = 0.2392157
 tempHeight * 50 = 11.96078
 tempHeight - 10 = 1.960784
  2,0 : tileHeight = 1.960784

 tempHeight = 0.2588235
 tempHeight * 50 = 12.94118
 tempHeight - 10 = 2.941177
  3,0 : tileHeight = 2.941177

I am expecting 0 : 1 : 2 : 3 . I don't know if it is the type of image (png, or should I save to .jpg), don't know about the different formats. Thanks..

avatar image AlucardJay · Dec 02, 2012 at 12:02 PM 0
Share

That is the Debug when reading, this is the Log for writing :

 tempColour at   height + 10 = 10
 tempColour at   tempColour * 0.02 = 0.2
 tileHeight 0 0 : tempColour 0.2
 0 0
 
 tempColour at   height + 10 = 11
 tempColour at   tempColour * 0.02 = 0.22
 tileHeight 1 1 : tempColour 0.22
 1 1
 
 tempColour at   height + 10 = 12
 tempColour at   tempColour * 0.02 = 0.24
 tileHeight 2 2 : tempColour 0.24
 2 2
 
 tempColour at   height + 10 = 13
 tempColour at   tempColour * 0.02 = 0.26
 tileHeight 3 3 : tempColour 0.26
 3 3

I think you can see what I'm trying to do. Can I use a texture pixel as a base_255 reference (store and return a value between 0 and 255, or just 0 and 50 in my case). Can this be done accurately to return integer values?

avatar image AlucardJay · Dec 02, 2012 at 01:05 PM 0
Share

Actually ... ignoring my calculations and just looking at what set/get pixels is showing :

the value for color.r in Set is :

 0.2; 0.22; 0.24; 0.26;

the value for color.r in Get is :

 0.2; 0.2196078; 0.2392157; 0.2588235;

this is what I find confusing, it is returning a different value for a pixel set by the same script. Hence my queries on image extension or import settings.

1 Reply

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by whydoidoit · Dec 02, 2012 at 12:04 PM

So images are not stored using floating points - they are stored using bytes :) 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 :)

Comment
AlucardJay

People who like this

1 Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AlucardJay · Dec 02, 2012 at 12:21 PM 0
Share

Thanks, as this is new ground for me, have some testing to do. Even the API says Using SetPixels32 is faster than calling SetPixels. , so shall let you know how I go with converting my 2D arrays to textures and back. (another command I was not aware of, thanks).

messing with it ... still chuckling. I get that sometimes from my colleague, or as he says doing it longhand. I thought I did ok normalizing an integer value between -10 and +40 :)

avatar image whydoidoit · Dec 02, 2012 at 12:22 PM 0
Share

Yeah that's why there's so much inaccuracy in the values coming back - they've been hacked around with too much. You could probably get away with it by using Mathf.RoundToInt() but it's not really the right method. We think of colours as floats in Unity - but that's really not the case anywhere but in the shader.

avatar image AlucardJay · Dec 02, 2012 at 12:50 PM 0
Share

thanks for the SetPixels32 help, that was a silly mistake.

avatar image AlucardJay · Dec 03, 2012 at 07:13 AM 0
Share

Here's what I came up with (see edit to question). Many thanks for all your help and pointers, have learned a new technique and a new command. Awesome.

avatar image AlucardJay · Dec 03, 2012 at 07:47 AM 0
Share

What I was having problems with ( and cannot get my head around) is that when the pixel is assigned, I divide by 255 :

 tempColourArray[ index ] = Color( myArray[ x, y ] / 255.0, 0.0, 0.0 );

when I read the pixel, it already comes back multiplied :

 readArray[ x, y ] = parseInt( tempArray[ index ].r * 1.0 );

so I write a value of value/255 and read value for the same value. I shall not question, it works.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

11 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

GetPixel Returning Inaccurate Color 1 Answer

Dynamically created texture is off in BFE... 0 Answers

Texture2D.GetPixel returning wrong colours 3 Answers

Fastest rendering of 2D world with lots of changes to screen every frame? 3 Answers

Unity change my color variation?? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges