5
\$\begingroup\$

I am trying to write a perlin noise class with c++ and sfml, but I am experiencing unwanted visual artifacts in the output. In the image, there are obvious lines being drawn between the points of the lattice:

My incorrect perlin noise


The class template representing the noise is a specialization of lattice noise for vectors. The important function, GetValue() expects values between 0.0-1.0, representing the coordinates at which to get the value of the noise, which should also return a value between 0.0-1.0. Calling the function at (0, 0) should return the value at the top left corner. NormX and normY are the distance between lattice points x0-x1 and y0-y1, again in the range 0.0-1.0.

Before calculating the dot product, the distance vector from each corner lattice point is calculated instead of only using the distance from the top left corner. Because the final value at any point may be negative (-1.0 - 1.0), it is mapped to the range 0.0-1.0 by adding 1 and dividing by two before being returned.

template<>
inline float LatticeNoise2D<sf::Vector2f>::GetValue(float u, float v)
{
    float normX = u * resX_;
    int x0 = normX;
    int x1 = x0 + 1;
    normX -= x0;

    float normY = v * resY_;
    int y0 = normY;
    int y1 = y0 + 1;
    normY -= y0;

    float fadeX = Fade(normX);
    float fadeY = Fade(normY);

    sf::Vector2f dist(normX, normY);
    float dot0 = Dot(At(x0, y0), dist);
    dist = sf::Vector2f(1 - normX, normY);
    float dot1 = Dot(At(x1, y0), dist);
    float lerp0 = Lerp(dot0, dot1, fadeX);

    dist = sf::Vector2f(normX, 1 - normY);
    dot0 = Dot(At(x0, y1), dist);
    dist = sf::Vector2f(1 - normX, 1 - normY);
    dot1 = Dot(At(x1, y1), dist);
    float lerp1 = Lerp(dot0, dot1, fadeX);

    float value = Lerp(lerp0, lerp1, fadeY);
    return (value + 1) / 2;
}

The At(x, y) function returns the pre-generated vector on the lattice (a 2d std::vector) at the given index. The dimensions of the lattice in each dimension are resX_ and resY_, respectivley.

template<typename value_type>
inline value_type LatticeNoise2D<value_type>::At(int x, int y)
{
    return lattice_[x % resX_][y % resY_];
}

The vectors at each point on the lattice are generated on the unit circle by randomly choosing an angle in radians (0-2pi) and then calculating the x & Y components given that the length of their hypotenuse is 1.0.

template<>
inline sf::Vector2f LatticeNoise2D<sf::Vector2f>::Random()
{
    float pi = 4 * atan(1);
    float theta = static_cast<float>(rand()) / RAND_MAX * 2 * pi;
    return sf::Vector2f(cos(theta), sin(theta));
}

The Lerp() function performs linear interpolation, and the Dot() function calculates the dot product of two vectors. The Fade(t) function maps a value from 0.0-0.1 to an S Curve to be used in the Lerp function instead of just the linear distance between lattice points.


Why am I getting these lines between the points of the lattice, and how can I fix them? My goal is to make noise like this example:

Ideal perlin noise

\$\endgroup\$
7
  • \$\begingroup\$ Does it improve if you switch from using linear interpolation to using a smoothstep function? \$\endgroup\$ Commented Apr 4, 2017 at 5:15
  • 1
    \$\begingroup\$ I would start by replacing rand() with c++ RNG, rand() is decades old and de facto obsolete in modern c++, not even mentioning RAND_MAX is typically very small integer, as small as 32k. \$\endgroup\$
    – wondra
    Commented Apr 4, 2017 at 6:35
  • \$\begingroup\$ @user1118321 I'm not really just doing linear interpolation, because the value gets passed through the Fade() function before being passed to Lerp(). Fade() smooths it according to the curve 6t^5-15t^4+10t^t, similarly to the curve used by smoothstep (according to Wikipedia) 3t^2-2t^3. Using smoothstep did not significantly change the image. \$\endgroup\$
    – Paraxon
    Commented Apr 4, 2017 at 23:06
  • \$\begingroup\$ OK, I should have read that part a little more closely. I know that I had similar artifacts that went away when I switched from linear to smoothstep, but must be something else this time. \$\endgroup\$ Commented Apr 5, 2017 at 1:17
  • \$\begingroup\$ Aren't normX and normY always 0 when going into Fade()? You set x0 to normX and then later subtract x0 from normX, leaving you with 0. \$\endgroup\$ Commented Apr 5, 2017 at 1:21

1 Answer 1

6
\$\begingroup\$

I don't entirely understand why, but I shouldn't have been doing 1-normX/Y. Instead, I looked at the question posted here and our approaches were similar enough that I could make It work. Changing from 1-x to x-1 seemed to do the trick.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Thank you for coming back and answering your own question. If only 98% of new users did the same. Good luck further in your endeavours. \$\endgroup\$
    – Engineer
    Commented Jun 30, 2017 at 7:06
  • \$\begingroup\$ Thanks! I wanted anyone with a similar problem to reach the answer with less searching than I did. \$\endgroup\$
    – Paraxon
    Commented Aug 23, 2017 at 3:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .