Welcome Guest! To enable all features please try to register or login.
Options
View
Go to last post Go to first unread
Cactusthorn  
#1 Posted : Friday, August 28, 2015 3:39:37 AM(UTC)
Cactusthorn

Rank: Member

Reputation:

Groups: Registered
Joined: 8/10/2015(UTC)
Posts: 11

Was thanked: 1 time(s) in 1 post(s)
After the last update i found my self putting in place a interpolation function to get more precise data out of the new heightmap.

I was wondering if a "float Map.Terrain.getHeight(float x, float z)" method or something close to get the height of any point on the map could be considered for a future update?
VictorTrax  
#2 Posted : Friday, August 28, 2015 6:08:19 AM(UTC)
VictorTrax

Rank: Administration

Reputation:

Groups: Administrators, Registered
Joined: 5/7/2015(UTC)
Posts: 42

Thanks: 2 times
Was thanked: 5 time(s) in 4 post(s)
There's already a Map.Terrain.GetHeight method, which uses nearest-neighbor interpolation. The heightmap resolution is 512 (i.e., 512 x 512), and since the map size is 1000 x 1000 meters, the value returned by GetHeight will be at least fairly accurate -- the height of a point on the ground less than 2 meters away on the X-Z plane (1000 / 512 = 1.953125). That is to say, the map doesn't have such drastic spikes or dips that happen within a 2 meter surface area that your result would be off by much.

We may add an override that provides a more precise value, perhaps one that does bilinear interpolation, for example, but the call would be more expensive of course. Until then, the existing method might be good enough for most cases. If it fails to work for you, maybe post your scenario so we can figure something out.

For reference, here's how the GetHeight method works right now:

Code:


// Do some one-time initialization:
_heightmapCenter = Heightmap.Resolution / 2;
_resXFactor = Heightmap.Resolution / (float)Map.Size.X;
_resYFactor = Heightmap.Resolution / (float)Map.Size.Y;

...

/// <summary>
/// Gets the approximate terrain height at a position on the game map.
/// </summary>
/// <param name="position">position (Y coordinate is ignored)</param>
/// <returns>height</returns>
public float GetHeight(Vector3D position)
{
	return Heightmap.Samples[
		(int)Math.Round(position.Z * _resYFactor + _heightmapCenter, MidpointRounding.AwayFromZero),
		(int)Math.Round(position.X * _resXFactor + _heightmapCenter, MidpointRounding.AwayFromZero)];
}

Edited by user Friday, August 28, 2015 6:23:43 AM(UTC)  | Reason: Not specified

Cactusthorn  
#3 Posted : Friday, August 28, 2015 6:15:27 AM(UTC)
Cactusthorn

Rank: Member

Reputation:

Groups: Registered
Joined: 8/10/2015(UTC)
Posts: 11

Was thanked: 1 time(s) in 1 post(s)
Oups, i didn't see the Map.Terrain.GetHeight methode, i'm sorry!
( I in deed used bilinear interpolation in my code, even though it has a higher calculation cost).

Thank you!
VictorTrax  
#4 Posted : Friday, August 28, 2015 6:31:56 AM(UTC)
VictorTrax

Rank: Administration

Reputation:

Groups: Administrators, Registered
Joined: 5/7/2015(UTC)
Posts: 42

Thanks: 2 times
Was thanked: 5 time(s) in 4 post(s)
Ah, OK. Do you mind sharing your interpolation method? It might be useful for others and we could compare it to what we're planning, too.
Cactusthorn  
#5 Posted : Friday, August 28, 2015 6:59:46 AM(UTC)
Cactusthorn

Rank: Member

Reputation:

Groups: Registered
Joined: 8/10/2015(UTC)
Posts: 11

Was thanked: 1 time(s) in 1 post(s)
Of course:
It's kind of messy, as i don't if the values of the heightmap come from the "middle" of the pixel or the corner or if its the average heigth or anything else. By this i mean don't know if heigthMap[0,0] is the heigth at coordonate (0,0) or the average/middle/(or whatever it is) heigth of the bottom-left "box" witch has a side of 1/512 * 1000 meters.
So there may be a slight offset.

Code:
 public float getHeight(Vector3D position)
        {
            // Here i supposed that heigthMape[x,y] value came from the center of the box, 
            //the -0.5 come from there
            float y = (float)(position.X + _origine.X)/ _width * _heightMap.Resolution - 0.5f,
                  x = (float)(position.Z + _origine.Z)/ _height * _heightMap.Resolution - 0.5f;

            int x2 = (int)Math.Ceiling(x),
                x1 = (int)Math.Floor(x),
                y2 = (int)Math.Ceiling(y),
                y1 = (int)Math.Floor(y);

            // Making sure to keep into index range --> the points on the outer edges will be 
            // interpolated from only 2 pts. See below
            if (x1 < 0)
                x1++;

            if (x2 > _heightMap.Resolution - 1)
                x2--;

            if (y1 < 0)
                y1++;

            if (y2 > _heightMap.Resolution - 1)
                y2--;

            if (x1 == x2 && y1 == y2)
                return _heightMap.Samples[x1, y1];
            else if (x1 == x2)
                return _heightMap.Samples[x1, y1] * (y2 - y) +
                        _heightMap.Samples[x1, y2] * (y - y1) /
                        (y2 - y1);
            else if (y1 == y2)
                return _heightMap.Samples[x1, y1] * (x2 - x) +
                        _heightMap.Samples[x2, y1] * (x - x1) /
                        ((x2 - x1));
            else
                return (_heightMap.Samples[x1, y1] * (x2 - x) * (y2 - y) +
                        _heightMap.Samples[x2, y1] * (x - x1) * (y2 - y) +
                        _heightMap.Samples[x1, y2] * (x2 - x) * (y - y1) +
                        _heightMap.Samples[x2, y2] * (x - x1) * (y - y1)) /
                        ((x2 - x1) * (y2 - y1));
        }


Basically this comes straigth from wikipedia: https://en.wikipedia.org.../Bilinear_interpolation. I just added the tweaked formulas for it to work on the edges.

PS: And yes the divisions are useless in this case.

Edited by user Friday, August 28, 2015 9:04:02 AM(UTC)  | Reason: Not specified

VictorTrax  
#6 Posted : Friday, August 28, 2015 9:47:26 AM(UTC)
VictorTrax

Rank: Administration

Reputation:

Groups: Administrators, Registered
Joined: 5/7/2015(UTC)
Posts: 42

Thanks: 2 times
Was thanked: 5 time(s) in 4 post(s)
Looks great. I think you need to add parentheses around the addition operations so it happens before the division, when averaging just two points, same as you do when averaging four. Also, why not just divide by the constants 2 and 4 in those places, like this?
Code:

            if (x1 == x2 && y1 == y2)
                return _heightMap.Samples[x1, y1];
            else if (x1 == x2)
                return (_heightMap.Samples[x1, y1] * (y2 - y) +
                        _heightMap.Samples[x1, y2] * (y - y1)) / 2;
            else if (y1 == y2)
                return (_heightMap.Samples[x1, y1] * (x2 - x) +
                        _heightMap.Samples[x2, y1] * (x - x1)) / 2;
            else
                return (_heightMap.Samples[x1, y1] * (x2 - x) * (y2 - y) +
                        _heightMap.Samples[x2, y1] * (x - x1) * (y2 - y) +
                        _heightMap.Samples[x1, y2] * (x2 - x) * (y - y1) +
                        _heightMap.Samples[x2, y2] * (x - x1) * (y - y1)) / 4;
        }

Edited by user Friday, August 28, 2015 9:48:46 AM(UTC)  | Reason: Not specified

Cactusthorn  
#7 Posted : Friday, August 28, 2015 10:14:07 AM(UTC)
Cactusthorn

Rank: Member

Reputation:

Groups: Registered
Joined: 8/10/2015(UTC)
Posts: 11

Was thanked: 1 time(s) in 1 post(s)
My bad for the parenthesis.
And unless i'm wrong, (x2 - x1) * (y2 - y1) always does 1 and do does the other dividers, so i can write:

Code:
if (x1 == x2 && y1 == y2)
                return _heightMap.Samples[x1, y1];
            else if (x1 == x2)
                return (_heightMap.Samples[x1, y1] * (y2 - y) +
                        _heightMap.Samples[x1, y2] * (y - y1));
            else if (y1 == y2)
                return (_heightMap.Samples[x1, y1] * (x2 - x) +
                         _heightMap.Samples[x2, y1] * (x - x1));
            else
                return (_heightMap.Samples[x1, y1] * (x2 - x) * (y2 - y) +
                        _heightMap.Samples[x2, y1] * (x - x1) * (y2 - y) +
                        _heightMap.Samples[x1, y2] * (x2 - x) * (y - y1) +
                        _heightMap.Samples[x2, y2] * (x - x1) * (y - y1));


VictorTrax  
#8 Posted : Friday, August 28, 2015 5:57:14 PM(UTC)
VictorTrax

Rank: Administration

Reputation:

Groups: Administrators, Registered
Joined: 5/7/2015(UTC)
Posts: 42

Thanks: 2 times
Was thanked: 5 time(s) in 4 post(s)
Ah, right, OK.

I think we'll have an interpolation option for the GetHeight method eventually so people can choose which one they want to use.

Edited by user Friday, August 28, 2015 5:57:46 PM(UTC)  | Reason: Not specified

Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You can vote in polls in this forum.

Notification

Icon
Error