【问题标题】:finding height on a heightmap stretched over a sphere C#在一个球体 C# 上的高度图上查找高度
【发布时间】:2013-01-22 00:26:07
【问题描述】:

我正在寻找一些数学方面的帮助。我有一个游戏是生成 2D 高度图,然后使用长度/方向公式在球体上拉伸。现在我需要知道如何计算高度图上两点之间的高度。

我知道的:

  • 保存高度图的数组
  • 我的对象的弧度角
  • 高度图上有多少个点

我的问题看起来有点像这样:

image

more images

红色和蓝色线是 2 个高度图点,浅蓝色是我要计算高度的位置。

这是我当前的代码,但效果不佳。

public double getheight(double angle)
{
    //find out angle between 2 heightmap point
    double offset = MathHelper.TwoPi / (heightmap.Length - 1);
    //total brainfart attempt
    double lowerAngle = offset * angle;
    double upperAngle = offset * angle + offset;
    //find heights
    double height1 = heightmap[(int)lowerAngle];
    double height2 = heightmap[(int)upperAngle];
    //find offset angle
    double u = angle - lowerAngle / (upperAngle - lowerAngle);
    //return the height
    return height1 + (height1 - height2) * u;
}

从我的植被代码来看,这似乎工作正常,但对于单位等来说使用起来很粗糙,因为它们在移动时会上下跳跃,因为它只使用 1 个高度图点。

double[] hMap = planet.getHeightMap();
double i = hMap.Length / (Math.PI * 2);
this.height = hMap[(int)(angle * i)];

【问题讨论】:

    标签: c# math angle heightmap


    【解决方案1】:

    编辑:最后基于附加问题信息的示例

    听起来像是线性插值 - 如果你从 2d 的角度来看它,你有两点:

    (x1, y1) = point one on heightmap
    (x2, y2) = point two on heightmap
    

    (x1,x2) 之间的某个点,高度未知:

    pu = (xu, yu)
    

    LERP 的通用公式是:

    pu = p0 + (p1 - p0) * u
    

    地点:

    • p0 = 第一个值
    • p1 = 第二个值
    • u = % 您的未知点位于 (p0,p1) 之间

    在这里,我们会说p0 == y2p1 == y1。现在我们需要确定未知点在x1x2 之间“多远” - 如果您知道两个高度图点的角度,这很容易:

    u = ang(xu) - ang(x1) / (ang(x2) - ang(x1))
    

    或者,您可以将角度投影到 Max(y1,y2) 并以这种方式获得“未知 x 位置”,然后计算上述内容。

    那么,让我们尝试一个人为的例子:

    p1 = point one in map = (1,2) therefore ang(p1) ~ 57 degrees
    p2 = point two in map = (2,4) therefore ang(p2) ~ 114 degrees
    

    注意这里的“x轴”是沿着球体表面,“y轴”是离球心的距离。

    pu = object location = py @angle 100 degrees ~ 1.74 radians
    
    px = (1.74 rad - 1 rad ) / (2 rad - 1 rad) = 0.74 / 1.0 = 0.74 => 74%
    
    py = y0 + (y1 - y0) * u
       = 2 + (4 - 2) * 0.74
       = 2.96
    

    希望我没有在某处丢掉或放错标志... :)

    好的,您的示例代码 - 我已经对其进行了一些调整,这是我想出的:

    首先,让我们定义一些我自己的助手:

    public static class MathHelper
    {
        public const double TwoPi = Math.PI * 2.0;
        public static double DegToRad(double deg)
        {
            return (TwoPi / 360.0) * deg;
        }
        public static double RadToDeg(double rad)
        {
            return (360.0 / TwoPi) * rad;
        }
    
        // given an upper/lower bounds, "clamp" the value into that
        // range, wrapping over to lower if higher than upper, and
        // vice versa    
        public static int WrapClamp(int value, int lower, int upper)
        {
            return value > upper ? value - upper - 1
                : value < lower ? upper - value - 1
                : value;
        }
    }
    

    我们的测试设置:

    void Main()
    {
        var random = new Random();
    
        // "sea level"
        var baseDiameter = 10;
    
        // very chaotic heightmap
        heightmap = Enumerable
            .Range(0, 360)
            .Select(_ => random.NextDouble() * baseDiameter)
            .ToArray();
    
        // let's walk by half degrees, since that's roughly how many points we have
        for(double i=0;i<360;i+=0.5)
        {
            var angleInDegrees = i;
            var angleInRads = MathHelper.DegToRad(i);
            Console.WriteLine("Height at angle {0}°({1} rad):{2} (using getheight:{3})",
                angleInDegrees,
                angleInRads,
                heightmap[(int)angleInDegrees],
                getheight(angleInRads));
        }
    }
    
    double[] heightmap;
    

    还有我们的“getheight”方法:

    // assume: input angle is in radians
    public double getheight(double angle)
    {
        //find out angle between 2 heightmap point
        double dTheta = MathHelper.TwoPi / (heightmap.Length);
    
        // our "offset" will be how many dThetas we are
        double offset = angle / dTheta;
    
        // Figure out two reference points in heightmap
        // THESE MAY BE THE SAME POINT, if angle ends up
        // landing on a heightmap index!
        int lowerAngle = (int)offset;
        int upperAngle = (int)Math.Round(
            offset, 
            0, 
            MidpointRounding.AwayFromZero);
    
        // find closest heightmap points to angle, wrapping
        // around if we go under 0 or over max
        int closestPointIndex = MathHelper.WrapClamp(
            lowerAngle, 
            0, 
            heightmap.Length-1);
        int nextPointIndex = MathHelper.WrapClamp(
            upperAngle, 
            0, 
            heightmap.Length-1);
    
        //find heights
        double height1 = heightmap[closestPointIndex];
        double height2 = heightmap[nextPointIndex];
    
        // percent is (distance from angle to closest angle) / (angle "step" per heightmap point)
        double percent = (angle - (closestPointIndex * dTheta)) / dTheta;
    
        // find lerp height = firstvalue + (diff between values) * percent
        double lerp = Math.Abs(height1 + (height2 - height1) * percent);
    
        // Show what we're doing
        Console.WriteLine("Delta ang:{0:f3}, Offset={1:f3} => compare indices:[{2}, {3}]", 
            dTheta, 
            offset, 
            closestPointIndex, 
            nextPointIndex);
        Console.WriteLine("Lerping {0:p} between heights {1:f4} and {2:f4} - lerped height:{3:f4}", 
            percent,
            height1, 
            height2,
            lerp);
    
        return lerp;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-05-15
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      • 2011-07-28
      相关资源
      最近更新 更多