Search Unity

  1. Check out our Unite Austin 2017 YouTube playlist to catch up on what you missed. More videos coming soon.
    Dismiss Notice
  2. Unity 2017.2 is now released.
    Dismiss Notice
  3. The Unity Gear Store is here to help you look great at your next meetup, user group or conference. With all new Unity apparel, stickers and more!
    Dismiss Notice
  4. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice
  6. Unity 2017.3 beta is now available for download.
    Dismiss Notice

[RELEASED]Terrain Importer

Discussion in 'Assets and Asset Store' started by gilley033, Aug 26, 2014.

  1. RandAlThor

    RandAlThor

    Joined:
    Dec 2, 2007
    Posts:
    1,222
    Send you an email and hope you can help.
     
  2. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    Great, I will be working on your problem exclusively tonight.
     
  3. fc2012

    fc2012

    Joined:
    Apr 22, 2017
    Posts:
    4
    Hi,
    I really appreciate your work. Actually, I have been working on a similar terrain procedure for some time until I found your assets. Here I have a question, it's about the seam between adjacent tiles.

    In my solution, I create TerrainData assets with the output heightmaps and textures from WorldMachine, then I load them and create terrain objects at runtime, but it seems to have seam between adjacent tiles. I have set terrain.neighbors and check that the adjacent tiles have the same heights on borders. As long as you have this perfect solution, I wonder if you have occured to such problem and how you deal with it?

    Any help will be very appreciated!
     

    Attached Files:

  4. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    Is there a full on gap between the terrains? That's how it appears in the screenshot, but obviously it's zoomed out so impossible to know for sure. In that case, the only thing I can think of is to make sure the heightmaps are a power of two + 1 resolution when exported from World Machine.

    Note that in some cases when exporting tile maps from World Machine, you may notice a "seam" between the terrain, but not like what's shown in your picture. So once you correct the gap (if that is indeed one), if you still notice a seam, it may or may not be avoidable. Increasing the blending region in World Machine may help. The issue is that Unity does not do texture blending between terrains, so if the neighboring between two alphamap pixels is not exactly the same, you'll likely notice a seam.

    For setting terrain neighbors, the only thing I can say is to make sure you call the Flush method after setting each terrain's neighbors, and also make sure the terrain object is fully created and activated before setting the neighbors.

    Good luck!
     
  5. fc2012

    fc2012

    Joined:
    Apr 22, 2017
    Posts:
    4
    First, thank you!

    I understand I'm actually having a "gap" rather than a "seam". I set my terrain heightmap resolution to ^2+1 in Unity, but I export heightmap from WM by just ^2. So I fix this and notice the seam between terrain(seam2.png), which I think it's just what you are talking about.
     

    Attached Files:

  6. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    @fc2012

    When you examine the alphamap textures do they have those yellow lines on the border? If not then it's definitely a terrain neighboring issue. I've offered the only advice I can in that area. If you want to post your neighboring code, maybe something will pop out as being at fault.

    Best Regards,
    Kyle Gillen
     
  7. fc2012

    fc2012

    Joined:
    Apr 22, 2017
    Posts:
    4
    For each tile, the output from WM is a single texture in 513x513, but when imported to Unity it turns out to be 512x512, and image_x0_y0.png is an example of my textures. I'm not sure setting the alphamapResolution as 513 or 512, but it seems to have the same result. I'm not sure if my texture code(creating TerrainData) is right, so here it is.
    Code (CSharp):
    1. private bool LoadTexture(TerrainData td, string tFilePath)
    2.     {
    3.         Texture2D tex = AssetDatabase.LoadAssetAtPath(tFilePath, typeof(Texture2D)) as Texture2D;
    4.         if (!tex)
    5.         {
    6.             Debug.Log("Fail to load texture file!");
    7.             return false;
    8.         }
    9.        
    10.         SplatPrototype splat = new SplatPrototype();
    11.         splat.texture = tex;
    12.         splat.tileSize = new Vector2(td.size.x, td.size.z);
    13.         td.splatPrototypes = new SplatPrototype[] { splat };
    14.         td.RefreshPrototypes();
    15.         return true;
    16.     }
    I write the following test script and attach it to Main Camera. It creates 9 adjacent terrains. The index of each tile in the List and corresponding position are shown in terrains.png.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class tryRemoveGap : MonoBehaviour {
    6.  
    7.     private List<GameObject> terrain;
    8.     private string assetPathName;
    9.     // Use this for initialization
    10.     void Start () {
    11.         terrain = new List<GameObject>();
    12.         assetPathName="tt/myTD";
    13.         TerrainData terrainData = new TerrainData();
    14.         for (int i = 0; i < 3; i++)
    15.         {
    16.             string suf0 = i.ToString();
    17.             for (int j = 0; j < 3; j++)
    18.             {
    19.                 string suf1 = j.ToString();
    20.                 string path = assetPathName + suf0 + suf1;
    21.                 terrainData = Resources.Load(path) as TerrainData;
    22.                
    23.                 GameObject newTerrainObject = Terrain.CreateTerrainGameObject(terrainData);
    24.                 newTerrainObject.transform.position = new Vector3(i * 500, 0, j * 500);
    25.                 terrain.Add(newTerrainObject);
    26.             }
    27.         }
    28.        
    29.         //SetNeighbors
    30.         terrain[0].GetComponent<Terrain>().SetNeighbors(null,
    31.             terrain[1].GetComponent<Terrain>(), terrain[3].GetComponent<Terrain>(), null);
    32.         terrain[3].GetComponent<Terrain>().SetNeighbors(terrain[0].GetComponent<Terrain>(),
    33.             terrain[4].GetComponent<Terrain>(), terrain[6].GetComponent<Terrain>(), null);
    34.         terrain[6].GetComponent<Terrain>().SetNeighbors(terrain[3].GetComponent<Terrain>(),
    35.             terrain[7].GetComponent<Terrain>(), null, null);
    36.         terrain[1].GetComponent<Terrain>().SetNeighbors(null, terrain[2].GetComponent<Terrain>(),
    37.             terrain[4].GetComponent<Terrain>(), terrain[0].GetComponent<Terrain>());
    38.         terrain[4].GetComponent<Terrain>().SetNeighbors(terrain[1].GetComponent<Terrain>(),
    39.             terrain[5].GetComponent<Terrain>(), terrain[7].GetComponent<Terrain>(), terrain[3].GetComponent<Terrain>());
    40.         terrain[7].GetComponent<Terrain>().SetNeighbors(terrain[4].GetComponent<Terrain>(),
    41.             terrain[8].GetComponent<Terrain>(), null, terrain[6].GetComponent<Terrain>());
    42.         terrain[2].GetComponent<Terrain>().SetNeighbors(null, null,
    43.             terrain[5].GetComponent<Terrain>(), terrain[1].GetComponent<Terrain>());
    44.         terrain[5].GetComponent<Terrain>().SetNeighbors(terrain[2].GetComponent<Terrain>(),
    45.             null, terrain[8].GetComponent<Terrain>(), terrain[4].GetComponent<Terrain>());
    46.         terrain[8].GetComponent<Terrain>().SetNeighbors(terrain[5].GetComponent<Terrain>(),
    47.             null, null, terrain[7].GetComponent<Terrain>());
    48.  
    49.         for (int i = 0; i < terrain.Count; i++)
    50.         {
    51.             Terrain t = terrain[i].GetComponent<Terrain>();
    52.             t.Flush();
    53.         }
    54.     }
    Many thanks!
     

    Attached Files:

  8. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    So I would try the following, in order, and see if the problem is fixed after each change:
    1) Move the Terrain Neighboring code to a different frame. There may be issues when trying to create the terrain and set the neighboring in a single start method, so I would put everything in a coroutine and then throw a "yield return null" in between the terrain creation and neighboring code.

    2) Try flushing each terrain immediately after setting its neighbors.

    3) Set the neighbors and flush only one terrain per frame. This is how I do it in my own code (if the code is in a coroutine, just put a "yield return null;" in between each terrain neighbor/flush). I can't remember if this was required to get things to work, or if it was just for performance reasons.

    None of these options are guaranteed to fix the issue, but it's what I would try if debugging this issue. The only other solution I can suggest is making sure to export the textures from WM at 512 resolution . . . but it sounds like maybe you've done this already? I doubt it's the issue anyway, even if the textures are 513 (but you never know). Are your terrain tile pieces 512 meters x 512 meters (physical size)?
     
  9. fc2012

    fc2012

    Joined:
    Apr 22, 2017
    Posts:
    4
    Thank you! I'll try these steps.

    Each of my terrain tile pieces is 3000m x 3000m in World Machine, but in this code I set the size to 500x500 in Unity. Is that really matters? In WM I use a Bitmap Output device to get a single texture for each terrain and I'm pretty sure it's 513.
     
  10. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    You're right, I don't think that would matter in this scenario. Hopefully my other suggestions fix the issue.
     
  11. MaximilianPs

    MaximilianPs

    Joined:
    Nov 7, 2011
    Posts:
    39
    I need some advice:
    I need to build a 20x20 km, I'm trying to create a grid 10x10 with a 2000x2000 terrain in Unity.
    I didn't have a World Machine pro, so I use gimp to slice the picture in small pieces.
    20480 x 2048 is a correct format?
    Also, sometime terrain Importer refuse to create a 2000x2000 terrain, but instead it set the terrain in smaller tile, like 800x800 or 1000x1000 any idea why it happen?
     
  12. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    It depends on what the resolution of your pre-sliced heightmap is. It should be a power of two + 1 value, something like 2049 or 4097 (or probably higher).

    Dividing the pre sliced heightmap into a 10x10 grid will not work, you have to use a power of two value, such 2x2, 4x4, or 8x8. Obviously 8 is the closest value to 10 so I'd advise using that. To find the resolution of the sliced images, use this formula:
    sliced_image_resolution = ((non_sliced_image_resolution - 1) / grid size) + 1

    where grid size is likely 8.

    When creating the slices, introduce overlap so that the right most column of pixels in each slice is exactly the same as the left most column of pixels in the slice to the right of it (and top most row of pixels in each slice is the same as the bottom most row of pixels in the slice above it). This will ensure that the heightmap values are the same along the borders of slices.

    I assume this is happening when you are importing a tile set. If that is the case, there is an option called "Use These Settings For Individual Tile Pieces", found in the "Dimensions/Resolutions" subsection of the "Base Terrain Settings" foldout.

    If you leave this option unchecked (which I think must be the case for you currently), then the tool will divide the width, length and all resolution settings by the value of the "Tiles Per Side" field in the "Tiled Import Settings" foldout.

    So, try checking the "Use These Settings For Individual Tile Pieces" option and see if the problem goes away. If it does not, or you didn't have this option unchecked to begin with, let me know and I will try to think of another reason this may be happening.

    Thanks!
     
    MaximilianPs likes this.
  13. ianmcmillian

    ianmcmillian

    Joined:
    Dec 31, 2013
    Posts:
    4
    Hey I have a question regarding heightmap tileset import. I created a 16x16 tileset in WM, each with a resolution of 2049x2049 in r16. Before, I managed to import a tileset correctly from TIF images. When choosing raw16 I additionally need to specify "File Width" and "File Height". I am not sure which resolution I should set: a) the 2049 with which each tile was rendered or the whole resolution of the complete (non-tiled) heigthmap? I just want to clarify this before I hit the initialize button because of obvious heavy workload incoming :)

    Fact: total build time of the terrain in WM was: Total Build Time elapsed: 18386.48s
    This is just a proof of concept test. The WM terrain is 56km x 56km. Looking forward to it.

    Update:
    While importing the monster I got a Unity out of memory error. This happened at terrain tile 15_12.
    out_of_memory.jpg

    My system has 8gb RAM which I know is not that much nowadays.
    Could I bypass this issue by importing only sets of the tileset? Say 1_1 -> 5_16; 6_1 -> 10_16; 11_1 -> 16_16? Or would the sequentially imported tiles ram up the RAM (pun intended)?
    How would I do this.
    Using the "Region to import" function?
    Or with "Tiles to import"? Therefore I would need to know the order of how Terrain Importer is importing the tiles.
    Does it first import a complete row or a complete column? Also the naming convention WM creates the tiles is _%x_%y incontrast to _%y_%x as the txt in the asset is telling me to do. This way I managed to import the TIFs correctly. _%y_%x did not work for me.

    Example:
    Assumptions: Rows are imported first.
    Tiles to import: First Row = 1; Last Row = 5 ; First Colum = 1 ; Last Column = 16
    Rinse and repeat for all 16 rows respectively columns (need to know which imports first..).
    Depending on what is imported first this could be subject to change. I guess if columns are imported first this would need to be like this: First Row = 1 ; Last Row = 16 ; First Column = 1; Last Column = 5.
    I will update this post once I check on this.

    Update 1:
    strange_r16.jpg
    The problem here seems to be the naming convention. As seen in this screenshot I used this exact naming convention when I created TIFs with WM and imported them using Terrain Import. It worked as intended with this naming convention. But with RAW16 (*.r16) I get these misalignings.
    As for Tiles to Import you can see the settings on the screenshot aswell.
     
    Last edited: Aug 6, 2017
  14. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    Yes, it is the heightmap size of each individual file you are importing, so 2049 is the correct size.

    The tool has been designed to free memory after each tile is imported, allowing for importing of large tile sets. If you're seeing this error it means there is a bug somewhere. I will figure out what is going on ASAP. Can you email me your invoice number (to kgillen@deepspacelabs.net)? That way I can email you an updated package once the fix has been implemented.

    You should absolutely be able to bypass this error by doing multiple partial imports (great idea!). You'll want to use the Tiles to Import functionality.

    I am not quite sure I understand why you need to know the order that the tiles import, but yes, every column is imported from one row before moving on to the row above. Import Tile row 1 column 1, Import Tile row 1 column 2 . . . etc., Import Tile row 2 column 1, Import Tile row 2 column 2 . . . etc.

    As for the naming convention, use whatever convention was used to export the tiles from World Machine.

    Your naming convention looks okay. I believe World Machine just flips the y axis for some reason. You should be able to fix this by checking the "Flip Vertical" option under Heightmap Import Settings.
     
    Last edited: Aug 7, 2017
  15. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    @ianmcmillian

    I think I know what is happening. I should have instantly picked up on this. Sorry! The brain must not be working right today.

    The issue is that Unity simply cannot handle all those high resolution terrains in the scene at once.

    When importing a large high resolution tile set, you need to create prefabs rather than creating terrain in the scene (or more accurately, create prefabs and then delete the terrain in the scene).

    Under the "Terrain Output Settings" section, you should see an option called "Create Prefabs". Check this option and specify the folder where you want the prefabs to be saved. Then check the "Remove Terrains From Scene" option.

    I am 99% sure this will resolve your issue. If not, please let me know! Hopefully you are utilizing some kind of dynamic loading solution to load only the terrain around your player in game. Otherwise, like I said, Unity cannot utilize so many high resolution terrains at once.

    If you're using the 32 bit editor you can try downloading the 64 bit one. That will (I believe) double the amount of memory that can be used by the editor. No guarantees though, and perhaps you are already using the 64 bit editor, in which case this tip will not help.

    Best Regards,
    Kyle Gillen
     
    Last edited: Aug 7, 2017
  16. f1ac

    f1ac

    Joined:
    May 23, 2016
    Posts:
    20
    Does this tool handle 16bit single channel TIFF files with non-(power of two plus one) dimensions?
     
  17. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    It should be able to, assuming the tiff file follows standard protocol. If the tiff file is using custom tags they'll just be ignored, though if it is a GeoTiff file, most of the meta data can be utilized. What program was used to generate the file? You can send the tiff file to me and I can test importing it to make sure it works (kgillen@deepspacelabs.net), assuming the file is small enough (alternatively you can find somewhere to host it and send me a download link).

    Also, note that you will not be able to import the full non power of two file, as Unity does not support terrain with a non power of two heightmap. Instead, you will import a sub region of the tiff file. You do this by specifying the heightmap of the terrain you are creating (or that already exist) and x and y pixel that is used as the bottom left pixel of the import region. You will most likely need to figure out the correct pixel to use in a third party image editing program, or possibly in the program you used to generate the tiff file. Of course, you can also just guess and and readjust the value by re importing the file over and over again.

    Best Regards,
    Kyle Gillen
     
  18. HeadClot88

    HeadClot88

    Joined:
    Jul 3, 2012
    Posts:
    588
    Hey @gilley033 - Got a few questions about this tool.

    1. Does this work with Unity 2017.1?
    2. Can I export multi tile terrain using this tool?
     
  19. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    There is no reason it shouldn't work with Unity 2017.1. I don't believe they've changed anything regarding the terrain system, though if anyone has information to the contrary please let me know. I have done some limited testing and everything appears to be working.

    As for exporting multi tile terrain, if you mean exporting terrain from Unity to an external heightmap, then no, the tool does not do any exporting.

    If you mean importing multi tile terrain heightmap/splatmaps from outside of Unity into Unity, then yes, it can do that!

    Best Regards,
    Kyle Gillen
     
  20. veddycent

    veddycent

    Joined:
    Jul 22, 2013
    Posts:
    68
    Hi all,

    Does this asset detect the terrain height automatically for each tile?
    Also how does it deal with heights that are below 0 for example sea bed?

    Regards
     
  21. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    Hi veddycent, and thanks for your interest!

    What kind of files are you importing? If you are importing GeoTiff or Terragen files, then the tool should be able to automatically detect the height of each tile, but otherwise you will have to manually enter a terrain height (I know of no other file format that stores this data). The manual settings are applied the same for each tile, so if you need tiles with different heights, there will be a problem (also, if the height cannot be retrieved from the file, the manual value will be used).

    In regards to your other question, absolute heights are not stored in the Unity. A heightmap simply consist of a set of floating point values between 0 and 1. Within Unity, these values are multiplied by the terrain height to find the World space height of each point above the current Y position of the terrain. If you want negative heights, then you just need to lower the Y position of the terrain, most likely to whatever the lowest height you want (otherwise, if left at 0, 0 will be the lowest height possible).

    For file formats that contain absolute heights, the tool will find the lowest height and highest height and then normalize each height in the file to within that range so that a value between 0 and 1 can be fed to Unity.

    I hope that answers your questions, but if not please feel free to clarify or restate your questions.

    Thanks!
     
  22. veddycent

    veddycent

    Joined:
    Jul 22, 2013
    Posts:
    68
    Thanks for the reply.

    I'll hopefully be using GeoTiffs. I'm going to try and load the whole of New York County and alot of the sea bed (used for offshore wind farm)

    I see what you mean about the heights being interpolated from 0 to 1 so any elevation below 0 will require the terrain gameobject being adjusted in the y axis accordingly. I might have to create a txt with the maximum and minimum heights for all the terrain segments then write a script in unity to set these values for each individual terrain gameobject.

    I'll have to do some testing first...

    Regards
     
  23. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    To be honest, I never envisioned needing this functionality because usually when importing a tile set, all the files utilize the same range of elevation data. Perhaps this assumption was flawed, however. There is already an option to try and preserve the absolute elevation data when importing Terragen or GeoTiff files, but it assumes that the tiles are all utilizing the same elevation range and you are simply trying to map the values to a new elevation range.

    Really what the tool needs to know is the minimum elevation and maximum elevation (taking into account all tiles in the tile set). We could then set the height of every tile to the same value (max elevation - min elevation), and map each raw elevation data point to this range.

    I could also add an option when getting the terrain height from the file to set the y position of the terrain to the lowest elevation data in the tile.

    Both of these possibilities rely on the GeoTiff storing its elevation data as floats, since this is only format in which the raw elevation data is stored, so the easiest option may be what you say, just write a little script to set the y position from a text file.

    If you want to email me or get to me one of your GeoTiff files once you create it, I can inspect it and determine if its in the correct format. There's no point to add this extra functionality if not (unless someone else request it).

    Regards,
    Kyle Gillen
     
  24. veddycent

    veddycent

    Joined:
    Jul 22, 2013
    Posts:
    68
    Hey,

    I've got another quick question...
    Can your asset load 32-bit GeoTiffs? I have been using a GIS program called GlobalMapper to process all the DEM data and I get the best results with 32-bit GeoTiffs. Unfortunately converting them to 16-bit GeoTiffs converts the elevation values to integers giving a stepped result which is not ideal for real world terrains.

    Regards
    Ved
     
  25. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    532
    Yes, the tool should be able to handle 32 bit uint, int, or float values, though only float values have been actually tested (but that is probably what your program is using). If you can send me a sample file I can test it out for you to make sure it does indeed import correctly. Just to be safe!