Opengl 具有脊状分形噪声的程序地形

Opengl 具有脊状分形噪声的程序地形,opengl,terrain,procedural-generation,Opengl,Terrain,Procedural Generation,我实现了双线性插值白噪声,以便按程序生成地形 我可以得到这样的结果: 我想实现脊状分形噪波,以获得更真实的地形,如: 然而,我找不到一个关于脊状分形噪声的好教程。你能给我解释一下怎么做吗?脊状柏林噪波实际上很容易做到-你只需要ABS()最终的高度贴图或噪波层的某个子集(然后反转生成的高度贴图值,以确保脊出现在高值处) 示例:(带有三线性插值的基本柏林噪声,然后是ABS和整个高度场的反转)。(反转表示“乘以-1”。) 我强烈建议尝试各种分形噪声层的配置和基本的数学/逻辑运算 另一个示例:(两个

我实现了双线性插值白噪声,以便按程序生成地形

我可以得到这样的结果:

我想实现脊状分形噪波,以获得更真实的地形,如:


然而,我找不到一个关于脊状分形噪声的好教程。你能给我解释一下怎么做吗?

脊状柏林噪波实际上很容易做到-你只需要ABS()最终的高度贴图或噪波层的某个子集(然后反转生成的高度贴图值,以确保脊出现在高值处)

示例:(带有三线性插值的基本柏林噪声,然后是ABS和整个高度场的反转)。(反转表示“乘以-1”。)

我强烈建议尝试各种分形噪声层的配置和基本的数学/逻辑运算

另一个示例:(两个不同的低频柏林噪声层使用逻辑交点/数学最小值函数合并)

但是,对分形噪波算法进行简单的修改,将不会为您提供“向下流动”(并使地形更加逼真和吸引人)的细节。要实现这些,您需要添加某种侵蚀模拟,这是一种更为复杂的beast(无论是算法方面还是CPU方面)

关于这方面的一些信息,我推荐这两篇论文(您可以忽略GPU部分,算法在CPU上运行良好,但根据我的经验,对于1000x1000 px图像,模拟将需要一分钟左右):

  • 编辑:

    让我们澄清我所说的“在高度场上应用ABS”的意思

    您只需获取地图每个像素的高度数值,并对其应用ABS()函数,丢弃其符号

    这假定柏林噪波生成器生成范围(或以0为中心的另一个范围)中的值~50%的像素的值应大于0,约50%的像素的值应小于0

    由于所有双线性/三线性插值将确保过去有一个平滑的坡度通过0值,因此ABS会在0处创建尖锐的脊线

    以这幅图像为例:


    它显示了两个COS(x)函数,其中一个是用ABS函数调制的(我添加了一个小偏移量,以确保两条线分别可见)。现在,假设紫色线垂直翻转-您最终看到两座山,山上有尖锐的山脊,山脊之间有一个山谷:)

    为了产生物理上真实的山脊,正如前面的答案所述,修改噪波函数可能不是最好的方法。相反,如果您从分形曲面开始,并对其应用适当的侵蚀功能,则可以相当轻松地创建具有物理真实形状的山脊

    我最近在我的网站上写下了我的努力:

    基本上,如果您的目标是简单的山脊,您可以修改热侵蚀方程以去除所有沉积(即,仅减去侵蚀)。我使用C#代码来腐蚀一个单点-它相当快,并且会在我的PC上在大约10秒内用250次迭代来腐蚀我的4096x4096测试环境(尽管在12个核上进行了一些并行化)

    位的混乱只是获取被侵蚀点的8个相邻点的有效方法——我的表示使用线性阵列,因此y坐标被预先乘以景观的宽度(yMul等)。为了简单起见,可以将步幅视为1。r2和位移位只是角点的1/sqrt(2)的快速乘法

    var x0 = (x1 - stride) & mask;
    var x2 = (x1 + stride) & mask;
    indices[0] = x0 + yMul0;
    indices[1] = x1 + yMul0;
    indices[2] = x2 + yMul0;
    indices[3] = x0 + yMul1;
    indices[4] = x2 + yMul1;
    indices[5] = x0 + yMul2;
    indices[6] = x1 + yMul2;
    indices[7] = x2 + yMul2;
    
    for (int i = 0; i < actualLength; i++)
    {
        elements[i] = thisSurface[indices[i]];
    }
    
    var height = thisSurface[x1 + yMul1];
    
    //Differences in height.
    //Corner differences multipled by 1/sqrt(2)
    diffs[0] = ((height - elements[0]) * r2denom) >> 8;
    diffs[1] = height - elements[1];
    diffs[2] = ((height - elements[2]) * r2denom) >> 8;
    diffs[3] = height - elements[3];
    diffs[4] = height - elements[4];
    diffs[5] = ((height - elements[5]) * r2denom) >> 8;
    diffs[6] = height - elements[6];
    diffs[7] = ((height - elements[7]) * r2denom) >> 8;
    
    //Compare the differences to the talus threshold.
    var max = 0;
    var talusSum = 0;
    var slopeSum = 0;
    for (var i = 0; i < actualLength; i++)
    {
        var diff = diffs[i];
        if (diff > 0)
        {
            if (diff > max)
            {
                max = diff;
            }
    
            talusSum += diff;
            if (diff > talusThreshold)
            {
                slopeSum += (diff - talusThreshold);
            }
        }
    }
    
    talusSum = talusSum / 2 - talusThreshold;
    
    if (talusSum > 0)
    {
        //Work out how much height to redistribute.
        var toMove = talusSum / 4;
        if (altitudeProportional)
        {
            toMove *= (height - minAltitude);
            toMove /= (maxAltitude - minAltitude);
        }
    
        newSurface[x1 + yMul1] -= toMove;
    }
    
    var x0=(x1-步幅)和掩码;
    变量x2=(x1+步幅)和遮罩;
    指数[0]=x0+yMul0;
    指数[1]=x1+yMul0;
    指数[2]=x2+yMul0;
    指数[3]=x0+yMul1;
    指数[4]=x2+yMul1;
    指数[5]=x0+yMul2;
    指数[6]=x1+yMul2;
    指数[7]=x2+yMul2;
    对于(int i=0;i<实际长度;i++)
    {
    元素[i]=该表面[i]];
    }
    var高度=该表面[x1+yMul1];
    //身高差异。
    //角差乘以1/sqrt(2)
    差异[0]=((高度-元素[0])*r2denom)>>8;
    差异[1]=高度-元素[1];
    差异[2]=((高度-元素[2])*r2denom)>>8;
    差异[3]=高度-元素[3];
    差异[4]=高度-元素[4];
    差异[5]=((高度-元素[5])*r2denom)>>8;
    差异[6]=高度-元素[6];
    差异[7]=((高度-元素[7])*r2denom)>>8;
    //将差异与距骨阈值进行比较。
    var max=0;
    talusSum变量=0;
    var slopeSum=0;
    对于(变量i=0;i<实际长度;i++)
    {
    var diff=差异[i];
    如果(差异>0)
    {
    如果(差异>最大值)
    {
    最大值=差值;
    }
    距骨+=diff;
    如果(差异>talusThreshold)
    {
    斜率sum+=(差-塔卢斯阈值);
    }
    }
    }
    talusSum=talusSum/2-talusThreshold;
    如果(距骨>0)
    {
    //计算出要重新分配的高度。
    var-toMove=talusSum/4;
    if(高度比例)
    {
    toMove*=(高度-高度);
    toMove/=(最大高度-最低高度);
    }
    newSurface[x1+yMul1]=toMove;
    }
    
    +1用于包含所需输出的示例-当我们都有相同的目标时,可以更轻松地对流程进行故障排除。说到这里,它看起来像一个模拟侵蚀可能已经被应用到获取输出-你在哪里找到它的?嗨:)谢谢你的帮助。我认为这是对噪波函数的一个修改,以获得脊线。我认为这是脊状分形噪声。但是我找不到我必须对我的噪音做的改变来得到这样的东西。在一个网站上,有人说这只是一个用绝对值函数改变的噪音。但我不知道如何使用绝对值函数来更改噪声输出:我不清楚如何使用ab