cloudy-raytracer/common/noise/noise.cpp

116 lines
3.1 KiB
C++
Raw Normal View History

2023-01-24 06:26:24 +01:00
#include <cmath>
#include "noise.h"
float Noise::getNoise(Vector3d point) const
{
return getNoise(point.x, point.y, point.z);
}
void Noise::generateNoiseMap(int size)
{
noiseMap.clear();
noiseMap.resize(size * size * size);
}
void Noise::setNoise(int x, int y, int z, float value)
{
long int index = x + y * (long int) size + z * size * (long int) size;
noiseMap[index] = value;
}
float Noise::getNoise(float x, float y, float z) const
{
// Scale to [0, size]
x *= size;
y *= size;
z *= size;
// Get corner points of the cube
2023-01-24 06:26:24 +01:00
int x_min = (int) fitToNoise(floor(x));
int y_min = (int) fitToNoise(floor(y));
int z_min = (int) fitToNoise(floor(z));
int x_max = fitToNoise(x_min + 1);
int y_max = fitToNoise(y_min + 1);
int z_max = fitToNoise(z_min + 1);
// Get the getNoise values at the corner points
float n000 = getCalculatedNoise(x_min, y_min, z_min);
float n001 = getCalculatedNoise(x_min, y_min, z_max);
float n010 = getCalculatedNoise(x_min, y_max, z_min);
float n011 = getCalculatedNoise(x_min, y_max, z_max);
float n100 = getCalculatedNoise(x_max, y_min, z_min);
float n101 = getCalculatedNoise(x_max, y_min, z_max);
float n110 = getCalculatedNoise(x_max, y_max, z_min);
float n111 = getCalculatedNoise(x_max, y_max, z_max);
// Get fractions
float fx = x - floor(x);
float fy = y - floor(y);
float fz = z - floor(z);
// Interpolate
float nx00 = interpolate(n000, n100, fx);
float nx01 = interpolate(n001, n101, fx);
float nx10 = interpolate(n010, n110, fx);
float nx11 = interpolate(n011, n111, fx);
float nxy0 = interpolate(nx00, nx10, fy);
float nxy1 = interpolate(nx01, nx11, fy);
float noise = interpolate(nxy0, nxy1, fz);
return noise;
}
float Noise::getCalculatedNoise(int x, int y, int z) const
{
long int index = x + y * (long int) size + z * size * (long int) size;
float noise = noiseMap[index];
if (invert)
{
noise = 1.0f - noise;
}
return noise;
}
Noise::Noise(int size)
{
this->size = size;
generateNoiseMap(size);
}
2023-01-24 06:26:24 +01:00
/* Function to linearly interpolate between a0 and a1
* Weight w should be in the range [0.0, 1.0]
*/
float Noise::interpolate(float a0, float a1, float w) const
{
/* // You may want clamping by inserting:
* if (0.0 > w) return a0;
* if (1.0 < w) return a1;
*/
return (a1 - a0) * ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) + a0;
return (a1 - a0) * (3.0 - w * 2.0) * w * w + a0;
return (a1 - a0) * w + a0;
/* // Use this cubic interpolation [[Smoothstep]] instead, for a smooth appearance:
* return (a1 - a0) * (3.0 - w * 2.0) * w * w + a0;
*
* // Use [[Smootherstep]] for an even smoother result with a second derivative equal to zero on boundaries:
* return (a1 - a0) * ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) + a0;
*/
}
float Noise::fitToNoise(float point) const
{
float remainingValue = fmod(point, size);
if (remainingValue < 0)
{
remainingValue += size;
}
return remainingValue;
}