Why does this Pshape plane with curved vertices render so strangely?

edited March 2018 in Questions about Code

Hi, it might just be an error within my code, but why does it not render how i would expect it? What i try to achieve is basically just one corner being higher or lower than the rest and that it goes smoothly, but what happens is, that one vertex(on the corner) goes down, but in a completely wrong(for what i want) way.

This is my code :

PShape Shape, Shape1;
PVector TBL = new PVector(0, 0, 0), TBM = new PVector(100, 0, 0), TBR = new PVector(200, 0, 0), TRM = new PVector(200, 0, 100), TFR = new PVector(200, 0, 200), TFM = new PVector(100, 0, 200), TFL = new PVector(0, 100, 200), TLM = new PVector(0, 0, 100);

void setup() {
  size(1200, 700, P3D); 

  Shape = createShape();
  Shape.beginShape();

  Shape.fill(random(255), random(255), random(255));

   Shape.curveVertex(TBL.x, TBL.y, TBL.z);
   Shape.curveVertex(TBL.x, TBL.y, TBL.z);
   Shape.curveVertex(TBM.x, TBM.y, TBM.z);
   Shape.curveVertex(TBR.x, TBR.y, TBR.z);
   Shape.curveVertex(TBR.x, TBR.y, TBR.z);
   Shape.vertex(TBR.x, TBR.y, TBR.z);

   Shape.fill(random(255), random(255), random(255));

   Shape.curveVertex(TBR.x, TBR.y, TBR.z);
   Shape.curveVertex(TBR.x, TBR.y, TBR.z);
   Shape.curveVertex(TRM.x, TRM.y, TRM.z);
   Shape.curveVertex(TFR.x, TFR.y, TFR.z);
   Shape.curveVertex(TFR.x, TFR.y, TFR.z);
   Shape.vertex(TFR.x, TFR.y, TFR.z);

   Shape.fill(random(255), random(255), random(255));

   Shape.curveVertex(TFR.x, TFR.y, TFR.z);
   Shape.curveVertex(TFR.x, TFR.y, TFR.z);
   Shape.curveVertex(TFM.x, TFM.y, TFM.z);
   Shape.curveVertex(TFL.x, TFL.y, TFL.z);
   Shape.curveVertex(TFL.x, TFL.y, TFL.z);
   Shape.vertex(TFL.x, TFL.y, TFL.z);

   Shape.fill(random(255), random(255), random(255));

   Shape.curveVertex(TFL.x, TFL.y, TFL.z);
   Shape.curveVertex(TFL.x, TFL.y, TFL.z);
   Shape.curveVertex(TLM.x, TLM.y, TLM.z);
   Shape.curveVertex(TBL.x, TBL.y, TBL.z);
   Shape.curveVertex(TBL.x, TBL.y, TBL.z);
   Shape.vertex(TBL.x, TBL.y, TBL.z);

   Shape.endShape();

}

void draw() {
  background(150);
  translate(500, 250);
  shape(Shape);
}

void keyPressed() {
  switch(keyCode) {
  case UP:
    Shape.rotateX(0.1);
    break;
  case DOWN:
    Shape.rotateX(-0.1);
    break;
  case LEFT:
    Shape.rotateY(0.1);
    break;
  case RIGHT:
    Shape.rotateY(-0.1);
    break;
  }
}

Thanks for the help :)

Tagged:

Answers

  • edited March 2018

    one vertex(on the corner) goes down, but in a completely wrong(for what i want) way.

    I'm not able to tell from the sketch or its output what the difference is between what you get and what you want.

    Can you explain more what your desired output is and how what you are currently getting is different? Draw a pencil sketch?

  • if you comment out the fill and the curveVertex calls the shape still looks wrong.

    Draw a pencil sketch

    do this

  • Its not the most beautiful, but i think it explains pretty good what i hope to achieve. I also included a 3d variant, since the end goal is to get it to work in 3d^^ The 1st pic is 2D, the second 3D and the 3rd is what its currently doing. Thanks for the help :)

  • edited March 2018

    Forgot the pic XD

    CurvePlain

    Edit: you can actually see in the left pic that the lines go pretty symetrically while the right one all just go to the vertex in the right. The small lines represent the where the curve is angled? im not sure how its called, but its pretty self explaining looking at the pic^^

    Edit: Commenting out the CurveVertex and fill, the resulting shape is what i wanted, just with curved sides, but not corners. So that from the top it looks like a normal square, but from the side it can be curved.

  • I think the main problem might be the way that the vertices are connected, but i dont know how i could change that, so that the plane only bends from the middle vertices and not on the corners...

  • I got fascinated by this problem which is usually a bad sign as I then spend hours trying to grok the problem and come up with a solution.

    I have a partial solution. It is partial in that instead of a curved corner it is more of a folded corner, but if you wrote you own "lerp()"...let's call it "cerp()" (curve interpolation) to plot vertex() points then I think you would get closer to what you want. ;)

    PShape Shape, Shape1;
    
    PVector lerpPt;
    
    PVector TBL = new PVector(0, 0, 0), 
      TBM = new PVector(100, 0, 0), 
      TBR = new PVector(200, 0, 0), 
      TRM = new PVector(200, 0, 100), 
      TFR = new PVector(200, 0, 200), 
      TFM = new PVector(100, 0, 200), 
      TFL = new PVector(0, 100, 200), 
      TLM = new PVector(0, 0, 100);
    
    void setup() {
      size(1200, 700, P3D); 
    
      Shape = createShape();
      Shape.beginShape();
    
      // Stage 1
      Shape.fill(255, 0, 0);
    
      Shape.vertex(TBL.x, TBL.y, TBL.z);
      Shape.vertex(TBR.x, TBR.y, TBR.z);
    
      // Stage 2
      Shape.fill(0, 255, 0);
    
      Shape.vertex(TFR.x, TFR.y, TFR.z);
      Shape.vertex(TFM.x, TFM.y, TFM.z);
    
      // Stage 3
      Shape.fill(0, 0, 255);
    
      // Interpolate vertex points between TFM to TFL
      lerpPt = TFM;
      for (int i = 0; i < 10; i++ ) {
        lerpPt = PVector.lerp(TFM, TFL, 0.1);
        Shape.vertex(lerpPt.x, lerpPt.y, lerpPt.z);
      }
    
      // Interpolate vertex points between TFL to TLM
      lerpPt = TFL;
      for (int i = 0; i < 10; i++ ) {
        lerpPt = PVector.lerp(TFL, TLM, 0.1);
        Shape.vertex(lerpPt.x, lerpPt.y, lerpPt.z);
      }
    
      Shape.vertex(TLM.x, TLM.y, TLM.z);
    
      // This is the kluge to prevent strange deformity, but leaves a black line
      // in the surface
      pushMatrix();
      noFill();
      noStroke();
      Shape.vertex(TFM.x, TFM.y, TFM.z);
      popMatrix();
    
      Shape.vertex(TLM.x, TLM.y, TLM.z);
    
      // Stage 4
      Shape.fill(255, 0 , 255);
      Shape.vertex(TBL.x, TBL.y, TBL.z);
    
      Shape.endShape();
    }
    
    void draw() {
      background(150);
      translate(500, 250);
      shape(Shape);
    }
    
    void keyPressed() {
      switch(keyCode) {
      case UP:
        Shape.rotateX(0.1);
        break;
      case DOWN:
        Shape.rotateX(-0.1);
        break;
      case LEFT:
        Shape.rotateY(0.1);
        break;
      case RIGHT:
        Shape.rotateY(-0.1);
        break;
      }
    }
    
  • edited April 2018

    Rather than using curveVertex() or a straight vertex(), here is an approach using vertex() with the QUAD_STRIP mode -- see:

    BentRectDemo--screenshot

    /**
      * BentRectDemo
      * 2018-04-21 Jeremy Douglass - Processing 3.3.6
      *
      * Demonstrates drawing a rectangle with a 3D bent corner
      * using a QUAD_STRIP shape. Includes a function bentRect(),
      * a manual function explaining the unrolled loop with comments,
      * and an interactive bend controlled by mouseX / mouseY.
     **/
    
    import peasy.PeasyCam;
    PeasyCam cam;
    
    void setup() {
      size(300, 300, P3D);
      cam = new PeasyCam(this, 300);
    }
    void draw() {
      background(0);
      rotateX(QUARTER_PI);
      rotateY(QUARTER_PI/2);
    
      // green arguments
      translate(-50, -50, 0);
      fill(128, 255, 128);
      bentRect(0, 0, 100, 100, 0.5, -20, 5);
    
      // red interactive
      translate(0, 0, 75);
      fill(255, 128, 128);
      bentRect(0, 0, 100, 100, mouseX/float(width), -50 * mouseY/float(height), 5);
    
      // blue manual
      translate(0, 0, -150);
      fill(128, 128, 255);
      bentRectManual(); 
    }
    
    /**
     * draw a rect that bends down on one corner using a sin curve.
     * 'start' is where the curve begins - 1.0 is all curved, 0 is no curve.
     * 'depth' is the distance the curved point descends from level.
     **/
    void bentRect(float x, float y, float w, float h, float start, float depth, int steps) {
      pushMatrix();
      translate(x, y);
      beginShape(QUAD_STRIP); 
      vertex(0, 0); 
      vertex(0, 0); 
      vertex(w, 0);
      vertex(0, h);
      float amt = 0;
      float bend = 0;
      for (int step=0; step<=steps; step++) {
        amt = start + (1-start) * step/float(steps);
        bend = depth-depth * sin(HALF_PI * (1-step/float(steps)));
        vertex(w, h * amt, bend);
        vertex(w * amt, h, bend);
      }
      endShape();
      popMatrix();
    }
    
    /**
     * manual demonstration of how bentRect() works
     **/
    void bentRectManual() {
      beginShape(QUAD_STRIP); 
      vertex(0, 0);    // first quad - flat triangle
      vertex(0, 0); 
      vertex(100, 0);
      vertex(0, 100);
      vertex(100, 50); // second quad - unbent
      vertex(50, 100);
      vertex(100, 60, bend(.2, -20)); // quad - bent
      vertex(60, 100, bend(.2, -20));
      vertex(100, 70, bend(.4, -20)); // quad - bent
      vertex(70, 100, bend(.4, -20));
      vertex(100, 80, bend(.6, -20)); // quad - bent
      vertex(80, 100, bend(.6, -20));
      vertex(100, 90, bend(.8, -20)); // quad - bent
      vertex(90, 100, bend(.8, -20));
      vertex(100, 100, bend(1, -20)); // quad - bent corner triangle
      vertex(100, 100, bend(1, -20));
      endShape();
    }
    float bend(float amt, float depth) {
      return depth-depth * sin(HALF_PI * (1-amt));
    }
    
  • If you are interested in this approach, note that the function can return a PShape --and it can also accept two color arguments and use lerpColor() to shade the quads based on e.g. how much they are bent.

    BentRectDemo2--screenshot

  • Cool Jeremy, I knew there had to be a better way to do it.

    Though, I am curious to know if it is possible to turn of the lines cutting across the surface? -- I tried using noStroke(), but that didn't work. :-?

  • edited April 2018

    noStroke() or myShape.noStroke() should both work just fine. I only included lines so you could see the quads.

    Posting an example with no stroke lines below.

  • edited April 2018

    BentRectDemo2--screenshot-b

    /**
      * BentRectDemo2
      * 2018-04-21 Jeremy Douglass - Processing 3.3.6
      *
      * Demonstrates drawing a rectangle with a 3D bent corner
      * using a QUAD_STRIP shape. Includes a function bentRect(),
      * a manual function explaining the unrolled loop with comments,
      * and an interactive bend controlled by mouseX / mouseY.
     **/
    import peasy.PeasyCam;
    
    PeasyCam cam;
    PShape bent1, bent2;
    color c1, c2;
    
    void setup() {
      size(300, 300, P3D);
      cam = new PeasyCam(this, 300);
      c1 = color(128,128,255);
      c2 = color(255,128,128);
      //stroke(192);
      //strokeWeight(0.5);
      noStroke(); // affects the manual shape only
      bent1 = bentRect(0, 0, 100, 100, 0.5, -20, 5, c1, c2);
    }
    
    void draw() {
      background(0);
      rotateX(QUARTER_PI);
      rotateY(QUARTER_PI/2);
    
      // green arguments
      translate(-50, -50, 0);
      fill(128, 255, 128);
      shape(bent1);
    
      // red interactive
      translate(0, 0, 75);
      fill(255, 128, 128);
      bent2 = bentRect(0, 0, 100, 100, mouseX/float(width), -50 * mouseY/float(height), 5, c1, c2);
      shape(bent2);
    
      // blue manual
      translate(0, 0, -150);
      fill(128, 128, 255);
      bentRectManual(); 
    }
    
    /**
     * draw a rect that bends down on one corner using a sin curve.
     * 'start' is where the curve begins - 1.0 is all curved, 0 is no curve.
     * 'depth' is the distance the curved point descends from level.
     **/
    PShape bentRect(float x, float y, float w, float h, float start, float depth, int steps, color c1, color c2) {
      PShape myShape = createShape();
      myShape.beginShape(QUAD_STRIP); 
      myShape.translate(x, y);
      myShape.noStroke();
      myShape.fill(c1);
      myShape.vertex(0, 0); 
      myShape.vertex(0, 0); 
      myShape.vertex(w, 0);
      myShape.vertex(0, h);
      float amt, bend = 0;
      for (int step=0; step<=steps; step++) {
        amt = start + (1-start) * step/float(steps);
        bend = 1 - sin(HALF_PI * (1-step/float(steps)));
        myShape.fill(lerpColor(c1, c2, bend));
        myShape.vertex(w, h * amt, depth * bend);
        myShape.vertex(w * amt, h, depth * bend);
      }
      myShape.endShape();
      return myShape;
    }
    
    /**
     * manual demonstration of how bentRect() works
     **/
    void bentRectManual() {
      pushStyle();
      beginShape(QUAD_STRIP); 
      vertex(0, 0);    // first quad - flat triangle
      vertex(0, 0); 
      vertex(100, 0);
      vertex(0, 100);
      vertex(100, 50); // second quad - unbent
      vertex(50, 100);
      vertex(100, 60, bend(.2, -20)); // quad - bent
      vertex(60, 100, bend(.2, -20));
      vertex(100, 70, bend(.4, -20)); // quad - bent
      vertex(70, 100, bend(.4, -20));
      vertex(100, 80, bend(.6, -20)); // quad - bent
      vertex(80, 100, bend(.6, -20));
      vertex(100, 90, bend(.8, -20)); // quad - bent
      vertex(90, 100, bend(.8, -20));
      vertex(100, 100, bend(1, -20)); // quad - bent corner triangle
      vertex(100, 100, bend(1, -20));
      endShape();
      popStyle();
    }
    float bend(float amt, float depth) {
      return depth-depth * sin(HALF_PI * (1-amt));
    }
    
  • Thank you for sharing your knowledge of the 3D world of Processing. I still only get my feet wet at the shallow end of this realm. :)

  • edited April 2018

    Thanks for the answers^^ Actually i already tried a similar approach using Triangle_Strip, but ended up having some concerns, since each plane would be made up of 16 triangles, just to give it the option to bend down each corner, and be able to bend halfways, which would end in having 96 triangles per cube. And I'd also need to calculate the distortion for the triangles on the other sides(if one side bends, the surrounding triangles would need to deform), which makes it all a bit more complicated, even though it would be possible. So the main concern would be performance, since i was planning to add a lot more Cubes,therefore i was trying to have each side be only composed of 4 vertices (or at least less than 48 (16triangles*3vertices) ^^), but that seems to be almost impossible, since i don't know how to work directly with the tangents(dont even know if thats the right word) like the curvevertex uses calculations for that. Well, I'd say, I'll look into how curvevertex works, but i already tried getting the grip of that and its way to confusing for now. Maybe once i reach a certain affinity with such complicated things XD. (Btw, dont know if that sentence actually was right^^)

  • edited April 2018

    i already tried a similar approach using Triangle_Strip, but ended up having some concerns, since each plane would be made up of 16 triangles, just to give it the option to bend down each corner, and be able to bend halfways, which would end in having 96 triangles per cube.

    Well, as you can see this approach gives a pretty good bend with just 5-7 quads -- a bit simpler than 96 triangles.

    i was trying to have each side be only composed of 4 vertices

    Even if you can interpolate waves across three points of a quadrilateral towards a fourth and can define this with a small number of vertices and curves, the actual 3D geometry still has to be rendered at some point in OpenGL -- so this is more like pursuing an approach that gives you the illusion of simplicity in your code, it might not be any less computationally expensive.

    As for finding out what actually impacts performance more, it isn't always obvious which of many approaches will perform better in OpenGL, or if number of shapes or color gradients will affect performance more, or event if there will be any performance impact at all -- better to just build a BoxCurved class, then test a lot of them and see.

  • edited April 2018

    Yeah, it looks simpler, but thinking about it, i assume it would be harder to process if it has to calculate for each "tangentpoint"(dont know exactly how that works, but i guess it still has to calculate that) to bend a litte more than the last, instead of having a straight line for 2-3 pixels, which still looks pretty much bend. (Edit : Actually, what about the lines inbetween triangles in the central parts? Since they dont really would stand out(because it would be a flat surfice with another triangle having the same direction) will those "tangents" also be calculated?)

    Well, as you can see this appraoch gives a pretty good bend with just 5-7 quads -- a bit simpler than 96 triangles.

    Thats true, however, using quads i'm only able to bend 2 corners... with some adjustment, it could reach the same result, but then it would again require pretty much the same number of quads as with triangles (would be more if i would want the same reaction as with triangles, but ~ the same if i go with a simpler curve) (in your example it had 6 quads on one side, so 6 on the other too, would make 12, just to bend BL(Back left) and FR(Front right) corners, so to be able to bend the other sides too, it would need double(24) the amount of quads. And then again double it, to get the option to bend it in half(not diagonaly) which ends up with 48 quads (48*4vertices = 192). And that would be 288 Quads per Cube. Even though the number of composed parts(quads or triangles) might really not matter too much in opengl, im pretty sure the triangles would be a bit easier to calculate within processing.^^ For singular direction bends it would be better to use Quads, but since i need multidirectional bends, I'll gave to use triangles for best results(Still not sure if it changes in Opengl, but in processing it'd be easier for me^^) (Sorry if it sounds kinda bad, but its just the best way i could find)

    Thanks for the info^^

  • using quads i'm only able to bend 2 corners

    Ah! Sorry, I didn't realize that bending all four corners (or all 8 for a cube) was your goal. In your question, you said:

    What i try to achieve is basically just one corner being higher or lower than the rest

    ...so I thought you specifically were trying to bend just one corner.

    And then again double it, to get the option to bend it in half (not diagonally)

    If you are trying to bend a curved surface freely in all directions then you can use a mesh. That could be a quad mesh or a triangle mesh -- TRIANGLE_STRIP is also one quick way to do that.

    Related: You might be interested in How to Draw a Cube with Triangle Strip.

  • Yes, thats pretty much what it looks like till now, just that having so many triangles gave me the concern for performance(and its just plain white and not transparent), but i guess i'll just have to go with it^^ (And seems like i really posted the question wrong xD oh well, now its solved anyways^^) Thanks for all the answers^^ I'll just set the last answer as the solution, since its the closest to what i'm actually trying to achieve, even though now another problem came up, but i'll open a new question for it, since its about relative (hierarchy) translation (or mainly rotation). Thanks again for the answers^^

Sign In or Register to comment.