3

I'm trying to implement fBm onto a sphere for a planet. To create my sphere, I convert it to such from a cube. Unfortunately, the fBm that gets generated appears as mirrored patches. In addition, it only does it on 2 faces (wrapping the values for the other faces). This leads to a similarly stretched look when rendered as a sphere

The noise function is the improved noise as described by Ken Perlin, I adapted this for HLSL:

  float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }

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

  float grad(int hash, float x, float y, float z) {
  int h = hash & 15;                      // CONVERT LO 4 BITS OF HASH CODE
  float u = h<8 ? x : y,                 // INTO 12 GRADIENT DIRECTIONS.
         v = h<4 ? y : h==12||h==14 ? x : z;
  return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
  } 
  int p[512] = { 151,...180 }; //0-255 twice

  float noise(float x, float y, float z) {


  int X = (int)floor(x) & 255;                  // FIND UNIT CUBE THAT
  int Y = (int)floor(y) & 255;                  // CONTAINS POINT.
  int Z = (int)floor(z) & 255;
  x -= floor(x);                                // FIND RELATIVE X,Y,Z
  y -= floor(y);                                // OF POINT IN CUBE.
  z -= floor(z);
  float u = fade(x),                                // COMPUTE FADE CURVES
         v = fade(y),                                // FOR EACH OF X,Y,Z.
         w = fade(z);
  int A = p[X  ]+Y, AA = p[A]+Z, AB = p[A+1]+Z,      // HASH COORDINATES OF
      B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z;      // THE 8 CUBE CORNERS,

  return lerp(w, lerp(v, lerp(u, grad(p[AA  ], x  , y  , z   ),  // AND ADD
                                 grad(p[BA  ], x-1, y  , z   )), // BLENDED
                         lerp(u, grad(p[AB  ], x  , y-1, z   ),  // RESULTS
                                 grad(p[BB  ], x-1, y-1, z   ))),// FROM  8
                 lerp(v, lerp(u, grad(p[AA+1], x  , y  , z-1 ),  // CORNERS
                                 grad(p[BA+1], x-1, y  , z-1 )), // OF CUBE
                         lerp(u, grad(p[AB+1], x  , y-1, z-1 ),
                                 grad(p[BB+1], x-1, y-1, z-1 ))));
  }

This implementation has worked as expected in a previous project, however for this project it appears to instead create a smoothed out grid when I use the vertex position as the input. It's a unit cube, so the values aren't integers but I can't figure out why it's not creating the typical Perlin noise texture.

Any help would be greatly appreciated, I'll provide more information if it's needed.

Skully
  • 31
  • 1

2 Answers2

0

The array of ints p can't be accessed by the function so I'm assuming the values in it are undefined. A quick fix is to make the array static, but this is really slow. So now I need to pass in the array. But I'm having trouble with that.

Skully
  • 31
  • 1
0

I use the noise function below in a Dx11 planet rendering project. I've included an fBm function too. I found it (written in GLSL) on the WebGL shader programming website ShaderToy.

It was written by the godlike inigo quilez, who authored the site.

Give it a try, I hope it's of some help. All credit should go to inigo quilez for his work. Porting it to HLSL is trivial. I've only tested in in shader model 5, but I'm sure it'll work under 4 at least.

// hash based 3d value noise
// function taken from https://www.shadertoy.com/view/XslGRr
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

// ported from GLSL to HLSL

cbuffer cbNoiseParameters
{
    float _rOctaves;
    float _rLacunarity;
    float _rFrequency;
    float _rAmplitude;
    float _rGain;
    float _rOffset;
};

float hash( float n )
{
    return frac(sin(n)*43758.5453);
}

float noise( float3 x )
{
    // The noise function returns a value in the range -1.0f -> 1.0f

    float3 p = floor(x);
    float3 f = frac(x);

    f       = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0 + 113.0*p.z;

    return lerp(lerp(lerp( hash(n+0.0), hash(n+1.0),f.x),
                   lerp( hash(n+57.0), hash(n+58.0),f.x),f.y),
               lerp(lerp( hash(n+113.0), hash(n+114.0),f.x),
                   lerp( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}

float fBm( float3 vPt )
{
    float octaves       = _rOctaves;    
    float lacunarity    = _rLacunarity;
    float frequency     = _rFrequency;
    float amplitude     = _rAmplitude;  
    float gain          = _rGain;
    float offset        = _rOffset;
    float value         = 0.f;

    for( int i = 0; i < octaves; ++ i )
    {
        value += noise( vPt * frequency ) * amplitude;

        amplitude *= gain;
        frequency *= lacunarity;
    }

    return value;
}
fishfood
  • 4,092
  • 4
  • 28
  • 35