简体   繁体   中英

How to draw a cube in Processing without the box() function?

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM