08 Three Dimensions

Slideshow Version

Three Dimensions

This module covers a more sophisticated means of creating complexity, through classes of objects.

Readings

Reading 1: In Processing, read “Transform 1: Translate, Matrices”, pgs 133-135

Reading 2: In Processing, read “Transform 2: Rotate, Scale”, pgs 137-143

Reading 3: In Processing, read “Extension2: 3D”, pgs 525-542

Extra Credit: Flatland, A Romance of Many Dimensions, by Edwin Abbott (2nd Edition, 1884) (link)

Assignment

There is no coding assignment this week. Instead students should prepare to describe their Final Project in detail during the next class. Every student will be required to present their ideas, direction, and beginning work.

3D Geometry

Most of Processing’s drawing functions have a 3-dimensional equivalent.

Functions like line() are called “overloaded” because there are two sets of parameters you could possibly pass to it. Processing knows only by the number and type of values you pass it whether to select the 2D or 3D version.
RENDERING MODE

size() does more than determine the size of the sketch. It also determines whether you’re drawing 2-dimensionally or 3-dimensionally.

Default Java2D renderer.


          size( 700, 400 );
          size( 700, 400, JAVA2D );
          

Processing’s 2D renderer.


          size( 700, 400, P2D );
          

Processing’s 3D renderer. Enables 3D support.


          size( 700, 400, P3D );
          

Processing’s OpenGL renderer. This requires importing the OpenGL library.


          size( 700, 400, OPENGL );
          

Some Three-Dimensional Graphics

Getting started in 3D is just a matter of looking at the Processing API for functions that include z values.

Just specify more coordinates for the 3D versions of each function.


          line( x1, y1, z1, x2, y2, z2 );
          vertex( x1, y1, z1 );
          

Coordinates

In the default coordinate system, negative z-values go away from you, and positive ones go toward you.

(In physics one remembers “The Right-hand rule.” In Processing, it may be easy to reverse that…)

Form and Shape

From this point on, the challenge becomes how to represent form through computational means, through the mathematical and logical relationships that can be established by code.

Lines and depth.


          void setup(){
            size(700, 400, P3D);
            stroke(0, 100);
          }
          
          void draw(){
            background(255);
            for( int x=0; x <= width; x+=50 ){
              for( int y=0; y <= height; y+=50 ){
                line(x, y, 0, x, y, mouseY-height/2);
              }
            }
          }
          

Generic spiral.


          void setup(){
            size(700, 400, P3D);
            noFill();
          }
          
          void draw(){
            background(255);
            beginShape();
            for( float r = 0; r < TWO_PI*20; r += 0.1 ){
              vertex( 200*cos(r), 200*sin(r), -r*10 );
            }
            endShape();
          }
          

Default Coordinate System

Translation

Translation – example 01


            int circleRadius = 190;
          
            void setup(){
              size(700, 400);
              noFill();
            }
          
            void draw(){
              background(255);
              float f = frameCount/20.0;
                 //move the coordinate system to the center
              translate(width/2, height/2);
                 //move the coordinate system to a point on a circle
              translate(sin(f)*circleRadius, cos(f)*circleRadius);
              rect(-15,-15,30,30);
          
               println ("The frame count is " + frameCount + ", so I'm using f as " + f + ", and the sin is " + sin(f) );
            }
          

Translation – example 02 – with Classes

Classes are usually written to have their own draw() function. When paired with changes in coordinate systems, this can create a very powerful workflow. In this case, the “planet” need not know where it is, merely how to draw itself.


            int circleRadius = 190;
            myRect planet;
          
            void setup() {
              size(700, 400);
              noFill();
              planet = new myRect(60);
            }
          
            void draw() {
              background(255);
              float f = frameCount/20.0;
                 //move the coordinate system to the center
              translate(width/2, height/2);
                 //move the coordinate system to a point on a circle
              translate(sin(f)*circleRadius, cos(f)*circleRadius);
                 //have the class draw itself.
              planet.drawRect();
              
              println ("The frame count is " + frameCount + ", so I'm using f as " + f + ", and the sin is " + sin(f) );
            }
          
            class myRect {
              int size;
              myRect(int s) {
                size = s;
              }
              void drawRect() {
                rect(-size/2, -size/2, size/2, size/2);
              }
            }
          
          

Rotation

Rotation – example 01


            void setup() {
              size(700, 400);
              noFill();
            }
          
            void draw() {
              background(255);
              float f = frameCount/20.0;
                 //move the coordinate system to the center
              translate(width/2, height/2);
                 //rotate the coordinate system to the center
              rotate (f);
              rect(0,0,30,30);
            }
          

Rotation – example 02 – with Classes


            int circleRadius = 190;
            myRect planet;
          
            void setup() {
              size(700, 400);
              noFill();
              planet = new myRect(60);
            }
          
            void draw() {
              background(255);
              float f = frameCount/20.0;
                 //move the coordinate system to the center
              translate(width/2, height/2);
                 //move the coordinate system to a point on a circle
              translate(sin(f)*circleRadius, cos(f)*circleRadius);
                 //rotate the coordinate system
              rotate(f);
                 //have the class draw itself.
              planet.drawRect();
            }
          
            class myRect {
              int size;
              myRect(int s) {
                size = s;
              }
              void drawRect() {
                rect(-size/2, -size/2, size/2, size/2);
              }
            }
          

Rotation – example 03 – CRAZY with Classes

Let’s draw a “planet” orbiting, with a “moon” orbiting it, and another “moon” orbiting the first:


            int circleRad1 = 180;
            int circleRad2 = 80;
            int circleRad3 = 60;
          
            myRect planet1;
            myRect planet2;
            myRect planet3;
          
            void setup() {
              size(800, 600);
              noFill();
              planet1 = new myRect(40);
              planet2 = new myRect(20);
              planet3 = new myRect(10);
            }
          
            void draw() {
              background(255);
              float f1 = frameCount/40.0;
              float f2 = frameCount/25.0;
              float f3 = frameCount/15.0;
                 //move the coordinate system to the center
              translate(width/2, height/2);
          
                 //rotate the coordinate system
              rotate(f1);
                 //translate out the orbital radius
              translate(circleRad1,0);
                 //have the class draw itself.
              planet1.drawRect();
          
              // HEY WHILE WERE HERE LET'S DRAW THE MOON!...
          
                 //rotate the coordinate system FOR A MOON
              rotate(f2);
                 //translate out the orbital radius
              translate(circleRad2,0);
                 //have the class draw itself.
              planet2.drawRect();
          
              // LET'S GIVE THE MOON A MOON!...
          
                 //rotate the coordinate system FOR A MOON
              rotate(f3);
                 //translate out the orbital radius
              translate(circleRad3,0);
                 //have the class draw itself.
              planet3.drawRect();
            }
          
            class myRect {
              int size;
              myRect(int s) {
                size = s;
              }
              void drawRect() {
                rect(-size/2, -size/2, size/2, size/2);
              }
            }
          
          

Rotation – example 03 – CRAZY with Classes

That was some messy code. We’re not using Classes to organize the data. Let’s try to organize this…


            int numPlanets = 5;
            Planet[] planets = new Planet[ numPlanets ];
          
            void setup() {
              size( 800, 800);
              for (int i=0; i < numPlanets; i++) {
                float r;
                if(i==0){r=0;}else{r=160-(i-1)*30;}
                planets[i] = new Planet( 105.0-(i*20), r );
              }
            }
          
            void draw() {
              background(255);
              float f = frameCount/80.0;
          
              translate(width/2, height/2);
          
              for (int i=0; i < numPlanets; i++) {
                rotate(f*i);
                translate(planets[i].orbitRad, 0);
                planets[i].drawRect();
              }
            }
          
            class Planet {
              float rectSize;
              float orbitRad;
          
              Planet(float s, float r) {
                rectSize = s;
                orbitRad = r;
              }
              void drawRect() {
                rect(-rectSize/2, -rectSize/2, rectSize/2, rectSize/2);
              }
            }
          

Scaling

Scaling – example 01


          void setup() {
            size(700, 500);
          }
          
          void draw() {
            background(255);
            rect(200,200,250,200);
            scale( abs(sin(frameCount*.01) ) );
            rect(200,200,250,200);
            println( sin(frameCount*.01) );
          }
          

Scaling – example 02 – map()

The map() function comes in handy with rotate() and scale(). Let’s look at an example…


          void setup() {
            size(700, 500);
          }
          
          void draw() {
            background(255);
            rect(200,200,250,200);
            scale( map(mouseX, 0, width, 0, 1) );
            rect(200,200,250,200);
          }
          

Order Matters : Translation + Rotation


            stroke(255,0,0);
            rotate(-PI/4);
            translate(width/2,height/2);
            rect(15,15,-15,-15);
          

Order Matters : Rotation + Translation


            stroke(255,0,0);
            translate(width/2,height/2);
            rotate(-PI/4);
            rect(15,15,-15,-15);
          

Push/Pop Stack

Push to Remember, then Pop to Restore

pushMatrix() popMatrix() + 3D


          void setup() {
            size(700, 500, P3D);
          }
          
          void draw() {
            background(255);
            translate(width/2, height/2); 
            
            pushMatrix(); 
            translate( sin(frameCount*.01)*300, 0, 0 );
            rotate( sin(frameCount*.1) );
            box(40);
            popMatrix();
            
            pushMatrix();
            rotate( sin(frameCount*.1) );
            translate( sin(frameCount*.01)*300, 0, 0 );
            box(40);
            popMatrix();
            
            box(40);
            
          }
          

Going 3D

3D Rotations

3D Rotations – Phyllotaxis Example


          int numDots = 400;
          float ellipseSize = 12;
          float rot = 0;
          
          float r; //radius
          float c; //constant scaling factor
          float n; //index number of the floret 
          
          
          void setup() {
            size(700, 500, P3D);
            c = 10;
          }
          
          void draw() {
            background(255);
            fill(0,0,255,150);
            //ellipseSize = ellipseSize + sin(frameCount*.01)*10;
            //c = c + sin(frameCount*.02)*10;
            
            translate(width/2, height/2); 
            for(n=0; n < numDots; n++){
              pushMatrix();
              
              r = c * sqrt(n);
              float angle = n * 137.5;
              
              rotate( radians(angle) );
              translate(r,0,0);
              
              rotateX( sin(frameCount*.04)*2  );
              ellipse(-ellipseSize, -ellipseSize, ellipseSize, ellipseSize);
              popMatrix();
            }
            
            ellipseSize = 12;
            c = 10;
          }
          

Now, let’s push this pattern into 3D…

Pyllo-3D (The Gurkin)


          int numDots = 500;
          float ellipseSize = 12;
          float rot = 0;
          
          float r; //radius
          float c; //constant scaling factor
          float n; //index number of the floret 
          
          
          void setup() {
            size(700, 500, P3D);
            c = 10;
          }
          
          void draw() {
            background(255);
            fill(0,0,255,240);
            c = c + sin(frameCount*.02)*10;
            
            translate(width/4, height/2); 
            for(n=0; n < numDots; n++){
              pushMatrix();
              
              r = c * sqrt(n);
              float angle = n * 137.5;
              
              rotateY(PI/3);
              rotate( radians(angle) );
              translate(r,0,(r*r)/100);
              
              rotateX( (frameCount*.04) );
              rotateY( (frameCount*.04) );
              box(10);
              popMatrix();
            }
            
            ellipseSize = 12;
            c = 10;
          }
          

3D Rotations – Orbits (Again)

Remember the Planets from earlier? Let’s add on 3D Rotation…


            int numPlanets = 6;
            Planet[] planets = new Planet[ numPlanets ];
          
            void setup() {
              size( 800, 800, P3D);
              for (int i=0; i < numPlanets; i++) {
                float r;
                if(i==0){r=0;}else{r=160-(i-1)*30;}
                planets[i] = new Planet( 105.0-(i*20), r );
              }
            }
          
            void draw() {
              background(250);
              float f = frameCount/80.0;
          
              translate(width/2, height/2);
          
              for (int i=0; i < numPlanets; i++) {
                rotate(f*i);
                rotateY(f*i); // THIS IS THE ONLY REAL CHANGE!
                translate(planets[i].orbitRad, 0);
                planets[i].drawBox();
              }
            }
          
            class Planet {
              float boxSize;
              float orbitRad;
          
              Planet(float s, float r) {
                boxSize = s;
                orbitRad = r;
              }
              void drawBox() {
                box(boxSize);
              }
            }
          

Complexity Through Conflation