Tutorial for Processing 3D: beginShape, endShape, vertex, texture, millis The Processing language supports creations of surfaces with texture provided by images. These textured surfaces can be rotated, displayed in different ways, by rotating the axes. I use the mouse coordinates when the mouse button is pressed to specify the amount of the rotation. In order to restore the original orientation of the axes, I arranged to check for a timing delay: if no mouse pressed has happened after a set amount of time, the original orientation of the axes is restored. The millis function returns the number of milliseconds since the start of the running of a sketch. This application demonstrates these features. The image below shows the opening display screen. The screen shows 4 shapes, 3 vertical walls with texture from an image called fruits and one oriented horizontally with texture from an image called ground. The back wall has the image elongated to fit its area. The next screen shot shows the shape rotated after I have clicked the mouse. The coordinates of the mouse when pressed is used to calculate values for the rotations around the X axis and around the Y axis. Each iteration of draw rotates the virtual world around the x-axis and around the y-axis. When the system detects no mouse presses for a certain interval of time, the rotation values are reset to zero. I encourage readers to experiment with the values of the 4 shapes and the expression for the rotations to gain familiarity with the 3D space. Shape and texture Textures are applied to shapes. The texture function takes as its argument a PImage. The PImage datatype has been shown in previous tutorials. The coding involves a declaration statement and an assignment statement: PImage fruit; fruit = loadImage("fruit.jpg"); [See also createImage.] Use the Sketch/Add file…. to move a copy of the image file to the data folder within the sketch folder. This sketch has two textures, fruit and ground and so I needed to do the coding and adding the file for each one. Shapes are set up using the beginShape and endShape commands. There are different modes for shapes. This application uses the default mode: no arguments for beginShape or endShape. Between the calls to beginShape and endShape, I coded a call to texture to specify the texture for the shape, and then 4 calls to vertex, thus specifying a rectangle in space. A call to vertex: vertex(x,y,z,u,v) specifies a point in 3D, x, y, z, and a point in the 2D image, u,v. The Processing system interpolates between these points. What I coded was pretty straight-forward: the upper left corner of the image is to be mapped to (think of it as tacking on) the upper left corner of the shape; the upper right corner of the image is to be mapped to the upper right corner of the shape, and so on. Rotating around an axis Processing 3D sets up a virtual world defined by x, y, and z coordinates. The x axis default position starts at the upper left corner and increasing moving horizontally. The y axis starts at the upper left corner and increases moving up vertically. The z axis starts at the upper left corner and moves away from the viewer. The display is defined in terms of many factors, including a camera position, type of projection (perspetive), focal point, and lights. This sketch only changes to orientation of the virtual world by rotating the x and y axes. Rotating the world around the x axis has the appearance of tipping the shape as shown in the screen shot. Similarly, rotating the world around the y axis, turns the shape around. Each mouse click specifies settings for x and y rotations. The following screen shot shows significant rotations in both axes: The most intuitive way to turn mouse clicks into rotations is subject to debate. Processing supplies the mousePress() function that is invoked each time the mouse button is pressed. Processing also supplies a function called map that converts numbers from one range of values to another. This means that a value between 0 and width, say, that would be the range of mouseX, can be translated into a value from –PI to PI. In the radian system of angles, PI is what we call doing a 180, a U turn and –PI and PI would leave the coordinates in the same state. I chose to make the mouseX position map to -PI to PI and make this change the Y rotation. I mapped to mouseY position to map to PI to –PI (note the sign change) and make this change the rotation around X. This made a click on the upper part of the screen push the object back into the screen and a click on the right side of the display screen push the right side back. I include in the code a println command to display the rotX and rotY values. Examine the code and change the numbers and comment out lines to just change along one or the other dimension to improve your feeling for the spatial relationships. The draw function uses background to erase (repaint) the display screen. It invokes translate to move the coordinates to the middle of the screen: translate(width/2, height/2); The width and height are built in variables indicating the width and heighr as specified by the size call. The code in the draw function does the two rotations based on the values of two variables, rotX and rotY. The code draws the shapes. All of this is done each frame. That is, the shapes do not persist as objects, but are re-drawn each time draw is invoked. Time delay After experimenting with the rotations, I realized I needed to get back to the original orientation. This was a good excuse to see how to handle timing. The millis function returns the number of milliseconds since the application/applet started. By invoking the function and saving the time of each invocation, I can write code to calculate if there has been an interval of at least a specified time since the last mouse press. A variable last is initialized to millis() in the setup function. A variable rest is set to 3000, 3 seconds. In the mousePressed function, last = millis(); In the draw function, millis is invoked each time so see if a long enough interval has passed. The code is if ((millis()-last)>rest) { } This means: calculate the difference between now (this is millis()) and last. Is it greater than rest, the time specified to be long enough? If yes, do something. Implementing Topsy-turvy fruit The code for this application requires two image files to be added to the sketch data folder using Sketch/Add file… These images were each manipulated to be close to 100 by 100 pixels. The Sketch includes definitions for the 3 Process defined functions: setup, draw and mousePressed. The Sketch has 6 global variables. PImage ground, fruit; float rotX, rotY; float last; float rest; void setup() { size(1000,600,P3D); ground = loadImage("leaves.jpg"); fruit = loadImage("fruit.jpg"); last = millis(); rest = 3000; frameRate(4); } void draw() { background(255); translate(width/2, height/2); if ((millis()-last)>rest) { rotY = 0; rotX = 0; } rotateY(rotY); rotateX(rotX); beginShape(); texture(fruit); vertex (-100,-100,0,0,0); vertex (200,-100,0,100,0); vertex (200,100,0,100,100); vertex(-100,100,0,0,100); endShape(); beginShape(); texture(fruit); vertex (-100,-100,200,0,0); vertex (-100,-100,0,100,0); vertex (-100,100,0,100,100); vertex(-100,100,200,0,100); endShape(); beginShape(); texture(fruit); vertex (200,-100,0,0,0); vertex (200,-100,200,100,0); vertex (200,100,200,100,100); vertex(200,100,0,0,100); endShape(); beginShape(); texture(ground); vertex (-100,100,0,0,0); vertex (200,100,0,100,0); vertex (200,100,200,100,100); vertex(-100,100,200,0,100); endShape(); } void mousePressed() { rotY =map(mouseX, 0, width, -PI, PI); rotX =map(mouseY, 0, height, -PI,PI); println("rotY is "+degrees(rotY)+" rotX is "+degrees(rotX)); last = millis(); } Exercises 1. Read in the reference section and change the shapes to other modes, such as TRIANGLES. 2. Change the coding to rotate just around X and then to just around Y. THEN make the change to toggle between the two by using a variable boolean changey = true; When this is true, make the changes for rotY; otherwise, make the change to rotX. Then change (toggle) changey = !changey 3. You can combine drawing spheres and boxes with shapes. Try it! .