\n
\r\npublic static class CellNoise\r\n{\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ Generates Cell Noise\r\n\t\/\/\/ <\/summary>\r\n\t\/\/\/ <param name="input">The location at which the cell noise function should be evaluated at.<\/param>\r\n\t\/\/\/ <param name="seed">The seed for the noise function<\/param>\r\n\t\/\/\/ <param name="distanceFunc">The function used to calculate the distance between two points. Several of these are defined as statics on the WorleyNoise class.<\/param>\r\n\t\/\/\/ <param name="distanceArray">An array which will store the distances computed by the Worley noise function. \r\n\t\/\/\/ The length of the array determines how many distances will be computed.<\/param>\r\n\t\/\/\/ <param name="combineDistancesFunc">The function used to color the location. The color takes the populated distanceArray\r\n\t\/\/\/ param and returns a float which is the greyscale value outputed by the worley noise function.<\/param>\r\n\t\/\/\/ <returns>The color worley noise returns at the input position<\/returns>\r\n\tpublic static Vector4 CellNoiseFunc(this Vector3 input, int seed, Func<Vector3, Vector3, float> distanceFunc, ref float[] distanceArray, Func<float[], float> combineDistancesFunc)\r\n\t{\r\n\t\t\/\/Declare some values for later use\r\n\t\tuint lastRandom, numberFeaturePoints;\r\n\t\tVector3 randomDiff, featurePoint;\r\n\t\tint cubeX, cubeY, cubeZ;\r\n\r\n\t\t\/\/Initialize values in distance array to large values\r\n\t\tfor (int i = 0; i < distanceArray.Length; i++)\r\n\t\t\tdistanceArray[i] = 6666;\r\n\r\n\t\t\/\/1. Determine which cube the evaluation point is in\r\n\t\tint evalCubeX = (int)Math.Floor(input.X);\r\n\t\tint evalCubeY = (int)Math.Floor(input.Y);\r\n\t\tint evalCubeZ = (int)Math.Floor(input.Z);\r\n\r\n\t\tfor (int i = -1; i < 2; ++i)\r\n\t\t\tfor (int j = -1; j < 2; ++j)\r\n\t\t\t\tfor (int k = -1; k < 2; ++k)\r\n\t\t\t\t{\r\n\t\t\t\t\tcubeX = evalCubeX + i;\r\n\t\t\t\t\tcubeY = evalCubeY + j;\r\n\t\t\t\t\tcubeZ = evalCubeZ + k;\r\n\r\n\t\t\t\t\t\/\/2. Generate a reproducible random number generator for the cube\r\n\t\t\t\t\tlastRandom = lcgRandom(hash((uint)(cubeX + seed), (uint)(cubeY), (uint)(cubeZ)));\r\n\t\t\t\t\t\/\/3. Determine how many feature points are in the cube\r\n\t\t\t\t\tnumberFeaturePoints = probLookup(lastRandom);\r\n\t\t\t\t\t\/\/4. Randomly place the feature points in the cube\r\n\t\t\t\t\tfor (uint l = 0; l < numberFeaturePoints; ++l)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tlastRandom = lcgRandom(lastRandom);\r\n\t\t\t\t\t\trandomDiff.X = (float)lastRandom \/ 0x100000000;\r\n\r\n\t\t\t\t\t\tlastRandom = lcgRandom(lastRandom);\r\n\t\t\t\t\t\trandomDiff.Y = (float)lastRandom \/ 0x100000000;\r\n\r\n\t\t\t\t\t\tlastRandom = lcgRandom(lastRandom);\r\n\t\t\t\t\t\trandomDiff.Z = (float)lastRandom \/ 0x100000000;\r\n\r\n\t\t\t\t\t\tfeaturePoint = new Vector3(randomDiff.X + (float)cubeX, randomDiff.Y + (float)cubeY, randomDiff.Z + (float)cubeZ);\r\n\r\n\t\t\t\t\t\t\/\/5. Find the feature point closest to the evaluation point. \r\n\t\t\t\t\t\t\/\/This is done by inserting the distances to the feature points into a sorted list\r\n\t\t\t\t\t\tinsert(distanceArray, distanceFunc(input, featurePoint));\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\/\/6. Check the neighboring cubes to ensure their are no closer evaluation points.\r\n\t\t\t\t\t\/\/ This is done by repeating steps 1 through 5 above for each neighboring cube\r\n\t\t\t\t}\r\n\r\n\t\tfloat color = combineDistancesFunc(distanceArray);\r\n\t\tif(color < 0) color = 0;\r\n\t\tif(color > 1) color = 1;\r\n\t\treturn new Vector4(color, color, color, 1);\r\n\t}\r\n\r\n\tpublic static float EuclidianDistanceFunc(Vector3 p1, Vector3 p2)\r\n\t{\r\n\t\treturn (p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y) + (p1.Z - p2.Z) * (p1.Z - p2.Z);\r\n\t}\r\n\r\n\tpublic static float ManhattanDistanceFunc(Vector3 p1, Vector3 p2)\r\n\t{\r\n\t\treturn Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y) + Math.Abs(p1.Z - p2.Z);\r\n\t}\r\n\r\n\tpublic static float ChebyshevDistanceFunc(Vector3 p1, Vector3 p2)\r\n\t{\r\n\t\tVector3 diff = p1 - p2;\r\n\t\treturn Math.Max(Math.Max(Math.Abs(diff.X), Math.Abs(diff.Y)), Math.Abs(diff.Z));\r\n\t}\r\n\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ Given a uniformly distributed random number this function returns the number of feature points in a given cube.\r\n\t\/\/\/ <\/summary>\r\n\t\/\/\/ <param name="value">a uniformly distributed random number<\/param>\r\n\t\/\/\/ <returns>The number of feature points in a cube.<\/returns>\r\n\t\/\/ Generated using mathmatica with "AccountingForm[N[Table[CDF[PoissonDistribution[4], i], {i, 1, 9}], 20]*2^32]"\r\n\tprivate static uint probLookup(uint value)\r\n\t{\r\n\t\tif (value < 393325350) return 1;\r\n\t\tif (value < 1022645910) return 2;\r\n\t\tif (value < 1861739990) return 3;\r\n\t\tif (value < 2700834071) return 4;\r\n\t\tif (value < 3372109335) return 5;\r\n\t\tif (value < 3819626178) return 6;\r\n\t\tif (value < 4075350088) return 7;\r\n\t\tif (value < 4203212043) return 8;\r\n\t\treturn 9;\r\n\t}\r\n\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ Inserts value into array using insertion sort. If the value is greater than the largest value in the array\r\n\t\/\/\/ it will not be added to the array.\r\n\t\/\/\/ <\/summary>\r\n\t\/\/\/ <param name="arr">The array to insert the value into.<\/param>\r\n\t\/\/\/ <param name="value">The value to insert into the array.<\/param>\r\n\tprivate static void insert(float[] arr, float value)\r\n\t{\r\n\t\tfloat temp;\r\n\t\tfor (int i = arr.Length - 1; i >= 0; i--)\r\n\t\t{\r\n\t\t\tif (value > arr[i]) break;\r\n\t\t\ttemp = arr[i];\r\n\t\t\tarr[i] = value;\r\n\t\t\tif (i + 1 < arr.Length) arr[i + 1] = temp;\r\n\t\t}\r\n\t}\r\n\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ LCG Random Number Generator.\r\n\t\/\/\/ LCG: http:\/\/en.wikipedia.org\/wiki\/Linear_congruential_generator\r\n\t\/\/\/ <\/summary>\r\n\t\/\/\/ <param name="lastValue">The last value calculated by the lcg or a seed<\/param>\r\n\t\/\/\/ <returns>A new random number<\/returns>\r\n\tprivate static uint lcgRandom(uint lastValue)\r\n\t{\r\n\t\treturn (uint)((1103515245u * lastValue + 12345u) % 0x100000000u);\r\n\t}\r\n\r\n\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ Constant used in FNV hash function.\r\n\t\/\/\/ FNV hash: http:\/\/isthe.com\/chongo\/tech\/comp\/fnv\/#FNV-source\r\n\t\/\/\/ <\/summary>\r\n\tprivate const uint OFFSET_BASIS = 2166136261;\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ Constant used in FNV hash function\r\n\t\/\/\/ FNV hash: http:\/\/isthe.com\/chongo\/tech\/comp\/fnv\/#FNV-source\r\n\t\/\/\/ <\/summary>\r\n\tprivate const uint FNV_PRIME = 16777619;\r\n\t\/\/\/ <summary>\r\n\t\/\/\/ Hashes three integers into a single integer using FNV hash.\r\n\t\/\/\/ FNV hash: http:\/\/isthe.com\/chongo\/tech\/comp\/fnv\/#FNV-source\r\n\t\/\/\/ <\/summary>\r\n\t\/\/\/ <returns>hash value<\/returns>\r\n\tprivate static uint hash(uint i, uint j, uint k)\r\n\t{\r\n\t\treturn (uint)((((((OFFSET_BASIS ^ (uint)i) * FNV_PRIME) ^ (uint)j) * FNV_PRIME) ^ (uint)k) * FNV_PRIME);\r\n\t}\r\n}\r\n\t<\/pre>\nConclusion<\/h3>\n
I hope this post has provided you with an understanding of what cell noise is and how it can be efficiently implemented. If you are confused about anything above leave a comment or read Steven\u00a0Worley’s paper on cell noise<\/a>.<\/p>\n<\/div>\n <\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"
What is Cell Noise? Cell noise (sometimes called Worley noise)\u00a0is a is a procedural texture primitive like Perlin Noise. Despite its numerous applications there are few good implementations and explanations available online. Perhaps the best way to be introduced to cell noise \u00a0is with a demo.\u00a0By the end of this blog post you will […]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,3,4,6,7],"tags":[],"_links":{"self":[{"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/posts\/64"}],"collection":[{"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/comments?post=64"}],"version-history":[{"count":42,"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/posts\/64\/revisions"}],"predecessor-version":[{"id":143,"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/posts\/64\/revisions\/143"}],"wp:attachment":[{"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/media?parent=64"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/categories?post=64"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aftbit.com\/wp-json\/wp\/v2\/tags?post=64"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}