2
0

Noise.pas 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. unit Noise;
  2. interface
  3. uses
  4. SysUtils, Math;
  5. const
  6. kNoisekPerumationMax = 256;
  7. type
  8. TNoiseValue = byte;
  9. TNoiseSeedArray = array[0..kNoisekPerumationMax-1] of TNoiseValue;
  10. TNoiseFloat = double;
  11. type
  12. TNoise = class (TObject)
  13. public
  14. constructor Create; overload;
  15. constructor Create (seed: TNoiseSeedArray); overload;
  16. function GetValue (x, y, z: TNoiseFloat): TNoiseFloat; overload;
  17. function GetValue (x, y, z: TNoiseFloat; octaves: integer; persistence: TNoiseFloat): TNoiseFloat; overload;
  18. function GetNoise (x, y: integer; width, height: integer; scale: TNoiseFloat; frequency: integer): TNoiseFloat; overload;
  19. private
  20. repeatValue: integer;
  21. p: array[0..(kNoisekPerumationMax * 2)-1] of TNoiseValue;
  22. function Inc (num: integer): integer; inline;
  23. function Grad (hash: integer; x, y, z: TNoiseFloat): TNoiseFloat; inline;
  24. function Fade (t: TNoiseFloat): TNoiseFloat; inline;
  25. function Lerp (a, b, x: TNoiseFloat): TNoiseFloat; inline;
  26. end;
  27. function RandomNoiseSeed (seed: cardinal = 0): TNoiseSeedArray;
  28. implementation
  29. function RandomNoiseSeed (seed: cardinal = 0): TNoiseSeedArray;
  30. var
  31. i: integer;
  32. begin
  33. for i := 0 to kNoisekPerumationMax - 1 do
  34. result[i] := Random(kNoisekPerumationMax);
  35. end;
  36. function TNoise.GetValue (x, y, z: TNoiseFloat; octaves: integer; persistence: TNoiseFloat): TNoiseFloat;
  37. var
  38. total: TNoiseFloat = 0;
  39. frequency: TNoiseFloat = 1;
  40. amplitude: TNoiseFloat = 1;
  41. maxValue: TNoiseFloat = 0; // Used for normalizing result to 0.0 - 1.0
  42. i: integer;
  43. begin
  44. for i := 0 to octaves - 1 do
  45. begin
  46. total += GetValue(x * frequency, y * frequency, z * frequency) * amplitude;
  47. maxValue += amplitude;
  48. amplitude *= persistence;
  49. frequency *= 2;
  50. end;
  51. result := total/maxValue;
  52. end;
  53. function TNoise.GetNoise (x, y: integer; width, height: integer; scale: TNoiseFloat; frequency: integer): TNoiseFloat;
  54. var
  55. nx, ny: TNoiseFloat;
  56. begin
  57. nx := x/width - 0.5;
  58. ny := y/height - 0.5;
  59. result := GetValue(nx * scale, ny * scale, 0, frequency, 0.5) / 2 + 0.5;
  60. end;
  61. function TNoise.GetValue (x, y, z: TNoiseFloat): TNoiseFloat;
  62. function FMod(const a, b: TNoiseFloat): TNoiseFloat;
  63. begin
  64. result:= a-b * trunc(a/b);
  65. end;
  66. var
  67. xi, yi, zi: integer;
  68. xf, yf, zf: TNoiseFloat;
  69. u, v, w: TNoiseFloat;
  70. aaa, aba, aab, abb, baa, bba, bab, bbb: integer;
  71. x1, x2, y1, y2: TNoiseFloat;
  72. begin
  73. // If we have any repeat on, change the coordinates to their "local" repetitions
  74. if (repeatValue > 0) then
  75. begin
  76. x := FMod(x, repeatValue);
  77. y := FMod(y, repeatValue);
  78. z := FMod(z, repeatValue);
  79. // ??? mod overloading for singles in trunk 3.1.1
  80. {x := x mod repeatValue;
  81. y := y mod repeatValue;
  82. z := z mod repeatValue;}
  83. end;
  84. xi := Floor(x) and 255; // Calculate the "unit cube" that the point asked will be located in
  85. yi := Floor(y) and 255; // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
  86. zi := Floor(z) and 255; // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube.
  87. xf := x-Floor(x); // We also fade the location to smooth the result.
  88. yf := y-Floor(y);
  89. zf := z-Floor(z);
  90. u := Fade(xf);
  91. v := Fade(yf);
  92. w := Fade(zf);
  93. aaa := p[p[p[ xi ]+ yi ]+ zi ];
  94. aba := p[p[p[ xi ]+self.Inc(yi)]+ zi ];
  95. aab := p[p[p[ xi ]+ yi ]+self.Inc(zi)];
  96. abb := p[p[p[ xi ]+self.Inc(yi)]+self.Inc(zi)];
  97. baa := p[p[p[self.Inc(xi)]+ yi ]+ zi ];
  98. bba := p[p[p[self.Inc(xi)]+self.Inc(yi)]+ zi ];
  99. bab := p[p[p[self.Inc(xi)]+ yi ]+self.Inc(zi)];
  100. bbb := p[p[p[self.Inc(xi)]+self.Inc(yi)]+self.Inc(zi)];
  101. x1 := Lerp( Grad(aaa, xf , yf , zf), // The gradient function calculates the dot product between a pseudorandom
  102. Grad(baa, xf-1, yf , zf), // gradient vector and the vector from the input coordinate to the 8
  103. u); // surrounding points in its unit cube.
  104. x2 := Lerp( Grad(aba, xf , yf-1, zf), // This is all then lerped together as a sort of weighted average based on the faded (u,v,w)
  105. Grad(bba, xf-1, yf-1, zf), // values we made earlier.
  106. u);
  107. y1 := Lerp(x1, x2, v);
  108. x1 := Lerp( Grad(aab, xf , yf , zf-1),
  109. Grad(bab, xf-1, yf , zf-1),
  110. u);
  111. x2 := Lerp( Grad(abb, xf , yf-1, zf-1),
  112. Grad(bbb, xf-1, yf-1, zf-1),
  113. u);
  114. y2 := Lerp(x1, x2, v);
  115. result := (Lerp(y1, y2, w)+1)/2; // For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1)
  116. end;
  117. function TNoise.Inc (num: integer): integer;
  118. begin
  119. num += 1;
  120. if repeatValue > 0 then
  121. num := num mod repeatValue;
  122. result := num;
  123. end;
  124. // http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html
  125. function TNoise.Grad (hash: integer; x, y, z: TNoiseFloat): TNoiseFloat;
  126. begin
  127. case (hash and $F) of
  128. $0:
  129. result := x + y;
  130. $1:
  131. result := -x + y;
  132. $2:
  133. result := x - y;
  134. $3:
  135. result := -x - y;
  136. $4:
  137. result := x + z;
  138. $5:
  139. result := -x + z;
  140. $6:
  141. result := x - z;
  142. $7:
  143. result := -x - z;
  144. $8:
  145. result := y + z;
  146. $9:
  147. result := -y + z;
  148. $A:
  149. result := y - z;
  150. $B:
  151. result := -y - z;
  152. $C:
  153. result := y + x;
  154. $D:
  155. result := -y + z;
  156. $E:
  157. result := y - x;
  158. $F:
  159. result := -y - z;
  160. otherwise
  161. result := 0; // never happens
  162. end;
  163. end;
  164. {
  165. function TNoise.Grad (hash: integer; x, y, z: TNoiseFloat): TNoiseFloat;
  166. var
  167. h: integer;
  168. u, v: TNoiseFloat;
  169. begin
  170. h := hash and 15; // Take the hashed value and take the first 4 bits of it (15 == 0b1111)
  171. if h < 8 then
  172. u := x
  173. else
  174. u := y;
  175. if h < 4 then
  176. v := y
  177. else if (h = 12) or (h = 14) then
  178. v := x
  179. else
  180. v := z;
  181. if h and 1 = 0 then
  182. result := u
  183. else
  184. result := -u;
  185. if h and 2 = 0 then
  186. result := result + v
  187. else
  188. result := result - v;
  189. end;
  190. }
  191. function TNoise.Fade (t: TNoiseFloat): TNoiseFloat;
  192. begin
  193. // Fade function as defined by Ken Perlin. This eases coordinate values
  194. // so that they will "ease" towards integral values. This ends up smoothing
  195. // the final output.
  196. result := t * t * t * (t * (t * 6 - 15) + 10); // 6t^5 - 15t^4 + 10t^3
  197. end;
  198. function TNoise.Lerp (a, b, x: TNoiseFloat): TNoiseFloat;
  199. begin
  200. result := a + x * (b - a);
  201. end;
  202. constructor TNoise.Create;
  203. begin
  204. Create(RandomNoiseSeed);
  205. end;
  206. constructor TNoise.Create (seed: TNoiseSeedArray);
  207. var
  208. i: integer;
  209. begin
  210. repeatValue := -1;
  211. for i := 0 to high(p) do
  212. p[i] := seed[i mod kNoisekPerumationMax];
  213. end;
  214. end.