Meteorit generator with simplex noise

1.4k views Asked by At

I try to make a meteor like this video, but I can only get like this:

http://johannes.gotlen.se/blog/wp-content/uploads/2011/07/MarchingTetrahedonsSimplexNoise.png

This is my simplex noise:

public class PerlinNoise{
int B = 256;
int[] m_perm = new int[B+B];
Texture2D m_permTex;
public int octava;
public float frequencia, amplitud;

public PerlinNoise(int seed, float frec, float amp, int oct)
{
    octava = oct;
    amplitud = amp;
    frequencia = frec;
    UnityEngine.Random.seed = seed;

     int i, j, k;
    for (i = 0 ; i < B ; i++) 
     {
        m_perm[i] = i;
    }

     while (--i != 0) 
    {
        k = m_perm[i];
        j = UnityEngine.Random.Range(0, B);
        m_perm[i] = m_perm[j];
        m_perm[j] = k;
     }

    for (i = 0 ; i < B; i++) 
    {
        m_perm[B + i] = m_perm[i];
    }

 }

float FADE(float t) { return t * t * t * ( t * ( t * 6.0f - 15.0f ) + 10.0f ); }

float LERP(float t, float a, float b) { return (a) + (t)*((b)-(a)); }

float GRAD1(int hash, float x ) 
{
    int h = hash & 15;
    float grad = 1.0f + (h & 7);
    if ((h&8) != 0) grad = -grad;
    return ( grad * x );
}

float GRAD2(int hash, float x, float y)
{       
    int h = hash & 7;
    float u = h<4 ? x : y;
    float v = h<4 ? y : x;
    return (((h&1) != 0)? -u : u) + (((h&2) != 0) ? -2.0f*v : 2.0f*v);
}


float GRAD3(int hash, float x, float y , float z)
{


    int h = hash & 15;
    float u = h<8 ? x : y;
    float v = (h<4) ? y : (h==12 || h==14) ? x : z;
    return (((h&1) != 0)? -u : u) + (((h&2) != 0)? -v : v);
}

float Noise1D( float x )
{
    //returns a noise value between -0.5 and 0.5
    int ix0, ix1;
    float fx0, fx1;
    float s, n0, n1;

    ix0 = (int)Mathf.Floor(x);  // Integer part of x
    fx0 = x - ix0;          // Fractional part of x
    fx1 = fx0 - 1.0f;
    ix1 = ( ix0+1 ) & 0xff;
    ix0 = ix0 & 0xff;       // Wrap to 0..255

    s = FADE(fx0);

    n0 = GRAD1(m_perm[ix0], fx0);
    n1 = GRAD1(m_perm[ix1], fx1);
    return 0.188f * LERP( s, n0, n1);
}

public float Noise2D( float x, float y )
{

    int ix0, iy0, ix1, iy1;
    float fx0, fy0, fx1, fy1, s, t, nx0, nx1, n0, n1;

    ix0 = (int)Mathf.Floor(x); 
    iy0 = (int)Mathf.Floor(y);  
    fx0 = x - ix0;        
    fy0 = y - iy0;      
    fx1 = fx0 - 1.0f;
    fy1 = fy0 - 1.0f;
    ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255
    iy1 = (iy0 + 1) & 0xff;
    ix0 = ix0 & 0xff;
     iy0 = iy0 & 0xff;

    t = FADE( fy0 );
    s = FADE( fx0 );

    nx0 = GRAD2(m_perm[ix0 + m_perm[iy0]], fx0, fy0);
    nx1 = GRAD2(m_perm[ix0 + m_perm[iy1]], fx0, fy1);

    n0 = LERP( t, nx0, nx1 );

    nx0 = GRAD2(m_perm[ix1 + m_perm[iy0]], fx1, fy0);
    nx1 = GRAD2(m_perm[ix1 + m_perm[iy1]], fx1, fy1);

    n1 = LERP(t, nx0, nx1);

    return 0.507f * LERP( s, n0, n1 );
 }

float Noise3D( float x, float y, float z )
{
    //returns a noise value between -1.5 and 1.5
    int ix0, iy0, ix1, iy1, iz0, iz1;
    float fx0, fy0, fz0, fx1, fy1, fz1;
    float s, t, r;
    float nxy0, nxy1, nx0, nx1, n0, n1;

    ix0 = (int)Mathf.Floor( x ); // Integer part of x
    iy0 = (int)Mathf.Floor( y ); // Integer part of y
    iz0 = (int)Mathf.Floor( z ); // Integer part of z
    fx0 = x - ix0;        // Fractional part of x
    fy0 = y - iy0;        // Fractional part of y
    fz0 = z - iz0;        // Fractional part of z
    fx1 = fx0 - 1.0f;
    fy1 = fy0 - 1.0f;
    fz1 = fz0 - 1.0f;
    ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255
    iy1 = ( iy0 + 1 ) & 0xff;
    iz1 = ( iz0 + 1 ) & 0xff;
    ix0 = ix0 & 0xff;
    iy0 = iy0 & 0xff;
     iz0 = iz0 & 0xff;

     r = FADE( fz0 );
     t = FADE( fy0 );
    s = FADE( fx0 );

    nxy0 = GRAD3(m_perm[ix0 + m_perm[iy0 + m_perm[iz0]]], fx0, fy0, fz0);
     nxy1 = GRAD3(m_perm[ix0 + m_perm[iy0 + m_perm[iz1]]], fx0, fy0, fz1);
    nx0 = LERP( r, nxy0, nxy1 );

    nxy0 = GRAD3(m_perm[ix0 + m_perm[iy1 + m_perm[iz0]]], fx0, fy1, fz0);
     nxy1 = GRAD3(m_perm[ix0 + m_perm[iy1 + m_perm[iz1]]], fx0, fy1, fz1);
    nx1 = LERP( r, nxy0, nxy1 );

    n0 = LERP( t, nx0, nx1 );

     nxy0 = GRAD3(m_perm[ix1 + m_perm[iy0 + m_perm[iz0]]], fx1, fy0, fz0);
    nxy1 = GRAD3(m_perm[ix1 + m_perm[iy0 + m_perm[iz1]]], fx1, fy0, fz1);
     nx0 = LERP( r, nxy0, nxy1 );

    nxy0 = GRAD3(m_perm[ix1 + m_perm[iy1 + m_perm[iz0]]], fx1, fy1, fz0);
        nxy1 = GRAD3(m_perm[ix1 + m_perm[iy1 + m_perm[iz1]]], fx1, fy1, fz1);
    nx1 = LERP( r, nxy0, nxy1 );

    n1 = LERP( t, nx0, nx1 );

    return 0.936f * LERP( s, n0, n1 );
}

public float FractalNoise1D(float x, int octNum, float frq, float amp)
{
    float gain = 1.0f;
    float sum = 0.0f;

    for(int i = 0; i < octNum; i++)
    {
        sum +=  Noise1D(x*gain/frq) * amp/gain;
        gain *= 2.0f;
    }
    return sum;
}

public float FractalNoise2D(float x, float y, int octNum, float frq, float amp)
{
    float gain = 1.0f;
    float sum = 0.0f;

    for(int i = 0; i < octNum; i++)
    {
        sum += Noise2D(x*gain/frq, y*gain/frq) * amp/gain;
        gain *= 2.0f;
    }
     return sum;
}
public int Noise2D(Vector3Int v3) {
    return Mathf.RoundToInt(FractalNoise2D(v3.x,v3.z,octava,frequencia,amplitud));
}
public int Noise2D(int x, int z)
{
    return Mathf.RoundToInt(FractalNoise2D(x, z, octava, frequencia, amplitud));
}
public float FractalNoise3D(float x, float y, float z, int octNum, float frq, float amp)
{
    float gain = 1.0f;
    float sum = 0.0f;

    for(int i = 0; i < octNum; i++)
    {
        sum +=  Noise3D(x*gain/frq, y*gain/frq, z*gain/frq) * amp/gain;
        gain *= 2.0f;
    }
    return sum;
}

public void LoadPermTableIntoTexture()
{
    m_permTex = new Texture2D(256, 1, TextureFormat.Alpha8, false);
    m_permTex.filterMode = FilterMode.Point;
    m_permTex.wrapMode = TextureWrapMode.Clamp;

    for(int i = 0; i < 256; i++)
    {
        float v = (float)m_perm[i] / 255.0f;

        m_permTex.SetPixel(i, 0, new Color(0,0,0,v));
    }

    m_permTex.Apply();
}
}

This is my implementation:

public void Resimulate() {
  PerlinNoise per = new PerlinNoise(seed, frec, amp, octa);

    for (int x = 0; x < TamX; x++)
    {
        for (int y = 0; y < TamY; y++)
        {
            for (int z = 0; z < TamZ; z++)
            {
                if (per.FractalNoise3D(x, y, z, octa, frec, amp)>0)
                {
                 lista.Add(new Bloque(new Vector3Int(x, y, z)));
                }

            }
        }
     }     
 }

I found information on various pages, blogs and here but found nothing that worked for me. If anyone has information I would greatly appreciate your help.

Thank you for helping me.

1

There are 1 answers

2
KdotJPG On BEST ANSWER

First, it's important to note that the code you have is not Simplex noise! It's the older "Perlin noise" algorithm that tends to exhibit visually significant directional artifacts.

I would suggest avoiding both Perlin noise and Simplex noise altogether. Perlin because of the directional artifacts, and Simplex because you run into patent issues with the 3D implementation.

There's an algorithm I've designed recently to get around both of those issues, that's starting to be adopted by a fair number of game developers, called OpenSimplex noise. Code: https://gist.github.com/KdotJPG/b1270127455a94ac5d19

(EDIT: Here's a C# port: https://gist.github.com/omgwtfgames/601497972e4e30fd9c5f)

Do something like this:

const double S = 24; //Sparsity of noise features
public void Resimulate() {
    //To get fractal noise, ideally you want multiple instances of noise so you don't get odd behavior near (0,0,0)
    OpenSimplexNoise n1 = new OpenSimplexNoise(seed);
    OpenSimplexNoise n2 = new OpenSimplexNoise(seed+1);
    OpenSimplexNoise n3 = new OpenSimplexNoise(seed+2);

    for (int x = 0; x < TamX; x++) {
        for (int y = 0; y < Tamy; z++) {
            for (int z = 0; z < TamZ; z++) {
                double n = (n1.eval(x / S, y / S, z / S)
                    + n2.eval(x / S / 2, y / S / 2, z / S / 2) * .5
                    + n3.eval(x / S / 4, y / S / 4, z / S / 4) * .25)
                    / (1 + .5 + .25);
                double dx = (TamX / 2.0 - x);
                double dy = (TamY / 2.0 - y);
                double dz = (TamZ / 2.0 - z);
                double d = dx*dx + dy*dy + dz*dz;

                //d is now your squared distance from the center.
                //n is your fractal noise value
                //you want to combine d and n to form some threshold that
                //determines whether or not there is a block.
                //threshold = d / C1 + n + C2 > 0 where C1 and C2 are constants you choose
            }
        }
    }
}

EDIT: Here's a visual difference between Perlin and OpenSimplex:

enter image description here

  • Left is noise(x, y, 0) grayscale
  • Next is noise(x, y, 0) > 0 ? white : black
  • Next is |noise(x, y, 0)| > 0.1 ? white : black
  • Next is noise(x, y, 0.5) grayscale