I actually managed to figure out cellular noise


eye kan kode gud
I wanted to see if I could figure out a cellular noise node before reading up on the Worley algorithm (which gives more interesting results, IMHO). Took me a whole freakin' day, but I got there.

The hard part is going to be implementing bump vector generation without absolutely killing render times.




eye kan kode gud
Did some refactoring, and also tried an LCG random-number generator, but it gave artifacty results compared to using the simplex noise for the coordinate distortion routine. A Worley cellular noise node will definitely be faster, but this one works out pretty well visually, especially when using a lot of octaves (which is where using the LCG rng directly tended to fail).

//  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;
            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(),
                                                          Gradient_Flags_t::No_Gradients ).Noise_01() );

The constant I use for scaling down the output was determined by trial-and-error because I don't math well.


eye kan kode gud
Oh hey, regions! Can't believe I forgot to wire up that particular output. I mean, the code was right there.




eye kan kode gud
Final verdict: pretty-looking, but slow and doesn't do anything a fully-featured Worley noise node wouldn't do. It was an interesting experiment, but I'm going to scrap this one and just move on to a good Worley implementation.


F&#559;rum Mole
hey jrandom, don't understand a things but it is always nice to see ppl stretching things to get somewhere :)



eye kan kode gud
There's not a lot of activity in this forum, so I talk a lot and post code in the hopes that it might help out any random newbie node devs who stumble through here.


eye kan kode gud
(My development cycle has slowed down greatly since I installed Skyrim on my XBox. In retrospect, that may have not been the greatest idea ever.)


eye kan kode gud
Nodes are great and highly-intuitive. You have to completely ditch the "layer" mindset, though. :) Instead of layering things on top of each other, you're plugging outputs into inputs. It's wonderfully powerful.


eye kan kode gud
If I can get Worley noise working this weekend, I'll go ahead and post the entire codebase so anyone who's trying to implement procedural texture nodes can take a look. (I won't actually be compiling the final binaries for win/mac as I don't want it to bo an official release until I get a wider variety of texture nodes implemented, so it'll be a source-only sorta deal.)

And to think this all started because I wanted a better Brick node...


eye kan kode gud
As promised, C++11 source code for Simplex and Worley Cellular noise types. The actual noise algorithms are in Noise/ and the nodes themselves are in RainyBrain_Nodes/Textures_3D.

The code could certainly stand for some refactoring and the Worley node doesn't have bump map generation implemented yet, but the basics are all there.

Worley_Example_01.png Worley_Example_02.png


  • Demo Proc 3D Nodes.zip
    103.1 KB · Views: 395
Last edited:


Vacant, pretty vacant
Here you go, Bonds. The standard running bond that LW and others produce is common on modern buildings that use brickwork as a decorative skin over blocks or concrete slab, but anything older than 50 years or so will use one of the alternating bonds as they are structural. I wouldn't fret about all of them, but English, Flemish, and possibly garden wall or American should do 99% of applications.

Oh, and if you haven't seen the DP Renderman brickwork node, have a look at it, it does some interesting things.
Top Bottom