# Panorama warping cylinder

**URL:** <https://discourse.processing.org/t/panorama-warping-cylinder/9131>\
**Category:** Libraries\
**Created:** [March 9, 2019, 1:08am UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131 "2019-03-09T01:08:41Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [March 9, 2019, 1:08am UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/1 "2019-03-09T01:08:41Z")

</div>

Hello, i would like to create this warp

 ![](https://yyz2.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/1/11dcfad9e0e7ff2d438adbcb6f514570085071cb.gif)  
(source: [http://paulbourke.net/stereographics/cylinder/](http://paulbourke.net/stereographics/cylinder/))

i Just found a way to use opencv but i am not super clear

> <https://stackoverflow.com/questions/39944635/convert-an-image-to-cylindrical-shape-in-java>

do you know any way to create in real time the cylinder warping image?  
I want to project in a cylinder structure

Thanks!

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [March 11, 2019, 12:17am UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/2 "2019-03-11T00:17:36Z")

</div>

There are several ways to approach this. I think you want to use the Shapes3D library – perhaps the Tube type:

[http://lagers.org.uk/s3d4p/index.html](http://lagers.org.uk/s3d4p/index.html)

If you want to use shaders, the Shaders tutorial also shows several examples of images on cylinders. The example uses texture on a PShape.

[https://processing.org/tutorials/pshader/](https://processing.org/tutorials/pshader/)

![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/dae62b61acce933de423c5ce9881f9e4f457de97.png)

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 4, 2019, 2:55pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/3 "2019-04-04T14:55:24Z")

</div>

Thanks for your answer. My question is, for example, if I project in the cylinder through a texture a straight line, will it look curved or can I keep it straight?

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [April 5, 2019, 4:22am UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/4 "2019-04-05T04:22:49Z")

</div>

> [@janebeta7](#):
>
> I want to project in a cylinder structure

Do you mean you are trying to project onto a real physical wall, and use processing to warp the projection (projection map) so it appears as if projected on a flat surface?

Is there only one audience member with a fixed point of view, or a distant audience? Because I think that optical illusion possible, but only from one perspective – moving would break the illusion.

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 5, 2019, 9:33am UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/5 "2019-04-05T09:33:00Z")

</div>

Yes, Cylinder phisical wall projectors inside the cylinder.  
The cylinder will be in a theatre then the audience only could see one part of the cylinder.

![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/a/a0dbabc650c80f5af97e85b9eec338c8c6c3095f.gif)

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [April 6, 2019, 2:03pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/6 "2019-04-06T14:03:38Z")

</div>

> [@janebeta7](#):
>
> if I project in the cylinder through a texture a straight line, will it look curved or can I keep it straight?

No – for a large theater audience, you cannot have a cylinder on stage with theater seating and project a shape onto it that will look like a true flat rectangle (perspective illusion) to everyone. It will only look right to a few audience members – unless the cylinder is small and far away. The top and bottom edge will look warped for any audience members not sitting in the sweet spot.

To test – make a paper tube, project a square on it, and draw it. Now prop it up and see what angles the illusion works from.

However, you CAN project from an angle and correct it to look like a wrapped label – eg a soup can label. That will should look “the same” to everyone – they will all see a different wrapping, but it will look normal, like a soup can, curved in z but straight in xy.

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 17, 2019, 11:48am UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/7 "2019-04-17T11:48:29Z")

</div>

thanks Jeremy, then , what its the best way to do this?.

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [April 17, 2019, 12:05pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/8 "2019-04-17T12:05:54Z")

</div>

If your only goal is to have the top and bottom borders of your image “parralel” to the top and bottom borders of the cylinder you are projecting on (i.e. the borders of your image will always be at the same distance to the borders of the cylinder) and the same for the right and left edges then yes it would work even for a large audience.

To acheive that effect, you could probably ray-trace with real life measurement (a bit like it is done with the first pic you posted) to project the transformation on a plane.

Once you have those points on the projected plane, you have a displacement grid that you can use on normal image to deform it the correct way.

Hope it helps.

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 17, 2019, 12:10pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/9 "2019-04-17T12:10:45Z")

</div>

> [@jb4x](#):
>
> If your only goal is to have the top and bottom borders of your image “parralel” to the top and bottom borders of the cylinder you are projecting on (i.e. the borders of your image will always be at the same distance to the borders of the cylinder) and the same for the right and left edges then yes it would work even for a large audience.
> 
> To acheive that effect, you could probably ray-trace with real life measurement (a bit like it is done with the first pic you posted) to project the transformation on a plane.
> 
> Once you have those points on the projected plane, you have a displacement grid that you can use on normal image to deform it the correct way.
> 
> Hope it helps.

Yes, I think that i need this. Then I need to create a cylinder mesh in Processing, that ray-trace to the plane like this  
/[http://paulbourke.net/stereographics/cylinder/](http://paulbourke.net/stereographics/cylinder/) but in a 3D space  
 ![](http://paulbourke.net/stereographics/cylinder/all.jpg)  
to move a ball or a square in polar coordinates, 4 example.  
But i don’t know how to do this ☹

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [April 17, 2019, 12:12pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/10 "2019-04-17T12:12:42Z")

</div>

I have made something similar in the past with plenty of helper functions to find intersection between line and plane, between line and line etc…

I don’t have it know, but I can post it here this evening (evening for me at least ^^)

It should help you do it.

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [April 17, 2019, 3:45pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/11 "2019-04-17T15:45:59Z")

</div>

Okay, so it’s a bit of a mess since it was something I was doing simply to get my head around something.

Basically the Line class and the Plan class are the one that you should aim for. They get a bunch of features that can be really helpful for you.

The Film class is there to draw the cylinder shape that you can see. The mirror is not shown but is basically a plan at 45° angle on which I compute bouncing light rays. The reference class is just there to draw The X, Y and Z axis.

Here you go:

```auto
import peasy.*;

PeasyCam cam;
Film film;
Reference ref;
Plan mirror, screen;
Line[] sourceBeams, reflectionBeams, displaySourceBeams, displayReflectionBeams;
PVector[] mirrorHits, screenHits;
float[] pointQuality;
float focalLength;

public void settings() {
  //size(800, 600, P3D);
  fullScreen(P3D);
}

public void setup() {  
  cam = new PeasyCam(this, 400);

  focalLength = 0.3*0.3*750;
  film = new Film(120, 60, focalLength, 1, 4);
  ref = new Reference(400);
  mirror = new Plan(0, -1, 1, new PVector(0, 20, 10));
  screen = new Plan(0, 0, 1, new PVector(0, 0, 35));

  PVector[][] filmVertices = film.getVertices();
  sourceBeams = new Line[filmVertices.length * filmVertices[0].length];
  displaySourceBeams = new Line[filmVertices.length * filmVertices[0].length];
  mirrorHits = new PVector[filmVertices.length * filmVertices[0].length];
  reflectionBeams = new Line[filmVertices.length * filmVertices[0].length];
  displayReflectionBeams = new Line[filmVertices.length * filmVertices[0].length];
  screenHits = new PVector[filmVertices.length * filmVertices[0].length];
  pointQuality = new float[filmVertices.length * filmVertices[0].length];

  for (int j = 0; j < filmVertices[0].length; j++) {
    for (int i = 0; i < filmVertices.length; i++) {
      sourceBeams[j * filmVertices.length + i] = new Line("POINT", new PVector(0, 0, 0), filmVertices[i][j].copy());
    }
  }

  computeRays();
}

void draw() {
  background(20);
  //scale(-1, 1, 1);
  lights();
  ref.show();
  film.show();
  screen.show();
  //mirror.show();
  //sourceBeams[8].show();
  //reflectionBeams[8].show();
  for (int i = 0; i < sourceBeams.length; i++) {
    displaySourceBeams[i].show();
    drawPoint(mirrorHits[i], color(200, 20, 200));
    displayReflectionBeams[i].show();
    drawPoint(screenHits[i], getQualityColor(pointQuality[i]));
  }
  //displaySourceBeams[0].show();
  //drawPoint(mirrorHits[0], color(200, 20, 200));
  //displayReflectionBeams[0].show();
  //drawPoint(screenHits[0], getQualityColor(pointQuality[0]));
}

void drawPoint(PVector vect, color col) {
  stroke(col);    
  fill(col);

  pushMatrix();
  translate(vect.x, vect.y, vect.z);
  sphere(0.5);
  popMatrix();
}

void computeRays() {
  PVector[][] filmVertices = film.getVertices();
  for (int j = 0; j < filmVertices[0].length; j++) {
    for (int i = 0; i < filmVertices.length; i++) {
      mirrorHits[j * filmVertices.length + i] = sourceBeams[j * filmVertices.length + i].getIntersectionPointWith(mirror);
      displaySourceBeams[j * filmVertices.length + i] = new Line("POINT", new PVector(0, 0, 0), mirrorHits[j * filmVertices.length + i].copy());
      reflectionBeams[j * filmVertices.length + i] = sourceBeams[j * filmVertices.length + i].getReflexionLineWih(mirror);
      screenHits[j * filmVertices.length + i] = reflectionBeams[j * filmVertices.length + i].getIntersectionPointWith(screen);
      displayReflectionBeams[j * filmVertices.length + i] = new Line("POINT", mirrorHits[j * filmVertices.length + i].copy(), screenHits[j * filmVertices.length + i].copy());
      pointQuality[j * filmVertices.length + i] = getDeltaFromFocus(mirrorHits[j * filmVertices.length + i], screenHits[j * filmVertices.length + i]);
    }
  }
}

void keyPressed() {
  if (keyCode == 129) {
    screen.movePlan(0, 0, -1);
  } else if (keyCode == 135) {
    screen.movePlan(0, 0, 1);
  } else if (keyCode == 131) {
    mirror.movePlan(0, 0, -1);
  } else if (keyCode == 137) {
    mirror.movePlan(0, 0, 1);
  }
  computeRays();
}

float getDeltaFromFocus(PVector mirrorPt, PVector screenPt) {
  float d, d1, d2;

  d1 = dist(0, 0, 0, mirrorPt.x, mirrorPt.y, mirrorPt.z);
  d2 = dist(mirrorPt.x, mirrorPt.y, mirrorPt.z, screenPt.x, screenPt.y, screenPt.z);
  d = d1 + d2;

  return abs(d - focalLength);
}

color getQualityColor(float delta) {
  float value = constrain(delta, 0, 20);
  value /= 20;

  return lerpColor(color(0, 255, 0), color(255, 0, 0), value);
}

class Film {
  private float w, h, d;
  private int heightSubLevel, widthSubLevel;
  //private ArrayList<PVector> vertices;
  private PVector[][] vertices;

  public Film(float w, float h, float d, int heightSubLevel, int widthSubLevel) {
    setupFilm(w, h, d, heightSubLevel, widthSubLevel);
  }

  private void setupFilm(float w, float h, float d, int heightSubLevel, int widthSubLevel) {
    this.w = w;
    this.h = h;
    this.d = d;
    this.heightSubLevel = heightSubLevel;
    this.widthSubLevel = widthSubLevel;
    computVertices();
  }

  private void computVertices() {
    int heighSub = (int)(pow(2, heightSubLevel));
    int widthSub = (int)(pow(2, widthSubLevel));

    PVector[] horSlice = new PVector[widthSub + 1];

    float filmOpeningAngle = w / d;
    float angleStep = filmOpeningAngle / widthSub;    
    float zStep = h / heighSub;

    float alpha = HALF_PI + (filmOpeningAngle / 2);
    for (int i = 0; i < horSlice.length; i++) {
      horSlice[i] = new PVector(d * cos(alpha), d * sin(alpha));
      alpha -= angleStep;
    }

    vertices = new PVector[widthSub + 1][heighSub + 1];
    float z = h / 2;
    for (int j = 0; j < heighSub + 1; j++) {
      for (int i = 0; i < horSlice.length; i++) {
        vertices[i][j] = new PVector(horSlice[i].x, horSlice[i].y, z);
      }
      z -= zStep;
    }
  }

  public void show() {
    fill(200);
    stroke(0);
    strokeWeight(1);
    for (int j = 0; j < vertices[0].length - 1; j++) { 
      for (int i = 0; i < vertices.length - 1; i++) {
        beginShape(QUADS);
        vertex(vertices[i][j].x, vertices[i][j].y, vertices[i][j].z);
        vertex(vertices[i][j+1].x, vertices[i][j+1].y, vertices[i][j+1].z);
        vertex(vertices[i+1][j+1].x, vertices[i+1][j+1].y, vertices[i+1][j+1].z);
        vertex(vertices[i+1][j].x, vertices[i+1][j].y, vertices[i+1][j].z);
        endShape();
      }
    }
    endShape();
  }
  
  public PVector[][] getVertices() {
    PVector[][] result = new PVector[vertices.length][vertices[0].length];
    for (int i = 0; i < vertices.length; i++) {
      for (int j = 0; j < vertices[0].length; j++) {
        result[i][j] = vertices[i][j].copy();
      }
    }
    return result;
  }
}

class Line {
  private PVector P0, P1, dir;

  public Line(String initType, PVector P0, PVector P1) {
    this.P0 = P0;

    if (initType == "POINT") {
      this.dir = P1.copy().sub(P0.copy()).normalize();
      this.P1 = P1.copy();
    } else if (initType == "DIR") {
      this.dir = P1.copy();
      this.P1 = new PVector(P0.x + 300*dir.x, P0.y + 300*dir.y, P0.z + 300*dir.z);
    } else {
      println("Error!");
    }
  }

  public void show() {
    stroke(81, 255, 162);
    strokeWeight(1);
    line(P0.x, P0.y, P0.z, P1.x, P1.y, P1.z);
  }

  public PVector getIntersectionPointWith(Plan plan) {
    float a = plan.getCoef()[0];
    float b = plan.getCoef()[1];
    float c = plan.getCoef()[2];
    float d = plan.getCoef()[3];

    float lambda = - (a * P0.x + b * P0.y + c * P0.z + d) / (a * dir.x + b * dir.y + c * dir.z);

    float x = P0.x + lambda * dir.x;
    float y = P0.y + lambda * dir.y;
    float z = P0.z + lambda * dir.z;

    return new PVector(x, y, z);
  }
  
  public PVector getDir() {
    return dir.copy();
  }
  
  //public Line getProjectionLineOn(Plan plan) {
  // PVector proj1, proj2;
  // Line line1, line2;
    
  // //Get the axis of rotation
  // float a = plan.getCoef()[0];
  // float b = plan.getCoef()[1];
  // float c = plan.getCoef()[2];
  // PVector planNormal = new PVector(a, b, c);
    
  // line1 = new Line("DIR", this.P0, planNormal);
  // line2 = new Line("DIR", this.P1, planNormal);
    
  // proj1 = line1.getIntersectionPointWith(plan);
  // proj2 = line2.getIntersectionPointWith(plan);
    
  // return new Line("POINT", proj1, proj2);
  //}
  
  public Line getReflexionLineWih(Plan plan) {
    // Get the point of intersection with the plan
    PVector I = this.getIntersectionPointWith(plan);
    
    //Get the plan normal
    float a = plan.getCoef()[0];
    float b = plan.getCoef()[1];
    float c = plan.getCoef()[2];
    PVector planNormal = new PVector(a, b, c);
    
    //Get line projection on plan direction
    //Line beamProjectionLine = this.getProjectionLineOn(mirror);
    
    // Get rotation axis
    PVector rotAxis = this.dir.copy().cross(planNormal).normalize();
    
    // Get the angle of rotation
    float theta = acos(dir.copy().dot(planNormal) / (dir.mag() * planNormal.mag()));
    theta = degrees(theta) - 90;
    float rotAngle = HALF_PI + radians(theta);
    
    // Get the matrix of rotation
    float[][] rotMatrix = new float[3][3];
    rotMatrix[0][0] = rotAxis.x * rotAxis.x * (1 - cos(rotAngle)) + cos(rotAngle);
    rotMatrix[1][0] = rotAxis.x * rotAxis.y * (1 - cos(rotAngle)) + rotAxis.z * sin(rotAngle);
    rotMatrix[2][0] = rotAxis.x * rotAxis.z * (1 - cos(rotAngle)) - rotAxis.y * sin(rotAngle);
    
    rotMatrix[0][1] = rotAxis.x * rotAxis.y * (1 - cos(rotAngle)) - rotAxis.z * sin(rotAngle);
    rotMatrix[1][1] = rotAxis.y * rotAxis.y * (1 - cos(rotAngle)) + cos(rotAngle);
    rotMatrix[2][1] = rotAxis.y * rotAxis.z * (1 - cos(rotAngle)) + rotAxis.x * sin(rotAngle);
    
    rotMatrix[0][2] = rotAxis.x * rotAxis.z * (1 - cos(rotAngle)) + rotAxis.y * sin(rotAngle);
    rotMatrix[1][2] = rotAxis.y * rotAxis.z * (1 - cos(rotAngle)) - rotAxis.x * sin(rotAngle);
    rotMatrix[2][2] = rotAxis.z * rotAxis.z * (1 - cos(rotAngle)) + cos(rotAngle);
    
    // Get the direction of the reflexion beam
    float x, y, z;
    x = rotMatrix[0][0] * planNormal.x + rotMatrix[0][1] * planNormal.y + rotMatrix[0][2] * planNormal.z;
    y = rotMatrix[1][0] * planNormal.x + rotMatrix[1][1] * planNormal.y + rotMatrix[1][2] * planNormal.z;
    z = rotMatrix[2][0] * planNormal.x + rotMatrix[2][1] * planNormal.y + rotMatrix[2][2] * planNormal.z;
    
    PVector reflexionDir = new PVector(-x, -y, -z);
    
    return new Line("DIR", I, reflexionDir);
  }
}

class Mirror extends Plan {
  private float w, h;
  private PVector[] vertices;
  private PVector center;
  
  public Mirror(float a, float b, float c, PVector P, float w, float h) {
    super(a, b, c, P);
    this.w = w;
    this.h = h;
    this.center = P;
    
    computeVertices();
  }
  
  private void computeVertices() {
    PVector U, V, N, up;
    
    N = new PVector(super.a, super.b, super.c);
    N.normalize();
    up = new PVector(0, 0, 1);
    U = up.cross(N);
    U.normalize();
    V = U.cross(N);
    V.normalize();
    
    vertices = new PVector[4];
    vertices[0] = U.copy().mult(-w/2).add(V.copy().mult(h/2)).add(center);
    vertices[1] = U.copy().mult(w/2).add(V.copy().mult(h/2)).add(center);
    vertices[2] = U.copy().mult(w/2).add(V.copy().mult(-h/2)).add(center);
    vertices[3] = U.copy().mult(-w/2).add(V.copy().mult(-h/2)).add(center);
  }
  
  public void show() {
    fill(40, 145, 237);
    stroke(0);
    strokeWeight(1);
    
    beginShape(QUADS);
    vertex(vertices[0].x, vertices[0].y, vertices[0].z);
    vertex(vertices[1].x, vertices[1].y, vertices[1].z);
    vertex(vertices[2].x, vertices[2].y, vertices[2].z);
    vertex(vertices[3].x, vertices[3].y, vertices[3].z);
    endShape();
  }
}

class Plan {
  // Plan of equation ax + by + cz + d = 0;
  private float a, b, c, d;
  private PVector[] vertices;
  private PVector P;

  public Plan(float a, float b, float c, PVector P) {
    this.a = a;
    this.b = b;
    this.c = c;    
    this.P = P.copy();

    d = - (a * P.x + b * P.y + c * P.z);
    vertices = new PVector[4];
    computeVertices();
  }

  private void computeVertices() {
    if (a == 0 && b == 0) {
      vertices[0] = new PVector(-200, 200, -d / c);
      vertices[1] = new PVector(200, 200, -d / c);
      vertices[2] = new PVector(200, -200, -d / c);
      vertices[3] = new PVector(-200, -200, -d / c);
    } else {
      vertices[0] = new PVector(-200, -(a * -200 + c * 200 + d) / b, 200);
      vertices[1] = new PVector(200, -(a * 200 + c * 200 + d) / b, 200);
      vertices[2] = new PVector(200, -(a * 200 + c * -200 + d) / b, -200);
      vertices[3] = new PVector(-200, -(a * -200 + c * -200 + d) / b, -200);
    }
  }
  
  public void movePlan(float dx, float dy, float dz) {
    P = new PVector(P.x + dx, P.y + dy, P.z + dz);
    d = - (a * P.x + b * P.y + c * P.z);
    computeVertices();
  }

  public void show() {
    fill(40, 145, 237, 0);
    stroke(0);
    strokeWeight(1);

    beginShape(QUADS);
    vertex(vertices[0].x, vertices[0].y, vertices[0].z);
    vertex(vertices[1].x, vertices[1].y, vertices[1].z);
    vertex(vertices[2].x, vertices[2].y, vertices[2].z);
    vertex(vertices[3].x, vertices[3].y, vertices[3].z);
    endShape();
  }

  public float[] getCoef() {
    float[] result = new float[4];
    result[0] = a;
    result[1] = b;
    result[2] = c;
    result[3] = d;

    return result;
  }
}

class Reference {
  private float size;
  
  public Reference(float size) {
    this.size = size;
  }
  
  public void show() {
    strokeWeight(1);
    
    // x in red
    stroke(200, 20, 20);    
    fill(200, 20, 20);
    
    line(-size/2,0,0,size/2,0,0);
    
    pushMatrix();
    translate(size/2, 0, 0);
    sphere(3);
    popMatrix();
    
    // y in green
    stroke(20, 200, 20);    
    fill(20, 200, 20);
    
    line(0,-size/2,0,0,size/2,0);
    
    pushMatrix();
    translate(0, size/2, 0);
    sphere(3);
    popMatrix();
    
    
    // z in blue
    stroke(20, 20, 200);    
    fill(20, 20, 200);
    
    line(0,0,-size/2,0,0,size/2);
    
    pushMatrix();
    translate(0, 0, size/2);
    sphere(3);
    popMatrix();
  }
}

```

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 17, 2019, 4:17pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/12 "2019-04-17T16:17:51Z")

</div>

Thnks 4 the Code & The explanation.  
I Have some questions:  
How can I use this in my case? for example to rotate a Cube around the Cylinder and and project it .I am going to use 4 projectors. And I want to pass after to MadMapper for the Blending.  
I Don’t know where can i Draw my 3d scene in your system.  
THanks!

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [April 17, 2019, 5:19pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/13 "2019-04-17T17:19:33Z")

</div>

> [@janebeta7](#):
>
> I Don’t know where can i Draw my 3d scene in your system.

I thought you were projecting onto a physical cylinder in a theater space from a fixed projector. What is your “3D scene”? Do you mean the position and angle of the projector?

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [April 17, 2019, 5:30pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/14 "2019-04-17T17:30:54Z")

</div>

This is great!

What are the keyCodes you map in keyPressed()? It would be helpful to comment them with their keyboard equivalents, or to add a comment to the top about what the UI options are. It looks like two of them move the projector, and two of them move the projection surface.

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 17, 2019, 6:17pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/15 "2019-04-17T18:17:14Z")

</div>

I will project with 4 projectors. The projectors (beamers) will be inside the cylinder.  
The 3d scene i mean in digital way. To have for example a shape moving around the circle .  
 ![46](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/9cd7889a78a4bceeaa4b1820aec8fcebd785b6b0.png)

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [April 17, 2019, 6:22pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/16 "2019-04-17T18:22:57Z")

</div>

How are you mapping sketch output to the four projectors? Are you running four synchronized sketches, each controlling one projector and each drawing part of the surface? Or are you running one sketch drawing to one stretched video output in a long rectangle, with each projector showing part of that rectangle?

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 17, 2019, 6:26pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/17 "2019-04-17T18:26:11Z")

</div>

I am going to mapping with Spout \> madmapper or this above tool  
I am going to use one 3d sketch , then i need to put the 3d surface in a long rectangle and each projector showing part of that

---

<div class="post-metadata">

**Author:** ![janebeta7](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/janebeta7/32/101_2.png) [@janebeta7](https://discourse.processing.org/u/janebeta7)\
**Post date:** [April 17, 2019, 6:28pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/18 "2019-04-17T18:28:49Z")

</div>

The first idea was to use this

> **[tracerstar/processing-360-video](https://github.com/tracerstar/processing-360-video)**
>
> A series of examples showing how to generate 360 videos with processing. - tracerstar/processing-360-video

  
but its for equirectangular projections.  
I would need the same but for Cylindrical projection

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [April 17, 2019, 6:36pm UTC](https://discourse.processing.org/t/panorama-warping-cylinder/9131/19 "2019-04-17T18:36:29Z")

</div>

One approach would be to use SurfaceMapper – and possibly try using the SurfaceMapperGUI (may need to be updated). The problem with an algorithmic solution in this case is that very tiny variations in your cylinder surface or in the angle of your projection mounts will cause a pure geometric approach to create distortion. An alternative is to create a segmented, bezier-curve controlled surface that you can tweak at installation time and save the settings, like this:

 ![](https://jasonwebb.io/wp-content/uploads/2013/10/bezier-warped-4.png)

> **[SurfaceMapperGUI - a simple Processing interface for projection mapping —...](https://jasonwebb.io/2013/11/surfacemappergui-a-simple-processing-interface-for-projection-mapping/)**
>
> SurfaceMapperGUI is a Processing sketch for simple projection mapping projects that allows users to easily map image and videos onto real-world objects. The documentation (available also as an Instructable), guides users through the entire projection...

The GUI might need to be updated for Processing 3 – I haven’t tried it.

Another old (deprecated) mapping library for Processing that supports curves – MappingTools

[http://www.patricksaintdenis.com/mappingtools/](http://www.patricksaintdenis.com/mappingtools/)

> **[patrick88/mappingtools](https://github.com/patrick88/mappingtools)**
>
> A Processing library that facilities mapping on straight or curved surfaces (deprecated) - patrick88/mappingtools

Check out in particular BezierWarp and ClusterBezierWarp.

A more up-to-date projection mapping library is Keystone, but it lacks the curve warping support that you will need. Perhaps the curve code from SurfaceMapper could be ported to KeyStone…

[https://fh-potsdam.github.io/doing-projection-mapping/processing-keystone/](https://fh-potsdam.github.io/doing-projection-mapping/processing-keystone/)
