How can I create a sphere (or other shape) with cubes? (3D)

Hi everyone I am new generally in coding ( not only in Processing) so I need your help if you can. What I want to do is to design 10 types of cubes with different color shades ( from white to totally black) without having the same dimension and with those cubes to fill (create) a 3D shape for instance a sphere or a cone. I have seen some tutorials on Youtube and I found the below simple code in which I tried to change in order to do what I want, but guess what, I did nothing

size(400,300);
background(0);
strokeWeight(2);
stroke(255);
fill(127);

for (int y = 0; y < height; y = y+20) {
for (int x = 0; x < width; x = x+20){
fill(random(255));

rect(x, y, 20, 20);

}
}

You need a 3D Sketch when I understand you correctly.

read P3D \ Processing.org

I’ll be back in a second with an example.

Hey, and welcome to the forum!

Great to have you here!

Warm regards,

Chrisir


Sketch

Click mouse to enter a new cube. You can move the last cube in 3D with cursor keys and p and “l” (“L”). You need to add a size changer (e.g. + and - ) and add automatic color from white to black.
You could save the cube position on Hard Drive (hard to do) or make a screen shot (command save() associated with key ‘s’ for example).

  • So you can make a sphere or a cone from cubes. I wouldn’t know how to do this automatically. Well, we could try.
// constants
final color BLACK  = color(0); 
final color WHITE  = color(255);

final color RED    = color(255, 0, 0); 
final color GREEN  = color(0, 255, 0);
final color BLUE   = color(0, 0, 255);

final color YELLOW = (#FFF80A); 

// the cubes 
ArrayList<Cube> cubes = new ArrayList();

// -------------------------------------------------------------------------------------

void setup() {
  size( 1200, 900, P3D ); // 3D Mode 

  //text 
  textMode(SHAPE);

  // add one cube - delete this
  Cube newCube = new Cube(); 
  newCube.pos=new PVector(60, 310, -60);
  newCube.colorForCube = color ( RED ) ;   
  cubes.add(newCube); 
  //
}//func

void draw() {

  background(0);

  // 3D part ---
  lights();

  for (Cube currentCube : cubes) {
    currentCube.display();
  }

  // 2D part --- 
  showMessages();
}//func 

// -----------------------------------------------------------------------------

void showMessages() {
  // 2D part --- 

  // prepare for 2D
  hint(DISABLE_DEPTH_TEST);
  camera();
  noLights();

  // 2D code 
  fill(255); 
  text("Place cubes with Mouse. Move last cube in Z with Cursor up and down (and left/right and p/l)", 17, 17);
  if (cubes.size()>0) {
    text("Last cube x,y,z: "
      +cubes.get(cubes.size()-1).pos.x
      +","
      +cubes.get(cubes.size()-1).pos.y
      +","
      +cubes.get(cubes.size()-1).pos.z, 17, 35);
  }

  // reset for 3D again 
  hint(ENABLE_DEPTH_TEST);
}

// ------------------------------------------------------------------------
// Inputs 

void mousePressed() {
  // add cube at mouse pos with z = 0.
  addCube(new PVector(mouseX, mouseY, 0));
}

void keyPressed() {

  if (key==CODED) {

    // CODED

    switch(keyCode) {
    case UP:
      cubes.get(cubes.size()-1).pos.z-=10; 
      break; 

    case DOWN:
      cubes.get(cubes.size()-1).pos.z += 10; 
      break;

    case LEFT:
      cubes.get(cubes.size()-1).pos.x-=10; 
      break; 

    case RIGHT:
      cubes.get(cubes.size()-1).pos.x += 10; 
      break;
    }//switch 1
  } 
  //-------

  else {

    // not CODED

    switch(key) {
    case 'p':
      cubes.get(cubes.size()-1).pos.y-=10; 
      break; 

    case 'l':
      cubes.get(cubes.size()-1).pos.y += 10; 
      break;
    }//switch 2
  } // else
}//func 

// ------------------------------------------------------------------------
// Tools

void addCube(PVector pos_) {

  Cube newCube = new Cube(); 
  newCube.pos=pos_.copy();
  newCube.colorForCube = color ( RED ) ;   

  cubes.add(newCube); 
  //
} // func

// =======================================================================

class Cube {

  // one cube

  PVector pos; 
  color colorForCube; 

  void display() {
    pushMatrix();
    stroke(111);
    fill(colorForCube);
    translate(pos.x, pos.y, pos.z);
    box(60);
    popMatrix();
  }  
  //
}//class
//

You can use Pythagoras to test whether a 3d position is inside a 3d field. I think there is no definition for dist (x,y,z,x2,y2,z2) but you can apply pythagoras twice:

boolean insideSphere(
    float cx,  float cy, float cz,   /*center*/
    float radius,                           /*radius*/
    float px, float py, float pz   /*test point*/
      )
{
    float x=px-cx;
    float y=py-cy;
    float cz=pz-cz;
    float R=radius*radius;
    if (R<(x*x+y*y+z*z)){
        return TRUE;
    }
    return FALSE;
}

Please note I left maths when I was 15 years old. So maybe there is an easier way.

thanks!

A few minor typos, check this:

boolean insideSphere(
  float cx, float cy, float cz, /*center*/
  float radius, /*radius*/
  float px, float py, float pz   /*test point*/
  )
{
  float x=px-cx;
  float y=py-cy;
  float z=pz-cz;
  float R=radius*radius;
  if ((x*x+y*y+z*z) < R) {
    return true;
  }
  return false;
}

can be shortened to

boolean insideSphere (
  float cx, float cy, float cz, // center
  float radius, // radius
  float px, float py, float pz    // test point
  ) {
  PVector center = new PVector(cx, cy, cz);
  PVector testPoint = new PVector(px, py, pz);
  return center.dist(testPoint) < radius;
}

Full code with peasy cam (and some PVector stuff):





import peasy.*;

PeasyCam peasyCam;

PVector center;  // center 
PVector testPoint=new PVector();  // test point

// -------------------------------------------

void setup() {
  size(1400, 940, P3D);
  peasyCam = new PeasyCam(this, 1000);
  center = new PVector(0, 0, 0);
}

void draw() {
  background(255);
  lights();
  fill(255, 0, 0);

  int radiusSphere=200; 
  for (int x=-radiusSphere; x<radiusSphere; x+=22) {
    for (int y=-radiusSphere; y<radiusSphere; y+=22) {
      for (int z=-radiusSphere; z<radiusSphere; z+=22) {

        if (insideSphere(radiusSphere/2, 
          x, y, z)) {
          pushMatrix();
          translate(x, y, z); 
          box(22-1); 
          popMatrix();
        }
      }
    }
  }

  peasyCam.beginHUD();
  noLights();
  fill(0);
  text("Use PeasyCam by dragging the mouse, pan etc. ", 12, 12); 
  peasyCam.endHUD();
}

// -------------------------------------------

boolean insideSphere ( float radius, // radius
  float px, float py, float pz    // test point
  ) {
  testPoint.set(px, py, pz);
  return 
    center.dist(testPoint) < radius;
}
//

1 Like

Hi! I detected my typo but I was too lazy to make a last edit to my post.

Thank you for the example with peasycam. I find wery frustrating the control of the camera. PeasyCam makes it easier!

1 Like

But still, the cubes are all the same in my example (and far too many)

That’s not really the idea

When the initial cubes have a fixed and individual size (and color) we need an array (or ArrayList) and a class Cube and some kind of optimization algorithm to pack them in a good way (when you want to do it automatically by an algorithm) - hard !

It’s unclear whether you mean

  • cubes (all six faces have the same size) of different sizes or
  • also cuboids (six faces of 3 different sizes) of different sizes.

Do you want to arrange the cubes or cuboids with or without overlapping? Is it really in 3D? Do you want to make the arrangement

  • automatically or
  • by user input, with mouse or keyboard?

Chrisir

P.S.

here is a similar example

A cube of 3x3x3 has to be filled with pieces

1 Like