2016-05-29 5 views
2

Я пытаюсь реализовать Perlin Noise в C++.Алгоритм Perlin Noise, похоже, не создает градиентный шум

Во-первых, проблема (я думаю) заключается в том, что выход не является тем, что я ожидаю. В настоящее время я просто использовать сгенерированные значения шума Перлина в полутоновых изображениях, и это результаты, которые я получаю: Perlin Noise Algorithm Output

Однако, от моего понимания, это должно выглядеть более вдоль линий: Expected Perlin Noise Output

То есть шум, который я производю в настоящее время, по-видимому, больше связан с «стандартными» нерегулярными шумами.

Это Перлин шум алгоритм я реализовал до сих пор:

float perlinNoise2D(float x, float y) 
{ 
    // Find grid cell coordinates 
    int x0 = (x > 0.0f ? static_cast<int>(x) : (static_cast<int>(x) - 1)); 
    int x1 = x0 + 1; 
    int y0 = (y > 0.0f ? static_cast<int>(y) : (static_cast<int>(y) - 1)); 
    int y1 = y0 + 1; 

    float s = calculateInfluence(x0, y0, x, y); 
    float t = calculateInfluence(x1, y0, x, y); 
    float u = calculateInfluence(x0, y1, x, y); 
    float v = calculateInfluence(x1, y1, x, y); 

    // Local position in the grid cell 
    float localPosX = 3 * ((x - (float)x0) * (x - (float)x0)) - 2 * ((x - (float)x0) * (x - (float)x0) * (x - (float)x0)); 
    float localPosY = 3 * ((y - (float)y0) * (y - (float)y0)) - 2 * ((y - (float)y0) * (y - (float)y0) * (y - (float)y0)); 

    float a = s + localPosX * (t - s); 
    float b = u + localPosX * (v - u); 

    return lerp(a, b, localPosY); 
} 

Функция calculateInfluence имеет работу генерации случайного вектора градиента и вектор расстояния для одного из угловых точек текущей сетки ячейку и возвращать точечный продукт из них. Он реализован в виде:

float calculateInfluence(int xGrid, int yGrid, float x, float y) 
{ 
    // Calculate gradient vector 
    float gradientXComponent = dist(rdEngine); 
    float gradientYComponent = dist(rdEngine); 

    // Normalize gradient vector 
    float magnitude = sqrt(pow(gradientXComponent, 2) + pow(gradientYComponent, 2)); 
    gradientXComponent = gradientXComponent/magnitude; 
    gradientYComponent = gradientYComponent/magnitude; 
    magnitude = sqrt(pow(gradientXComponent, 2) + pow(gradientYComponent, 2)); 

    // Calculate distance vectors 
    float dx = x - (float)xGrid; 
    float dy = y - (float)yGrid; 

    // Compute dot product 
    return (dx * gradientXComponent + dy * gradientYComponent); 
} 

Здесь расстояние представляет собой генератор случайных чисел из C++ 11:

std::mt19937 rdEngine(1); 
std::normal_distribution<float> dist(0.0f, 1.0f); 

И лерп просто реализован как:

float lerp(float v0, float v1, float t) 
{ 
    return (1.0f - t) * v0 + t * v1; 
} 

Для реализации алгоритма я в основном использовал следующие два ресурса:

Perlin Noise FAQ Perlin Noise Pseudo Code

Это трудно для меня, чтобы точно определить, где я, кажется, Мессинг. Может быть, я неправильно генерирую векторы градиента, так как я не совсем уверен, какой тип распределения они должны иметь. Я пробовал с равномерным распределением, однако, похоже, это создавало повторяющиеся шаблоны в текстуре!

Также может быть, что я неправильно усредняю ​​значения влияния. Было немного сложно понять, как это должно быть сделано из статьи часто задаваемых вопросов о шуме Perlin.

Есть ли у кого-нибудь какие-либо намеки относительно того, что может быть неправильным с кодом? :)

ответ

5

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

Для создания нескольких октав шума, использовать что-то похожее на это:

float multiOctavePerlinNoise2D(float x, float y, int octaves) 
{ 
    float v = 0.0f; 
    float scale = 1.0f; 
    float weight = 1.0f; 
    float weightTotal = 0.0f; 
    for(int i = 0; i < octaves; i++) 
    { 
     v += perlinNoise2D(x * scale, y * scale) * weight; 
     weightTotal += weight; 
     // "ever-increasing frequencies and ever-decreasing amplitudes" 
     // (or conversely decreasing freqs and increasing amplitudes) 
     scale *= 0.5f; 
     weight *= 2.0f; 
    } 
    return v/weightTotal; 
} 

Для дополнительной случайности можно использовать по-разному высевает генератор случайных чисел для каждой октавы. Кроме того, веса, заданные каждой октаве, могут варьироваться для регулировки эстетического качества шума. Если весовая переменная не изменяется на каждую итерацию, то приведенный выше пример равен "pink noise" (каждое удвоение частоты несет одинаковый вес).

Кроме того, вам нужно использовать генератор случайных чисел, который каждый раз возвращает одно и то же значение для данной пары xGrid, yGrid.

+0

Aha! Проблема с использованием октав, казалось, была проблемой :) Я получаю гораздо лучшие результаты сейчас! – CodingBeagle

+0

Невероятно, у меня также была эта проблема совсем недавно! – Dave3of5

 Смежные вопросы

  • Нет связанных вопросов^_^