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:
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:
rand()
with c++ RNG, rand() is decades old and de facto obsolete in modern c++, not even mentioningRAND_MAX
is typically very small integer, as small as 32k. \$\endgroup\$normX
andnormY
always 0 when going intoFade()
? You setx0
tonormX
and then later subtractx0
fromnormX
, leaving you with 0. \$\endgroup\$