Jump to content

[SOLVED] - Dear Dave, Need Your Help


MackeyK24
 Share

Recommended Posts

Hey Dave... I really need your help in finishing up my build in babylonjs terrain system. I think i may need some mods to the CreateGroundFromHeightmap or maybe help in creating a new CreateGroundFromUnityHeightmap where we go in and compensate for the height map coming from unity and 'post' process those height values to make it look good in babylon.  Please take a look at the the video link explaining the problem (Also is attached a TestTerrain.png height map at 100 width/length and 50 height for to try to get to make look good with a creategroundfromheightmap call):

Dear Dave - Please Help

Try This Playground and see if can't get not so choppy around the edges:

http://www.babylonjs-playground.com/#RDPE6#1

 

TestTerrain.png

Link to comment
Share on other sites

Hello Mackey, I'm not @davrous but I'm pretty sure the problem is in the texture generated. There is not enough detail (as far as I can see it generates color (height) from dark to dark grey where it is supposed to generate from black to white).

Everything else seems fine.

The subdivisions value is the number of triangle per row.

Here only 5 subdivisions: (so 5 triangles per row)

Capture.JPG

Here with 10:

Capture2.JPG

So in your case, if you want a smooth terrain 100 is really fine (as long as you provide a back to white height map)

Link to comment
Share on other sites

So not greyscale... So any idea on how to to take those greyscale values and make them more black and white?

Here is the Code to get terrain heights (raw grayscale heights):

                int hwidth = terrain.terrainData.heightmapWidth;
                int hheight = terrain.terrainData.heightmapHeight;
                float[,] rawHeights = terrain.terrainData.GetHeights(0, 0, hwidth, hheight);
                Texture2D heightMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false);
                for (int y=0; y < hheight; y++) {
                    for (int x=0; x < hwidth; x++) {
                        float inverted = rawHeights[y, x];
                        Color pixel = new Color(inverted, inverted, inverted, 1.0f);
                        heightMap.SetPixel(x, y, pixel);
                    }
                }
                heightMap.Apply();

 

Link to comment
Share on other sites

I guess in Unity each sample (0 - 1) is relative to the (0 - size.y) of your terrain.data.size so not normalized against each other so if your max (size.y) is 1000 but you have no "big mountains", your values could get stuck between (0 and 10) e.g (0 - 0.01) in your samples.

This is then converted to 8 bit picture so only 0 - 255  where 0 would be 0 and 255 -> size.y e.g. 1000 therefore each unit in color is about a step of 4 in the terrain height meaning all of your value would be either 0 or 1 for 4 or 2 for 8 or 3 for 12 which would be almost fully black as we are seeing in your picture and creates a really low res height.

Maybe you could at export find the min - max sample and normalized everything in between. Those values could then be used in your metadata to control the ground creation in bjs and you would be sure to use the full 255 available units in your texture.

The number are all wrong and made up and only here to illustrate. Not sure I am clear enough btw....

I normalized your texture by hand and have now this:

http://www.babylonjs-playground.com/#RDPE6#2

with

normalized.png

I agree it may still not be smooth enough but the limitation to byte for the texture is annoying (only 255 different levels).

2 solutions to smooth it more would be:

    1. Interpolating in the create ground map function so if our res is bigger than the texture, we can infer some values (still have some artifacts).

    2. Or we could add a way to pack the data from unity in the the 4 textures channels (or 2 only cause Unity stores terraindata in 16 bit integer I guess not 32) and create back the ground from it.

Link to comment
Share on other sites

What about this:

Instead of using raw heights, use GetInterpolatedHeight(x,y)

If you have to use TerrainData for some reason, then you'd want GetInterpolatedHeight. The x and y values that you supply are normalized to the terrain, so that 0.0, 0.0 is the lower-left corner, and 1.0, 1.0 is the upper-right corner

 

Link to comment
Share on other sites

If we just can't get it with using unity height maps... Maybe ill just pull that feature and focus on Terrain Exporter instead...Which might not be a bad idea because i can't seem to get to the Terrain Mesh Renderer (SharedRender) so i can't get to the light map baking info for shadows cast on to the terrain. If i use a scene to create a terrain and save as mesh asset you can then use in your actual scene as a regular mesh so you can then bake light maps onto the material using the mesh renderer.  Also if you re-export the terrain since its and exported asset in the project it SHOULD just refresh and show the changes you made to the asset.

Dunno... i will keep playing with terrains...

I gotta get that working because that segues to my next feature (which is working beautifully so far) Navigation Mesh, Navigation Agent and Off Link Mesh MetaData Support (that my scene manager wraps up in a nice API to use the native unity navigation information to implement our own babylonjs open navigation system... you can use WHATEVER pathfinding system you want using the supplied navigation mesh, plus all the aux data you need to fully implement your AI things like obstacle avoidance )

And i need to be able to put a navigation mesh on a terrain and use them BOTH in my babylon scene :)

 

Link to comment
Share on other sites

Hey @Sebavan ... Do you think you have a hot minute to help me with some code... I don't know how to 'normalize' the image like you did. But your height map looks great. I don't know the what math formula to use to change color pixels to a 'normalized' image. CAN YOU PLEASE edit the following code where i get all the grayscale pixels and simply put back into normalized map pixels... Can you actually tweak that little bit of code to 'normalize' the Color32[] pixels and set that new Color32[] pixel array into the normalmapTexture.SetPixels32():

 

Vector3 terrainSize = terrain.terrainData.size;
int hwidth = terrain.terrainData.heightmapWidth;
int hheight = terrain.terrainData.heightmapHeight;
float[,] rawHeights = terrain.terrainData.GetHeights(0, 0, hwidth, hheight);
Texture2D heightMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false);
for (int y = 0; y < hheight; y++) {
	for (int x = 0; x < hwidth; x++) {
		float inverted = rawHeights[y, x];
		Color pixel = new Color(inverted, inverted, inverted, 1.0f);
		heightMap.SetPixel(x, y, pixel);
	}
}
heightMap.Apply();
Texture2D normalizedMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false);
Color32[] grayscalePixels = heightMap.GetPixels32();

////////////////////////////////////////////////////////////////////////////////////////
// PLEASE HELP - TODO: Normailize Pixels from heightMapTexture to normalizedMapTexture 
// For Now Just Set Same Pixel Back, No Conversion Yet
///////////////////////////////////////////////////////////////////////////////////////

normalizedMap.SetPixels32(grayscalePixels);

///////////////////////////////////////////////////////////////////////////////////////

normalizedMap.Apply();
string tempFilename = "temp" + terrain.name.Replace(" ", "").Replace("(", "").Replace(")", "") + "Heightmap.png";
string tempTexturePath = Path.Combine(Application.dataPath.Replace("/Assets", "/Temp/data"), tempFilename);
byte[] heightmapBytes = normalizedMap.EncodeToPNG();
string temp = Path.GetDirectoryName(tempTexturePath);
if (!Directory.Exists(temp)) Directory.CreateDirectory(temp);
File.WriteAllBytes(tempTexturePath, heightmapBytes);

 

Link to comment
Share on other sites

Hello,

Here is your new loop:

        float min = float.MaxValue;
        float max = float.MinValue;

        for (int y = 0; y < hheight; y++)
        {
            for (int x = 0; x < hwidth; x++)
            {
                float inverted = rawHeights[y, x];

                min = Mathf.Min(min, inverted);
                max = Mathf.Max(max, inverted);
            }
        }

        float ratio = 1.0f / (max - min);

        for (int y = 0; y < hheight; y++)
        {
            for (int x = 0; x < hwidth; x++)
            {
                float inverted = rawHeights[y, x];

                inverted *= ratio;

                Color pixel = new Color(inverted, inverted, inverted, 1.0f);
                heightMap.SetPixel(x, y, pixel);
            }
        }

Think to also reuse the min max as the min max in BJS when you create the height map.

The dual mesh approach will help a lot. I guess you could maybe also leverage the LOD from unity.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...