【问题标题】:Why doesn't my gradient noise generator work?为什么我的梯度噪声发生器不起作用?
【发布时间】:2020-08-19 05:37:48
【问题描述】:

我尝试制作一个程序,为地形生成生成梯度噪声。它应该打印 40 到 99 之间的数字数组,但它在这部分停止:

    for(int k=16; k>1; k/=2)
        for(int y=Y; y<Y+16; y+=k+1)
            for(int x=X; x<X+16; x+=k+1)
            {
                tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))+min(tab[y][x],tab[y+16][x]);
                tab[y][x+k/2]=rand()%(max(tab[y][x],tab[y][x+16])-min(tab[y][x],tab[y][x+16]))+min(tab[y][x],tab[y][x+16]);
                tab[y+k/2][x+k/2]=rand()%(max(tab[y][x],tab[y+16][x+16])-min(tab[y][x],tab[y+16][x+16]))+min(tab[y][x],tab[y+16][x+16]);
            }

当我删除循环的内容时,它不会停止。它编译得很好但返回 -1 (0xFFFFFFFF)

这是完整的代码:

#include<ctime>
#include<iostream>
using namespace std;
const short int Size=8;
short int tab[Size*16+1][Size*16+1];
void chunk(int X, int Y)
{
    srand(time(NULL));
    for(int k=16; k>1; k/=2)
        for(int y=Y; y<Y+16; y+=k+1)
            for(int x=X; x<X+16; x+=k+1)
            {
                tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))+min(tab[y][x],tab[y+16][x]);
                tab[y][x+k/2]=rand()%(max(tab[y][x],tab[y][x+16])-min(tab[y][x],tab[y][x+16]))+min(tab[y][x],tab[y][x+16]);
                tab[y+k/2][x+k/2]=rand()%(max(tab[y][x],tab[y+16][x+16])-min(tab[y][x],tab[y+16][x+16]))+min(tab[y][x],tab[y+16][x+16]);
            }
}
int main()
{
    srand(time(NULL));
    for(int i=0; i<Size; i+=16)
        for(int j=0; j<Size; j+=16)
            tab[16*i][16*j]=rand()%(100-40)+40;
    for(int x=0; x<Size*16+1; x+=16)
        for(int y=0; y<Size*16+1; y+=16)
            chunk(x,y);

    return 0;
}

编辑: 它没有工作,因为

rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))

数组中的元素可以相等。 我在读取数组时也犯了一些愚蠢的错误,导致超出了它的大小。 现在它运行没有错误,但显示一些低于 40 的数字,这是不应该发生的。 这是修改后的代码:

#include<ctime>
#include<iostream>
using namespace std;
const short int Size=1;
short int tab[Size*16+1][Size*16+1];
void chunk(int X, int Y)
{
    for(int k=16; k>1; k/=2)
        for(int y=Y; y<Y+16; y+=k)
            for(int x=X; x<X+16; x+=k)
            {
                if(Y!=Size*16)
                    if(tab[y][x]==tab[y+k][x])
                        tab[y+k/2][x]=tab[y][x];
                    else
                        tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+k][x])-min(tab[y][x],tab[y+k][x]))+min(tab[y][x],tab[y+k][x]);
                if(X!=Size*16)
                    if(tab[y][x]==tab[y][x+k])
                        tab[y+k/2][x]=tab[y][x];
                    else
                        tab[y][x+k/2]=rand()%(max(tab[y][x],tab[y][x+k])-min(tab[y][x],tab[y][x+k]))+min(tab[y][x],tab[y][x+k]);
                if(X!=Size*16||Y!=Size*16)
                if(tab[y][x]==tab[y+k][x+k])
                    tab[y+k/2][x]=tab[y][x];
                else
                    tab[y+k/2][x+k/2]=rand()%(max(tab[y][x],tab[y+k][x+k])-min(tab[y][x],tab[y+k][x+k]))+min(tab[y][x],tab[y+k][x+k]);
            }
}
int main()
{
    srand(time(NULL));
    for(int i=0; i<=Size*16; i+=16)
        for(int j=0; j<=Size*16; j+=16)
            tab[j][i]=rand()%60+40;
    for(int x=0; x<=Size*16; x+=16)
        for(int y=0; y<=Size*16; y+=16)
            chunk(x,y);

    for(int a=0; a<Size*16; a++){
        for(int b=0; b<Size*16; b++)
        {
            cout<<tab[b][a]<<' ';
            if(tab[b][a]<10)
                cout<<' ';
        }
        cout<<'\n';
    }
    return 0;
}

edit 2:算法将每 16 行和每列的两个选定值之间的伪随机值写入数组。然后它每 16 个单元格跳跃一次,在已经填充的单元格之间放置一个伪随机值,如下所示:

XOOOOOOO+OOOOOOF
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
+OOOOOOO+OOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
FOOOOOOOOOOOOOOF

X - 正在检查的单元格 F - 填充单元格 + - 要填充的单元格 0 - 空单元格 算法用“X”单元格和“F”单元格的值之间的伪随机值填充“+”单元格。当算法跳过所有“F”单元格时,它会再次跳转一半的时间,现有的“+”单元格变为“F”单元格。它一直持续到跳转长度等于 1,这意味着数组已满。

【问题讨论】:

  • 相关问题:srand() — why call it only once?。因为srand 出现在您的函数中,所以当您在循环中调用您的函数时,函数的每次调用可能会生成完全相同的结果,因为它们可能会在time(NULL) 返回的相同时间单位内执行。
  • 您的tab 初始化已损坏。 Size 是 8,但您将循环变量增加 16,因此循环将始终只执行一次,ij 等于 0。我不知道为什么你然后将 ij 乘以 16 来访问表元素,但看起来你忘记了你已经将迭代变量增加了 16。编辑:你可能将除以零从未正确初始化的tab 读取。
  • 感谢您提供重现问题的程序。当我运行您的代码时,我收到错误Program received signal SIGFPE, Arithmetic exception. 这是您的程序“停止”的意思吗?您是否尝试过使用调试器? gdb 显示第 13 行发生的错误:tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))+min(tab[y][x],tab[y+16][x]);
  • 似乎在第 13 行,它正在执行 rand()%(0),这会导致错误。
  • 您能否编辑您的问题,添加一个关于算法应该做什么的简单解释(用英文而不是伪代码)?

标签: c++ noise-generator


【解决方案1】:

看起来你正在炸毁你的阵列。 在某些时候,您调用 chunk 的值为 X,即 Size*16

然后在子例程中,您只有很少的 x(顺便说一句,仅通过大写来区分变量会使代码难以阅读)上升到 X+16,因此只需执行 tab[x, ...] 即可 炸掉你的数组,你就有了 tab[x+16,...]

【讨论】:

    【解决方案2】:

    最大的问题是在索引计算中,导致访问超出数组的范围。

    在下面的 sn-p 中,我将展示算法的可能实现,假设我已经理解了这个问题。

    #include <algorithm>
    #include <array>
    #include <iostream>
    #include <iomanip>
    #include <random>  // <- I won't use srand / rand
    
    /*  Example of fill sequence (in 1D)
                                         start   step
    1---------------1---------------1      0      16
    1-------2-------1-------2-------1      8      16
    1---3---2---3---1---3---2---3---1      4       8
    1-4-3-4-2-4-3-4-1-4-3-4-2-4-3-4-1      2       4
    154535452545354515453545254535451      1       2
    
    1     <-2->    1     Dependencies 
    
    ^     \   /
    2       2 
    v     /   \
    
    1              1
    
    */
    
    template <class Gen>
    int rand_between(int a, int b, Gen& gen)
    {
        if (b < a)
            std::swap(a, b);
        std::uniform_int_distribution dist(a, b);
        return dist(gen);
    }
    
    template <class Gen>
    int rand_between(int a, int b, int c, int d, Gen& gen)
    {
        auto e = std::minmax({a, b, c, d});
        std::uniform_int_distribution dist(e.first, e.second);
        return dist(gen);
    }
    
    int main()
    {
        std::random_device rd;
        std::seed_seq ss{rd(), rd(), rd()};
        std::mt19937 gen{ss};
    
        constexpr size_t first_step{ 16 };
        constexpr size_t repetitions{ 2 };
        constexpr size_t size{ first_step * repetitions + 1 };
    
        std::array<std::array<int, size>, size> m{};
    
        // First fill
        std::uniform_int_distribution dist(40, 99);
        for (size_t i{0}; i < size; i += first_step)
        {
            for (size_t j{0}; j < size; j += first_step)
            {
                m[i][j] = dist(gen);
            }
        }
    
        // Inner filling
        size_t half_step{ first_step / 2 };
        size_t step{ first_step };
        while (half_step > 0)
        {
            for (size_t i{0}; i < size; i += step)
            {
                for (size_t j{half_step}; j < size; j += step)
                {
                    m[i][j] = rand_between(m[i][j - half_step], m[i][j + half_step], gen);
                }
                if (size <= i + half_step)
                    break;
                for (size_t j{0}; j < size; j += step)
                {
                    m[i + half_step][j] = rand_between(m[i][j], m[i + step][j], gen);
                    if (j + step < size)
                    {
                        m[i + half_step][j + half_step] = rand_between(
                            m[i][j], m[i + step][j], m[i][j + step], m[i + step][j + step], gen
                        );
                    }
                }
            }
            step = half_step;
            half_step /= 2;
        }
    
        for (size_t i{0}; i < size; ++i)
        {
            for (size_t j{0}; j < size; ++j)
            {
                std::cout << std::setw(3) << m[i][j];
            }
            std::cout << '\n';
        }
    }
    

    可测试here;

    【讨论】:

      猜你喜欢
      • 2021-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-27
      • 2013-03-29
      • 1970-01-01
      • 2021-09-08
      相关资源
      最近更新 更多