using System; using UnityEngine; public static class NoiseS3D { private static int seed_; /// /// The seed for the noise function. Randomized at startup by default. /// public static int seed { get { return seed_; } set { seed_ = value; UnityEngine.Random.seed = value; SetupNoise(); } } private static int[][] grad3 = {new int[]{1,1,0}, new int[]{-1,1,0}, new int[]{1,-1,0}, new int[]{-1,-1,0}, new int[]{1,0,1}, new int[]{-1,0,1}, new int[]{1,0,-1}, new int[]{-1,0,-1}, new int[]{0,1,1}, new int[]{0,-1,1}, new int[]{0,1,-1}, new int[]{0,-1,-1}}; private static int[][] grad4 = {new int[]{0,1,1,1}, new int[]{0,1,1,-1}, new int[]{0,1,-1,1}, new int[]{0,1,-1,-1}, new int[]{0,-1,1,1},new int[] {0,-1,1,-1},new int[] {0,-1,-1,1},new int[] {0,-1,-1,-1}, new int[]{1,0,1,1}, new int[]{1,0,1,-1}, new int[]{1,0,-1,1}, new int[]{1,0,-1,-1}, new int[]{-1,0,1,1},new int[] {-1,0,1,-1},new int[] {-1,0,-1,1},new int[] {-1,0,-1,-1}, new int[]{1,1,0,1}, new int[]{1,1,0,-1}, new int[]{1,-1,0,1}, new int[]{1,-1,0,-1}, new int[]{-1,1,0,1},new int[] {-1,1,0,-1},new int[] {-1,-1,0,1},new int[] {-1,-1,0,-1}, new int[]{1,1,1,0}, new int[]{1,1,-1,0}, new int[]{1,-1,1,0}, new int[]{1,-1,-1,0}, new int[]{-1,1,1,0},new int[] {-1,1,-1,0},new int[] {-1,-1,1,0},new int[] {-1,-1,-1,0}}; private static int[] p = null; private static int[] perm_ = null; private static int[] perm { get { if(perm_ == null) SetupNoise(); return perm_; } set { perm_ = value; } } private static void SetupNoise() { p = new int[256]; for(int i = 0; i < 256; i++) p[i] = Mathf.FloorToInt(UnityEngine.Random.value * 256); perm_ = new int[512]; for(int i = 0; i < 512; i++) perm_[i] = p[i & 255]; } private static int[][] simplex = { new int[]{0,1,2,3}, new int[]{0,1,3,2}, new int[]{0,0,0,0}, new int[]{0,2,3,1}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{1,2,3,0}, new int[]{0,2,1,3}, new int[]{0,0,0,0}, new int[]{0,3,1,2}, new int[]{0,3,2,1}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{1,3,2,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{1,2,0,3}, new int[]{0,0,0,0}, new int[]{1,3,0,2}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{2,3,0,1}, new int[]{2,3,1,0}, new int[]{1,0,2,3}, new int[]{1,0,3,2}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{2,0,3,1}, new int[]{0,0,0,0}, new int[]{2,1,3,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{2,0,1,3}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{3,0,1,2}, new int[]{3,0,2,1}, new int[]{0,0,0,0}, new int[]{3,1,2,0}, new int[]{2,1,0,3}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{0,0,0,0}, new int[]{3,1,0,2}, new int[]{0,0,0,0}, new int[]{3,2,0,1}, new int[]{3,2,1,0}}; private static int fastfloor(double x) { return x > 0 ? (int)x : (int)x - 1; } private static double dot(int[] g, double x, double y) { return g[0] * x + g[1] * y; } private static double dot(int[] g, double x, double y, double z) { return g[0] * x + g[1] * y + g[2] * z; } private static double dot(int[] g, double x, double y, double z, double w) { return g[0] * x + g[1] * y + g[2] * z + g[3] * w; } //////////////////////////////////////////////////////////////////////////////////////////////// // NOISE GENERATION USING DOUBLES //////////////////////////////////////////////////////////////////////////////////////////////// /// /// Returns value between -1 and 1 that represents a value from a 1D noise field at the given coordinates. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. /// z coordinate parameter for the noise function. /// w coordinate parameter for the noise function. public static double Noise(double x) { return Noise(x, 0); } /// /// Returns value between -1 and 1 that represents a 2D value from a noise field at the given coordinates. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. /// z coordinate parameter for the noise function. /// w coordinate parameter for the noise function. public static double Noise(double x, double y) { double n0, n1, n2; double F2 = 0.5 * (Math.Sqrt(3.0) - 1.0); double s = (x + y) * F2; int i = fastfloor(x + s); int j = fastfloor(y + s); double G2 = (3.0 - Math.Sqrt(3.0)) / 6.0; double t = (i + j) * G2; double X0 = i - t; double Y0 = j - t; double x0 = x - X0; double y0 = y - Y0; int i1, j1; if(x0 > y0) { i1 = 1; j1 = 0; } else { i1 = 0; j1 = 1; } double x1 = x0 - i1 + G2; double y1 = y0 - j1 + G2; double x2 = x0 - 1.0 + 2.0 * G2; double y2 = y0 - 1.0 + 2.0 * G2; int ii = i & 255; int jj = j & 255; int gi0 = perm[ii + perm[jj]] % 12; int gi1 = perm[ii + i1 + perm[jj + j1]] % 12; int gi2 = perm[ii + 1 + perm[jj + 1]] % 12; double t0 = 0.5 - x0 * x0 - y0 * y0; if(t0 < 0) n0 = 0.0; else { t0 *= t0; n0 = t0 * t0 * dot(grad3[gi0], x0, y0); } double t1 = 0.5 - x1 * x1 - y1 * y1; if(t1 < 0) n1 = 0.0; else { t1 *= t1; n1 = t1 * t1 * dot(grad3[gi1], x1, y1); } double t2 = 0.5 - x2 * x2 - y2 * y2; if(t2 < 0) n2 = 0.0; else { t2 *= t2; n2 = t2 * t2 * dot(grad3[gi2], x2, y2); } return 70.0 * (n0 + n1 + n2); } /// /// Returns value between -1 and 1 that represents a value from a 3D noise field at the given coordinates. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. /// z coordinate parameter for the noise function. /// w coordinate parameter for the noise function. public static double Noise(double x, double y, double z) { double n0, n1, n2, n3; double F3 = 1.0 / 3.0; double s = (x + y + z) * F3; int i = fastfloor(x + s); int j = fastfloor(y + s); int k = fastfloor(z + s); double G3 = 1.0 / 6.0; double t = (i + j + k) * G3; double X0 = i - t; double Y0 = j - t; double Z0 = k - t; double x0 = x - X0; double y0 = y - Y0; double z0 = z - Z0; int i1, j1, k1; int i2, j2, k2; if(x0 >= y0) { if(y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } else if(x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } } else { if(y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } else if(x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } } double x1 = x0 - i1 + G3; double y1 = y0 - j1 + G3; double z1 = z0 - k1 + G3; double x2 = x0 - i2 + 2.0 * G3; double y2 = y0 - j2 + 2.0 * G3; double z2 = z0 - k2 + 2.0 * G3; double x3 = x0 - 1.0 + 3.0 * G3; double y3 = y0 - 1.0 + 3.0 * G3; double z3 = z0 - 1.0 + 3.0 * G3; int ii = i & 255; int jj = j & 255; int kk = k & 255; int gi0 = perm[ii + perm[jj + perm[kk]]] % 12; int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12; int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12; int gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12; double t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0; if(t0 < 0) n0 = 0.0; else { t0 *= t0; n0 = t0 * t0 * dot(grad3[gi0], x0, y0, z0); } double t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1; if(t1 < 0) n1 = 0.0; else { t1 *= t1; n1 = t1 * t1 * dot(grad3[gi1], x1, y1, z1); } double t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2; if(t2 < 0) n2 = 0.0; else { t2 *= t2; n2 = t2 * t2 * dot(grad3[gi2], x2, y2, z2); } double t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3; if(t3 < 0) n3 = 0.0; else { t3 *= t3; n3 = t3 * t3 * dot(grad3[gi3], x3, y3, z3); } return 32.0 * (n0 + n1 + n2 + n3); } /// /// Returns value between -1 and 1 that represents a value from a 4D noise field at the given coordinates. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. /// z coordinate parameter for the noise function. /// w coordinate parameter for the noise function. public static double Noise(double x, double y, double z, double w) { double F4 = (Math.Sqrt(5.0) - 1.0) / 4.0; double G4 = (5.0 - Math.Sqrt(5.0)) / 20.0; double n0, n1, n2, n3, n4; double s = (x + y + z + w) * F4; int i = fastfloor(x + s); int j = fastfloor(y + s); int k = fastfloor(z + s); int l = fastfloor(w + s); double t = (i + j + k + l) * G4; double X0 = i - t; double Y0 = j - t; double Z0 = k - t; double W0 = l - t; double x0 = x - X0; double y0 = y - Y0; double z0 = z - Z0; double w0 = w - W0; int c1 = (x0 > y0) ? 32 : 0; int c2 = (x0 > z0) ? 16 : 0; int c3 = (y0 > z0) ? 8 : 0; int c4 = (x0 > w0) ? 4 : 0; int c5 = (y0 > w0) ? 2 : 0; int c6 = (z0 > w0) ? 1 : 0; int c = c1 + c2 + c3 + c4 + c5 + c6; int i1, j1, k1, l1; int i2, j2, k2, l2; int i3, j3, k3, l3; i1 = simplex[c][0] >= 3 ? 1 : 0; j1 = simplex[c][1] >= 3 ? 1 : 0; k1 = simplex[c][2] >= 3 ? 1 : 0; l1 = simplex[c][3] >= 3 ? 1 : 0; i2 = simplex[c][0] >= 2 ? 1 : 0; j2 = simplex[c][1] >= 2 ? 1 : 0; k2 = simplex[c][2] >= 2 ? 1 : 0; l2 = simplex[c][3] >= 2 ? 1 : 0; i3 = simplex[c][0] >= 1 ? 1 : 0; j3 = simplex[c][1] >= 1 ? 1 : 0; k3 = simplex[c][2] >= 1 ? 1 : 0; l3 = simplex[c][3] >= 1 ? 1 : 0; double x1 = x0 - i1 + G4; double y1 = y0 - j1 + G4; double z1 = z0 - k1 + G4; double w1 = w0 - l1 + G4; double x2 = x0 - i2 + 2.0 * G4; double y2 = y0 - j2 + 2.0 * G4; double z2 = z0 - k2 + 2.0 * G4; double w2 = w0 - l2 + 2.0 * G4; double x3 = x0 - i3 + 3.0 * G4; double y3 = y0 - j3 + 3.0 * G4; double z3 = z0 - k3 + 3.0 * G4; double w3 = w0 - l3 + 3.0 * G4; double x4 = x0 - 1.0 + 4.0 * G4; double y4 = y0 - 1.0 + 4.0 * G4; double z4 = z0 - 1.0 + 4.0 * G4; double w4 = w0 - 1.0 + 4.0 * G4; int ii = i & 255; int jj = j & 255; int kk = k & 255; int ll = l & 255; int gi0 = perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32; int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32; int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32; int gi3 = perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32; int gi4 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32; double t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; if(t0 < 0) n0 = 0.0; else { t0 *= t0; n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0); } double t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; if(t1 < 0) n1 = 0.0; else { t1 *= t1; n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1); } double t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; if(t2 < 0) n2 = 0.0; else { t2 *= t2; n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2); } double t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; if(t3 < 0) n3 = 0.0; else { t3 *= t3; n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3); } double t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; if(t4 < 0) n4 = 0.0; else { t4 *= t4; n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4); } return 27.0 * (n0 + n1 + n2 + n3 + n4); } private static int octaves_ = 4; /// /// Number of octaves to use when generating combined noise octaves, higher number of octaves result in less blurry, more cloudy noise; /// Value is clamped between 1 and 10. Higher values take longer to compute. /// public static int octaves { get { return octaves_; } set { octaves_ = Mathf.Clamp(value, 1, 10); } } /// /// Value that defines how much higher octaves effect the end result in combined noise generation; /// public static float falloff = 0.5f; //////////////////////////////////////////////////////////////////////////////////////////////// // OCTAVE METHODS DOUBLE //////////////////////////////////////////////////////////////////////////////////////////////// private static double CombineNoise(double[] noiseValues) { double finalNoiseValue = 0.0; double amplitude = 1.0; double totalAmplitude = 0.0; for(int o = 0; o < octaves; o++) { amplitude *= falloff; totalAmplitude += amplitude; finalNoiseValue += noiseValues[o] * amplitude; } return finalNoiseValue / totalAmplitude; } private static double[] GetNoiseValues(double x, double y, double z, double w, int dimension) { double[] noiseValues = new double[octaves]; double freq = 1.0; switch(dimension) { case 1: for(int o = 0; o < octaves; o++) { noiseValues[o] = Noise(x * freq); freq *= 2.0; } break; case 2: for(int o = 0; o < octaves; o++) { noiseValues[o] = Noise(x * freq, y * freq); freq *= 2.0; } break; case 3: for(int o = 0; o < octaves; o++) { noiseValues[o] = Noise(x * freq, y * freq, z * freq); freq *= 2.0; } break; case 4: for(int o = 0; o < octaves; o++) { noiseValues[o] = Noise(x * freq, y * freq, z * freq, w * freq); freq *= 2.0; } break; } return noiseValues; } /// /// Returns value between -1 and 1 that represents a value from a 1D combined noise field at the given coordinates. /// This method uses the octaves variable to generate noise combined over the set number of octaves. /// The falloff variable defines how much higher octaves effect the end result. /// /// double /// x coordinate parameter for the noise function. public static double NoiseCombinedOctaves(double x) { double[] noiseValues = GetNoiseValues(x, 0, 0, 0, 1); return CombineNoise(noiseValues); } /// /// Returns value between -1 and 1 that represents a value from a 2D combined noise field at the given coordinates. /// This method uses the octaves variable to generate noise combined over the set number of octaves. /// The falloff variable defines how much higher octaves effect the end result. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. public static double NoiseCombinedOctaves(double x, double y) { double[] noiseValues = GetNoiseValues(x, y, 0, 0, 2); return CombineNoise(noiseValues); } /// /// Returns value between -1 and 1 that represents a value from a 3D combined noise field at the given coordinates. /// This method uses the octaves variable to generate noise combined over the set number of octaves. /// The falloff variable defines how much higher octaves effect the end result. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. /// z coordinate parameter for the noise function. public static double NoiseCombinedOctaves(double x, double y, double z) { double[] noiseValues = GetNoiseValues(x, y, z, 0, 3); return CombineNoise(noiseValues); } /// /// Returns value between -1 and 1 that represents a value from a 4D combined noise field at the given coordinates. /// This method uses the octaves variable to generate noise combined over the set number of octaves. /// The falloff variable defines how much higher octaves effect the end result. /// /// double /// x coordinate parameter for the noise function. /// y coordinate parameter for the noise function. /// z coordinate parameter for the noise function. /// w coordinate parameter for the noise function. public static double NoiseCombinedOctaves(double x, double y, double z, double w) { double[] noiseValues = GetNoiseValues(x, y, z, w, 4); return CombineNoise(noiseValues); } // // GPU STUFF // static bool needsFakeBuffer = true; private static void SetShaderVars(ComputeShader shader, Vector2 noiseOffset, bool normalize, float noiseScale, int kernel) { shader.SetInt("octaves", octaves); shader.SetFloat("falloff", falloff); shader.SetInt("normalize", System.Convert.ToInt32(normalize)); shader.SetFloat("noiseScale", noiseScale); shader.SetVector("offset", noiseOffset); if (needsFakeBuffer) { ComputeBuffer cb = new ComputeBuffer(1, 4); shader.SetBuffer(kernel, "float1Array", cb); shader.SetBuffer(kernel, "float2Array", cb); shader.SetBuffer(kernel, "float3Array", cb); shader.SetBuffer(kernel, "float4Array", cb); cb.Release(); needsFakeBuffer = false; } } private static Texture2D ToTexture2DNoise(this RenderTexture inTex, bool apply = true, bool release = false, TextureFormat format = TextureFormat.RGBA32) { Texture2D tex = new Texture2D(inTex.width, inTex.height, format, false); RenderTexture.active = inTex; tex.ReadPixels(new Rect(0, 0, inTex.width, inTex.height), 0, 0); if(release) { RenderTexture.active = null; inTex.Release(); } if(apply) tex.Apply(); return tex; } private static string shaderPath = "Shaders/NoiseS3DGPU"; private static string noShaderMsg = "Could not find the noise compute shader. Did you move/rename any of the files?"; /// /// Uses the GPU to generate a RenderTexture where the pixels in the texture represent noise. /// Set the octaves variable before calling this to a desired value. /// /// RenderTexture /// Width of the texture to generate. /// Height of the texture to generate. /// X Coordinate of the offset for the noise on the texture. /// Y Coordinate of the offset for the noise on the texture. /// Value to scale the noise coordinates by. /// Whether or not to remap the noise from (-1, 1) to (0, 1). public static RenderTexture GetNoiseRenderTexture(int width, int height, float noiseOffsetX = 0, float noiseOffsetY = 0, float noiseScale = 0.01f, bool normalize = true) { RenderTexture retTex = new RenderTexture(width, height, 0); retTex.enableRandomWrite = true; retTex.Create(); ComputeShader shader = Resources.Load(shaderPath) as ComputeShader; if(shader == null) { Debug.LogError(noShaderMsg); return null; } int[] resInts = { width, height}; int kernel = shader.FindKernel("ComputeNoise"); shader.SetTexture(kernel, "Result", retTex); SetShaderVars(shader, new Vector2(noiseOffsetX, noiseOffsetY), normalize, noiseScale, kernel); shader.SetInts("reses", resInts); ComputeBuffer permBuffer = new ComputeBuffer(perm.Length, 4); permBuffer.SetData(perm); shader.SetBuffer(kernel, "perm", permBuffer); shader.Dispatch(kernel, Mathf.CeilToInt(width / 16f), Mathf.CeilToInt(height / 16f), 1); permBuffer.Release(); return retTex; } /// /// Uses the GPU to generate a Texture2D where the pixels in the texture represent noise. /// Set the octaves variable before calling this to a desired value. /// /// Texture2D /// Width of the texture to generate. /// Height of the texture to generate. /// X Coordinate of the offset for the noise on the texture. /// Y Coordinate of the offset for the noise on the texture. /// Value to scale the noise coordinates by. /// Whether or not to remap the noise from (-1, 1) to (0, 1). public static Texture2D GetNoiseTexture(int width, int height, float noiseOffsetX = 0, float noiseOffsetY = 0, float noiseScale = 0.01f, bool normalize = true) { RenderTexture renderTex = GetNoiseRenderTexture(width, height, noiseOffsetX, noiseOffsetY, noiseScale, normalize); Texture2D retTex = renderTex.ToTexture2DNoise(true, true); return retTex; } /// /// Uses the GPU to process an array of 1D coordinates for noise and return an array with the noise at the specified coordinates. /// /// Float array /// Array of coordinates to process. /// Value to scale the noise coordinates by. /// Whether or not to remap the noise from (-1, 1) to (0, 1). public static float[] NoiseArrayGPU(float[] positions, float noiseScale = 0.01f, bool normalize = true) { ComputeShader shader = Resources.Load(shaderPath) as ComputeShader; if(shader == null) { Debug.LogError(noShaderMsg); return null; } int kernel = shader.FindKernel("ComputeNoiseArray"); SetShaderVars(shader, Vector2.zero, normalize, noiseScale, kernel); shader.SetInts("dimension", 1); ComputeBuffer permBuffer = new ComputeBuffer(perm.Length, 4); permBuffer.SetData(perm); shader.SetBuffer(kernel, "perm", permBuffer); ComputeBuffer posBuffer = new ComputeBuffer(positions.Length, 4); posBuffer.SetData(positions); shader.SetBuffer(kernel, "float1Array", posBuffer); ComputeBuffer outputBuffer = new ComputeBuffer(positions.Length, 4); shader.SetBuffer(kernel, "outputArray", outputBuffer); shader.Dispatch(kernel, Mathf.CeilToInt(positions.Length / 16f), 1, 1); float[] outputData = new float[positions.Length]; outputBuffer.GetData(outputData); permBuffer.Release(); posBuffer.Release(); outputBuffer.Release(); return outputData; } /// /// Uses the GPU to process an array of 2D coordinates for noise and return an array with the noise at the specified coordinates. /// /// Float array /// Array of coordinates to process. /// Value to scale the noise coordinates by. /// Whether or not to remap the noise from (-1, 1) to (0, 1). public static float[] NoiseArrayGPU(Vector2[] positions, float noiseScale = 0.01f, bool normalize = true) { ComputeShader shader = Resources.Load(shaderPath) as ComputeShader; if(shader == null) { Debug.LogError(noShaderMsg); return null; } int kernel = shader.FindKernel("ComputeNoiseArray"); SetShaderVars(shader, Vector2.zero, normalize, noiseScale, kernel); shader.SetInt("dimension", 2); ComputeBuffer permBuffer = new ComputeBuffer(perm.Length, 4); permBuffer.SetData(perm); shader.SetBuffer(kernel, "perm", permBuffer); ComputeBuffer posBuffer = new ComputeBuffer(positions.Length, 8); posBuffer.SetData(positions); shader.SetBuffer(kernel, "float2Array", posBuffer); ComputeBuffer outputBuffer = new ComputeBuffer(positions.Length, 4); shader.SetBuffer(kernel, "outputArray", outputBuffer); shader.Dispatch(kernel, Mathf.CeilToInt(positions.Length / 16f), 1, 1); float[] outputData = new float[positions.Length]; outputBuffer.GetData(outputData); permBuffer.Release(); posBuffer.Release(); outputBuffer.Release(); return outputData; } /// /// Uses the GPU to process an array of 3D coordinates for noise and return an array with the noise at the specified coordinates. /// /// Float array /// Array of coordinates to process. /// Value to scale the noise coordinates by. /// Whether or not to remap the noise from (-1, 1) to (0, 1). public static float[] NoiseArrayGPU(Vector3[] positions, float noiseScale = 0.01f, bool normalize = true) { ComputeShader shader = Resources.Load(shaderPath) as ComputeShader; if(shader == null) { Debug.LogError(noShaderMsg); return null; } int kernel = shader.FindKernel("ComputeNoiseArray"); SetShaderVars(shader, Vector2.zero, normalize, noiseScale, kernel); shader.SetInt("dimension", 3); ComputeBuffer permBuffer = new ComputeBuffer(perm.Length, 4); permBuffer.SetData(perm); shader.SetBuffer(kernel, "perm", permBuffer); ComputeBuffer posBuffer = new ComputeBuffer(positions.Length, 12); posBuffer.SetData(positions); shader.SetBuffer(kernel, "float3Array", posBuffer); ComputeBuffer outputBuffer = new ComputeBuffer(positions.Length, 4); shader.SetBuffer(kernel, "outputArray", outputBuffer); shader.Dispatch(kernel, Mathf.CeilToInt(positions.Length / 16f), 1, 1); float[] outputData = new float[positions.Length]; outputBuffer.GetData(outputData); permBuffer.Release(); posBuffer.Release(); outputBuffer.Release(); return outputData; } /// /// Uses the GPU to process an array of 4D coordinates for noise and return an array with the noise at the specified coordinates. /// /// Float array /// Array of coordinates to process. /// Value to scale the noise coordinates by. /// Whether or not to remap the noise from (-1, 1) to (0, 1). public static float[] NoiseArrayGPU(Vector4[] positions, float noiseScale = 0.01f, bool normalize = true) { ComputeShader shader = Resources.Load(shaderPath) as ComputeShader; if(shader == null) { Debug.LogError(noShaderMsg); return null; } int kernel = shader.FindKernel("ComputeNoiseArray"); SetShaderVars(shader, Vector2.zero, normalize, noiseScale, kernel); shader.SetInt("dimension", 4); ComputeBuffer permBuffer = new ComputeBuffer(perm.Length, 4); permBuffer.SetData(perm); shader.SetBuffer(kernel, "perm", permBuffer); ComputeBuffer posBuffer = new ComputeBuffer(positions.Length, 16); posBuffer.SetData(positions); shader.SetBuffer(kernel, "float4Array", posBuffer); ComputeBuffer outputBuffer = new ComputeBuffer(positions.Length, 4); shader.SetBuffer(kernel, "outputArray", outputBuffer); shader.Dispatch(kernel, Mathf.CeilToInt(positions.Length / 16f), 1, 1); float[] outputData = new float[positions.Length]; outputBuffer.GetData(outputData); permBuffer.Release(); posBuffer.Release(); outputBuffer.Release(); return outputData; } }