Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • 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
0
Question by fparedesg · Jun 21, 2013 at 08:08 PM · heightmapbytes16 bits

How are the bytes in a 16bit heightmap organized?

I'm writing a script that reads a heightmap from a binary text file, and programmatically sets said heightmap to the active terrain. To do this for an 8bit heightmap, it's pretty simple: I just read each byte in the text file, store it in a byte[] array, translate that into a float[][] matrix, and load the heightmap using terrain.terrainData.SetHeights(0, 0, float[][]) (See code at the end for actual implementation).

This works, but the resolution of the terrain is pretty bad, as the elevations look kind of like stairs. Because of this, I'm going to have to use a 16bit heightmap, but I don't know how to interpret the bytes from the binary text file, as I don't know how they're organized. I'm assuming the corresponding pair of bytes used to represent each elevation value is side by side...?

Here's the current (working) code for the 8bit heightmap:

 using UnityEngine;
 using System.Collections;
 
     public class TerrainGenerate : MonoBehaviour
     {
         public TextAsset binaryData;
         
         private Terrain terrain; // terrain to modify
         protected int heightmapWidth; // heightmap width
         protected int heightmapHeight; // heightmap height
         
         void Start ()
         {
             terrain = Terrain.activeTerrain;
             heightmapWidth = terrain.terrainData.heightmapWidth;
             heightmapHeight = terrain.terrainData.heightmapHeight;
                     
             byte[] bytes = binaryData.bytes; // Loads the whole heightmap file into this array
             float[,] heightmap = new float[heightmapWidth,heightmapHeight];
             int byteNumber = 0; // Will be used to iterate through the 'bytes' array
             for(int width = 0; width < bytes.Length/heightmapHeight; width++)
             {
                 for(int height = 0; height < bytes.Length/heightmapHeight; height++)
                 {
                     heightmap[width, height] = bytes[byteNumber]/256.0f; // Sets value in 'bytes' array to matrix
                     byteNumber++;
                 }
             }
             
             terrain.terrainData.SetHeights(0, 0, heightmap); // Loads matrix into terrain.
         }
     }


Comment
Add comment
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

3 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Carey403 · Jun 22, 2013 at 12:41 AM

I'm somewhat unfamiliar with C#, but assuming you can only save byte arrays then you could do the follow, assuming you already have your heightmap stored in an array of integers:

 byte[] byteArray = new byte[intArray.length*2];
 for(int i=0; i<intArray.length; i+=2)
 {
     bytearray[i] = intArray[i] & 0xFF;
     bytearray[i+1] = (intArray[i] & 0xFF00) >> 0x08;
 }

To get it back into int form you can this:

 //Assuming byteArray contains bytes read from serialized data
 int[] intArray = new int[byteArray.length/2];
 for(int i=0; i<byteArray.length; i+=2)
 {
     intArray[i] = (byteArray[i+1] << 0x08) | (byteArray[i]); 
 }

Then just transform that int array into your float matrix, should work.

Comment
Add comment · 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 Eric5h5 · Jun 22, 2013 at 12:47 AM 0
Share

There wouldn't be any integers involved; ints are signed 32-bits and the heightmap is 16-bits, unsigned (i.e., ushort). Also, as I mentioned, both big-endian and little-endian storage are valid and need to be accounted for.

avatar image Carey403 · Jun 22, 2013 at 01:28 AM 0
Share

I am well aware ints are larger than 16bits, but 16bit variables still fit in an int. What I'm suggesting the OP do is manually handle data conversion between integer and byte, that way the endianness becomes irrelevant for him.

He could store them in ushort if its 16bit, as I said, I am unfamiliar with C# and its data types. Integer would work as well

avatar image fparedesg · Jun 22, 2013 at 01:36 AM 0
Share

Well, it works nicely, thanks to both of you. Here's the end code. This loads up the 16bit heightmap correctly:

 using UnityEngine;
 using System.Collections;
 
 public class TerrainGenerate : $$anonymous$$onoBehaviour
 {
     public TextAsset binaryData;
     
     private Terrain terrain; // terrain to modify
     protected int heightmapWidth; // heightmap width
     protected int heightmapHeight; // heightmap height
     
     void Start ()
     {
         terrain = Terrain.activeTerrain;
         heightmapWidth = terrain.terrainData.heightmapWidth;
         heightmapHeight = terrain.terrainData.heightmapHeight;
                 
         byte[] bytes = binaryData.bytes; // Loads the whole heightmap file into this array
         float[,] heightmap = new float[heightmapWidth,heightmapHeight];
         int byteNumber = 0; // Will be used to iterate through the 'bytes' array
         for(int width = 0; width < bytes.Length/(heightmapHeight*2); width++)
         {
             for(int height = 0; height < bytes.Length/(heightmapHeight*2); height++)
             {
                 heightmap[width, height] = ((bytes[byteNumber] << 0x08) | bytes[byteNumber+1])/65536f; // Sets value in 'bytes' array to matrix
                 byteNumber += 2;
             }
         }
         
         terrain.terrainData.SetHeights(0, 0, heightmap);
     }
 }
avatar image Sruti Davis · May 13, 2014 at 10:08 AM 0
Share

Thank you so much @fparedesg! This helped me load a 16-bit .raw heightmap onto a terrain. It worked! I had to make a small change in your code because my heightmap was having little-endian byte order (windows). So for it to work all I had to do was make a small change in line 25.

  heightmap[width, height] = ((bytes[byteNumber+1] << 0x08) | bytes[byteNumber])/65536f;
avatar image Sruti Davis · May 13, 2014 at 10:33 AM 0
Share

Also, I had to set the heightmap resolution in the code because of some exception I was facing. When the TerrainData was constructed, for some reason, the resolution was set to 33 by default. I knew my heightmap resolution, so I set it to that:

 terrainData.heightmapResolution = 257;
 int heightmapWidth = terrainData.heightmapWidth;
 int heightmapHeight = terrainData.heightmapHeight;
avatar image
0

Answer by Eric5h5 · Jun 21, 2013 at 11:19 PM

With a 16-bit heightmap, you have 2 bytes for each pixel, organized as either little-endian (where the least significant byte is first) or big-endian (where the most significant byte is first). There's no way to know which is used in the file, so it would be best to support both.

Comment
Add comment · 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
0

Answer by tds dave · Nov 02, 2014 at 09:27 PM

Bit late to the party. Converting byte arrays ( binary data ) into other simple types (ushorts etc )in c# use System.BitConverter. New to unity though not c# so I'm presume this is available. It has functionality to help with architecture endian also. http://msdn.microsoft.com/en-us/library/system.bitconverter(v=vs.110).aspx

Comment
Add comment · 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

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.

Follow this Question

Answers Answers and Comments

19 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Import 8bit .raw file, and 16bit explanation. 2 Answers

Modifying an heightmap at runtime 2 Answers

How to get heightmap of unity terrain ? 1 Answer

Heightmap is spiky, unsolvable for me 3 Answers

Gradual Terrain Smoothing from a Flat Area (at Runtime) 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