Skip to content

Instantly share code, notes, and snippets.

@igaln
Created August 16, 2017 20:09
Show Gist options
  • Save igaln/5db575ff6e2883bc2d9e7410f8eeda0b to your computer and use it in GitHub Desktop.
Save igaln/5db575ff6e2883bc2d9e7410f8eeda0b to your computer and use it in GitHub Desktop.
Procedural Mesh with Perlin noise
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Grid : MonoBehaviour {
public float xOrg;
public float yOrg;
public float scale = 0.1F;
public int xSize, ySize;
private Mesh mesh;
private Vector3[] vertices;
private void Awake () {
Generate();
}
void Update() {
Generate();
}
private void Generate () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Procedural Grid";
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
Vector2[] uv = new Vector2[vertices.Length];
Vector4[] tangents = new Vector4[vertices.Length];
Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
for (int i = 0, y = 0; y <= ySize; y++) {
for (int x = 0; x <= xSize; x++, i++) {
float xCoord = xOrg + x / xSize * scale;
float yCoord = yOrg + y / ySize * scale;
float sample = Noise.Perlin3D (new Vector3 (x, y), scale);
vertices[i] = new Vector3(x, y,sample);
uv[i] = new Vector2((float)x / xSize, (float)y / ySize);
tangents[i] = tangent;
}
}
mesh.vertices = vertices;
mesh.uv = uv;
mesh.tangents = tangents;
int[] triangles = new int[xSize * ySize * 6];
for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++) {
for (int x = 0; x < xSize; x++, ti += 6, vi++) {
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 2] = vi + 1;
triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
triangles[ti + 5] = vi + xSize + 2;
}
}
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
}
using UnityEngine;
public delegate float NoiseMethod (Vector3 point, float frequency);
public enum NoiseMethodType {
Value,
Perlin
}
public static class Noise {
public static NoiseMethod[] valueMethods = {
Value1D,
Value2D,
Value3D
};
public static NoiseMethod[] perlinMethods = {
Perlin1D,
Perlin2D,
Perlin3D
};
public static NoiseMethod[][] methods = {
valueMethods,
perlinMethods
};
private static int[] hash = {
151,160,137, 91, 90, 15,131, 13,201, 95, 96, 53,194,233, 7,225,
140, 36,103, 30, 69,142, 8, 99, 37,240, 21, 10, 23,190, 6,148,
247,120,234, 75, 0, 26,197, 62, 94,252,219,203,117, 35, 11, 32,
57,177, 33, 88,237,149, 56, 87,174, 20,125,136,171,168, 68,175,
74,165, 71,134,139, 48, 27,166, 77,146,158,231, 83,111,229,122,
60,211,133,230,220,105, 92, 41, 55, 46,245, 40,244,102,143, 54,
65, 25, 63,161, 1,216, 80, 73,209, 76,132,187,208, 89, 18,169,
200,196,135,130,116,188,159, 86,164,100,109,198,173,186, 3, 64,
52,217,226,250,124,123, 5,202, 38,147,118,126,255, 82, 85,212,
207,206, 59,227, 47, 16, 58, 17,182,189, 28, 42,223,183,170,213,
119,248,152, 2, 44,154,163, 70,221,153,101,155,167, 43,172, 9,
129, 22, 39,253, 19, 98,108,110, 79,113,224,232,178,185,112,104,
218,246, 97,228,251, 34,242,193,238,210,144, 12,191,179,162,241,
81, 51,145,235,249, 14,239,107, 49,192,214, 31,181,199,106,157,
184, 84,204,176,115,121, 50, 45,127, 4,150,254,138,236,205, 93,
222,114, 67, 29, 24, 72,243,141,128,195, 78, 66,215, 61,156,180,
151,160,137, 91, 90, 15,131, 13,201, 95, 96, 53,194,233, 7,225,
140, 36,103, 30, 69,142, 8, 99, 37,240, 21, 10, 23,190, 6,148,
247,120,234, 75, 0, 26,197, 62, 94,252,219,203,117, 35, 11, 32,
57,177, 33, 88,237,149, 56, 87,174, 20,125,136,171,168, 68,175,
74,165, 71,134,139, 48, 27,166, 77,146,158,231, 83,111,229,122,
60,211,133,230,220,105, 92, 41, 55, 46,245, 40,244,102,143, 54,
65, 25, 63,161, 1,216, 80, 73,209, 76,132,187,208, 89, 18,169,
200,196,135,130,116,188,159, 86,164,100,109,198,173,186, 3, 64,
52,217,226,250,124,123, 5,202, 38,147,118,126,255, 82, 85,212,
207,206, 59,227, 47, 16, 58, 17,182,189, 28, 42,223,183,170,213,
119,248,152, 2, 44,154,163, 70,221,153,101,155,167, 43,172, 9,
129, 22, 39,253, 19, 98,108,110, 79,113,224,232,178,185,112,104,
218,246, 97,228,251, 34,242,193,238,210,144, 12,191,179,162,241,
81, 51,145,235,249, 14,239,107, 49,192,214, 31,181,199,106,157,
184, 84,204,176,115,121, 50, 45,127, 4,150,254,138,236,205, 93,
222,114, 67, 29, 24, 72,243,141,128,195, 78, 66,215, 61,156,180
};
private const int hashMask = 255;
private static float[] gradients1D = {
1f, -1f
};
private const int gradientsMask1D = 1;
private static Vector2[] gradients2D = {
new Vector2( 1f, 0f),
new Vector2(-1f, 0f),
new Vector2( 0f, 1f),
new Vector2( 0f,-1f),
new Vector2( 1f, 1f).normalized,
new Vector2(-1f, 1f).normalized,
new Vector2( 1f,-1f).normalized,
new Vector2(-1f,-1f).normalized
};
private const int gradientsMask2D = 7;
private static Vector3[] gradients3D = {
new Vector3( 1f, 1f, 0f),
new Vector3(-1f, 1f, 0f),
new Vector3( 1f,-1f, 0f),
new Vector3(-1f,-1f, 0f),
new Vector3( 1f, 0f, 1f),
new Vector3(-1f, 0f, 1f),
new Vector3( 1f, 0f,-1f),
new Vector3(-1f, 0f,-1f),
new Vector3( 0f, 1f, 1f),
new Vector3( 0f,-1f, 1f),
new Vector3( 0f, 1f,-1f),
new Vector3( 0f,-1f,-1f),
new Vector3( 1f, 1f, 0f),
new Vector3(-1f, 1f, 0f),
new Vector3( 0f,-1f, 1f),
new Vector3( 0f,-1f,-1f)
};
private const int gradientsMask3D = 15;
private static float Dot (Vector2 g, float x, float y) {
return g.x * x + g.y * y;
}
private static float Dot (Vector3 g, float x, float y, float z) {
return g.x * x + g.y * y + g.z * z;
}
private static float Smooth (float t) {
return t * t * t * (t * (t * 6f - 15f) + 10f);
}
private static float sqr2 = Mathf.Sqrt(2f);
public static float Value1D (Vector3 point, float frequency) {
point *= frequency;
int i0 = Mathf.FloorToInt(point.x);
float t = point.x - i0;
i0 &= hashMask;
int i1 = i0 + 1;
int h0 = hash[i0];
int h1 = hash[i1];
t = Smooth(t);
return Mathf.Lerp(h0, h1, t) * (1f / hashMask);
}
public static float Value2D (Vector3 point, float frequency) {
point *= frequency;
int ix0 = Mathf.FloorToInt(point.x);
int iy0 = Mathf.FloorToInt(point.y);
float tx = point.x - ix0;
float ty = point.y - iy0;
ix0 &= hashMask;
iy0 &= hashMask;
int ix1 = ix0 + 1;
int iy1 = iy0 + 1;
int h0 = hash[ix0];
int h1 = hash[ix1];
int h00 = hash[h0 + iy0];
int h10 = hash[h1 + iy0];
int h01 = hash[h0 + iy1];
int h11 = hash[h1 + iy1];
tx = Smooth(tx);
ty = Smooth(ty);
return Mathf.Lerp(
Mathf.Lerp(h00, h10, tx),
Mathf.Lerp(h01, h11, tx),
ty) * (1f / hashMask);
}
public static float Value3D (Vector3 point, float frequency) {
point *= frequency;
int ix0 = Mathf.FloorToInt(point.x);
int iy0 = Mathf.FloorToInt(point.y);
int iz0 = Mathf.FloorToInt(point.z);
float tx = point.x - ix0;
float ty = point.y - iy0;
float tz = point.z - iz0;
ix0 &= hashMask;
iy0 &= hashMask;
iz0 &= hashMask;
int ix1 = ix0 + 1;
int iy1 = iy0 + 1;
int iz1 = iz0 + 1;
int h0 = hash[ix0];
int h1 = hash[ix1];
int h00 = hash[h0 + iy0];
int h10 = hash[h1 + iy0];
int h01 = hash[h0 + iy1];
int h11 = hash[h1 + iy1];
int h000 = hash[h00 + iz0];
int h100 = hash[h10 + iz0];
int h010 = hash[h01 + iz0];
int h110 = hash[h11 + iz0];
int h001 = hash[h00 + iz1];
int h101 = hash[h10 + iz1];
int h011 = hash[h01 + iz1];
int h111 = hash[h11 + iz1];
tx = Smooth(tx);
ty = Smooth(ty);
tz = Smooth(tz);
return Mathf.Lerp(
Mathf.Lerp(Mathf.Lerp(h000, h100, tx), Mathf.Lerp(h010, h110, tx), ty),
Mathf.Lerp(Mathf.Lerp(h001, h101, tx), Mathf.Lerp(h011, h111, tx), ty),
tz) * (1f / hashMask);
}
public static float Perlin1D (Vector3 point, float frequency) {
point *= frequency;
int i0 = Mathf.FloorToInt(point.x);
float t0 = point.x - i0;
float t1 = t0 - 1f;
i0 &= hashMask;
int i1 = i0 + 1;
float g0 = gradients1D[hash[i0] & gradientsMask1D];
float g1 = gradients1D[hash[i1] & gradientsMask1D];
float v0 = g0 * t0;
float v1 = g1 * t1;
float t = Smooth(t0);
return Mathf.Lerp(v0, v1, t) * 2f;
}
public static float Perlin2D (Vector3 point, float frequency) {
point *= frequency;
int ix0 = Mathf.FloorToInt(point.x);
int iy0 = Mathf.FloorToInt(point.y);
float tx0 = point.x - ix0;
float ty0 = point.y - iy0;
float tx1 = tx0 - 1f;
float ty1 = ty0 - 1f;
ix0 &= hashMask;
iy0 &= hashMask;
int ix1 = ix0 + 1;
int iy1 = iy0 + 1;
int h0 = hash[ix0];
int h1 = hash[ix1];
Vector2 g00 = gradients2D[hash[h0 + iy0] & gradientsMask2D];
Vector2 g10 = gradients2D[hash[h1 + iy0] & gradientsMask2D];
Vector2 g01 = gradients2D[hash[h0 + iy1] & gradientsMask2D];
Vector2 g11 = gradients2D[hash[h1 + iy1] & gradientsMask2D];
float v00 = Dot(g00, tx0, ty0);
float v10 = Dot(g10, tx1, ty0);
float v01 = Dot(g01, tx0, ty1);
float v11 = Dot(g11, tx1, ty1);
float tx = Smooth(tx0);
float ty = Smooth(ty0);
return Mathf.Lerp(
Mathf.Lerp(v00, v10, tx),
Mathf.Lerp(v01, v11, tx),
ty) * sqr2;
}
public static float Perlin3D (Vector3 point, float frequency) {
point *= frequency;
int ix0 = Mathf.FloorToInt(point.x);
int iy0 = Mathf.FloorToInt(point.y);
int iz0 = Mathf.FloorToInt(point.z);
float tx0 = point.x - ix0;
float ty0 = point.y - iy0;
float tz0 = point.z - iz0;
float tx1 = tx0 - 1f;
float ty1 = ty0 - 1f;
float tz1 = tz0 - 1f;
ix0 &= hashMask;
iy0 &= hashMask;
iz0 &= hashMask;
int ix1 = ix0 + 1;
int iy1 = iy0 + 1;
int iz1 = iz0 + 1;
int h0 = hash[ix0];
int h1 = hash[ix1];
int h00 = hash[h0 + iy0];
int h10 = hash[h1 + iy0];
int h01 = hash[h0 + iy1];
int h11 = hash[h1 + iy1];
Vector3 g000 = gradients3D[hash[h00 + iz0] & gradientsMask3D];
Vector3 g100 = gradients3D[hash[h10 + iz0] & gradientsMask3D];
Vector3 g010 = gradients3D[hash[h01 + iz0] & gradientsMask3D];
Vector3 g110 = gradients3D[hash[h11 + iz0] & gradientsMask3D];
Vector3 g001 = gradients3D[hash[h00 + iz1] & gradientsMask3D];
Vector3 g101 = gradients3D[hash[h10 + iz1] & gradientsMask3D];
Vector3 g011 = gradients3D[hash[h01 + iz1] & gradientsMask3D];
Vector3 g111 = gradients3D[hash[h11 + iz1] & gradientsMask3D];
float v000 = Dot(g000, tx0, ty0, tz0);
float v100 = Dot(g100, tx1, ty0, tz0);
float v010 = Dot(g010, tx0, ty1, tz0);
float v110 = Dot(g110, tx1, ty1, tz0);
float v001 = Dot(g001, tx0, ty0, tz1);
float v101 = Dot(g101, tx1, ty0, tz1);
float v011 = Dot(g011, tx0, ty1, tz1);
float v111 = Dot(g111, tx1, ty1, tz1);
float tx = Smooth(tx0);
float ty = Smooth(ty0);
float tz = Smooth(tz0);
return Mathf.Lerp(
Mathf.Lerp(Mathf.Lerp(v000, v100, tx), Mathf.Lerp(v010, v110, tx), ty),
Mathf.Lerp(Mathf.Lerp(v001, v101, tx), Mathf.Lerp(v011, v111, tx), ty),
tz);
}
public static float Sum (NoiseMethod method, Vector3 point, float frequency, int octaves, float lacunarity, float persistence) {
float sum = method(point, frequency);
float amplitude = 1f;
float range = 1f;
for (int o = 1; o < octaves; o++) {
frequency *= lacunarity;
amplitude *= persistence;
range += amplitude;
sum += method(point, frequency) * amplitude;
}
return sum / range;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment