Fake 3D: Stereokinetic Depth

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: [raw] [/raw] 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:
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);
}

Leave a Reply

Your email address will not be published. Required fields are marked *