I need to draw a cube in processing without the use of built-in functions. All I could find was using the box() function then rotating the image to see it in 3D.
How can I achieve this?
I need to draw a cube in processing without the use of built-in functions. All I could find was using the box() function then rotating the image to see it in 3D.
How can I achieve this?
An alternative is using createShape(BOX)
instead:
PShape cube;
void setup(){
size(600, 600, P3D);
strokeWeight(9);
cube = createShape(BOX, 150);
}
void draw(){
background(255);
lights();
translate(width * 0.5, height * 0.5, 0);
rotateY(map(mouseX, 0, width, -PI, PI));
rotateX(map(mouseY, 0, height, PI, -PI));
shape(cube);
}
If this is for a homework/assignment it might not be enough (and you should state that in the question, and you should also post a code snippet of your attempt with a description of what didn't work). You'll need to draw the box from scratch. One easy way to think about is to draw the 8 cube vertices on pen and paper with 0,0,0 at the centre, then keeping in mind where -x/+x, -y/+y, -z/+z axes point, mark each vertex, for example:
( x, y, z)
(-1,-1,-1)
(+1,-1,-1)
(+1,+1,-1)
(-1,+1,-1)
should be the back face. Repeat the process for the rest of the faces.
In Processing you'd use beginShape(QUADS)
since you're drawing a cube and it's faces are quads, vertex(x, y, z)
to specify each point/vertex and finally endShape()
to complete the shape (and "join the dots"):
void setup(){
size(600, 600, P3D);
strokeWeight(9);
}
void draw(){
background(255);
lights();
translate(width * 0.5, height * 0.5, 0);
rotateY(map(mouseX, 0, width, -PI, PI));
rotateX(map(mouseY, 0, height, PI, -PI));
cubeFaces(150);
}
void cubeFaces(float size){
// half size: keep the pivot at the center of the mesh
float s = size * 0.5;
beginShape(QUADS);
// back (-z)
vertex(-s, -s, -s);
vertex(+s, -s, -s);
vertex(+s, +s, -s);
vertex(-s, +s, -s);
// front (+z)
vertex(-s, -s, +s);
vertex(+s, -s, +s);
vertex(+s, +s, +s);
vertex(-s, +s, +s);
// top (-y)
vertex(-s, -s, +s);
vertex(-s, -s, -s);
vertex(+s, -s, -s);
vertex(+s, -s, +s);
// bottom (+y)
vertex(+s, +s, +s);
vertex(+s, +s, -s);
vertex(-s, +s, -s);
vertex(-s, +s, +s);
// left (-x)
vertex(-s, -s, +s);
vertex(-s, -s, -s);
vertex(-s, +s, -s);
vertex(-s, +s, +s);
// right (+x)
vertex(+s, -s, +s);
vertex(+s, -s, -s);
vertex(+s, +s, -s);
vertex(+s, +s, +s);
endShape();
}
PShape
is useful because you can cache the geometry using a very similar beginShape()
/endShape()
, but rather than recreating the shape every frame you can simply render the predefined geometry:
PShape cube;
void setup(){
size(600, 600, P3D);
strokeWeight(9);
cube = getCube(150);
}
void draw(){
background(255);
lights();
translate(width * 0.5, height * 0.5, 0);
rotateY(map(mouseX, 0, width, -PI, PI));
rotateX(map(mouseY, 0, height, PI, -PI));
shape(cube);
}
void cubeFaces(float size){
// half size: keep the pivot at the center of the mesh
float s = size * 0.5;
beginShape(QUADS);
// back (-z)
vertex(-s, -s, -s);
vertex(+s, -s, -s);
vertex(+s, +s, -s);
vertex(-s, +s, -s);
// front (+z)
vertex(-s, -s, +s);
vertex(+s, -s, +s);
vertex(+s, +s, +s);
vertex(-s, +s, +s);
// top (-y)
vertex(-s, -s, +s);
vertex(-s, -s, -s);
vertex(+s, -s, -s);
vertex(+s, -s, +s);
// bottom (+y)
vertex(+s, +s, +s);
vertex(+s, +s, -s);
vertex(-s, +s, -s);
vertex(-s, +s, +s);
// left (-x)
vertex(-s, -s, +s);
vertex(-s, -s, -s);
vertex(-s, +s, -s);
vertex(-s, +s, +s);
// right (+x)
vertex(+s, -s, +s);
vertex(+s, -s, -s);
vertex(+s, +s, -s);
vertex(+s, +s, +s);
endShape();
}
PShape getCube(float size){
PShape cube = createShape();
// half size: keep the pivot at the center of the mesh
float s = size * 0.5;
cube.beginShape(QUADS);
// back (-z)
cube.vertex(-s, -s, -s);
cube.vertex(+s, -s, -s);
cube.vertex(+s, +s, -s);
cube.vertex(-s, +s, -s);
// front (+z)
cube.vertex(-s, -s, +s);
cube.vertex(+s, -s, +s);
cube.vertex(+s, +s, +s);
cube.vertex(-s, +s, +s);
// top (-y)
cube.vertex(-s, -s, +s);
cube.vertex(-s, -s, -s);
cube.vertex(+s, -s, -s);
cube.vertex(+s, -s, +s);
// bottom (+y)
cube.vertex(+s, +s, +s);
cube.vertex(+s, +s, -s);
cube.vertex(-s, +s, -s);
cube.vertex(-s, +s, +s);
// left (-x)
cube.vertex(-s, -s, +s);
cube.vertex(-s, -s, -s);
cube.vertex(-s, +s, -s);
cube.vertex(-s, +s, +s);
// right (+x)
cube.vertex(+s, -s, +s);
cube.vertex(+s, -s, -s);
cube.vertex(+s, +s, -s);
cube.vertex(+s, +s, +s);
cube.endShape();
return cube;
}
Bonus points, there's yet another way you can draw a cube: as a special case of a cylinder with 4 subdivions where the radius is half the height. Processing ships with an example you can tweak in Processing > Examples > Topics > Geometry > Vertices.
Here's a modified version of the example rendering a cube:
/**
* Vertices
* by Simon Greenwold.
*
* Draw a cylinder centered on the y-axis, going down
* from y=0 to y=height. The radius at the top can be
* different from the radius at the bottom, and the
* number of sides drawn is variable.
*/
void setup() {
size(640, 360, P3D);
}
void draw() {
background(0);
lights();
translate(width / 2, height / 2);
rotateY(map(mouseX, 0, width, 0, PI));
rotateZ(map(mouseY, 0, height, 0, -PI));
noStroke();
fill(255, 255, 255);
translate(0, -40, 0);
//drawCylinder(10, 180, 200, 16); // Draw a mix between a cylinder and a cone
//drawCylinder(70, 70, 120, 64); // Draw a cylinder
//drawCylinder(0, 180, 200, 4); // Draw a pyramid
// Draw a cube
drawCylinder(50, 50, 75, 4);
}
void drawCylinder(float topRadius, float bottomRadius, float tall, int sides) {
float angle = 0;
float angleIncrement = TWO_PI / sides;
beginShape(QUAD_STRIP);
for (int i = 0; i < sides + 1; ++i) {
vertex(topRadius*cos(angle), 0, topRadius*sin(angle));
vertex(bottomRadius*cos(angle), tall, bottomRadius*sin(angle));
angle += angleIncrement;
}
endShape();
// If it is not a cone, draw the circular top cap
if (topRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, 0, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
// If it is not a cone, draw the circular bottom cap
if (bottomRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, tall, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
}
(You can find my explanation of the polar to cartesian formula used above in this answer)
The above is very similar to the old school OpenGL immediate mode drawing. If this is for a more recent CS oriented course for OpenGL one, you might need to use PGL and a vertex array buffer, slightly different calls. The Cube OpenGL Tutorial cover that nicely. Even though it's c++, you'll recognize functions such as genBuffers()
, glBindBuffer()
, glBufferData()
in Processing's PGL
class (
Processing > Examples > Demos > Graphics > LowLevelGL* examples are great starting points and align nicely with the triangle OpenGL tutorial)
Update:
There's yet another example that can easily be tweaked to draw a cube: Processing > Examples > Demos > Graphics > Wiggling.
Here's a tweaked version that draws the cube without the wiggling nor the holes in the faces:
PShape cube;
float cubeSize = 320;
void setup() {
size(1024, 768, P3D);
createCube();
}
void draw() {
background(0);
translate(width/2, height/2);
rotateX(frameCount * 0.01f);
rotateY(frameCount * 0.01f);
shape(cube);
if (frameCount % 60 == 0) println(frameRate);
}
public void keyPressed() {
if (key == '1') {
cube.setStrokeWeight(1);
} else if (key == '2') {
cube.setStrokeWeight(5);
} else if (key == '3') {
cube.setStrokeWeight(10);
}
}
void createCube() {
cube = createShape(GROUP);
PShape face;
// Create all faces at front position
for (int i = 0; i < 6; i++) {
face = createShape();
createFace(face);
cube.addChild(face);
}
// Rotate all the faces to their positions
// Front face - already correct
face = cube.getChild(0);
// Back face
face = cube.getChild(1);
face.rotateY(radians(180));
// Right face
face = cube.getChild(2);
face.rotateY(radians(90));
// Left face
face = cube.getChild(3);
face.rotateY(radians(-90));
// Top face
face = cube.getChild(4);
face.rotateX(radians(90));
// Bottom face
face = cube.getChild(5);
face.rotateX(radians(-90));
}
void createFace(PShape face) {
face.beginShape(POLYGON);
face.stroke(255, 0, 0);
face.fill(255);
// Draw main shape Clockwise
face.vertex(-cubeSize/2, -cubeSize/2, +cubeSize/2);
face.vertex(+cubeSize/2, -cubeSize/2, +cubeSize/2);
face.vertex(+cubeSize/2, +cubeSize/2, +cubeSize/2);
face.vertex(-cubeSize / 2, +cubeSize / 2, +cubeSize / 2);
face.endShape(CLOSE);
}