//
// Cellular_Noise.cpp
// RainyBrain_Nodes
//
// Author: Bradley Wilson
// E-Mail: [email protected]
// Public Domain, Zero Restrictions
//
// ============================================================================ Standard Includes
// Standard Includes
// ----------------------------------------------------------------------------
#include <cmath>
// ============================================================================ RainyBrain Includes
// RainyBrain Includes
// ----------------------------------------------------------------------------
#include "../Types/LWTypes.h"
#include "Cellular_Noise.h"
namespace Noise
{
// ======================================================================== Noise Generators
// Noise Generators
// ------------------------------------------------------------------------ Generate (3D)
Cellular_Result Cellular::Generate( const double x,
const double y,
const double z )
{
// Construct points representing the corners of
// a 3x3 integer box region surrounding the incoming
// point.
LWTypes::LWDVector corners[64];
const double x_floor = std::floor(x);
const double y_floor = std::floor(y);
const double z_floor = std::floor(z);
const double x_ceil = std::ceil (x);
const double y_ceil = std::ceil (y);
const double z_ceil = std::ceil (z);
const double x_coords[4] = { x_floor - 1.0, x_floor, x_ceil, x_ceil + 1.0 };
const double y_coords[4] = { y_floor - 1.0, y_floor, y_ceil, y_ceil + 1.0 };
const double z_coords[4] = { z_floor - 1.0, z_floor, z_ceil, z_ceil + 1.0 };
for ( int ix = 0, icorner = 0; ix < 4; ++ix )
for ( int iy = 0; iy < 4; ++iy, icorner += 4 )
{
corners[ icorner ] = LWTypes::LWDVector( x_coords[ix], y_coords[iy], z_coords[0] );
corners[ icorner + 1 ] = LWTypes::LWDVector( x_coords[ix], y_coords[iy], z_coords[1] );
corners[ icorner + 2 ] = LWTypes::LWDVector( x_coords[ix], y_coords[iy], z_coords[2] );
corners[ icorner + 3 ] = LWTypes::LWDVector( x_coords[ix], y_coords[iy], z_coords[3] );
}
// Create set of distorted corner points deviating at
// most 0.5 units from the original coordinate.
LWTypes::LWDVector distorted_corners[64];
auto Distort_Point = [&](LWTypes::LWDVector point) -> LWTypes::LWDVector
{
const Noise::Simplex_Result simplex_noise( Noise::Simplex::Generate( point.X(), point.Y(), point.Z() ) );
return LWTypes::LWDVector ( point.X() + simplex_noise.Noise_dX * 0.25,
point.Y() + simplex_noise.Noise_dY * 0.25,
point.Z() + simplex_noise.Noise_dZ * 0.25 );
};
for ( unsigned i = 0; i < 64; ++i )
distorted_corners[i] = Distort_Point( corners[i] );
// Find distorted corner closest to incoming point
const LWTypes::LWDVector xyz_prime( x, y, z );
unsigned closest_corner_index = 0;
double closest_distance_squared = Math::Distance_Squared( xyz_prime, distorted_corners[0] );
for ( unsigned current_corner_index = 1;
current_corner_index < 64;
++current_corner_index)
{
const double distorted_distance_squared = Math::Distance_Squared( xyz_prime, distorted_corners[current_corner_index] );
if ( distorted_distance_squared < closest_distance_squared )
{
closest_corner_index = current_corner_index;
closest_distance_squared = distorted_distance_squared;
}
}
// Return distance scaled to [-1, 1] and region
const double downsample ( 0.625 );
const LWTypes::LWDVector closest_corner ( distorted_corners[closest_corner_index] );
return Cellular_Result( (closest_distance_squared * downsample * 2.0) - 1.0,
Noise::Simplex::Generate( closest_corner.X(),
closest_corner.Y(),
closest_corner.Z(),
Gradient_Flags_t::No_Gradients ).Noise_01() );
}
}