Perlin Noise在Y轴上得到错误的值(C ++)

时间:2018-02-17 15:20:47

标签: c++ opengl procedural-generation perlin-noise

问题

我尝试在2D中使用大小为16x16的单个八度音程实现Perlin Noise算法。我将它用作地形的高度图数据,但它似乎只能在一个轴上工作。每当样本点移动到Perlin Noise网格中的新Y部分时,渐变与我期望的非常不同(例如,它经常从0.98翻转到-0.97,这是一个非常突然的变化)。 enter image description here

此图显示z方向上的交错地形(2D Perlin Noise网格中的y轴)

代码

我已经把代码计算在最后使用哪个样本点,因为它很长,我相信它不是问题所在,但实际上我缩小了地形匹配Perlin噪声网格(16x16),然后通过所有点进行采样。

渐变点

因此,在采样点计算出梯度的代码如下:

// Find the gradient at a certain sample point
float PerlinNoise::gradientAt(Vector2 point)
{
    // Decimal part of float
    float relativeX = point.x - (int)point.x;
    float relativeY = point.y - (int)point.y;
    Vector2 relativePoint = Vector2(relativeX, relativeY);

    vector<float> weights(4);

    // Find the weights of the 4 surrounding points
    weights = surroundingWeights(point);


    float fadeX = fadeFunction(relativePoint.x);
    float fadeY = fadeFunction(relativePoint.y);


    float lerpA = MathUtils::lerp(weights[0], weights[1], fadeX);
    float lerpB = MathUtils::lerp(weights[2], weights[3], fadeX);
    float lerpC = MathUtils::lerp(lerpA, lerpB, fadeY);


    return lerpC;
}

点周围重量

我认为问题出在这里,在计算样本点的4个周围点的权重的函数中,但是我似乎无法弄清楚什么是错误的,因为所有的值似乎都是合理的。踩过它时起作用。

// Find the surrounding weight of a point
vector<float> PerlinNoise::surroundingWeights(Vector2 point){

    // Produces correct values
    vector<Vector2> surroundingPoints = surroundingPointsOf(point);

    vector<float> weights;

    for (unsigned i = 0; i < surroundingPoints.size(); ++i) {
        // The corner to the sample point
        Vector2 cornerToPoint = surroundingPoints[i].toVector(point);

        // Getting the seeded vector from the grid
        float x = surroundingPoints[i].x;
        float y = surroundingPoints[i].y;
        Vector2 seededVector = baseGrid[x][y];

        // Dot product between the seededVector and corner to the sample point vector
        float dotProduct = cornerToPoint.dot(seededVector);

        weights.push_back(dotProduct);
    }

    return weights;

}

OpenGL设置和采样点

设置高度图并获取采样点。变量&#39; wrongA&#39;和&#39; wrongA&#39;是渐变翻转和突然变化的一个例子。

void HeightMap :: GenerateRandomTerrain(){

int perlinGridSize = 16;

PerlinNoise perlin_noise = PerlinNoise(perlinGridSize, perlinGridSize);

numVertices = RAW_WIDTH * RAW_HEIGHT;
numIndices = (RAW_WIDTH - 1) * (RAW_HEIGHT - 1) * 6;

vertices = new Vector3[numVertices];
textureCoords = new Vector2[numVertices];
indices = new GLuint[numIndices];

float perlinScale = RAW_HEIGHT/ (float) (perlinGridSize -1);

float height = 50;

float wrongA = perlin_noise.gradientAt(Vector2(0, 68.0f / perlinScale));
float wrongB = perlin_noise.gradientAt(Vector2(0, 69.0f / perlinScale));

for (int x = 0; x < RAW_WIDTH; ++x) {
    for (int z = 0; z < RAW_HEIGHT; ++z) {
        int offset = (x* RAW_WIDTH) + z;

        float xVal = (float)x / perlinScale;
        float yVal = (float)z / perlinScale;

        float noise = perlin_noise.gradientAt(Vector2( xVal , yVal));

        vertices[offset]        = Vector3(x * HEIGHTMAP_X,      noise * height,  z * HEIGHTMAP_Z);
        textureCoords[offset]   = Vector2(x * HEIGHTMAP_TEX_X,  z * HEIGHTMAP_TEX_Z);

    }
}
numIndices = 0;
for (int x = 0; x < RAW_WIDTH - 1; ++x) {
    for (int z = 0; z < RAW_HEIGHT - 1; ++z) {
        int a = (x      * (RAW_WIDTH)) + z;
        int b = ((x + 1)* (RAW_WIDTH)) + z;
        int c = ((x + 1)* (RAW_WIDTH)) + (z + 1);
        int d = (x      * (RAW_WIDTH)) + (z + 1);

        indices[numIndices++] = c;
        indices[numIndices++] = b;
        indices[numIndices++] = a;

        indices[numIndices++] = a;
        indices[numIndices++] = d;
        indices[numIndices++] = c;
    }
}
BufferData();

}

1 个答案:

答案 0 :(得分:2)

原来这个问题是在插值阶段:

 float lerpA = MathUtils::lerp(weights[0], weights[1], fadeX);
 float lerpB = MathUtils::lerp(weights[2], weights[3], fadeX);
 float lerpC = MathUtils::lerp(lerpA, lerpB, fadeY);

我在y轴上的插值是错误的,所以应该是:

lerp(lerpB, lerpA, fadeY)

而不是:

lerp(lerpA, lerpB, fadeY)