The following source code will create a truncated cube with the P3D renderer using beginShape()…endShape() with multiple vertices. Since it is difficult to add components to a GLWindow a separate JFrame controller window with Swing components was used. Two sliders provide alteration of cube size and crop length. Exploration with various settings result in interesting outputs. Cube rotation is achieved by click dragging the mouse in the main window. The control window is not closable; the app may be quit by closing the main window or hitting the ‘Quit’ button in the controller window. Using ‘Cmd-Q’ on a Mac will cause the runtime to hang due to thread destruction. This demo was developed on MacOS and has not been tested on other platforms.
Source code:
// LT = left top : RT = right top : RB = right bottom : LB = left bottom
import javax.swing.*;
import javax.swing.event.*;
float rotx = PI/4;
float roty = PI/4;
int s = 150;
int crop = s/2;
void buildControllerWnd() {
JFrame frame = new JFrame("Controller Wnd");
frame.setLayout(null);
frame.setBounds(50, 100, 300, 270);
// ====== Info Label ======= //
JLabel infoLabel = new JLabel("<html>Click on main window to select it, then click and drag mouse to rotate cube.</html>");
infoLabel.setBounds(30, 5, 250, 48);
// ====== Size Label ======= //
JLabel sizeLabel = new JLabel("Size");
sizeLabel.setBounds(30, 55, 80, 24);
// ====== Size Value ======= //
JLabel sValue = new JLabel();
sValue.setHorizontalAlignment(JLabel.CENTER);
sValue.setBounds(220, 75, 50, 24);
sValue.setText(Integer.toString(s));
// ====== Size Slider ======= //
JSlider sizeSlider = new JSlider(JSlider.HORIZONTAL, 0, 250, 150);
sizeSlider.setBounds(30, 75, 200, 24);
sizeSlider.addChangeListener(new ChangeListener() {
void stateChanged(ChangeEvent changeEvent) {
s = sizeSlider.getValue();
sValue.setText(Integer.toString(sizeSlider.getValue()));
}
}
);
// ======== Crop Label ======== //
JLabel cropLabel = new JLabel("Crop");
cropLabel.setBounds(30, 100, 80, 24);
// ======== Crop Value ======== //
JLabel cropValue = new JLabel();
cropValue.setHorizontalAlignment(JLabel.CENTER);
cropValue.setBounds(220, 120, 50, 24);
cropValue.setText(Integer.toString(crop));
// ======== Crop Slider ======= //
JSlider cropSlider = new JSlider(JSlider.HORIZONTAL, 0, 250, 75);
cropSlider.setBounds(30, 120, 200, 24);
cropSlider.addChangeListener(new ChangeListener() {
void stateChanged(ChangeEvent changeEvent) {
crop = cropSlider.getValue();
cropValue.setText(Integer.toString(cropSlider.getValue()));
}
}
);
// ====== Quit Label ======= //
JLabel quitLabel = new JLabel("<html>Close main window to quit the app or use Quit button below. Do not use cmd-Q (will hang runtime).</html>");
quitLabel.setBounds(30, 155, 250, 48);
// ====== Quit Button ====== //
JButton quitBtn = new JButton("Quit");
quitBtn.setBounds(190, 210, 80, 24);
quitBtn.addActionListener( e -> {
exit();
}
);
frame.add(infoLabel);
frame.add(sizeLabel);
frame.add(sValue);
frame.add(sizeSlider);
frame.add(cropLabel);
frame.add(cropValue);
frame.add(cropSlider);
frame.add(quitLabel);
frame.add(quitBtn);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setVisible(true);
}
void setup() {
size( 800, 800, P3D );
surface.setTitle("Truncated Cube");
strokeWeight(4);
javax.swing.SwingUtilities.invokeLater(()-> {
buildControllerWnd(); // Build components on EventDispatchThread
}
);
}
void draw() {
background(128);
translate(width/2.0, height/2.0, -100);
rotateX(rotx);
rotateY(roty);
// ============ 6 Faces =========== //
// Front face
beginShape();
fill(255, 0, 0); // Red
vertex(-s, -s+crop, s); // LT lower crop * -> Front LT Triangle
vertex(-s+crop, -s, s); // LT upper crop * -> Front LT Triangle
vertex( s-crop, -s, s); // RT upper crop * -> Front RT Triangle
vertex( s, -s+crop, s); // RT lower crop * -> Front RT Triangle
vertex( s, s-crop, s); // RB upper crop * -> Front RB Triangle
vertex( s-crop, s, s); // RB lower crop * -> Front RB Triangle
vertex(-s+crop, s, s); // LB lower crop * -> Front LB Triangle
vertex(-s, s-crop, s); // LB upper crop * -> Front LB Triangle
endShape();
// Back face
beginShape();
fill(255, 255, 0); // Yellow
vertex( s, -s+crop, -s); // LT lower crop * -> Back LT Triangle
vertex( s-crop, -s, -s); // LT upper crop * -> Back LT Triangle
vertex(-s+crop, -s, -s); // RT upper crop * -> Back RT Triangle
vertex(-s, -s+crop, -s); // RT lower crop * -> Back RT Triangle
vertex(-s, s-crop, -s); // RB upper crop * -> Back RB Triangle
vertex(-s+crop, s, -s); // RB lower crop * -> Back RB Triangle
vertex( s-crop, s, -s); // LB lower crop * -> Back LB Triangle
vertex( s, s-crop, -s); // LB upper crop * -> Back LB Triangle
endShape();
// Bottom face
beginShape();
fill(255, 0, 255); // Magenta
vertex(-s, s, s-crop); // LT lower crop
vertex(-s+crop, s, s); // LT upper crop
vertex( s-crop, s, s); // RT upper crop
vertex( s, s, s-crop); // RT lower crop
vertex( s, s, -s+crop); // RB upper crop
vertex( s-crop, s, -s); // RB lower crop
vertex(-s+crop, s, -s); // LB lower crop
vertex(-s, s, -s+crop); // LB upper crop
endShape();
// Top face
beginShape();
fill(0, 255, 0); // Green
vertex(-s, -s, -s+crop); // LT lower crop
vertex(-s+crop, -s, -s); // LT upper crop
vertex( s-crop, -s, -s); // RT upper crop
vertex( s, -s, -s+crop); // RT lower crop
vertex( s, -s, s-crop); // RB upper crop
vertex( s-crop, -s, s); // RB lower crop
vertex(-s+crop, -s, s); // LB lower crop
vertex(-s, -s, s-crop); // LB upper crop
endShape();
// Right face
beginShape();
fill(0, 0, 255); // Blue
vertex( s, -s+crop, s); // LT lower crop
vertex( s, -s, s-crop); // LT upper crop * -> Front RT Triangle
vertex( s, -s, -s+crop); // RT upper crop * -> Back LT Triangle
vertex( s, -s+crop, -s); // RT lower crop
vertex( s, s-crop, -s); // RB upper crop
vertex( s, s, -s+crop); // RB lower crop * -> Back LB Triangle
vertex( s, s, s-crop); // LB lower crop * -> Front RB Triangle
vertex( s, s-crop, s); // LB upper crop
endShape();
// Left face
beginShape();
fill(0, 255, 255); // Turquoise
vertex(-s, -s+crop, -s); // LT lower crop
vertex(-s, -s, -s+crop); // LT upper crop * -> Back RT Triangle
vertex(-s, -s, s-crop); // RT upper crop * -> Front LT Triangle
vertex(-s, -s+crop, s); // RT lower crop
vertex(-s, s-crop, s); // RB upper crop
vertex(-s, s, s-crop); // RB lower crop * -> Front LB Triangle
vertex(-s, s, -s+crop); // LB lower crop * -> Back RB Triangle
vertex(-s, s-crop, -s); // LB upper crop
endShape();
// ========== 8 Triangles =========== //
beginShape(); // Front face LT triangle
fill(255); // White
vertex(-s, -s+crop, s); // Front LT lower crop * -> LT Triangle
vertex(-s+crop, -s, s); // Front LT upper crop * -> LT Triangle
vertex(-s, -s, s-crop); // Left RT upper crop * -> LT Triangle
endShape();
beginShape(); // Front face RT triangle
fill(255); // White
vertex( s-crop, -s, s); // Front RT upper crop * -> RT Triangle
vertex( s, -s+crop, s); // Front RT lower crop * -> RT Triangle
vertex( s, -s, s-crop); // Right LT upper crop * -> RT Triangle
endShape();
beginShape(); // Front face RB triangle
fill(255); // White
vertex( s, s-crop, s); // Front RB upper crop * -> RB Triangle
vertex( s-crop, s, s); // Front RB lower crop * -> RB Triangle
vertex( s, s, s-crop); // Right LB lower crop * -> RB Triangle
endShape();
beginShape(); // Front face LB triangle
fill(255); // White
vertex(-s+crop, s, s); // Front LB lower crop * -> LB Triangle
vertex(-s, s-crop, s); // Front LB upper crop * -> LB Triangle
vertex(-s, s, s-crop); // Left RB lower crop * -> LB Triangle
endShape();
beginShape(); // Back face LT triangle
fill(255); // White
vertex( s, -s+crop, -s); // Back LT lower crop * -> LT Triangle
vertex( s-crop, -s, -s); // Back LT upper crop * -> LT Triangle
vertex( s, -s, -s+crop); // Left RT upper crop * -> LT Triangle
endShape();
beginShape(); // Back face RT triangle
fill(255); // White
vertex(-s+crop, -s, -s); // Back RT upper crop * -> RT Triangle
vertex(-s, -s+crop, -s); // Back RT lower crop * -> RT Triangle
vertex(-s, -s, -s+crop); // Right LT upper crop * -> RT Triangle
endShape();
beginShape(); // Back face RB triangle
fill(255); // White
vertex(-s, s-crop, -s); // Back RB upper crop * -> RB Triangle
vertex(-s+crop, s, -s); // Back RB lower crop * -> RB Triangle
vertex(-s, s, -s+crop); // Left LB lower crop * -> RB Triangle
endShape();
beginShape(); // Back face LB triangle
fill(255); // White
vertex( s-crop, s, -s); // Back LB lower crop * -> LB Triangle
vertex( s, s-crop, -s); // Back LB upper crop * -> LB Triangle
vertex( s, s, -s+crop); // Right RB lower crop * -> LB Triangle
endShape();
}
void mouseDragged() {
float rate = 0.01;
rotx += (pmouseY-mouseY) * rate;
roty += (mouseX-pmouseX) * rate;
}
Normal Output:
Interesting Output:
Truncated Cube with Textures
The source code below demonstrates applying textures to octagonal shapes with the aid of textureMode(NORMAL). The images used for the textures are shown below and should be copy/pasted into a folder entitled ‘data’ inside the sketch folder. The normal coordinates of a quadrilateral image are 0,0 (left top), 1,0 (right top), 1,1 (right bottom), and 0,1 (left bottom). Octagonal u,v (horizontal, vertical) coordinates which yield distortion-free images are shown below (not to scale with octagon in demo). The crop points are calculated by taking one half of the crop percentage, 0.16 in this case, and using it in combination with 0.84 (1.0 - 0.16). Mouse down and drag to rotate cube.
Source code:
// LT = left top : RT = right top : RB = right bottom : LB = left bottom
PImage imgOne;
PImage imgTwo;
PImage imgThree;
PImage imgFour;
PImage imgFive;
PImage imgSix;
int _wndW = 600;
int _wndH = 600;
float rotx = PI/4;
float roty = PI/4;
int s = 100;
int crop = s/3;
void cube(){
// ============ 6 Faces =========== //
textureMode(NORMAL);
// Front face
beginShape();
texture(imgOne);
vertex(-s, -s+crop, s, 0.0, 0.16); // LT lower crop * -> Front LT Triangle
vertex(-s+crop, -s, s, 0.16, 0.0); // LT upper crop * -> Front LT Triangle
vertex( s-crop, -s, s, 0.84, 0.0); // RT upper crop * -> Front RT Triangle
vertex( s, -s+crop, s, 1.0, 0.16); // RT lower crop * -> Front RT Triangle
vertex( s, s-crop, s, 1.0, 0.84); // RB upper crop * -> Front RB Triangle
vertex( s-crop, s, s, 0.84, 1.0); // RB lower crop * -> Front RB Triangle
vertex(-s+crop, s, s, 0.16, 1.0); // LB lower crop * -> Front LB Triangle
vertex(-s, s-crop, s, 0.0, 0.84); // LB upper crop * -> Front LB Triangle
endShape();
// Back face
beginShape();
texture(imgSix);
vertex( s, -s+crop, -s, 0.0, 0.16); // LT lower crop * -> Back LT Triangle
vertex( s-crop, -s, -s, 0.16, 0.0); // LT upper crop * -> Back LT Triangle
vertex(-s+crop, -s, -s, 0.84, 0.0); // RT upper crop * -> Back RT Triangle
vertex(-s, -s+crop, -s, 1.0, 0.16); // RT lower crop * -> Back RT Triangle
vertex(-s, s-crop, -s, 1.0, 0.84); // RB upper crop * -> Back RB Triangle
vertex(-s+crop, s, -s, 0.84, 1.0); // RB lower crop * -> Back RB Triangle
vertex( s-crop, s, -s, 0.16, 1.0); // LB lower crop * -> Back LB Triangle
vertex( s, s-crop, -s, 0.0, 0.84); // LB upper crop * -> Back LB Triangle
endShape();
// Bottom face
beginShape();
texture(imgFour);
vertex(-s, s, s-crop, 0.0, 0.16); // LT lower crop
vertex(-s+crop, s, s, 0.16, 0.0); // LT upper crop
vertex( s-crop, s, s, 0.84, 0.0); // RT upper crop
vertex( s, s, s-crop, 1.0, 0.16); // RT lower crop
vertex( s, s, -s+crop, 1.0, 0.84); // RB upper crop
vertex( s-crop, s, -s, 0.84, 1.0); // RB lower crop
vertex(-s+crop, s, -s, 0.16, 1.0); // LB lower crop
vertex(-s, s, -s+crop, 0.0, 0.84); // LB upper crop
endShape();
// Top face
beginShape();
texture(imgThree);
vertex(-s, -s, -s+crop, 0.0, 0.16); // LT lower crop
vertex(-s+crop, -s, -s, 0.16, 0.0); // LT upper crop
vertex( s-crop, -s, -s, 0.84, 0.0); // RT upper crop
vertex( s, -s, -s+crop, 1.0, 0.16); // RT lower crop
vertex( s, -s, s-crop, 1.0, 0.84); // RB upper crop
vertex( s-crop, -s, s, 0.84, 1.0); // RB lower crop
vertex(-s+crop, -s, s, 0.16, 1.0); // LB lower crop
vertex(-s, -s, s-crop, 0.0, 0.84); // LB upper crop
endShape();
// Right face
beginShape();
texture(imgTwo);
vertex( s, -s+crop, s, 0.0, 0.16); // LT lower crop
vertex( s, -s, s-crop, 0.16, 0.0); // LT upper crop * -> Front RT Triangle
vertex( s, -s, -s+crop, 0.84, 0.0); // RT upper crop * -> Back LT Triangle
vertex( s, -s+crop, -s, 1.0, 0.16); // RT lower crop
vertex( s, s-crop, -s, 1.0, 0.84); // RB upper crop
vertex( s, s, -s+crop, 0.84, 1.0); // RB lower crop * -> Back LB Triangle
vertex( s, s, s-crop, 0.16, 1.0); // LB lower crop * -> Front RB Triangle
vertex( s, s-crop, s, 0.0, 0.84); // LB upper crop
endShape();
// Left face
beginShape();
texture(imgFive);
vertex(-s, -s+crop, -s, 0.0, 0.16); // LT lower crop
vertex(-s, -s, -s+crop, 0.16, 0.0); // LT upper crop * -> Back RT Triangle
vertex(-s, -s, s-crop, 0.84, 0.0); // RT upper crop * -> Front LT Triangle
vertex(-s, -s+crop, s, 1.0, 0.16); // RT lower crop
vertex(-s, s-crop, s, 1.0, 0.84); // RB upper crop
vertex(-s, s, s-crop, 0.84, 1.0); // RB lower crop * -> Front LB Triangle
vertex(-s, s, -s+crop, 0.16, 1.0); // LB lower crop * -> Back RB Triangle
vertex(-s, s-crop, -s, 0.0, 0.84); // LB upper crop
endShape();
// ========== 8 Triangles =========== //
beginShape(); // Front face LT triangle
fill(0);
vertex(-s, -s+crop, s); // Front LT lower crop * -> LT Triangle
vertex(-s+crop, -s, s); // Front LT upper crop * -> LT Triangle
vertex(-s, -s, s-crop); // Left RT upper crop * -> LT Triangle
endShape();
beginShape(); // Front face RT triangle
fill(0);
vertex( s-crop, -s, s); // Front RT upper crop * -> RT Triangle
vertex( s, -s+crop, s); // Front RT lower crop * -> RT Triangle
vertex( s, -s, s-crop); // Right LT upper crop * -> RT Triangle
endShape();
beginShape(); // Front face RB triangle
fill(0);
vertex( s, s-crop, s); // Front RB upper crop * -> RB Triangle
vertex( s-crop, s, s); // Front RB lower crop * -> RB Triangle
vertex( s, s, s-crop); // Right LB lower crop * -> RB Triangle
endShape();
beginShape(); // Front face LB triangle
fill(0);
vertex(-s+crop, s, s); // Front LB lower crop * -> LB Triangle
vertex(-s, s-crop, s); // Front LB upper crop * -> LB Triangle
vertex(-s, s, s-crop); // Left RB lower crop * -> LB Triangle
endShape();
beginShape(); // Back face LT triangle
fill(0);
vertex( s, -s+crop, -s); // Back LT lower crop * -> LT Triangle
vertex( s-crop, -s, -s); // Back LT upper crop * -> LT Triangle
vertex( s, -s, -s+crop); // Left RT upper crop * -> LT Triangle
endShape();
beginShape(); // Back face RT triangle
fill(0);
vertex(-s+crop, -s, -s); // Back RT upper crop * -> RT Triangle
vertex(-s, -s+crop, -s); // Back RT lower crop * -> RT Triangle
vertex(-s, -s, -s+crop); // Right LT upper crop * -> RT Triangle
endShape();
beginShape(); // Back face RB triangle
fill(0);
vertex(-s, s-crop, -s); // Back RB upper crop * -> RB Triangle
vertex(-s+crop, s, -s); // Back RB lower crop * -> RB Triangle
vertex(-s, s, -s+crop); // Left LB lower crop * -> RB Triangle
endShape();
beginShape(); // Back face LB triangle
fill(0);
vertex( s-crop, s, -s); // Back LB lower crop * -> LB Triangle
vertex( s, s-crop, -s); // Back LB upper crop * -> LB Triangle
vertex( s, s, -s+crop); // Right RB lower crop * -> LB Triangle
endShape();
}
void setup(){
size( _wndW, _wndH, P3D );
surface.setTitle("Truncated Cube");
strokeWeight(4);
imgOne = loadImage("one.png");
imgTwo = loadImage("two.png");
imgThree = loadImage("three.png");
imgFour = loadImage("four.png");
imgFive = loadImage("five.png");
imgSix = loadImage("six.png");
}
void draw(){
background(128);
translate(width/2.0, height/2.0, -100);
rotateX(rotx);
rotateY(roty);
cube();
}
void mouseDragged() {
float rate = 0.01;
rotx += (pmouseY-mouseY) * rate;
roty += (mouseX-pmouseX) * rate;
}
Images:
one.png
two.png
three.png
four.png
five.png
six.png
Octagonal Normal Coordinates:
Output:









