Cube with rounded edges

Hi there! I am working on a mobile quizapp based on rotating a cube. I am currently using this code for drawing a cube:

  beginShape(QUADS);
  texture(front);
  vertex(-1, -1,  1, 0, 0);
  vertex( 1, -1,  1, 1, 0);
  vertex( 1,  1,  1, 1, 1);
  vertex(-1,  1,  1, 0, 1);
  endShape();
  beginShape(QUADS);
  vertex( 1, -1, -1, 0, 0);
  vertex(-1, -1, -1, 1, 0);
  vertex(-1,  1, -1, 1, 1);
  vertex( 1,  1, -1, 0, 1);
  endShape();
  beginShape(QUADS);
  texture(any);
  vertex(-1,  1,  1, 0, 0);
  vertex( 1,  1,  1, 1, 0);
  vertex( 1,  1, -1, 1, 1);
  vertex(-1,  1, -1, 0, 1);
  endShape();
  beginShape(QUADS);
  texture(any);
  vertex(-1, -1, -1, 0, 0);
  vertex( 1, -1, -1, 1, 0);
  vertex( 1, -1,  1, 1, 1);
  vertex(-1, -1,  1, 0, 1);
  endShape();
  beginShape(QUADS);
  texture(any);
  vertex( 1, -1,  1, 0, 0);
  vertex( 1, -1, -1, 1, 0);
  vertex( 1,  1, -1, 1, 1);
  vertex( 1,  1,  1, 0, 1);
  endShape();
  beginShape(QUADS);
  texture(any);
  vertex(-1, -1, -1, 0, 0);
  vertex(-1, -1,  1, 1, 0);
  vertex(-1,  1,  1, 1, 1);
  vertex(-1,  1, -1, 0, 1);
  endShape();

Now I want the cube to look more dynamic. To achieve that, I am trying to round the cube’s edges like in this 3D Model: https://1drv.ms/u/s!AlgOmiL5mgw21lWz_pmcUoAcVRY0?e=blu6u0. Can anyone show me how I can do that? I am not really good with shapes.

Hello,

You could use Blender to create a cube and bevel the edges the way you want. Then you could export the cube with the .OBJ format and use the loadShape() function to import it into your project.

2 Likes

Thanks for the advise, but I already tried that without sucess. I can load the shape, but it behaves weird. It rotates around some weird axes and completely loses it’s form on rotation.

here is my way…

Unbenannt

first we take a sphere, then we cut out another smaller sphere from its center .

This leaves a hollow sphere.

Now we take the cube and minus the hollow sphere.

When all sizes are chosen correctly, the hollow sphere just cuts off the edges of the cube.

  // This is where the magic happens
  csgResult = roundedCube();

Chrisir


//https://stackoverflow.com/questions/56999816/is-it-possible-to-use-jcsg-library-with-processing
//https://discourse.processing.org/t/csg-constructive-solid-geometry/12693

// the PShape reference which will contain the converted CSG 
PShape csgResult;

void setup() {
  size(900, 900, P3D);
  // This is where the magic happens
  csgResult = roundedCube(); 
  println("Use mouse to rotate.");
}

void draw() {
  background(0);
  lights();
  translate(width * 0.5, height * 0.5, 0);
  rotateY(map(mouseX, 0, width, -PI, PI));
  rotateX(map(mouseY, 0, height, PI, -PI));

  shape(csgResult);
}

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

PShape roundedCube() {

  PShape csgResult;

  noStroke();

  // JCSG sample code:
  // we use cube and sphere as base geometries
  CSG cube = new Cube(2.78).toCSG();

  CSG sphere1 = new Sphere(3).toCSG();         // outer sphere 
  CSG sphere2 = new Sphere(2.0941, 39, 39).toCSG();    // inner sphere - the smaller this is, the more we cut off from the cube! 
  //CSG sphere2 = new Sphere(1.80941).toCSG(); // the smaller this is, the more we cut off from the cube! 

  // perform difference: this gives a hollow sphere  
  CSG sphere3 = sphere1.difference(sphere2);

  // perform difference again: this gives a cube with rounded edges 
  CSG cubeMinusSphere = cube.difference(sphere3);
  //  cubeMinusSphere = sphere.difference(cube);

  // Convert CSG to PShape -> Note: CSG units are small so we scale them up so the shapes are visible in Processing
  csgResult = CSGToPShape(cubeMinusSphere, 45);

  return csgResult;
} //func 

// re-usable function to convert a CSG mesh to a Processing PShape
PShape CSGToPShape(CSG mesh, float scale) {
  // allocate a PShape group
  PShape csgResult = createShape(GROUP);
  // for each CSG polygon (Note: these can have 3,4 or more vertices)
  for (Polygon p : mesh.getPolygons()) {
    // make a child PShape
    PShape polyShape = createShape();
    // begin setting vertices to it
    polyShape.beginShape();
    polyShape.fill(255, 0, 0); 
    // for each vertex in the polygon
    for (Vertex v : p.vertices) {
      // add each (scaled) polygon vertex 
      polyShape.vertex((float)v.pos.getX() * scale, (float)v.pos.getY() * scale, (float)v.pos.getZ() * scale);
    }
    // finish this polygon
    polyShape.endShape();
    //append the child PShape to the parent
    csgResult.addChild(polyShape);
  }
  return csgResult;
}
//
4 Likes

Thanks for the attempt, but fortunately I was able to get loading the 3d model working.

But there still is a big problem:


PShape cubeShape;
PShape secondaryShape;
PImage cubeImage;
PImage blank;
float rotationX;
float rotationY;
float sX, sY;
int childs;
PFont questionFont, optionFont;

void setup(){
  frameRate(60);
  orientation(PORTRAIT);
  fullScreen(P3D);
  shapeMode(CORNER);
  textAlign(CORNER);
  smooth(5);
  cubeShape = loadShape("Abc.obj");
  cubeShape.setFill(color(255));
  cubeShape.setTint(color(255));
  secondaryShape = loadShape("Abc.obj");
  secondaryShape.setFill(color(255));
  secondaryShape.setTint(color(255,255,255));
  cubeImage = loadImage("cubesite_front.PNG");
  childs = cubeShape.getChildCount();
  questionFont = createFont("cube.ttf",7); 
  optionFont = createFont("cube.ttf", 85);
  textureWrap(REPEAT);
  textureMode(IMAGE);
  secondaryShape.setTexture(loadImage("cubesite_any.png"));
  rotationX = 0.0f;
  rotationY = 0.0f;
  editSite(cubeImage, "Test", "Left", "Top", "Right", "Bottom");
  cubeImage = getMirror(cubeImage);
}

void draw(){
  cubeShape.setTexture(cubeImage);
  Runtime runtime = Runtime.getRuntime();
  float usedRam = 1.0f - (float) runtime.freeMemory() / (float) runtime.totalMemory();
  int usedRamPercent = (int) (usedRam*100.0f);
  background(255);
  lights();
  textSize(width/20);
  fill(0,125,255);
  text("Rotation X: " + String.valueOf(degrees(rotationX)).split("\\.")[0]+"°\n"+"Rotation Y: " + String.valueOf(degrees(rotationY)).split("\\.")[0]+"°",width/20,height/20);
  String rightBar = "Touch X: " + String.valueOf(sX) + "\nTouch Y: " + String.valueOf(sY) 
  + "\n\nRAM: " + usedRamPercent + "%"
  + "\nFPS: " + String.valueOf(frameRate).split("\\.")[0];
  text(rightBar,width-width/20-textWidth(rightBar),height/20); 
  textSize(width/20);
  fill(125,25,0);
  text("",width/2,height/7);
  if (rotationX>=TWO_PI||rotationX<=-TWO_PI) rotationX=0;
  if (rotationY>=TWO_PI||rotationY<=-TWO_PI) rotationY=0;
  for (int i = 0; i <childs; i++){
    PShape currentChild = cubeShape.getChild(i); 
    PShape secondaryChild = secondaryShape.getChild(i);
    boolean front = true;
    for (int j = 0; j < currentChild.getVertexCount(); j++){
      PVector currentVector = currentChild.getVertex(j);
      front = !(currentVector.z<0.95);
    }
    pushMatrix();
    translate(width/2,height/2,height/6);
    scale(height/7);
    rotateX(rotationX);
    rotateY(rotationY);
    shape(front ? currentChild : secondaryChild);
    popMatrix();
  }
}
 

PImage getMirror(PImage img) {
  PGraphics pg = createGraphics(img.width, img.height, JAVA2D);
  pg.beginDraw();
  pg.smooth(4);
  pg.scale(-1, 1);
  pg.image(img, -img.width, 0);
  pg.endDraw();
  return pg.get();
}

private void editSite(PImage background, String center, String left, String top, String right, String bottom){ 
  PGraphics siteGraphics = createGraphics(background.width,background.height); 
  imageMode(CORNER); 
  siteGraphics.beginDraw(); 
  siteGraphics.image(background,0,0); 
  siteGraphics.textSize(width/10); 
  fittedText(siteGraphics,center,questionFont,siteGraphics.width/2,siteGraphics.height/2,siteGraphics.width-siteGraphics.width/6,siteGraphics.height-siteGraphics.height/6); 
  siteGraphics.pushMatrix(); 
  siteGraphics.translate(0,0);
  siteGraphics.rotate(-HALF_PI); 
  siteGraphics.textAlign(CENTER, CENTER); 
  siteGraphics.textFont(optionFont); 
  siteGraphics.text(left,-siteGraphics.height/2,siteGraphics.width/6/2); 
  siteGraphics.rotate(PI); 
  siteGraphics.text(right,siteGraphics.height/2,-siteGraphics.width+siteGraphics.width/6/2); 
  siteGraphics.rotate(-HALF_PI); 
  siteGraphics.text(top,siteGraphics.width/2,siteGraphics.height/6/2); 
  siteGraphics.text(bottom,siteGraphics.width/2,siteGraphics.height-siteGraphics.height/6/2); siteGraphics.popMatrix(); 
  siteGraphics.endDraw(); 
  cubeImage = siteGraphics.get(); 
}


private final char NEWLINE = '\n'; private final String SPACE_SEPARATOR = " "; private final String SPLIT_REGEXP= "\\s+"; String breakLines(String input, int maxLineLength) { String[] tokens = input.split(SPLIT_REGEXP); StringBuilder output = new StringBuilder(input.length()); int lineLen = 0; for (int i = 0; i < tokens.length; i++) { String word = tokens[i]; if (lineLen + (SPACE_SEPARATOR + word).length() > maxLineLength) { if (i > 0) output.append(NEWLINE); lineLen = 0; } if (i < tokens.length - 1 && (lineLen + (word + SPACE_SEPARATOR).length() + tokens[i + 1].length() <=maxLineLength)) word += SPACE_SEPARATOR; output.append(word); lineLen += word.length(); } return output.toString();}
void fittedText(PGraphics graphics,String text, PFont font, float posX, float posY, float fitX, float fitY){ 
  text = breakLines(text, 15); 
  graphics.textFont(font); 
  graphics.textAlign(CENTER,CENTER); 
  graphics.textSize(min(font.getSize()*fitX/textWidth(text), fitY)); 
  graphics.textLeading(graphics.textSize*1.1); 
  graphics.text(text, posX, posY);
}


void mousePressed(){
  sX = mouseX;
  sY = mouseY;
}
void mouseDragged(){
  rotationX += (mouseY-sY)*(HALF_PI/(width));
  sY = mouseY;
  rotationY += (mouseX-sX)*(HALF_PI/(width));
  sX = mouseX;
}

The above demo code functions perfectly when run via APDE, but the texture is just one solid ugly color when build/run from a windows machine via PDE or Android Studio:

Do(es) you/anyone know(s) why this is happening and how I can fix it?

If needed I will upload the model as well if it is relevant!

1 Like

I have no idea…

Chrisir

That’s a shame… I can’t understand why this is happening either. What is APDE doing differently?

1 Like