# QUAD\_STRIP in P3D

**URL:** <https://discourse.processing.org/t/quad-strip-in-p3d/42579>\
**Category:** Coding Questions\
**Created:** [August 11, 2023, 2:40am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579 "2023-08-11T02:40:11Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![travis.stdenis](https://avatars.discourse-cdn.com/v4/letter/t/67e7ee/32.png) [@travis.stdenis](https://discourse.processing.org/u/travis.stdenis)\
**Post date:** [August 11, 2023, 2:40am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/1 "2023-08-11T02:40:11Z")

</div>

I am attempting to convert this ribbon shape that uses lines into using QUAD\_STRIP or even TRIANGLE\_STRIP.

 ![ribbon_of_lines](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/9/e/9efb2ea726c2f3de0a7fa76a9e4cdf635d842635.png)

Here is the code snippet that generates this:

```auto
noFill();
pushMatrix();
translate(midPt.x, midPt.y, midPt.z);
for(int i=0; i<numLines; i++){
  stroke(lerpColor(colorArray[ribbonClrA], colorArray[ribbonClrB], ((1/float(numLines)) * i)));
  strokeWeight(1);
  beginShape();
  for(float a=ribbonPhase; a<TWO_PI+ribbonPhase; a+=0.01){
    float currRad = map(i, 0, numLines, innerRad, outerRad);
    float currAmp = map(i, 0, numLines, innerAmp, outerAmp);
    float Xpos = currAmp * sin(map(a, 0, TWO_PI, 0, PI * ribbonFreq));
    float Ypos = currRad * sin(a);
    float Zpos = currRad * cos(a);
    curveVertex((i * lineSpace) + Xpos, Ypos, Zpos);
  }
  endShape(CLOSE);
}
popMatrix();

```

When using QUAD\_STRIP i get this results:  
 ![ribbon_of_quads](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/2/1/21dfdc974595f6c0d77eb1da9eac7a668a7652a2.png)

And here is the code:

```auto
fill(colorArray[ribbonClrA], 175);
noStroke();
pushMatrix();
translate(midPt.x, midPt.y, midPt.z);
beginShape(QUAD_STRIP);
for(float a=ribbonPhase; a<=TWO_PI+ribbonPhase; a+=0.01){
  float innerXpos = innerAmp * sin(map(a, 0, TWO_PI, 0, PI * ribbonFreq));
  float innerYpos = innerRad * sin(a);
  float innerZpos = innerRad * cos(a);
  vertex(innerXpos, innerYpos, innerZpos);
  float outerXpos = outerAmp * sin(map(a, 0, TWO_PI, 0, PI * ribbonFreq));
  float outerYpos = outerRad * sin(a);
  float outerZpos = outerRad * cos(a);
  vertex(outerXpos, outerYpos, outerZpos);
}
endShape();
popMatrix();

```

How might I get this to work? Does QUAD\_STRIP even work in P3D (there’s nothing to suggest it won’t)? Is there another solution altogether that is recommended?

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 11, 2023, 6:43am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/2 "2023-08-11T06:43:34Z")

</div>

Please always post entire / runable code

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 11, 2023, 7:26am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/3 "2023-08-11T07:26:37Z")

</div>

in `draw()` consider

```auto
void draw() {
   background(0); 
   avoidClipping(); 
   lights(); 
   ...

```

and paste this

```auto

// Tools 

void avoidClipping() {
  // avoid clipping (at camera): 
  // https : // 
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func

```

also, you can use peasyCam to rotate freely in 3D: [peasycam](https://mrfeinberg.com/peasycam/)

Chrisir

not related QUADS example

```auto

final int resolution = 32;

QUAD3D[] points = new QUAD3D[resolution * resolution];
float scale = 250.0;

void setup() {
  size(1720, 905, P3D);
  // perspective(PI / 3.0, -width / (float)height, 0.001, 1000.0);
  noStroke();

  int len = points.length;

  // Calc points.
  float toFac = 1.0 / (resolution - 1.0);
  for (int k = 0; k < len; ++k) {
    int i = k / resolution;
    int j = k % resolution;

    float iFac = i * toFac;
    float jFac = j * toFac;

    float iSigned = iFac + iFac - 1.0;
    float jSigned = jFac + jFac - 1.0;
    float fxy = iSigned * iSigned * jSigned;

    float x = iSigned * scale;
    float y = jSigned * scale;
    float z = fxy * scale;

    int red = (int)(0.5 + 255.0 * iFac);
    int green = (int)(0.5 + 255.0 * jFac);
    int blue = (int)(0.5 + 255.0 * (fxy * 0.5 + 0.5));

    points[k] = new QUAD3D();
    points[k].col = 0xff000000 | (red << 0x10) | (green << 0x08) | blue;
    points[k].pos.set(x, y, z);
  }
}

void draw() {
  surface.setTitle(nfs(frameRate, 1, 1));

  background(#202020);

  camera(
    width/2, -633, 320,
    0.0, 0.0, 0.0,
    0.0, 1, 0);

  avoidClipping();
  lights();

  // coord()

  strokeWeight(1.0);
  stroke(#ff0000);
  line(0.0, 0.0, 0.0, 100.0, 0.0, 0.0);
  stroke(#00ff00);
  line(0.0, 0.0, 0.0, 0.0, 100.0, 0.0);
  stroke(#0000ff);
  line(0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
  noStroke();

  // Draw.
  /*
  if (mousePressed) {
   strokeWeight(1.0);
   stroke(#ffffff);
   } else {
   noStroke();
   }
   */

  rotateZ(frameCount * 0.01);

  beginShape(QUADS);
  for (int i = 0; i < resolution - 1; ++i) {

    int noff0 = i * resolution;
    int noff1 = noff0 + resolution;
    for (int j = 0; j < resolution - 1; ++j) {
      int v00 = noff0 + j;
      int v10 = v00 + 1;
      int v01 = noff1 + j;
      int v11 = v01 + 1;

      points[v00].display();
      points[v10].display();
      points[v11].display();
      points[v01].display();
    }
  }
  endShape(CLOSE);
}

// Tools

void avoidClipping() {
  // avoid clipping (at camera):
  // https : //
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func

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

class QUAD3D {
  PVector pos=new PVector();
  color col=color(0);

  // no constr

  void display() {
    fill(col);
    vertex(pos.x, pos.y, pos.z);
  }
  //
}//class
//

```

**Quad\_strip example**

```auto

import peasy.*;

final int GENERAL_Y_HEIGHT = 500;

//
PeasyCam camera;
PShape shapeBridgeToCastleGate;

// Array of ArrayList
ArrayList[] arrListBridgeToCastle = new ArrayList[2];

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

void setup() {
  size (1400, 800, P3D);

  avoidClipping();

  // The bridge over the water
  makeBridgeToCastle();

  camera = new PeasyCam(this, width/2, height/2, 0, 900);
} // func

void draw() {
  background(#12AEFF);

  // apply lights
  lights();

  shape(shapeBridgeToCastleGate);
}

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

void makeBridgeToCastle() {
  // plate in front - way to castle

  // make ArrayLists
  for ( ArrayList<PVector> a1 : arrListBridgeToCastle) {
    a1 = new ArrayList();
  }//for

  float depthHalf = 100;

  arrListBridgeToCastle[0] = getLineArc2( 115, depthHalf ); // lower right // arc
  arrListBridgeToCastle[1] = getLineArc2( 115, -depthHalf ); // lower left // arc

  noStroke();
  // fill(183, 143, 11);//brown
  fill(255, 0, 0);
  shapeBridgeToCastleGate=createShape();
  shapeBridgeToCastleGate.beginShape(QUAD_STRIP);

  // Eval ArrayLists
  for (int i3=0; i3<200-1; i3++) { //
    makeVertex3D2a( arrListBridgeToCastle[0], i3);
    makeVertex3D2a( arrListBridgeToCastle[0], i3+1);

    makeVertex3D2a( arrListBridgeToCastle[1], i3);
    makeVertex3D2a( arrListBridgeToCastle[1], i3+1);
  }//for

  shapeBridgeToCastleGate.endShape();
}//func

void makeVertex3D2a( ArrayList<PVector> arrL_, int i ) {

  // ArrayList version

  PVector v = arrL_.get(i);
  shapeBridgeToCastleGate.vertex(v.x, v.y, v.z);
}

void avoidClipping() {
  // avoid clipping :
  // https : //
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func

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

ArrayList<PVector> getLineArc2 ( float y_, float z_ ) {

  // fill ArrayList with Arc

  // make ArrayList
  ArrayList<PVector> newArrayList = new ArrayList();

  for (int i3=0; i3<800; i3++) { //

    float farAngle=PI/3;
    float angle=map(i3, 0, 800, -farAngle, farAngle);
    angle+=radians(310);
    float r =580 ;
    float x=cos(angle)*r;
    float y=sin(angle)*r+y_;

    // store points in list

    PVector pv1 = new PVector(2.5*x+394+222+111-32-32, 4.1*y+GENERAL_Y_HEIGHT+941+400+22+22+12+22+333+111, zValue2(z_, angle));

    newArrayList.add(pv1);
  } //for

  return newArrayList;
  //
}// func ---

float zValue2(float z_, float angle_) {
  float factor1=3.1;
  if (z_<0)
    return z_-angle_*factor1;
  else
    return z_+angle_*factor1;
}
//

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 11, 2023, 12:41pm UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/4 "2023-08-11T12:41:38Z")

</div>

As you can see in the last example your usage of the QuadStrip might be wrong imho

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [August 11, 2023, 4:03pm UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/5 "2023-08-11T16:03:36Z")

</div>

In these code snippets

```auto
beginShape(QUAD_STRIP);
    // vertex data in correct order
endShape();

```

and

```auto
beginShape(TRIANGLE_STRIP);
    // vertex data in correct order
endShape();

```

the vertex data order is exactly the same so the only code difference is the first line but there is still a difference between using quads and triangles.

You have probably heard the phrase

> _three points define a plane_

so for any three points in 3D space they will always sit on a flat pane. Quads require 4 points to define them and there is no guarantee that they will all sit on the same flat plane.

In your example I would recommend using triangle strips because the complex curvature in the shape. A quad strip might produce a more angular surface.

So all that remains is to determine the vertex order to use.

Consider the following geometry 7 x 4 points -

 ![Scan 1](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/c/0/c07144a6f00ede716f1802062e2ed9a9e8c2b475.jpeg)

In both quad and triangle strip the vertices are specified in pairs like this

```auto
// First strip
beginShape(TRIANGLE_STRIP);
    [0 1] [2 3] [4 5]......[12 13]
endShape();
// Second strip
beginShape(TRIANGLE_STRIP);
    [14 15] [16 17] [18 19]......[26 27]
endShape();
// and so on

```

The numbers represent the order the points should be specified. Note that some represent the same point e.g.  
`{1 & 14} {13 26} {21 & 34}`

To avoid calculating these points twice I suggest that you create a 2D array for the points then

1. calculate the XYZ position for each point and store it in the array
2. use the array to render the shape.

Separating the calculation form the rendering has several benefits

- each vertex is calculated just once and then shared when rendering
- the vertex calculations only need to be done if the shape changes
- simplifies the code by compartmentalizing it into responsibilities
- the array can be used with p5.Geometry for super fast rendering (advanced topic)

---

<div class="post-metadata">

**Author:** ![travis.stdenis](https://avatars.discourse-cdn.com/v4/letter/t/67e7ee/32.png) [@travis.stdenis](https://discourse.processing.org/u/travis.stdenis)\
**Post date:** [August 12, 2023, 8:56pm UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/6 "2023-08-12T20:56:38Z")

</div>

can you explain this a bit more please. the link isn’t working. what is happening in the call to perspective and what is it solving for?

```auto
void avoidClipping() {
  // avoid clipping (at camera): 
  // https : // 
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 13, 2023, 6:35am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/7 "2023-08-13T06:35:35Z")

</div>

Sure, it avoids clipping/ cut off at the camera

Sometimes shapes are cut off when it’s too near the camera

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [August 13, 2023, 9:00am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/8 "2023-08-13T09:00:55Z")

</div>

> [@travis.stdenis](#):
>
> ` perspective(PI/3.0, (float) width/height, 1, 1000000);`

The last 2 parameters determine the _near_ and _far zone_ distances respectively. Any point closer than the near zone or further than the far zone distance will not be rendered.

So in this statement only points \>=1 and \<=1000000 will be rendered. This is an extremely wide render zone and could _adversely_ impact performance because distant objects will be rendered even if the display size ends up smaller than a pixel! Similarly very near objects could be outside the field of view and be needlessly rendered.

The default values depend on the width and height of your sketch window and you can calculate them using the reference for [perspective](https://processing.org/reference/perspective_.html). The actual values you need depend on your sketch size and what you want to render. I suggest you calculate them for your sketch size and only increase the render zone if you have to,

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [August 13, 2023, 3:36pm UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/9 "2023-08-13T15:36:03Z")

</div>

Hello @travis.stdenis,

Your code (I added to it) did generate a single ribbon with QUAD\_STRIP or TRIANGLE\_STRIP:

```auto
// Original code:
// https://discourse.processing.org/t/quad-strip-in-p3d/42579

// Some additions and modifications by glv 2023-08-13 here:
// https://discourse.processing.org/t/quad-strip-in-p3d/42579/9

size(500, 500, P3D);  
background(192);  

translate(width/2, height/2, -400); // z moved back
rotateY(TAU/16);

float innerRad = 150; 
float innerAmp = 150; 

float outerRad = 150+30; 
float outerAmp = 150+30; 

float ribbonFreq = 4;

beginShape(QUAD_STRIP);
//beginShape(TRIANGLE_STRIP);
  
int steps = 50;

for(int j=0; j<=steps; j++) // This replaces the for loop commented below
  {
  float th = j*(TWO_PI/steps);

//for(float th=0; th<TWO_PI; th+=0.05)
// {
  
  float innerXpos = innerAmp * sin(map(th, 0, TWO_PI, 0, PI * ribbonFreq));
  float innerYpos = innerRad * sin(th);
  float innerZpos = innerRad * cos(th);
  vertex(innerXpos, innerYpos, innerZpos);
  
  float outerXpos = outerAmp * sin(map(th, 0, TWO_PI, 0, PI * ribbonFreq));
  float outerYpos = outerRad * sin(th);
  float outerZpos = outerRad * cos(th);
  vertex(outerXpos, outerYpos, outerZpos);
  }
endShape();  

```

Output:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/9/6/9682882b0e03460611580058f60e8171c3488ebe.png)

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/5/d/5d5321d5f871ada127d03e125e9aad22571df0ef.png)

I repeated the above ribbon in a nested for() loop and modified _Rad_ and _Amp_ as required:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/a/0/a0f2be91df163e87e2ff33a7615cb052402f1783.png)

Scrutinize the code for other changes.

Related:

- [# Coding Challenge #25: Spherical Geometry](https://www.youtube.com/watch?v=RkuBWEkBrZA)
- [Triangle Strip / Examples / Processing.org](https://processing.org/examples/trianglestrip.html)

`:)`

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [August 14, 2023, 9:09am UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/10 "2023-08-14T09:09:55Z")

</div>

new version with

- lights(), peasyCam and avoidClipping

```auto

// Original code:
// https://discourse.processing.org/t/quad-strip-in-p3d/42579
// Some additions 

import peasy.*;

PeasyCam camera;

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

void setup() {
  size(500, 500, P3D);
  background(192);

  camera = new PeasyCam(this, width/2, height/2, 0, 900);
}

void draw() {
  background(192);

  avoidClipping();

  lights();
  translate(width/2, height/2, -400); // z moved back
  rotateY(TAU/16);

  float innerRad = 150;
  float innerAmp = 150;

  float outerRad = 150+30;
  float outerAmp = 150+30;

  float ribbonFreq = 4;

  //translate(midPt.x, midPt.y, midPt.z);

  beginShape(QUAD_STRIP);
  //beginShape(TRIANGLE_STRIP);

  int steps = 50;

  //fill(colorArray[ribbonClrA], 175);
  fill(255, 0, 0, 175);
  noStroke();
  pushMatrix();

  float ribbonPhase=0.83;
  for (float a=ribbonPhase; a<=TWO_PI+ribbonPhase; a+=0.01) {
    float innerXpos = innerAmp * sin(map(a, 0, TWO_PI, 0, PI * ribbonFreq));
    float innerYpos = innerRad * sin(a);
    float innerZpos = innerRad * cos(a);
    vertex(innerXpos, innerYpos, innerZpos);
    float outerXpos = outerAmp * sin(map(a, 0, TWO_PI, 0, PI * ribbonFreq));
    float outerYpos = outerRad * sin(a);
    float outerZpos = outerRad * cos(a);
    vertex(outerXpos, outerYpos, outerZpos);
  }
  endShape();
  popMatrix();
}

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

void avoidClipping() {
  // avoid clipping :
  // https : //
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func
// ---------------------------------------------------------------------------------------
//

```

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [August 14, 2023, 9:04pm UTC](https://discourse.processing.org/t/quad-strip-in-p3d/42579/11 "2023-08-14T21:04:42Z")

</div>

Hello @travis.stdenis,

- Also give consideration to the for loops (integer vs floating point) you are using:  
[https://www.google.com/search?q=floating+point+loop](https://www.google.com/search?q=floating+point+loop)  
The search will reveal numerous topics on this subject.

- Show the strokes during development to see the strips.

Integer for() loop:

```auto
for(int j=0; j<steps; j++)
  {
  float th = j*(TWO_PI/steps); // TWO_PI/steps most likely optimized but can be taken out of loop

```

Output with integer for() loop:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/3/6/36bf3e6f4f12ef6ff8fa9eb476816c1660995ba9.png)

Floating point for() loop:

```auto
for(float th=0; th<=TWO_PI; th+=TWO_PI/50)
  {

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/a/7/a783bce74d6e9c745f5c210672e97ccf51e53109.png)

```auto
for(float th=0; th<=TWO_PI; th+=.01)
  {

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/3/739ff632ef4d964f7483f4396568ac2fb8b2f63a.png)

Zoomed in to see the gap:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/1/812b5c18d976ab56e6fd6766d14bb4238bed7dfd.png)

Do you need this density of triangles?

Some code to examine the different methods for integer for() loop:

```auto
int steps = 100;
float inc = TWO_PI/steps;
float th0=0, th1=0;

for(int j=0; j<=steps; j++)
  {
  th0 = j*inc; // Preferred!
  println("th0:", th0, " th1:", th1, " diff:", th1-th0);
  th1 = th1 += inc; // The Processing example did this!
  }
  
println("TWO_PI", TWO_PI);

Output:

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/b/7b29120c0fd103da877b88da7e945ae5310e7657.png)

`:)`
