This is exactly the kind of terrain I've been trying to explore lately, without making any progress.

I'll be studying this.

Thank you.

/*-------------------------------------------------------------------------------------------------------------------------------- Noise Based Warping Explorer Ale González · 2012 · Dominio Público | Public Domain ---------------------------------------------------------------------------------------------------------------------------------- A explorer of noise based warping, as explained here: http://www.iquilezles.org/www/articles/warp/warp.htm And as pointed out here: http://amnonp5.wordpress.com/2012/06/17/playing-with-glsl-in-processing/ ---------------------------------------------------------------------------------------------------------------------------------- The process as described basically by Iñigo: "Say you have some geometry or image defined as a function of space. For geometry, that would be a function of the form f(x,y,z) and for an image it would be f(x,y). We can just write both cases more compactly as f(p), where p is the position in space for which we can evaluate the volumetric density that will define our (iso)surface or image color. Warping simply means we distort the domain with another function g(p) before we evaluate f. Basically, we replace f(p) with f(g(p)). g can be anything, but often we want to distort the image of f just a little bit with respect its regular behabiour. Then, it makes sense to have g(p) being just the identiy plus a small arbitary distortion h(p), or in other words, g(p) = p + h(p), meaning we will be computing f( p + h(p) ) This technique is really powerful and allows you to shape apples, buildings, animals or any other thing you might imagine. For the purpose of this article, we are going to work only with fbm based patterns, both for f ang h. This will produce some abstract but beautiful images with a pretty organic quality to them." ---------------------------------------------------------------------------------------------------------------------------------- Thanks to both, Íñigo and Amnon, for dedicating so much time to share. ;-) ---------------------------------------------------------------------------------------------------------------------------------- Font: 'sw!ft' by orgdot, as shared on dafont, http://www.dafont.com/orgdot.d518. Thanks again! --------------------------------------------------------------------------------------------------------------------------------*/ /* Global variables and objects */ //Canvas size final int W= 500, H= 500; //A font to output frameRate PFont theFont; //Default level of recursion and text properties int level = 1, txt_x = 25, txt_y = 25, txt_c = 0xddffff00, txt_s = 10; //default values to instantiate the noise domain and warper objects float perlin_x= .01, perlin_y= .01, simplex_x= .0045, simplex_y= .0045, min_V = -1f, max_V = 1f, vK=4f; boolean moving = false, hud = true; DomainStrategy domain; DomainWarper warper; /* Main methods */ void setup(){ size (W,H,P2D); cursor (CROSS); domain = new Perlin (255, perlin_x, perlin_y); warper = new DomainWarper (level, min_V, max_V, vK); textFont (loadFont("SWFTv01-16.vlw"), txt_s); fill (txt_c); } void draw(){ loadPixels(); if (moving) {warper.x2--; warper.y1++;} //Iterate over screen pixels for (int y=0, yW=0; y<H; y++, yW+=W) { for(int x=0; x<W; x++) { //And use domain values (v) to set grayscale values to them, using the domain function provided int v = (int) warper.getValue (x,y, domain); pixels[x+yW] = v<<16|v<<8|v; } } updatePixels(); if (hud) text ("Level: " + level + " - K: " + vK + " - Framerate: " + nfc(frameRate,2), txt_x, txt_y); } /* Some interaction here: · Move mouse to shift the warping, acting onto one of the vectors that define the parent of the tree structure · Keys: '1' : use Perlin noise based domain '2' : use Simplex noise based domain 'Up' : increase level of recursion (up to 5) 'Down' : decrease level of recursion (down to 0). */ void mousePressed(){ switch (mouseButton) { case (LEFT): moving= !moving; break; case (RIGHT): hud = !hud; break; } } void keyPressed(){ if (key!=CODED) { switch (key) { case (KeyEvent.VK_1) : //key '1' constant value as implemented in KeyEvent Java class domain = new Perlin (255, perlin_x, perlin_y); break; case (KeyEvent.VK_2) : //... domain = new Simplex (255, simplex_x, simplex_y); break; } } else { if (keyCode==UP && level<10) warper= new DomainWarper (++level, min_V, max_V, vK); else if (keyCode==DOWN && level>1) warper= new DomainWarper (--level, min_V, max_V, vK); else if (keyCode==RIGHT && vK<=10) warper= new DomainWarper (level, min_V, max_V, ++vK); else if (keyCode==LEFT && vK>=0) warper= new DomainWarper (level, min_V, max_V, --vK); } }

/* A domain-based compound warper. Each possible level of recursion is encapsulated in a warper object inside a unary tree structure */ class DomainWarper { //Each warping level is 'described' by two points, defined by the vectors: v1{x1,y1} and v2{x2,y2} //k is a constant that scales the effect of the correspondent recursion level float x1, y1, x2, y2, k; //Further depth level, only accesible from its direct parent private DomainWarper child; /* Constructors */ //Create a custom warper from given parameters DomainWarper (float x1, float y1, float x2, float y2, float k) { this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; this.k=k; child = null; } //Create a warper of given depth, defined at each level by a given k and random vectors, //using a float range minV<-->maxV. DomainWarper (int level, float minV, float maxV, float k){ x1= random (minV, maxV); y1= random (minV, maxV); x2= random (minV, maxV); y2= random (minV, maxV); this.k=k; if(--level>0) this.addLevel (new DomainWarper(level, minV, maxV, k)); } /* Methods */ /* To add recursively a new level, defined by a Warper child: If the node is a leaf, add it the new child, else traverse its children until a leaf is found and the warper is finally added to this one */ void addLevel (DomainWarper rw) { if (child==null) child=rw; else child.addLevel (rw); } /* This method calculates recursively the sum of associated vectors of parent node and its children. The associated vector of a warper object is defined by calculating its coordinates as the result of applying the domain algorithm to p{x,y}+v1 and p+v2, scaled by the k coefficient afterwards. */ PVector getLevelVector (int x, int y, DomainStrategy domain) { PVector levelVector = new PVector (domain.getValue (x+x1, y+y1) *k, domain.getValue (x+x2, y+y2) *k); if (child!=null) levelVector.add (child.getLevelVector (x, y, domain)); return levelVector; } /* The main output of the object is this value, result of applying the domain algorithm to the associated vector of the parent of the tree */ float getValue (int x, int y, DomainStrategy domain) { PVector v = getLevelVector (x, y, domain); return domain.getValue (x+v.x, y+v.y); } }

/* Interface DomainStrategy. I have preferred to encapsulate different domain math algorithms in objects implementing this interface in order to be easily extended, keeping clean the warper class. */ interface DomainStrategy { float getValue (float x, float y); } /* This one uses Perlin noise as ported to P5 by Toxi from the original implementation by german demo group Farbrausch: http://www.farb-rausch.de/fr010src.zip Original implementation: Ken Perlin, 1984 */ class Perlin implements DomainStrategy { float magnitude, kX, kY; Perlin (float magnitude, float kX, float kY) { this.magnitude = magnitude; this.kX = kX; this.kY = kY; } float getValue (float x, float y) { return magnitude * noise (kX*x, kY*y); } } /* Simplex noise as implemented by Toxi in his Math library, and as described in this paper by Stefan Gustavson: http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf. Original implementation: Ken Perlin, 2001 http://mrl.nyu.edu/~perlin/paper445.pdf Siggraph 2002 paper explaining the new algorithm http://mrl.nyu.edu/~perlin/noise/ the raw code -- quite hardcoded, compact, beautiful... and absolutely impenetrable :-) */ import toxi.math.noise.SimplexNoise; class Simplex implements DomainStrategy { float magnitude, kX, kY; Simplex (float magnitude, float kX, float kY) { this.magnitude = magnitude; this.kX = kX; this.kY = kY; } float getValue (float x, float y) { //Simplex yields values from -1d to 1d unlike standard P5 noise implementation (that gives values from 0 to 1f), //so this object yields the absolute value casted to float: return magnitude * abs((float) SimplexNoise.noise(kX*x, kY*y)); } }

Report Sketch

Report for inappropriate content

Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

This sketch tries to go deep into noise based warping, a technique described by Iñigo Quilez here:

http://www.iquilezles.org/www/articles/warp/warp.htm

and pointed out by Amnon Owed here:

http://amnonp5.wordpress.com/2012/06/17/playing-with-glsl-in-processing/

(Thanks to both)

I've done the sketch as an exercise that tries to understand the technique and to observe the effect of the different parameters involved in the final result. I've designed it with this objective in mind, so it isn't a much efficient design for real time animations.

R.A. Robertson

4 Sep 2012

4 Sep 2012

Absolutely amazing.

This is exactly the kind of terrain I've been trying to explore lately, without making any progress.

I'll be studying this.

Thank you.

This is exactly the kind of terrain I've been trying to explore lately, without making any progress.

I'll be studying this.

Thank you.

1 Sep 2012

- Key UP -- Add a domain

- Key DOWN -- Remove it

- Key RIGHT -- Increase the coeficient that scales the effect of each domain into the whole

- Key LEFT -- Decrease it

- Key 1 -- Standard P5 Perlin noise

- Key 2 -- Simplex Noise

- Mousebutton LEFT -- Toggle animating the vectors that define the domain

- Mousebutton RIGHT -- Toggle showing the Info

Conclusions:

- If you want to get rich effects for real time is best to increase the coefficient (vK in the Code) instead of increasing the level of complexity. Maths are very expensive here.

- Simplex is by far more efficient than simple noise but the effect is less interesting in organic terms.

- For real-time is better to use a LUT approach, storing in a PVector[level][x][y] all level vectors. This increases x2 the framerate although is quite expensive in memory terms, so it isn't a useful approach (for instance) to get hi-res pictures. It'd be a good exercise to create a general-purpose design for the class Warper.

Font: 'sw!ft' by orgdot, as shared on dafont, http://www.dafont.com/orgdot.d518. Thanks again!