Search code examples
c#unity-game-enginemathgridnoise

How to calculate 2D height disparities on a noise map


I'm creating a tile-based game in Unity (C#) with a hexagonal grid. I am making hills and mountains in my game, and to optimize, I only activate the top layer of tiles and leave the rest of them inactive. I render each tile with a noise-based height map (please note the colors on the grid itself such as brown, green, and grey do not correspond to height).

enter image description here enter image description here

However, I encounter issues when the hills become high and a vertical gap between one tile and the next reveals a hole in the map due to height disparities.

enter image description here

To fix this, I am making a retroactive function which cycles through each pixel on the noise map and if it detects a disparity between one pixel and another which borders it, then it will activate the tile below the higher tile in the disparity. The blue tiles below represent the tiles that it detected as being in a disparity, and the red ones are the tiles activated as a result of their higher counterparts being detected as such.

enter image description here

Most the time, however, the disparities are not recognized in the right positions. You can see in the image above that the brown tile which should be considered as having a disparity (since it's leaving a gap) has a gaping hole and no red tile beneath it, while others which have no gaps are considered as having disparities and are thus blue. Here is a representation of how there's little correlation between the height map and the disparities detected:

enter image description hereenter image description here

You can see above that the white on the height map, representing high areas, does not correspond with the blue on the grid, which should correspond with disparities (and thus mainly correspond with where the white and the black converge on the noise map, outlining the location between high and low areas).

Here is my code to detect disparities:

//ADD BLOCKS BELOW WHERE MAGNITUDE IS HIGH SO NO OPEN SPACES
int wi = -1;
int thisChunkX = 0;
for (int w = 0; w < thisTexture.width; w++)
{
    wi++;

    if (wi == chunkSize.x) { wi = 0; thisChunkX++; }

    int hi = -1;
    int thisChunkZ = 0;

    for (int h = 0; h < thisTexture.height; h++)
    {
        hi++;

        if (hi == chunkSize.z) { hi = 0; thisChunkZ++; }

        if (w - 1 >= 0 && h - 1 >= 0 && w + 1 < thisTexture.width && h + 1 < thisTexture.height)//for all non-direct borders in the texture
        {
            List<float> surroundingHexes = new List<float>
            {
                thisTexture.GetPixel(w+1, h).maxColorComponent,//top
                thisTexture.GetPixel(w-1, h).maxColorComponent,//bottom
                thisTexture.GetPixel(w-1, h+1).maxColorComponent,//top left
                thisTexture.GetPixel(w+1, h+1).maxColorComponent,//top right
                thisTexture.GetPixel(w-1, h).maxColorComponent,//bottom left
                thisTexture.GetPixel(w+1, h).maxColorComponent//bottom right
            };

            float thisHex = thisTexture.GetPixel(w, h).maxColorComponent;

            foreach (float thisSurroundingHex in surroundingHexes)
            {
                float hexMagnitude = thisHex - thisSurroundingHex;//IMPORTANT!!!

                if (thisTexture.GetPixel(w, h) != new Color(1, 0, 0) && hexMagnitude > 0.25f)//IMPORTANT!!!
                {
                    //DISPARITY IS DETECTED
                    
                    //other stuff

                    break;
                }
            }
        }
    }

Even if hexMagnitude > 0.25f is not the most accurate, wouldn't there still be a strongish correlation representing height disparities since hexMagnitude = thisHex - thisSurroundingHex, where thisHex and thisSurroundingHex are each values which correspond with height? Any help would be greatly appreciated. Thank you!


Solution

  • May i suggest naming your for-loop-variables x and y instead of w and h? I think x and y are more obviously assigned for the two coordinates. Anyway. I haven't entirely checked if this is the only issue, but I feel like you've set your pixel-checks up wrong. (see below)

    thisTexture.GetPixel(w+1, h).maxColorComponent,//top  << shouldn't this be (w, h+1)?
    thisTexture.GetPixel(w-1, h).maxColorComponent,//bottom  << Shouldn't this be (w, h-1)?
    thisTexture.GetPixel(w-1, h+1).maxColorComponent,//top left  << Looks fine
    thisTexture.GetPixel(w+1, h+1).maxColorComponent,//top right  << Looks fine
    thisTexture.GetPixel(w-1, h).maxColorComponent,//bottom left  << This is the same as "bottom". Shouldn't this be (w-1, h-1)?
    thisTexture.GetPixel(w+1, h).maxColorComponent//bottom right  << This is the same as "top". shouldn't this be (w+1, h-1)?
    

    Also, in theory you don't need every pixel around the pixel. When you check the pixel on the bottom right and later get to that same pixel you no longer need to check the pixel on the top left, since that check has already been made. So all you really need there is

    thisTexture.GetPixel(w, h+1).maxColorComponent,//top
    thisTexture.GetPixel(w+1, h+1).maxColorComponent,//top right
    thisTexture.GetPixel(w+1, h-1).maxColorComponent,//bottom right
    

    depending on the order of tiles checked you might need to change the check-directions or even add a fourth one (haven't worked with hex-gird before)