Трехмерный симплексный шум: внезапное изменение высоты

У меня проблема с генерацией трехмерного шума.

Я написал фреймворк, который использует DirectX11 для рендеринга всего.

Я создаю геосферу и изменяю значения высоты с помощью функции 3D Simplex Noise.

Проблема в том, что когда я вижу результат, я вижу резкие изменения высоты, которые совсем не похожи на шум ...

введите описание изображения здесь

(прямоугольник в центре рисунка)

Я изменил Persistence на 0.1, поэтому здесь легко увидеть ошибку ...

введите описание изображения здесь

Я не могу понять, в чем проблема с резким изменением высоты. Это же ошибка?

Я рассчитываю высоту по следующей формуле ...

for( int i = 0; i < sphere.Vertices.size(); ++i )
{
    // seperate out our positions
    float x = sphere.Vertices[ i ].Position.x;
    float y = sphere.Vertices[ i ].Position.y;
    float z = sphere.Vertices[ i ].Position.z;

    // get our noise value ( -1 to 1 )
    float ix = noise.octavenoise3D( 10, 0.1, 0.5, x, y, z, perm, &grad3[0][0] );

    // pack our coordinates into a vector
    XMVECTOR curPos = { x, y, z };

    // get the normalized vector of our position
    XMVECTOR normPos = XMVector3Normalize( curPos );

    // seperate our normalzed x y and z 
     float normX = XMVectorGetX( normPos );
     float normY = XMVectorGetY( normPos );
     float normZ = XMVectorGetZ( normPos );

    // figure out the height of this specific vertice, maxHeight = sphereRadius / 3.0f;
    float height = ix * maxHeight;
    float change = height + sphereRadius;

    // calculate the offset x y and z by the noise
    float changeX = change * normX;
    float changeY = change * normY;
    float changeZ = change * normZ;

    // save our new x y and z
    vertices[ i ].Pos.x = x + changeX;
    vertices[ i ].Pos.y = y + changeY;
    vertices[ i ].Pos.z = z + changeZ;

    // calculate color based on noise value 
    float colorChange = ( 0.5f * ix );
    float color = 0.5f + colorChange;

    // save color value in r g b
    vertices[ i ].Color.x = color;
    vertices[ i ].Color.y = color;
    vertices[ i ].Color.z = color;
}   

Кроме того, изменение базовых координат функции не избавляет от этого странного вывода. (для тех, кто думает, что начало с 0,0,0 как-то испортило)

Реализация шума

float Noise :: octavenoise3D (октавы const float, постоянство const float, масштаб const float, const float x, const float y, const float z, int * perm, int * grad3)

float total = 0;
float frequency = scale;
float amplitude = 1;
float maxAmplitude = 0;
for( int i = 0; i < octaves; i++ ) 
{
    total = total + rawnoise3D( x * frequency, y * frequency, z * frequency, perm, grad3 ) * amplitude;

    frequency = frequency * 2;
    maxAmplitude = maxAmplitude + amplitude;
    amplitude = amplitude * persistence;
}
return total / maxAmplitude;

float Noise :: rawnoise3D (const float x, const float y, const float z, int * perm, int * grad3)

float n0, n1, n2, n3;

float F3 = 1.0 / 3.0;
float s = ( x + y + z ) * F3;
int i = fastfloor( x + s );
int j = fastfloor( y + s );
int k = fastfloor( z + s );

float G3 = 1.0 / 6.0;
float t = ( i + j + k ) * G3;
float X0 = i - t;
float Y0 = j - t;
float Z0 = k - t;
float x0 = x - X0;
float y0 = y - Y0;
float z0 = z - Z0;

int i1, j1, k1;
int i2, j2, k2;

if( x0 >= y0 )
{
    if( y0 >= z0 )
    {
        i1 = 0;
        j1 = 0;
        k1 = 1;
        i2 = 1;
        j2 = 1;
        k2 = 0;
    }
    else if( x0 >= z0 )
    {
        i1 = 1;
        j1 = 0;
        k1 = 0;
        i2 = 1;
        j2 = 0;
        k2 = 1;
    }
    else
    {
        i1 = 0;
        j1 = 0;
        k1 = 1;
        i2 = 1;
        j2 = 0;
        k2 = 1;
    }
}
else
{
    if( y0 < z0 )
    {
        i1 = 0;
        j1 = 0;
        k1 = 1;
        i2 = 0;
        j2 = 1;
        k2 = 0;
    }
    else if( x0 < z0 )
    {
        i1 = 0;
        j1 = 1;
        k1 = 0;
        i2 = 0;
        j2 = 1;
        k2 = 1;
    }
    else
    {
        i1 = 0;
        j1 = 1;
        k1 = 0;
        i2 = 1;
        j2 = 1;
        k2 = 0;
    }
}

float x1 = x0 - i1 + G3; 
float y1 = y0 - j1 + G3;
float z1 = z0 - k1 + G3;
float x2 = x0 - i2 + 2.0 * G3; 
float y2 = y0 - j2 + 2.0  *G3;
float z2 = z0 - k2 + 2.0  *G3;
float x3 = x0 - 1.0 + 3.0 * G3; 
float y3 = y0 - 1.0 + 3.0 * G3;
float z3 = z0 - 1.0 + 3.0 * G3;

int ii = i & 255;
int jj = j & 255;
int kk = k & 255;
int gi0 = perm[ ii + perm[ jj + perm[ kk ] ] ] % 12;
int gi1 = perm[ ii+ i1 + perm[ jj + j1 + perm[ kk + k1 ] ] ] % 12;
int gi2 = perm[ ii + i2 + perm[ jj + j2 + perm[ kk + k2 ] ] ] % 12;
int gi3 = perm[ ii + 1 + perm[ jj + 1 + perm[ kk + 1 ] ] ] % 12;

float t0 = 0.6 - ( x0 * x0 ) - ( y0 * y0 ) - ( z0 * z0 );
if( t0 < 0 ) 
{
    n0 = 0.0;
}
else 
{
    t0 = t0 * t0;
    n0 = ( t0 * t0 ) * dot( &grad3[ gi0 ], x0, y0, z0);
}

float t1 = 0.6 - ( x1 * x1 ) - ( y1 * y1 ) - ( z1 * z1  );
if( t1 < 0 )
{
    n1 = 0.0;
}
else 
{
    t1 *= t1;
    n1 = ( t1 * t1 ) * dot( &grad3[ gi1 ], x1, y1, z1);
}

float t2 = 0.6 - ( x2 * x2 ) - ( y2 * y2 ) - ( z2 * z2 );

if( t2 < 0 ) 
{
    n2 = 0.0;
}
else 
{
    t2 *= t2;
    n2 = ( t2 * t2 ) * dot( &grad3[ gi2 ], x2, y2, z2);
}

float t3 = 0.6 - ( x3 * x3 ) - ( y3 * y3 ) - ( z3 * z3 );
if( t3 < 0 ) 
{
    n3 = 0.0;
}
else 
{
    t3 = t3 * t3;
    n3 = t3 * t3 * dot( &grad3[ gi3 ], x3, y3, z3);
}

float final = 32.0 * ( n0 + n1 + n2 + n3 );
return final;

int Noise :: fastfloor (константа с плавающей запятой x)

return x > 0 ? (int)x : (int)x - 1;

float Noise :: dot (const int * g, const float x, const float y, const float z)

return g[0]*x + g[1]*y + g[2]*z; 

person phatgreen    schedule 12.12.2015    source источник
comment
Сфера центрирована в начале оси? В противном случае, когда вы обновляете координаты, вы должны добавить центральную позицию.   -  person Bob__    schedule 12.12.2015
comment
сфера сосредоточена в мире   -  person phatgreen    schedule 12.12.2015
comment
Как noise.octavenoise3D реализовано? Похоже, капля идет вокруг главных плоскостей. Я подозреваю, что это ошибка знака. Вы использовали fmod(a,1.0f) вместо a-floor(a)?   -  person Tamas Hegedus    schedule 12.12.2015
comment
Я добавил к вопросу шумовые функции   -  person phatgreen    schedule 12.12.2015


Ответы (1)


Я нашел решение ...

Решение: я был глуп. У меня была тупая ошибка в моей функции сырого шума, но я исправил ее сейчас

Это фиксированная часть кода

if( x0 >= y0 )
{
    if( y0 >= z0 )
    {
        i1 = 1;
        j1 = 0;
        k1 = 0;
        i2 = 1;
        j2 = 1;
        k2 = 0;
    }
    else if( x0 >= z0 )
    {
        i1 = 1;
        j1 = 0;
        k1 = 0;
        i2 = 1;
        j2 = 0;
        k2 = 1;
    }
    else
    {
        i1 = 0;
        j1 = 0;
        k1 = 1;
        i2 = 1;
        j2 = 0;
        k2 = 1;
    }
}
else
{
    if( y0 < z0 )
    {
        i1 = 0;
        j1 = 0;
        k1 = 1;
        i2 = 0;
        j2 = 1;
        k2 = 1;
    }
    else if( x0 < z0 )
    {
        i1 = 0;
        j1 = 1;
        k1 = 0;
        i2 = 0;
        j2 = 1;
        k2 = 1;
    }
    else
    {
        i1 = 0;
        j1 = 1;
        k1 = 0;
        i2 = 1;
        j2 = 1;
        k2 = 0;
    }
}

Оказалось, у меня в старом было несколько неверных значений.

person phatgreen    schedule 12.12.2015
comment
Старый вариант не был явно неправильным, а этот - не совсем правильным. Можно ли упростить это еще больше, чтобы было удобнее читать? - person dascandy; 12.12.2015
comment
Я не уверен. Этот код может быть трудно читать, но он довольно нишевый, так что теперь, когда он готов, все готово. - person phatgreen; 13.12.2015