The sketch here is inspired by this page which references “Wilson, J., Robinson, J., & Piggins, D. (1983) Wobble cones and wobble holes: the stereokinetic effect revisited. Perception, 12, 187-193.“. You can change the speed by moving your mouse:
The author notes:
In stereokinetic depth, rotary movement enhances the impression of depth seen in patterns of concentric rings. Typically, rotation creates a vivid impression of a wobbly protruding cone or receding tunnel, or both, as in this demonstration. The effect indicates that the visual system has an in-built assumption that shapes tend to be rigid, and interprets the changing rings as a rigid 3-D shape moving in depth, rather than as an ameoba-like form changing shape.
Stereokinetic depth was actually first described by Musatti (1924; see Zanforlin, 1988). It was also used in the 1920’s by the artist Marcel Duchamp, who called his spinning wobbly discs ‘rotoreliefs’.
See:
- Clara, E., Regolin, L., Zanforlin, M., & Vallortigara, G. (2006). Domestic chicks perceive stereokinetic illusions. Perception, 35, 983-992.
- Shearer, R.R., & Gould, S.J. (1999) Of two minds and one nature. Science, 286, 1093-1094.
Wilson, J., Robinson, J., & Piggins, D. (1983) Wobble cones and wobble holes: the stereokinetic effect revisited. Perception, 12, 187-193. - Zanforlin, M. (1988) The height of a stereokinetic cone: A quantitative determination of a 3-D effect from 2-D moving patterns without a “rigidity assumption”. Psychological Research, 50, 162-172.
Code for the effect follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
float cx,cy,diam; float rotationsPerSecond = 0.5; float angle = 0; void setup() { size(700,600); cx = (width-100)/2 + 100; cy = height / 2; diam = height; } void draw() { noStroke(); int back = 0; background(255); pushMatrix(); translate(cx,cy); angle += 1 / 60.0 / 1 * 2 * PI * rotationsPerSecond; rotate(angle); ellipseMode(CENTER); ellipse(0,0,diam,diam); int outers = 7; float diamshrink = 50; for(int i = 0; i < outers; i++) { float offset = i * diamshrink; fill(back); back = 255 - back; ellipse(offset/2,0,diam - offset, diam - offset); } float cx2 = (outers-1) * diamshrink / 2, cy2 = 0, diam2 = diam - (outers-1)*diamshrink; ellipse(cx2,cy2,5,5); pushMatrix(); translate(cx2,cy2); rotate(PI); int inners = 6; for(int i = 1; i < inners; i++) { float offset = i * diamshrink; fill(back); back = 255 - back; ellipse(offset/2,0,diam2 - offset, diam2 - offset); } popMatrix(); popMatrix(); drawSlider(); } void drawSlider() { rectMode(CENTER); float cx = 100 / 2, cy = height / 2, ch = height - 100, cw = 80; stroke(0); fill(0); rect(cx,cy,5,ch); float sliderY = constrain(mouseY,cy-ch/2,cy+ch/2); rect(cx,sliderY,cw,5); rotationsPerSecond = map(sliderY,cy+ch/2,cy-ch/2,-2,2); textAlign(CENTER,CENTER); textSize(20); text(""+round(rotationsPerSecond*10)/10.0,cx,cy-ch/2-30); } |