Perlin Noise

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Usage)
(Usage)
Line 4: Line 4:
  
 
== Usage ==
 
== Usage ==
 +
Download the package. Open Unity with your own project folder. Double click on the unityPackage in the finder.
 +
[[Media:Noise_174.unitypackage.zip|Noise.unitypackage]]
  
Add this script anywhere in your project folder.
+
This installs the perlin noise class and 3 scripts implementing:
Attach the javascript to any transform to make that transform smoothly and randomly move around.
+
# Animated light intensity noise
 +
# Animated noise position
 +
# Animated noise rotation
  
[[Media:Noise_174.unitypackage.zip|Noise_174.unitypackage.zip]]
+
To use one of the scripts, just drag them on a game object, to make them move, rotate, animate light based on noise.
 
+
<javascript>
+
// Moves the object along as far as range units randomly but in a smooth way.
+
// This script requires the Noise.cs script.
+
var speed = 1.0;
+
var range = Vector3 (1.0, 1.0, 1.0);
+
 
+
private var noise = new Noise();
+
private var position : Vector3;
+
 
+
function Start()
+
{
+
position = transform.position;
+
}
+
 
+
function Update () {
+
transform.position = position + Vector3.Scale(SmoothRandom.GetVector3(speed), range);
+
}
+
</javascript>
+
 
+
 
+
Place this script in a folder called Plugins as a sub folder of the Assets folder. This will allow you to access the PerlinNoise class which is written in C# from Javascript.
+
 
+
<csharp>
+
using System.Collections;
+
using System;
+
using UnityEngine;
+
 
+
public class Perlin
+
{
+
const int B = 0x100;
+
const int BM = 0xff;
+
const int N = 0x1000;
+
 
+
int[] p = new int[B + B + 2];
+
float[,] g3 = new float [B + B + 2 , 3];
+
float[,] g2 = new float[B + B + 2,2];
+
float[] g1 = new float[B + B + 2];
+
 
+
float s_curve(float t)
+
{
+
return t * t * (3.0F - 2.0F * t);
+
}
+
+
float lerp (float t, float a, float b)
+
{
+
return a + t * (b - a);
+
}
+
 
+
void setup (float value, out int b0, out int b1, out float r0, out float r1)
+
{
+
        float t = value + N;
+
        b0 = ((int)t) & BM;
+
        b1 = (b0+1) & BM;
+
        r0 = t - (int)t;
+
        r1 = r0 - 1.0F;
+
}
+
+
float at2(float rx, float ry, float x, float y) { return rx * x + ry * y; }
+
 
+
public float Noise1D(float arg)
+
{
+
int bx0, bx1;
+
float rx0, rx1, sx, u, v;
+
setup(arg, out bx0, out bx1, out rx0, out rx1);
+
+
sx = s_curve(rx0);
+
u = rx0 * g1[ p[ bx0 ] ];
+
v = rx1 * g1[ p[ bx1 ] ];
+
+
return(lerp(sx, u, v));
+
}
+
 
+
public float Noise2D(float x, float y)
+
{
+
int bx0, bx1, by0, by1, b00, b10, b01, b11;
+
float rx0, rx1, ry0, ry1, sx, sy, a, b, u, v;
+
int i, j;
+
+
setup(x, out bx0, out bx1, out rx0, out rx1);
+
setup(y, out by0, out by1, out ry0, out ry1);
+
+
i = p[ bx0 ];
+
j = p[ bx1 ];
+
+
b00 = p[ i + by0 ];
+
b10 = p[ j + by0 ];
+
b01 = p[ i + by1 ];
+
b11 = p[ j + by1 ];
+
+
sx = s_curve(rx0);
+
sy = s_curve(ry0);
+
+
u = at2(rx0,ry0, g2[ b00, 0 ], g2[ b00, 1 ]);
+
v = at2(rx1,ry0, g2[ b10, 0 ], g2[ b10, 1 ]);
+
a = lerp(sx, u, v);
+
+
u = at2(rx0,ry1, g2[ b01, 0 ], g2[ b01, 1 ]);
+
v = at2(rx1,ry1, g2[ b11, 0 ], g2[ b11, 1 ]);
+
b = lerp(sx, u, v);
+
+
return lerp(sy, a, b);
+
}
+
/*
+
double noise3(double vec[3])
+
{
+
  int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+
  double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
+
  int i, j;
+
+
  if (start) {
+
  start = 0;
+
  init();
+
  }
+
+
  setup(0, bx0,bx1, rx0,rx1);
+
  setup(1, by0,by1, ry0,ry1);
+
  setup(2, bz0,bz1, rz0,rz1);
+
+
  i = p[ bx0 ];
+
  j = p[ bx1 ];
+
+
  b00 = p[ i + by0 ];
+
  b10 = p[ j + by0 ];
+
  b01 = p[ i + by1 ];
+
  b11 = p[ j + by1 ];
+
+
  t  = s_curve(rx0);
+
  sy = s_curve(ry0);
+
  sz = s_curve(rz0);
+
+
  q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0);
+
  q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0);
+
  a = lerp(t, u, v);
+
+
  q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0);
+
  q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0);
+
  b = lerp(t, u, v);
+
+
  c = lerp(sy, a, b);
+
+
  q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1);
+
  q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1);
+
  a = lerp(t, u, v);
+
+
  q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1);
+
  q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1);
+
  b = lerp(t, u, v);
+
+
  d = lerp(sy, a, b);
+
+
  return lerp(sz, c, d);
+
}
+
*/
+
void normalize2(ref float x, ref float y)
+
{
+
  float s;
+
+
s = (float)Math.Sqrt(x * x + y * y);
+
x = y / s;
+
y = y / s;
+
}
+
+
void normalize3(ref float x, ref float y, ref float z)
+
{
+
float s;
+
s = (float)Math.Sqrt(x * x + y * y + z * z);
+
x = y / s;
+
y = y / s;
+
z = z / s;
+
}
+
+
public Perlin()
+
{
+
int i, j, k;
+
System.Random rnd = new System.Random();
+
+
  for (i = 0 ; i < B ; i++) {
+
  p[i] = i;
+
  g1[i] = (float)(rnd.Next(B + B) - B) / B;
+
+
  for (j = 0 ; j < 2 ; j++)
+
g2[i,j] = (float)(rnd.Next(B + B) - B) / B;
+
  normalize2(ref g2[i, 0], ref g2[i, 1]);
+
+
  for (j = 0 ; j < 3 ; j++)
+
g3[i,j] = (float)(rnd.Next(B + B) - B) / B;
+
+
+
  normalize3(ref g3[i, 0], ref g3[i, 1], ref g3[i, 2]);
+
  }
+
+
  while (--i != 0) {
+
  k = p[i];
+
  p[i] = p[j = rnd.Next(B)];
+
  p[j] = k;
+
  }
+
+
  for (i = 0 ; i < B + 2 ; i++) {
+
  p[B + i] = p[i];
+
  g1[B + i] = g1[i];
+
  for (j = 0 ; j < 2 ; j++)
+
g2[B + i,j] = g2[i,j];
+
  for (j = 0 ; j < 3 ; j++)
+
g3[B + i,j] = g3[i,j];
+
  }
+
}
+
}
+
 
+
 
+
public class SmoothRandom
+
{
+
public static Vector3 GetVector3 (float speed)
+
{
+
float time = Time.time * 0.01F * speed;
+
return new Vector3(Get().HybridMultifractal(time, 15.73F, 0.65F), Get().HybridMultifractal(time, 63.94F, 0.65F), Get().HybridMultifractal(time, 0.2F, 0.65F));
+
}
+
+
public static float Get (float speed)
+
{
+
float time = Time.time * 0.01F * speed;
+
return Get().HybridMultifractal(time * 0.01F, 15.7F, 0.65F);
+
}
+
 
+
private static FractalNoise Get () {
+
if (s_Noise == null)
+
s_Noise = new FractalNoise (1.27F, 2.06F, 8.36F);
+
return s_Noise;
+
}
+
 
+
private static FractalNoise s_Noise;
+
}
+
 
+
 
+
 
+
public class FractalNoise
+
{
+
public FractalNoise (float inH, float inLacunarity, float inOctaves)
+
: this (inH, inLacunarity, inOctaves, null)
+
{
+
+
}
+
 
+
public FractalNoise (float inH, float inLacunarity, float inOctaves, Perlin noise)
+
{
+
m_Lacunarity = inLacunarity;
+
m_Octaves = inOctaves;
+
m_IntOctaves = (int)inOctaves;
+
m_Exponent = new float[m_IntOctaves+1];
+
float frequency = 1.0F;
+
for (int i = 0; i < m_IntOctaves+1; i++)
+
{
+
m_Exponent[i] = (float)Math.Pow (m_Lacunarity, -inH);
+
frequency *= m_Lacunarity;
+
}
+
+
if (noise == null)
+
m_Noise = new Perlin();
+
else
+
m_Noise = noise;
+
}
+
+
+
public float HybridMultifractal(float x, float y, float offset)
+
{
+
float weight, signal, remainder, result;
+
+
result = (m_Noise.Noise2D (x, y)+offset) * m_Exponent[0];
+
weight = result;
+
x *= m_Lacunarity;
+
y *= m_Lacunarity;
+
int i;
+
for (i=1;i<m_IntOctaves;i++)
+
{
+
if (weight > 1.0F) weight = 1.0F;
+
signal = (m_Noise.Noise2D (x, y) + offset) * m_Exponent[i];
+
result += weight * signal;
+
weight *= signal;
+
x *= m_Lacunarity;
+
y *= m_Lacunarity;
+
}
+
remainder = m_Octaves - m_IntOctaves;
+
if (remainder != 0.0F)
+
result += remainder * m_Noise.Noise2D (x,y) * m_Exponent[i];
+
+
return result;
+
}
+
+
Perlin m_Noise;
+
float[] m_Exponent;
+
int m_IntOctaves;
+
float m_Octaves;
+
float m_Lacunarity;
+
}
+
 
+
 
+
public class Noise
+
{
+
public float Noise1D(float x)
+
{
+
return Noise2D(x, 0.5F);
+
}
+
 
+
public float Noise2D(float x, float y)
+
{
+
int Xint = (int)x;
+
int Yint = (int)y;
+
float Xfrac = x - Xint;
+
float Yfrac = y - Yint;
+
 
+
float x0y0 = Smooth_Noise(Xint, Yint);  //find the noise values of the four corners
+
float x1y0 = Smooth_Noise(Xint+1, Yint);
+
float x0y1 = Smooth_Noise(Xint, Yint+1);
+
float x1y1 = Smooth_Noise(Xint+1, Yint+1);
+
 
+
//interpolate between those values according to the x and y fractions
+
float v1 = Interpolate(x0y0, x1y0, Xfrac); //interpolate in x direction (y)
+
float v2 = Interpolate(x0y1, x1y1, Xfrac); //interpolate in x direction (y+1)
+
float fin = Interpolate(v1, v2, Yfrac);  //interpolate in y direction
+
 
+
return fin;
+
}
+
 
+
private float Interpolate(float x, float y, float a)
+
{
+
float b = 1-a;
+
float fac1 = (float)(3*b*b - 2*b*b*b);
+
float fac2 = (float)(3*a*a - 2*a*a*a);
+
 
+
return x*fac1 + y*fac2; //add the weighted factors
+
}
+
 
+
protected float GetRandomValue(int x, int y)
+
{
+
x = (x+m_nNoiseWidth) % m_nNoiseWidth;
+
y = (y+m_nNoiseHeight) % m_nNoiseHeight;
+
float fVal = (float)m_aNoise[(int)(m_fScaleX*x), (int)(m_fScaleY*y)];
+
return fVal/255*2-1f;
+
}
+
 
+
private float Smooth_Noise(int x, int y)
+
{
+
float corners = ( Noise2d(x-1, y-1) + Noise2d(x+1, y-1) + Noise2d(x-1, y+1) + Noise2d(x+1, y+1) ) / 16.0f;
+
float sides = ( Noise2d(x-1, y) +Noise2d(x+1, y) + Noise2d(x, y-1) + Noise2d(x, y+1) ) / 8.0f;
+
float center = Noise2d(x, y) / 4.0f;
+
return corners + sides + center;
+
}
+
 
+
public float Noise2d(int x, int y)
+
{
+
x = (x+m_nNoiseWidth) % m_nNoiseWidth;
+
y = (y+m_nNoiseHeight) % m_nNoiseHeight;
+
+
float fVal = (float)m_aNoise[(int)(m_fScaleX*x), (int)(m_fScaleY*y)];
+
+
return fVal/255*2-1f;
+
}
+
 
+
public Noise()
+
{
+
m_nNoiseWidth = 100;
+
m_nNoiseHeight = 100;
+
m_fScaleX = 1.0F;
+
m_fScaleY = 1.0F;
+
System.Random rnd = new System.Random();
+
m_aNoise = new int[m_nNoiseWidth,m_nNoiseHeight];
+
for (int x = 0; x<m_nNoiseWidth; x++)
+
{
+
for (int y = 0; y<m_nNoiseHeight; y++)
+
{
+
m_aNoise[x,y] = rnd.Next(255);
+
}
+
}
+
}
+
+
private int[,] m_aNoise;
+
protected int m_nNoiseWidth, m_nNoiseHeight;
+
private float m_fScaleX, m_fScaleY;
+
}
+
 
+
 
+
/* float noise1[];
+
float noise2[];
+
float noise3[];
+
int indices[];
+
 
+
float PerlinSmoothStep (float t)
+
{
+
return t * t * (3.0f - 2.0f * t);
+
}
+
+
float PerlinLerp(float t, float a, float b)
+
{
+
return a + t * (b - a);
+
}
+
+
float PerlinRand()
+
{
+
return Random.rand () / float(RAND_MAX)  * 2.0f - 1.0f;
+
}
+
+
+
PerlinNoise::PerlinNoise ()
+
{
+
long i, j, k;
+
float x, y, z, denom;
+
+
Random rnd = new Random();
+
 
+
+
noise1 = new float[1 * (PERLIN_B + PERLIN_B + 2)];
+
noise2 = new float[2 * (PERLIN_B + PERLIN_B + 2)];
+
noise3 = new float[3 * (PERLIN_B + PERLIN_B + 2)];
+
indices = new long[PERLIN_B + PERLIN_B + 2];
+
+
for (i = 0; i < PERLIN_B; i++)
+
{
+
indices[i] = i;
+
+
x = PerlinRand();
+
y = PerlinRand();
+
z = PerlinRand();
+
+
noise1[i] = x;
+
+
denom = sqrt(x * x + y * y);
+
if (denom > 0.0001f) denom = 1.0f / denom;
+
+
j = i << 1;
+
noise2[j + 0] = x * denom;
+
noise2[j + 1] = y * denom;
+
+
denom = sqrt(x * x + y * y + z * z);
+
if (denom > 0.0001f) denom = 1.0f / denom;
+
+
j += i;
+
noise3[j + 0] = x * denom;
+
noise3[j + 1] = y * denom;
+
noise3[j + 2] = z * denom;
+
}
+
+
while (--i != 0)
+
{
+
j = rand() & PERLIN_BITMASK;
+
std::swap (indices[i], indices[j]);
+
}
+
+
for (i = 0; i < PERLIN_B + 2; i++)
+
{
+
j = i + PERLIN_B;
+
+
indices[j] = indices[i];
+
+
noise1[j] = noise1[i];
+
+
j = j << 1;
+
k = i << 1;
+
noise2[j + 0] = noise2[k + 0];
+
noise2[j + 1] = noise2[k + 1];
+
+
j += i + PERLIN_B;
+
k += i + PERLIN_B;
+
noise3[j + 0] = noise3[k + 0];
+
noise3[j + 1] = noise3[k + 1];
+
noise3[j + 2] = noise3[k + 2];
+
}
+
}
+
+
PerlinNoise::~PerlinNoise ()
+
{
+
delete []noise1;
+
delete []noise2;
+
delete []noise3;
+
delete []indices;
+
}
+
+
void PerlinSetup (float v, long& b0, long& b1, float& r0, float& r1);
+
void PerlinSetup(
+
float v,
+
long& b0,
+
long& b1,
+
float& r0,
+
float& r1)
+
{
+
v += PERLIN_N;
+
+
long vInt = (long)v;
+
+
b0 = vInt & PERLIN_BITMASK;
+
b1 = (b0 + 1) & PERLIN_BITMASK;
+
r0 = v - (float)vInt;
+
r1 = r0 - 1.0f;
+
}
+
+
+
float PerlinNoise::Noise1 (float x)
+
{
+
long bx0, bx1;
+
float rx0, rx1, sx, u, v;
+
+
PerlinSetup(x, bx0, bx1, rx0, rx1);
+
+
sx = PerlinSmoothStep(rx0);
+
+
u = rx0 * noise1[indices[bx0]];
+
v = rx1 * noise1[indices[bx1]];
+
+
return PerlinLerp (sx, u, v);
+
}
+
+
float PerlinNoise::Noise2(float x, float y)
+
{
+
long bx0, bx1, by0, by1, b00, b01, b10, b11;
+
float rx0, rx1, ry0, ry1, sx, sy, u, v, a, b;
+
+
PerlinSetup (x, bx0, bx1, rx0, rx1);
+
PerlinSetup (y, by0, by1, ry0, ry1);
+
+
sx = PerlinSmoothStep (rx0);
+
sy = PerlinSmoothStep (ry0);
+
+
b00 = indices[indices[bx0] + by0] << 1;
+
b10 = indices[indices[bx1] + by0] << 1;
+
b01 = indices[indices[bx0] + by1] << 1;
+
b11 = indices[indices[bx1] + by1] << 1;
+
+
u = rx0 * noise2[b00 + 0] + ry0 * noise2[b00 + 1];
+
v = rx1 * noise2[b10 + 0] + ry0 * noise2[b10 + 1];
+
a = PerlinLerp (sx, u, v);
+
+
u = rx0 * noise2[b01 + 0] + ry1 * noise2[b01 + 1];
+
v = rx1 * noise2[b11 + 0] + ry1 * noise2[b11 + 1];
+
b = PerlinLerp (sx, u, v);
+
+
u = PerlinLerp (sy, a, b);
+
+
return u;
+
}
+
+
float PerlinNoise::Noise3(float x, float y, float z)
+
{
+
long bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+
float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
+
+
PerlinSetup (x, bx0, bx1, rx0, rx1);
+
PerlinSetup (y, by0, by1, ry0, ry1);
+
PerlinSetup (z, bz0, bz1, rz0, rz1);
+
+
b00 = indices[indices[bx0] + by0] << 1;
+
b10 = indices[indices[bx1] + by0] << 1;
+
b01 = indices[indices[bx0] + by1] << 1;
+
b11 = indices[indices[bx1] + by1] << 1;
+
 
+
t = PerlinSmoothStep (rx0);
+
sy = PerlinSmoothStep (ry0);
+
sz = PerlinSmoothStep (rz0);
+
+
#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
+
+
q = &noise3[b00 + bz0]; u = at3(rx0,ry0,rz0);
+
q = &noise3[b10 + bz0]; v = at3(rx1,ry0,rz0);
+
a = PerlinLerp(t, u, v);
+
+
q = &noise3[b01 + bz0]; u = at3(rx0,ry1,rz0);
+
q = &noise3[b11 + bz0]; v = at3(rx1,ry1,rz0);
+
b = PerlinLerp(t, u, v);
+
+
c = PerlinLerp(sy, a, b);
+
+
q = &noise3[b00 + bz1]; u = at3(rx0,ry0,rz1);
+
q = &noise3[b10 + bz1]; v = at3(rx1,ry0,rz1);
+
a = PerlinLerp(t, u, v);
+
+
q = &noise3[b01 + bz1]; u = at3(rx0,ry1,rz1);
+
q = &noise3[b11 + bz1]; v = at3(rx1,ry1,rz1);
+
b = PerlinLerp(t, u, v);
+
+
d = PerlinLerp(sy, a, b);
+
+
return PerlinLerp (sz, c, d);
+
}
+
*/
+
</csharp>
+

Revision as of 13:40, 1 August 2006

Description

The following snippet shows how to smoothly randomly move a transform around.

Usage

Download the package. Open Unity with your own project folder. Double click on the unityPackage in the finder. Noise.unitypackage

This installs the perlin noise class and 3 scripts implementing:

  1. Animated light intensity noise
  2. Animated noise position
  3. Animated noise rotation

To use one of the scripts, just drag them on a game object, to make them move, rotate, animate light based on noise.

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox