Guest User

Procedural Texture Generation

a guest
May 16th, 2020
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.40 KB | None | 0 0
  1. ArrayList<Bucket> buckets;
  2. ArrayList<BucketCluster> bucketClusters;
  3. ArrayList<Bucket> selectedBuckets;
  4. ArrayList<Path> paths;
  5.  
  6. int xOffsetInteractive;
  7. int yOffsetInteractive;
  8. float speed = 0.01f;
  9.  
  10. long seed = 0;
  11. int noiseShelf = 20;
  12. int noiseShelfFilter = 5;
  13. int amountOfSampledPoints = 200;
  14.  
  15. int level = 0;
  16.  
  17. interface IEntity
  18. {
  19. public int getX();
  20. public int getY();
  21. }
  22. class Path{
  23. int x1;
  24. int y1;
  25. int x2;
  26. int y2;
  27.  
  28. public Path(int x1, int y1, int x2, int y2)
  29. {
  30. this.x1 = x1;
  31. this.x2 = x2;
  32. this.y1 = y1;
  33. this.y2 = y2;
  34. }
  35. }
  36. class BucketCluster implements IEntity
  37. {
  38. public ArrayList<Bucket> buckets;
  39. public int centerX;
  40. public int centerY;
  41.  
  42. public int getX(){
  43. return centerX;
  44. }
  45. public int getY(){
  46. return centerY;
  47. }
  48.  
  49. public BucketCluster(ArrayList<Bucket> buckets){
  50. this.buckets = buckets;
  51. int sum_x = 0;
  52. int sum_y = 0;
  53. for (int i = 0; i < buckets.size(); i++){
  54. sum_x += buckets.get(i).x;
  55. sum_y += buckets.get(i).y;
  56. }
  57. centerX = round(sum_x / buckets.size());
  58. centerY = round(sum_y / buckets.size());
  59. }
  60. }
  61.  
  62. class Bucket implements Comparable<Bucket>, IEntity{
  63. public int x;
  64. public int y;
  65. public float value;
  66. public int step;
  67. public int getX(){
  68. return x;
  69. }
  70. public int getY(){
  71. return y;
  72. }
  73. public Bucket(int x, int y, float value, int step)
  74. {
  75. this.x = x;
  76. this.y = y;
  77. this.value = value;
  78. this.step = step;
  79. }
  80.  
  81. int compareTo(Bucket other){
  82. if (value > other.value)
  83. return 1;
  84. else if (value < other.value)
  85. return -1;
  86.  
  87. return 0;
  88. }
  89.  
  90. public boolean containsPoint(int x, int y){
  91. boolean output = x - this.x < step
  92. && x - this.x >= 0
  93. && y - this.y < step
  94. && y - this.y >= 0;
  95.  
  96. return output;
  97. }
  98. }
  99.  
  100. void setup(){
  101. size(1000,1000);
  102. textSize(16);
  103. }
  104.  
  105. void draw(){
  106. perlinMap();
  107. fill(0, 255,0);
  108. text("Band Width: " + noiseShelf, 10, 20);
  109. text("Selected Band: " + noiseShelfFilter, 10, 40);
  110. text("Seed: " + seed, 10, 60);
  111. fill(0,0,255);
  112. if (level >= 2)
  113. {
  114. text("Bucket Count: " + buckets.size(), 10, 80);
  115. }
  116. if (level >= 3)
  117. {
  118. text("Bucket Cluster Count: " + bucketClusters.size(), 10, 100);
  119. }
  120. }
  121. void keyPressed(){
  122. if (key == CODED)
  123. {
  124. if (keyCode == UP){
  125. noiseShelf++;
  126. }
  127. else if (keyCode == DOWN){
  128. noiseShelf--;
  129. }
  130. else if (keyCode == LEFT){
  131. noiseShelfFilter--;
  132. }
  133. else if (keyCode == RIGHT){
  134. noiseShelfFilter++;
  135. }
  136. if (keyCode == ALT){
  137. seed = (long)random(1200);
  138. }
  139.  
  140.  
  141.  
  142. }
  143. if (key == 'w'){
  144. yOffsetInteractive++;
  145. }
  146. else if(key == 's')
  147. {
  148. yOffsetInteractive--;
  149. }
  150. if (key == 'a'){
  151. xOffsetInteractive--;
  152. }
  153. else if(key == 'd')
  154. {
  155. xOffsetInteractive++;
  156. }
  157.  
  158. if (key =='e')
  159. {
  160. level++;
  161. }
  162. else if (key == 'q'){
  163. level--;
  164. }
  165.  
  166. }
  167.  
  168. void perlinMap(){
  169. noiseSeed(seed);
  170. baseNoise(0.01, noiseShelf);
  171.  
  172. if (level >= 1)
  173. filterPaths(noiseShelfFilter);
  174. //smooth step
  175. //smoothNoise(width*height);
  176. if (level >= 2)
  177. {
  178. genGrid(20);
  179. java.util.Collections.sort(buckets);
  180. selectBuckets(amountOfSampledPoints);
  181. drawBuckets();
  182. }
  183. //noiseSeed(seed);
  184. //baseNoise(0.01, noiseShelf);
  185. ArrayList<IEntity> toDraw = new ArrayList<IEntity>();
  186. if (level >= 3)
  187. {
  188. mergeBuckets(3);
  189. toDraw.addAll(bucketClusters);
  190. }
  191.  
  192. if (level >= 4)
  193. {
  194. stroke(color(0,255,0));
  195. drawConnections(toDraw, 200.0);
  196. }
  197. }
  198.  
  199. void drawConnections(ArrayList<IEntity> entities, float dist)
  200. {
  201. for (int i = 0; i < entities.size(); i++){
  202. IEntity e1 = entities.get(i);
  203. for (int j = 0; j < entities.size(); j++){
  204. if (e1 == entities.get(j))
  205. continue;
  206.  
  207. IEntity e2= entities.get(j);
  208. if(distance(e1, e2) > dist)
  209. continue;
  210.  
  211. line(e1.getX(), e1.getY(), e2.getX(), e2.getY());
  212. }
  213.  
  214.  
  215. //todo: Test what happens if you use 2-nearest neighbours instead of all in range.
  216. }
  217. }
  218.  
  219. float distance(IEntity e1, IEntity e2)
  220. {
  221. float x1 = e1.getX() - e2.getX();
  222. float y1 = e1.getY() - e2.getY();
  223. return sqrt(x1*x1 + y1*y1);
  224. }
  225.  
  226. void drawBuckets()
  227. {
  228. for (int i = 0; i < selectedBuckets.size(); i++){
  229. Bucket b = selectedBuckets.get(i);
  230. for (int y = b.y; y < b.y + b.step; y++)
  231. {
  232. for (int x = b.x; x < b.x+b.step; x++)
  233. {
  234. pixels[x + y *width] = color(255,0,0);
  235. }
  236. }
  237. }
  238. updatePixels();
  239.  
  240. }
  241.  
  242. void mergeBuckets(int mergeRadius)
  243. {
  244. ArrayList<Bucket> open = new ArrayList<Bucket>();
  245. open.addAll(selectedBuckets);
  246. bucketClusters = new ArrayList<BucketCluster>();
  247.  
  248. for (int i = 0; i < open.size(); i++){
  249. Bucket b = open.get(i);
  250. open.remove(i);
  251. ArrayList<Bucket> neighbours = getNeighbours(b.x, b.y, open, mergeRadius, b.step);
  252. open.removeAll(neighbours);
  253. neighbours.add(b);
  254. bucketClusters.add(new BucketCluster(neighbours));
  255. }
  256.  
  257. for (int i = 0; i< bucketClusters.size(); i++){
  258. BucketCluster bc = bucketClusters.get(i);
  259. rect(bc.centerX, bc.centerY, 15, 15);
  260. }
  261. }
  262.  
  263. ArrayList<Bucket> getNeighbours(int x, int y, ArrayList<Bucket> buckets, int checkRadius, int stepSize){
  264. ArrayList<Bucket> output = new ArrayList<Bucket>();
  265.  
  266. for (int x_o = -checkRadius*stepSize; x_o <= checkRadius*stepSize; x_o+= stepSize)
  267. {
  268. for (int y_o = -checkRadius*stepSize; y_o <= checkRadius*stepSize; y_o+=stepSize)
  269. {
  270. for (int i = 0; i < buckets.size(); i++)
  271. {
  272. if (buckets.get(i).containsPoint(x_o + x, y_o + y))
  273. output.add(buckets.get(i));
  274. }
  275. }
  276. }
  277.  
  278. return output;
  279. }
  280.  
  281. void selectBuckets(int amount){
  282. selectedBuckets = new ArrayList<Bucket>();
  283. int trg = min(buckets.size(), amount);
  284. for (int i = 0; i < trg; i++)
  285. {
  286. Bucket b = buckets.get(i);
  287. selectedBuckets.add(b);
  288.  
  289. }
  290. }
  291.  
  292. void genGrid(int step){
  293. buckets = new ArrayList<Bucket>();
  294. loadPixels();
  295. for (int y = 0; y < height - step; y+=step){
  296. for (int x = 0; x < width - step; x+=step)
  297. {
  298. float sum = 0;
  299. float count = 0.0;
  300. for (int y0 = y; y0 < y + step; y0++)
  301. {
  302. for (int x0 = x; x0 < x + step; x0++){
  303. if (!inBounds(x0, y0))
  304. continue;
  305.  
  306. sum += red(pixels[x0 + y0*width]) / 255.0f;
  307. count++;
  308. //pixels[x0 + y0*width] = color(y*4,x*4,0);
  309. }
  310. }
  311. sum /= count;
  312. buckets.add(
  313. new Bucket(x, y, sum, step));
  314. }
  315. }
  316. updatePixels();
  317. }
  318.  
  319. void filterPaths(int shelfMul){
  320. if (shelfMul <= 0) return;
  321. for(int i = 0; i < width; i++){
  322. for (int j = 0; j < height; j++){
  323.  
  324. if (red(get(i,j)) == noiseShelf*shelfMul)
  325. set(i,j, color(0,0,255/shelfMul));
  326. else
  327. set(i,j, color(255,255,255));
  328. }
  329. }
  330. }
  331.  
  332. void baseNoise(float noiseScale, int noiseShelf){
  333.  
  334. for(int i = 0; i < width; i++){
  335. for (int j = 0; j < height; j++){
  336.  
  337. float nv = noise(xOffsetInteractive *speed + i * noiseScale,yOffsetInteractive * speed + j * noiseScale);
  338. nv *= 255.0;
  339. int cv = (int)nv;
  340. cv /= noiseShelf;
  341. cv *= noiseShelf;
  342. color col = color(cv, cv, cv);
  343. set(i,j, col);
  344. }
  345. }
  346. }
  347. boolean inBounds(int x, int y){
  348. return x >= 0 && x < width && y >= 0 && y < height;
  349. }
  350.  
  351. void smoothNoise(int numPixels){
  352. int off = 2;
  353. loadPixels();
  354. int[] newPixels = new int[pixels.length];
  355. for(int y = 0; y < height; y++){
  356. for (int x = 0; x < width; x++){
  357. color col = get(x,y);
  358. float sum = 0.0;
  359. float count = 0.0;
  360. for (int j1 = y - off; j1 <= y + off; j1++){
  361. for (int i1 = x - off; i1 <= x + off; i1++){
  362. if (i1 == x && j1 == y || !inBounds(i1,j1))
  363. {
  364. continue;
  365. }
  366. color neighbourCol = pixels[i1 + width*j1];
  367. sum += red(neighbourCol);
  368. count += 1.0;
  369. }
  370. }
  371. sum /= 255.0;
  372. float fv = sum / count;
  373. int iv = (int)(fv * 255);
  374. iv = max(iv, 0);
  375. iv = min(iv, 255);
  376. newPixels[x+width*y] = color(iv,iv,iv);
  377. }
  378. }
  379. arrayCopy(newPixels, pixels);
  380. updatePixels();
  381. }
Advertisement
Add Comment
Please, Sign In to add comment