New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ortho function is broken #1278

Closed
processing-bugs opened this Issue Feb 10, 2013 · 38 comments

Comments

Projects
None yet
8 participants
@processing-bugs

processing-bugs commented Feb 10, 2013

Original author: bearmoun...@gmail.com (September 12, 2012 17:01:00)

  1. ortho() works fine
  2. ortho(0, width, 0, height) seem to be be misaligned
  3. ortho(0, width, 0, height, -10, 10) don't seem to show anything

For any practical use of ortho(...) function you must now be followed up with a call to translate(...) with specific coordinates which depend on the left, right, top, and bottom parameters for the ortho call as well as width and height of your window. This is unpractical.

Reproduce:
void setup() {
size(800, 600, OPENGL);
}

void draw() {
float x0 = 124213;
float x1 = x0 + 512;
float y0 = 2342;
float y1 = y0 + 384;
float tx = width/2 + x0;
float ty = height/2 - y1;

ortho(x0, x1, y0, y1);

translate(tx, ty);

background(0x234567);
rect(0, 0, 10, 10);
line(0, 0, width, height);
rect(x1-x0, y1-y0, -10, -10);

}

Version 2.0b3 Mac OSX Mountain Lion 10.8.1

note: I have yet to figure out how to get ortho(left,right,bottom,top,far,near) to display anything.

Original issue: http://code.google.com/p/processing/issues/detail?id=1240

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From bearmoun...@gmail.com on September 12, 2012 17:55:03
Above contains error for tx and ty, please use following:

void setup() {
size(800, 600, OPENGL);
}

void draw() {
float x0 = 124213;
float x1 = x0 + 512;
float y0 = 2342;
float y1 = y0 + 384;
float tx = width/2;
float ty = height/2 - y1 - y0;

ortho(x0, x1, y0, y1);

translate(tx, ty);

background(0x234567);
rect(x0, y0, 10, 10);
rect(x1, y1, -10, -10);
line(x0,y0,x1,y1);

}

processing-bugs commented Feb 10, 2013

From bearmoun...@gmail.com on September 12, 2012 17:55:03
Above contains error for tx and ty, please use following:

void setup() {
size(800, 600, OPENGL);
}

void draw() {
float x0 = 124213;
float x1 = x0 + 512;
float y0 = 2342;
float y1 = y0 + 384;
float tx = width/2;
float ty = height/2 - y1 - y0;

ortho(x0, x1, y0, y1);

translate(tx, ty);

background(0x234567);
rect(x0, y0, 10, 10);
rect(x1, y1, -10, -10);
line(x0,y0,x1,y1);

}

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From andres.c...@gmail.com on September 13, 2012 18:46:18
Hello, what happens is that the left, right, bottom, top arguments in ortho() refer to the center of the screen, with the y-axis inverted with respect to the default orientation in Processing: e.g: botton-to-top instead of top-to-bottom. The reason for this is to follow the convention of the original OpenGL function glOrtho(), in the same way that frustum() follows glFrustum().

For instance, if you need to set the an orthographic projection exactly covering the rectangle starting at the origin and having the same dimensions as the screen size, then you would call ortho(-width/2, +width/2, -height/2, +height/2) (not ortho(0, width, 0, height)).

In general, if you want to set an orthographic projection covering the rectangle determined by the top-left corner (x0, y0) and bottom-right corner (x1, y1), you would need to pass to ortho() the following parameters:
left = x0 - width/2
right = x1 - width/2
bottom = -(y1 - height/2)
top = -(y0 - height/2)
that correspond to the change of coordinates between the system located at the screen center with the Y-axis bottom-to-top, and Processing's system.

So the following code in your example should work:

void setup() {
size(800, 600, P3D);
}

void draw() {
float x0 = 124213;
float x1 = x0 + 512;
float y0 = 2342;
float y1 = y0 + 384;

ortho(x0-width/2, x1-width/2, -(y1-height/2), -(y0-height/2));

background(0x234567);
rect(x0, y0, 10, 10);
rect(x1, y1, -10, -10);
line(x0,y0,x1,y1);
}

processing-bugs commented Feb 10, 2013

From andres.c...@gmail.com on September 13, 2012 18:46:18
Hello, what happens is that the left, right, bottom, top arguments in ortho() refer to the center of the screen, with the y-axis inverted with respect to the default orientation in Processing: e.g: botton-to-top instead of top-to-bottom. The reason for this is to follow the convention of the original OpenGL function glOrtho(), in the same way that frustum() follows glFrustum().

For instance, if you need to set the an orthographic projection exactly covering the rectangle starting at the origin and having the same dimensions as the screen size, then you would call ortho(-width/2, +width/2, -height/2, +height/2) (not ortho(0, width, 0, height)).

In general, if you want to set an orthographic projection covering the rectangle determined by the top-left corner (x0, y0) and bottom-right corner (x1, y1), you would need to pass to ortho() the following parameters:
left = x0 - width/2
right = x1 - width/2
bottom = -(y1 - height/2)
top = -(y0 - height/2)
that correspond to the change of coordinates between the system located at the screen center with the Y-axis bottom-to-top, and Processing's system.

So the following code in your example should work:

void setup() {
size(800, 600, P3D);
}

void draw() {
float x0 = 124213;
float x1 = x0 + 512;
float y0 = 2342;
float y1 = y0 + 384;

ortho(x0-width/2, x1-width/2, -(y1-height/2), -(y0-height/2));

background(0x234567);
rect(x0, y0, 10, 10);
rect(x1, y1, -10, -10);
line(x0,y0,x1,y1);
}

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From bearmoun...@gmail.com on September 15, 2012 09:12:28
I've looked into the source code and I've figured out what was wrong and this is how it can be solved

Overview

  • small change to ortho()
  • small change ortho(float,float,float,float)
  • revert comment for ortho
  • swap and invert bottom and top variables in both main frustum function and main ortho function (the ones that do all the calc)
  • add information to reference documentation of ortho() and frustum() about calling resetMatrix()

Discussion
The problems we have previously experienced derive from Processing creates a default camera which is centered at width/2 and height/2. Each frame the camera matrix is added to the modelview matrix in beginDraw. I believe this is desired for most users and sketches. However, we can avoid future misunderstandings regarding this if we add information in the ortho(), frustum() as well as the camera() documentation.

I've looked hard and tested many things for any side effects this change would have, but I've found nothing yet. Doing the suggested changes will make Processing OpenGL work as all others OpenGL implementations. The parameter "bottom" in frustum and ortho really means 'top' since processing y-coordinates is reversed in comparison to cartesian coordinates. The perspective()-function will continue to work as expected.

Details of changes:

In PGraphicsOpenGL.java fix the following:

  1. line 4451 frustum(float, float, float, floaf, float, float) function, right after "flush();"
    add
    float temp = -bottom;
    bottom = -top;
    top = temp;
  2. line 4380 ortho(float, float, float, floaf, float, float) function, right after "flush();"
    add
    float temp = -bottom;
    bottom = -top;
    top = temp;
  3. line 4346:
    change
    ortho(left, right, bottom, top, cameraNear, cameraFar);
    to
    ortho(left, right, bottom, top, -10, 10);
  4. line 4335:
    change
    ortho(-width/2, +width/2, -height/2, +height/2, cameraNear, cameraFar);
    to the default as it says in the help text for ortho
    ortho(0, width, 0, height, -10, 10);

Changes to reference documentation

  1. in camera() add something along the lines of:
    "camera() is called once automatically when creating 3d context"
  2. in ortho() and..
  3. in frustum() add something like:
    "camera() is called once automatically when creating 3d context with default values. If this is undesirable you can reset the camera matrix with resetMatrix()".

processing-bugs commented Feb 10, 2013

From bearmoun...@gmail.com on September 15, 2012 09:12:28
I've looked into the source code and I've figured out what was wrong and this is how it can be solved

Overview

  • small change to ortho()
  • small change ortho(float,float,float,float)
  • revert comment for ortho
  • swap and invert bottom and top variables in both main frustum function and main ortho function (the ones that do all the calc)
  • add information to reference documentation of ortho() and frustum() about calling resetMatrix()

Discussion
The problems we have previously experienced derive from Processing creates a default camera which is centered at width/2 and height/2. Each frame the camera matrix is added to the modelview matrix in beginDraw. I believe this is desired for most users and sketches. However, we can avoid future misunderstandings regarding this if we add information in the ortho(), frustum() as well as the camera() documentation.

I've looked hard and tested many things for any side effects this change would have, but I've found nothing yet. Doing the suggested changes will make Processing OpenGL work as all others OpenGL implementations. The parameter "bottom" in frustum and ortho really means 'top' since processing y-coordinates is reversed in comparison to cartesian coordinates. The perspective()-function will continue to work as expected.

Details of changes:

In PGraphicsOpenGL.java fix the following:

  1. line 4451 frustum(float, float, float, floaf, float, float) function, right after "flush();"
    add
    float temp = -bottom;
    bottom = -top;
    top = temp;
  2. line 4380 ortho(float, float, float, floaf, float, float) function, right after "flush();"
    add
    float temp = -bottom;
    bottom = -top;
    top = temp;
  3. line 4346:
    change
    ortho(left, right, bottom, top, cameraNear, cameraFar);
    to
    ortho(left, right, bottom, top, -10, 10);
  4. line 4335:
    change
    ortho(-width/2, +width/2, -height/2, +height/2, cameraNear, cameraFar);
    to the default as it says in the help text for ortho
    ortho(0, width, 0, height, -10, 10);

Changes to reference documentation

  1. in camera() add something along the lines of:
    "camera() is called once automatically when creating 3d context"
  2. in ortho() and..
  3. in frustum() add something like:
    "camera() is called once automatically when creating 3d context with default values. If this is undesirable you can reset the camera matrix with resetMatrix()".
@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From andres.c...@gmail.com on September 18, 2012 15:07:36
Thanks a lot for your suggestions. I will pass them along the other member of the team in order to discuss the final form of the ortho() function.

processing-bugs commented Feb 10, 2013

From andres.c...@gmail.com on September 18, 2012 15:07:36
Thanks a lot for your suggestions. I will pass them along the other member of the team in order to discuss the final form of the ortho() function.

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From bearmoun...@gmail.com on October 25, 2012 04:48:57
Is there any update on this issue?

processing-bugs commented Feb 10, 2013

From bearmoun...@gmail.com on October 25, 2012 04:48:57
Is there any update on this issue?

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From f...@processing.org on November 25, 2012 02:15:15
Is this actually a problem where ortho() is not behaving like glOrtho/gluOrtho? (and is broken)
http://www.khronos.org/opengles/documentation/opengles1_0/html/glOrtho.html

Or is it just that the method is not as convenient as it could be?

processing-bugs commented Feb 10, 2013

From f...@processing.org on November 25, 2012 02:15:15
Is this actually a problem where ortho() is not behaving like glOrtho/gluOrtho? (and is broken)
http://www.khronos.org/opengles/documentation/opengles1_0/html/glOrtho.html

Or is it just that the method is not as convenient as it could be?

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From bearmoun...@gmail.com on November 25, 2012 18:32:46
Short answer: Yes ortho is broken.

Long answer: My suggested changes mentioned above will solve the issue, but I'm not sure it's the most proper way to go at it.

  1. One part of the problem is caused by Processing use left handed coordinates compared to OpenGL's right handed coordinate system. I mean, what is "bottom" in processing (as parameters are called in ortho/glOrtho and frustum/glFrustum). Bottom in opengl's right-handed system is both low-y and down compared to "top" parameter when viewed from person eye, but what should it be Processing? It's unclear, and it affects both frustum(), perspective(), ortho() calls. Therefore I cannot say if the most proper way to use ortho is
    ortho(lowX, highX, lowY, highY, nearZ, farZ) or
    ortho(lowX, highX, highY, lowY, nearZ, farZ).
    Though as it is now, neither of them work.

The inverted y axis also affects the camera() function (which is also broken). It's supposed to mimic gluLookAt which you call with eye and lookat positions together with the up direction. But in Processing you call it with eye and lookat pos but with the DOWN direction.

  1. The other part is the deafult camera wich you set it to look at center which works for perspective projection but if you want to use ortho you need to reset the camera by resetMatrix. That should be mentioned in the documentation some place.

processing-bugs commented Feb 10, 2013

From bearmoun...@gmail.com on November 25, 2012 18:32:46
Short answer: Yes ortho is broken.

Long answer: My suggested changes mentioned above will solve the issue, but I'm not sure it's the most proper way to go at it.

  1. One part of the problem is caused by Processing use left handed coordinates compared to OpenGL's right handed coordinate system. I mean, what is "bottom" in processing (as parameters are called in ortho/glOrtho and frustum/glFrustum). Bottom in opengl's right-handed system is both low-y and down compared to "top" parameter when viewed from person eye, but what should it be Processing? It's unclear, and it affects both frustum(), perspective(), ortho() calls. Therefore I cannot say if the most proper way to use ortho is
    ortho(lowX, highX, lowY, highY, nearZ, farZ) or
    ortho(lowX, highX, highY, lowY, nearZ, farZ).
    Though as it is now, neither of them work.

The inverted y axis also affects the camera() function (which is also broken). It's supposed to mimic gluLookAt which you call with eye and lookat positions together with the up direction. But in Processing you call it with eye and lookat pos but with the DOWN direction.

  1. The other part is the deafult camera wich you set it to look at center which works for perspective projection but if you want to use ortho you need to reset the camera by resetMatrix. That should be mentioned in the documentation some place.
@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From caseyr...@gmail.com on December 04, 2012 23:09:32
In regard to the ortho() example in the reference:

size(100, 100, P3D);
noFill();
ortho(0, width, 0, height, -10, 10);
translate(100, 100, 0);
rotateX(-PI/6);
rotateY(PI/3);
box(45);

The current code 2b6 behaves differently. To get the equivalent images in 2b6, the following changes need to be made:

ortho(0, width, 0, height);
translate(width/2, height/2, 0);

processing-bugs commented Feb 10, 2013

From caseyr...@gmail.com on December 04, 2012 23:09:32
In regard to the ortho() example in the reference:

size(100, 100, P3D);
noFill();
ortho(0, width, 0, height, -10, 10);
translate(100, 100, 0);
rotateX(-PI/6);
rotateY(PI/3);
box(45);

The current code 2b6 behaves differently. To get the equivalent images in 2b6, the following changes need to be made:

ortho(0, width, 0, height);
translate(width/2, height/2, 0);

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From bearmoun...@gmail.com on December 14, 2012 16:25:19
I just tried it with 2.0b7 and I the changes to ortho has once again confused me. This is my workaround that gives "correct" (read below) results:

void simpleOrtho(float xLo, float xHi, float yLo, float yHi, float near, float far) {
resetMatrix(); // get rid of default model view

// calculations according to glOrtho spec
float tx = - (xHi+xLo) / (xHi-xLo);
float ty = - (yHi+yLo) / (yHi-yLo);
float tz = - (far+near) / (far-near);
float a = 2.0/(xHi-xLo);
float b = 2.0/(yHi-yLo);
float c = -2.0/(far-near);

// invert y axis (this is done to account for Processing's different coordinate system than OpenGL)
b = -b;
ty = -ty;

PMatrix3D mat = new PMatrix3D(); 
mat.set(  a, 0.0, 0.0, tx, 
0.0, b, 0.0, ty, 
0.0, 0.0, c, tz, 
0.0, 0.0, 0.0, 1.0);

PGraphicsOpenGL gl = (PGraphicsOpenGL)g;
gl.setProjection(mat);

}

Notice that I've gotten changed the parameter names of "left, right, top, bottom" to avoid confusion. As you can see in the image (from OpenGL red book), the parameter "bottom" is the one that usually corresponds to the plane that is aligned to the lower part of the screen/window, and it makes sense in OpenGL as positive y axis goes upwards. If you want to stay true to the function name and correct order of parameters, ortho would be default as ortho(0,width,height,0,-1,1), but I think it makes more sense to use as I have.

Anyway, hope this can be to some help, and I'm happy to answer any questions.


Also, you can check the example sketch I've attached which demonstrates that it works.

processing-bugs commented Feb 10, 2013

From bearmoun...@gmail.com on December 14, 2012 16:25:19
I just tried it with 2.0b7 and I the changes to ortho has once again confused me. This is my workaround that gives "correct" (read below) results:

void simpleOrtho(float xLo, float xHi, float yLo, float yHi, float near, float far) {
resetMatrix(); // get rid of default model view

// calculations according to glOrtho spec
float tx = - (xHi+xLo) / (xHi-xLo);
float ty = - (yHi+yLo) / (yHi-yLo);
float tz = - (far+near) / (far-near);
float a = 2.0/(xHi-xLo);
float b = 2.0/(yHi-yLo);
float c = -2.0/(far-near);

// invert y axis (this is done to account for Processing's different coordinate system than OpenGL)
b = -b;
ty = -ty;

PMatrix3D mat = new PMatrix3D(); 
mat.set(  a, 0.0, 0.0, tx, 
0.0, b, 0.0, ty, 
0.0, 0.0, c, tz, 
0.0, 0.0, 0.0, 1.0);

PGraphicsOpenGL gl = (PGraphicsOpenGL)g;
gl.setProjection(mat);

}

Notice that I've gotten changed the parameter names of "left, right, top, bottom" to avoid confusion. As you can see in the image (from OpenGL red book), the parameter "bottom" is the one that usually corresponds to the plane that is aligned to the lower part of the screen/window, and it makes sense in OpenGL as positive y axis goes upwards. If you want to stay true to the function name and correct order of parameters, ortho would be default as ortho(0,width,height,0,-1,1), but I think it makes more sense to use as I have.

Anyway, hope this can be to some help, and I'm happy to answer any questions.


Also, you can check the example sketch I've attached which demonstrates that it works.

@processing-bugs

This comment has been minimized.

Show comment
Hide comment
@processing-bugs

processing-bugs Feb 10, 2013

From ericthe...@gmail.com on January 09, 2013 18:39:05
I'm running 2.0b7 on a Mac. The example code on the website doesn't produce any visible results, nor does the code in Comment 3. The change in Comment 9 does work.

Is this issue stabilizing & if so could someone update the example?

processing-bugs commented Feb 10, 2013

From ericthe...@gmail.com on January 09, 2013 18:39:05
I'm running 2.0b7 on a Mac. The example code on the website doesn't produce any visible results, nor does the code in Comment 3. The change in Comment 9 does work.

Is this issue stabilizing & if so could someone update the example?

@ghost ghost assigned codeanticode Feb 11, 2013

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 3, 2013

Member

I think that many of the arguments in this discussion boil down to a matter of preference, and also to the idea of following the original gl functions (gluOrtho(), glFustrum, etc). About the latter, it should be noted that GLES 2.0+, GL 3.0+ and WebGL deprecated all those functions, so their value as a model is not very significant at this point.

About perspective() and frustum(): I think they shouldn't be changed. The main reason for this is that many camera libraries that are around use the current "up" convention.

Regarding ortho(), one thing I should note to @alignedleft is that the example in the reference page:

http://trunk.processing.org/reference/ortho_.html

is indeed broken and does not work with the latest revision from the repo.

The following modified example code does work:

size(100, 100, P3D);
noFill();
ortho(0, width, 0, height); // same as ortho()
translate(width/2, height/2, 0);
rotateX(-PI/6);
rotateY(PI/3);
box(45);

Regarding the near and far arguments in ortho(), they now have exactly the same meaning as in perspective(), i.e.: near and far are the distances from the eye of the camera to the near and far planes, respectively (while before they didn't, notice the -10, 10 values used in the example). The following code makes the equivalence more clear:

boolean persp = true;

void setup() {
  size(100, 100, P3D);
  noFill();
}

void draw() {
  background(150);
  float far = map(mouseX, 0, width, 10, 150);
  if (persp) perspective(PI/3.0, float(width)/float(height), 10, far);  
  else ortho(0, width, 0, height, 10, far);
  translate(width/2, height/2, 0);
  rotateX(-PI/6);
  rotateY(PI/3);
  box(45);
}

void keyPressed() {
  persp = !persp;  
}

@benfry, @REAS: let me know if you have any comments about this.

Member

codeanticode commented Jun 3, 2013

I think that many of the arguments in this discussion boil down to a matter of preference, and also to the idea of following the original gl functions (gluOrtho(), glFustrum, etc). About the latter, it should be noted that GLES 2.0+, GL 3.0+ and WebGL deprecated all those functions, so their value as a model is not very significant at this point.

About perspective() and frustum(): I think they shouldn't be changed. The main reason for this is that many camera libraries that are around use the current "up" convention.

Regarding ortho(), one thing I should note to @alignedleft is that the example in the reference page:

http://trunk.processing.org/reference/ortho_.html

is indeed broken and does not work with the latest revision from the repo.

The following modified example code does work:

size(100, 100, P3D);
noFill();
ortho(0, width, 0, height); // same as ortho()
translate(width/2, height/2, 0);
rotateX(-PI/6);
rotateY(PI/3);
box(45);

Regarding the near and far arguments in ortho(), they now have exactly the same meaning as in perspective(), i.e.: near and far are the distances from the eye of the camera to the near and far planes, respectively (while before they didn't, notice the -10, 10 values used in the example). The following code makes the equivalence more clear:

boolean persp = true;

void setup() {
  size(100, 100, P3D);
  noFill();
}

void draw() {
  background(150);
  float far = map(mouseX, 0, width, 10, 150);
  if (persp) perspective(PI/3.0, float(width)/float(height), 10, far);  
  else ortho(0, width, 0, height, 10, far);
  translate(width/2, height/2, 0);
  rotateX(-PI/6);
  rotateY(PI/3);
  box(45);
}

void keyPressed() {
  persp = !persp;  
}

@benfry, @REAS: let me know if you have any comments about this.

@REAS

This comment has been minimized.

Show comment
Hide comment
@REAS

REAS Jun 3, 2013

Member

@codeanticode If you think it's the way to do it, it's OK with me. I've just changed the reference entry to include the modified example.

Member

REAS commented Jun 3, 2013

@codeanticode If you think it's the way to do it, it's OK with me. I've just changed the reference entry to include the modified example.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 3, 2013

Member

great, thank you Casey.

I was thinking that it could be useful to add the last example I mentioned above to the Basic|Camera section. Do you guys agree?

Member

codeanticode commented Jun 3, 2013

great, thank you Casey.

I was thinking that it could be useful to add the last example I mentioned above to the Basic|Camera section. Do you guys agree?

@REAS

This comment has been minimized.

Show comment
Hide comment
@REAS

REAS Jun 3, 2013

Member

Yes, I'll add it. I will make it 600 x 360 and format it like the rest of the examples. Thanks for making it and sorting this out.

Member

REAS commented Jun 3, 2013

Yes, I'll add it. I will make it 600 x 360 and format it like the rest of the examples. Thanks for making it and sorting this out.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 3, 2013

Member

Ok.

The fact that the perspective and ortho functions don't exactly match the original gluPerspective and gluOrtho functions should also be noted in the updated opengl wiki (#866).

Member

codeanticode commented Jun 3, 2013

Ok.

The fact that the perspective and ortho functions don't exactly match the original gluPerspective and gluOrtho functions should also be noted in the updated opengl wiki (#866).

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jan 23, 2014

Member

The behavior of the ortho() function is by now (2.1.1) stabilized, closing this issue. Again, the wiki needs to be properly updated to reflect all the changes in the GL renderers.

Member

codeanticode commented Jan 23, 2014

The behavior of the ortho() function is by now (2.1.1) stabilized, closing this issue. Again, the wiki needs to be properly updated to reflect all the changes in the GL renderers.

@bearmountainbranch

This comment has been minimized.

Show comment
Hide comment
@bearmountainbranch

bearmountainbranch Feb 12, 2014

Example 1:

size(600, 600, P3D);
ortho(-width, width, -height, height);
line(-width, 0, width, 0);
line(0, -height, 0, height);
rect(0, 0, width*0.7, height*.3);

I expect to see:

a window with with two axis crossing the center vertically and horizontally. Then a rectangle starting from center of screen going a bit down.

I see:

Image described above, but shifted half a screen up.

Example 2:

size(600, 600, P3D);
ortho(-1, 1, -1, 1);
line(-1, 0, 1, 0);
line(0, -1, 0, 1);
rect(0, 0, 0.7, 0.3);

I expect to see:

the same as in example 1

I see:

blank, grey screen

bearmountainbranch commented Feb 12, 2014

Example 1:

size(600, 600, P3D);
ortho(-width, width, -height, height);
line(-width, 0, width, 0);
line(0, -height, 0, height);
rect(0, 0, width*0.7, height*.3);

I expect to see:

a window with with two axis crossing the center vertically and horizontally. Then a rectangle starting from center of screen going a bit down.

I see:

Image described above, but shifted half a screen up.

Example 2:

size(600, 600, P3D);
ortho(-1, 1, -1, 1);
line(-1, 0, 1, 0);
line(0, -1, 0, 1);
rect(0, 0, 0.7, 0.3);

I expect to see:

the same as in example 1

I see:

blank, grey screen

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Feb 13, 2014

Member

Ok, I will look into it.

Member

codeanticode commented Feb 13, 2014

Ok, I will look into it.

@codeanticode codeanticode reopened this Feb 13, 2014

codeanticode added a commit that referenced this issue Mar 4, 2014

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Mar 4, 2014

Member

7a26ddd should solve this problem. But you need to add a camera() call before ortho() so that the modelview transformation centers the scene at (0,0) and not at (width/2,height/2):

size(600, 600, P3D);
camera(0, 0, 1, 0, 0, 0, 0, 1, 0);
ortho(-width, width, -height, height);
line(-width, 0, width, 0);
line(0, -height, 0, height);
rect(0, 0, width*0.7, height*.3);
size(600, 600, P3D);
camera(0, 0, 1, 0, 0, 0, 0, 1, 0);
ortho(-1, 1, -1, 1);
line(-1, 0, 1, 0);
line(0, -1, 0, 1);
rect(0, 0, 0.7, 0.3);

Let me know if there is any other inconsistency with the ortho() function, so I can close this issue. Thanks!

Member

codeanticode commented Mar 4, 2014

7a26ddd should solve this problem. But you need to add a camera() call before ortho() so that the modelview transformation centers the scene at (0,0) and not at (width/2,height/2):

size(600, 600, P3D);
camera(0, 0, 1, 0, 0, 0, 0, 1, 0);
ortho(-width, width, -height, height);
line(-width, 0, width, 0);
line(0, -height, 0, height);
rect(0, 0, width*0.7, height*.3);
size(600, 600, P3D);
camera(0, 0, 1, 0, 0, 0, 0, 1, 0);
ortho(-1, 1, -1, 1);
line(-1, 0, 1, 0);
line(0, -1, 0, 1);
rect(0, 0, 0.7, 0.3);

Let me know if there is any other inconsistency with the ortho() function, so I can close this issue. Thanks!

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Mar 28, 2014

Member

closing as the issue seems solved, and haven't received any further comments.

Member

codeanticode commented Mar 28, 2014

closing as the issue seems solved, and haven't received any further comments.

@yousifucv

This comment has been minimized.

Show comment
Hide comment
@yousifucv

yousifucv Apr 18, 2014

Intro

Hey. This is a great discussion that I discovered a while ago about a problem I've been personally studying for a while, until 4 months ago. I just revisited the problem and was happy to see some new developments and a nice fix.

I was able to remedy the old problem with some translations to keep things centered, (something that was mention in this thread before too) but another part of the problem still persists.

Issue

It has to do with rotating the camera around the centre while looking at the centre.

void setup() {
  size(1024, 512, P3D);
}

void draw() {
  background(200);

  //cam variables
  float fov = PI / 3;
  float cameraEyeZ = (height / 2) / (tan(fov / 2));
  float angle = (mouseY * 1.0 / height) * 2 * PI; //cam rotation angle around the origin [0, 2*PI]

  camera(
  cameraEyeZ * sin(angle), 0.0, cameraEyeZ * cos(angle), //position
  0.0, 0.0, 0.0, //centre
  0.0, 1.0, 0.0); //up

  //ortho
  float m = 1.0;
  ortho(-width/2 * m, width/2  * m, -height/2  * m, height/2 * m, cameraEyeZ * 0.10, cameraEyeZ * 100.0);
  stroke(0);
  fill(255);
  box(30, 30, 30);
}

What I expect to see:

White cube rotating in the centre.

What I see:

White cube rotating in an arc.

In ortho, the camera rotates and looks at (0,0,cameraEyeZ); To prove it, just add a translate(0,0,cameraEyeZ); before drawing the box.

Here are other tests I did that demonstrate the general issues.

Same as above but with perspective
http://pastebin.com/wm4AAh46

Same as above, but with more cubes, and some commented code to try
http://pastebin.com/seTHeqjn

Am I using the camera/ortho functions properly here?

yousifucv commented Apr 18, 2014

Intro

Hey. This is a great discussion that I discovered a while ago about a problem I've been personally studying for a while, until 4 months ago. I just revisited the problem and was happy to see some new developments and a nice fix.

I was able to remedy the old problem with some translations to keep things centered, (something that was mention in this thread before too) but another part of the problem still persists.

Issue

It has to do with rotating the camera around the centre while looking at the centre.

void setup() {
  size(1024, 512, P3D);
}

void draw() {
  background(200);

  //cam variables
  float fov = PI / 3;
  float cameraEyeZ = (height / 2) / (tan(fov / 2));
  float angle = (mouseY * 1.0 / height) * 2 * PI; //cam rotation angle around the origin [0, 2*PI]

  camera(
  cameraEyeZ * sin(angle), 0.0, cameraEyeZ * cos(angle), //position
  0.0, 0.0, 0.0, //centre
  0.0, 1.0, 0.0); //up

  //ortho
  float m = 1.0;
  ortho(-width/2 * m, width/2  * m, -height/2  * m, height/2 * m, cameraEyeZ * 0.10, cameraEyeZ * 100.0);
  stroke(0);
  fill(255);
  box(30, 30, 30);
}

What I expect to see:

White cube rotating in the centre.

What I see:

White cube rotating in an arc.

In ortho, the camera rotates and looks at (0,0,cameraEyeZ); To prove it, just add a translate(0,0,cameraEyeZ); before drawing the box.

Here are other tests I did that demonstrate the general issues.

Same as above but with perspective
http://pastebin.com/wm4AAh46

Same as above, but with more cubes, and some commented code to try
http://pastebin.com/seTHeqjn

Am I using the camera/ortho functions properly here?

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Apr 22, 2014

Member

I'd say some calculations in the camera/ortho function need some more additional work to properly take care of this scenarios. For the time being, calling ortho() only in setup() should work:

void setup() {
  size(1024, 512, P3D);
  ortho();
}

void draw() {
  background(200);

  float fov = PI / 3;
  float cameraEyeZ = (height / 2) / (tan(fov / 2));
  float angle = map(mouseX, 0, width, 0, TWO_PI);

  camera(cameraEyeZ * sin(angle), 0.0, cameraEyeZ * cos(angle),
         0.0, 0.0, 0.0,
         0.0, 1.0, 0.0);

  stroke(0);
  fill(255);
  box(50, 50, 50);
}
Member

codeanticode commented Apr 22, 2014

I'd say some calculations in the camera/ortho function need some more additional work to properly take care of this scenarios. For the time being, calling ortho() only in setup() should work:

void setup() {
  size(1024, 512, P3D);
  ortho();
}

void draw() {
  background(200);

  float fov = PI / 3;
  float cameraEyeZ = (height / 2) / (tan(fov / 2));
  float angle = map(mouseX, 0, width, 0, TWO_PI);

  camera(cameraEyeZ * sin(angle), 0.0, cameraEyeZ * cos(angle),
         0.0, 0.0, 0.0,
         0.0, 1.0, 0.0);

  stroke(0);
  fill(255);
  box(50, 50, 50);
}

@codeanticode codeanticode reopened this Apr 22, 2014

@benfry benfry removed the bug label Nov 15, 2014

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 1, 2015

Member

I went through the different use cases of the ortho() function, and I realize that my decision of using the upper left corner as the reference point (so ortho() is equivalent to ortho(0, 0, width, height)) is problematic due to two reasons: one, the automatic offset the renderer currently applies so that (0, 0, width, height) corresponds to (-width/2, width/2, -height/2, height/2) only works when the camera is aligned to the z axis. I think it is possible to come up with the correct transformation that would work for any camera orientation, but not 100% sure. Even if we add the correct offset transformation, people will keep coming back to this issue and reporting that (-width/2, width/2, -height/2, height/2) doesn't work, because it is the standard way of defining the orthographic projection

@benfry, @REAS, @shiffman, @alignedleft I would strongly recommend to go back to the original way of specifying the ortho() arguments, so the default orthographic projection setup is ortho(-width/2, width/2, -height/2, height/2). I will update the examples and reference accordingly.

Member

codeanticode commented Jun 1, 2015

I went through the different use cases of the ortho() function, and I realize that my decision of using the upper left corner as the reference point (so ortho() is equivalent to ortho(0, 0, width, height)) is problematic due to two reasons: one, the automatic offset the renderer currently applies so that (0, 0, width, height) corresponds to (-width/2, width/2, -height/2, height/2) only works when the camera is aligned to the z axis. I think it is possible to come up with the correct transformation that would work for any camera orientation, but not 100% sure. Even if we add the correct offset transformation, people will keep coming back to this issue and reporting that (-width/2, width/2, -height/2, height/2) doesn't work, because it is the standard way of defining the orthographic projection

@benfry, @REAS, @shiffman, @alignedleft I would strongly recommend to go back to the original way of specifying the ortho() arguments, so the default orthographic projection setup is ortho(-width/2, width/2, -height/2, height/2). I will update the examples and reference accordingly.

@benfry

This comment has been minimized.

Show comment
Hide comment
@benfry

benfry Jun 1, 2015

Member

By "original" way do you mean OpenGL? GLU? Processing 1.x?

Bottom line, it should follow glOrtho() or gluOrtho() (the source had this in the comments, no?) This isn't a function we're trying to reinvent/simplify/etc. It's there for porting, and for the more technically-minded who are familiar with the GL variants.

The questions about the example/docs are a separate issue. I think those were just written to get something that worked with the function as it stood at that time.

Member

benfry commented Jun 1, 2015

By "original" way do you mean OpenGL? GLU? Processing 1.x?

Bottom line, it should follow glOrtho() or gluOrtho() (the source had this in the comments, no?) This isn't a function we're trying to reinvent/simplify/etc. It's there for porting, and for the more technically-minded who are familiar with the GL variants.

The questions about the example/docs are a separate issue. I think those were just written to get something that worked with the function as it stood at that time.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 1, 2015

Member

1.x, which followed gluOrtho2D() I believe.

Member

codeanticode commented Jun 1, 2015

1.x, which followed gluOrtho2D() I believe.

@benfry

This comment has been minimized.

Show comment
Hide comment
@benfry

benfry Jun 1, 2015

Member

That sounds like the correct solution. We should just verify that we're following gluOrtho2D() properly.

Member

benfry commented Jun 1, 2015

That sounds like the correct solution. We should just verify that we're following gluOrtho2D() properly.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 1, 2015

Member

Yes, actually we should follow gluOrtho(), which allows to set near/far planes.

Member

codeanticode commented Jun 1, 2015

Yes, actually we should follow gluOrtho(), which allows to set near/far planes.

@yousifucv

This comment has been minimized.

Show comment
Hide comment
@yousifucv

yousifucv Jun 2, 2015

Hello again, I should have mentioned this earlier, but I think I fixed this issue.

In PGraphicsOpenGL's ortho(float, float, float, float, float, float) function there were unnecessary translations.
There is no need to apply camera translation. Comment out the following lines:

left -= cameraEyeX;
right -= cameraEyeX;
bottom -= cameraEyeY;
top -= cameraEyeY;

Going off my previous example, the cube rotates around the centre now, as expected.

void setup() {
  size(1024, 512, P3D);
}

void draw() {
  background(200);

  //cam variables
  float fov = PI / 3;
  float cameraEyeZ = (height / 2) / (tan(fov / 2));
  float angle = (mouseY * 1.0 / height) * 2 * PI; //cam rotation angle around the origin [0, 2*PI]

  camera(
  cameraEyeZ * sin(angle), 0.0, cameraEyeZ * cos(angle), //position
  0.0, 0.0, 0.0, //centre
  0.0, 1.0, 0.0); //up

  //ortho
  float m = 1.0;
  ortho2(-width/2 * m, width/2  * m, -height/2  * m, height/2 * m, cameraEyeZ * 0.10, cameraEyeZ * 100.0);
  stroke(0);
  fill(255);
  box(30, 30, 30);
}

void ortho2(float left, float right, 
float bottom, float top, 
float near, float far) {
  float w = right - left;
  float h = top - bottom;
  float d = far - near;

  //This causes bugs
  // Applying the camera translation (only on x and y, as near and far
  // are given as distances from the viewer)
  //    left   -= cameraEyeX;
  //    right  -= cameraEyeX;
  //    bottom -= cameraEyeY;
  //    top    -= cameraEyeY;
  // Flushing geometry with a different perspective configuration.
  flush();

  float x = +2.0f / w;
  float y = +2.0f / h;
  float z = -2.0f / d;

  float tx = -(right + left) / w;
  float ty = -(top + bottom) / h;
  float tz = -(far + near) / d;

  // The minus sign is needed to invert the Y axis.
  ((PGraphics3D) g).projection.set(x, 0, 0, tx, 
  0, -y, 0, ty, 
  0, 0, z, tz, 
  0, 0, 0, 1);

  ((PGraphics3D) g).updateProjmodelview();
}

yousifucv commented Jun 2, 2015

Hello again, I should have mentioned this earlier, but I think I fixed this issue.

In PGraphicsOpenGL's ortho(float, float, float, float, float, float) function there were unnecessary translations.
There is no need to apply camera translation. Comment out the following lines:

left -= cameraEyeX;
right -= cameraEyeX;
bottom -= cameraEyeY;
top -= cameraEyeY;

Going off my previous example, the cube rotates around the centre now, as expected.

void setup() {
  size(1024, 512, P3D);
}

void draw() {
  background(200);

  //cam variables
  float fov = PI / 3;
  float cameraEyeZ = (height / 2) / (tan(fov / 2));
  float angle = (mouseY * 1.0 / height) * 2 * PI; //cam rotation angle around the origin [0, 2*PI]

  camera(
  cameraEyeZ * sin(angle), 0.0, cameraEyeZ * cos(angle), //position
  0.0, 0.0, 0.0, //centre
  0.0, 1.0, 0.0); //up

  //ortho
  float m = 1.0;
  ortho2(-width/2 * m, width/2  * m, -height/2  * m, height/2 * m, cameraEyeZ * 0.10, cameraEyeZ * 100.0);
  stroke(0);
  fill(255);
  box(30, 30, 30);
}

void ortho2(float left, float right, 
float bottom, float top, 
float near, float far) {
  float w = right - left;
  float h = top - bottom;
  float d = far - near;

  //This causes bugs
  // Applying the camera translation (only on x and y, as near and far
  // are given as distances from the viewer)
  //    left   -= cameraEyeX;
  //    right  -= cameraEyeX;
  //    bottom -= cameraEyeY;
  //    top    -= cameraEyeY;
  // Flushing geometry with a different perspective configuration.
  flush();

  float x = +2.0f / w;
  float y = +2.0f / h;
  float z = -2.0f / d;

  float tx = -(right + left) / w;
  float ty = -(top + bottom) / h;
  float tz = -(far + near) / d;

  // The minus sign is needed to invert the Y axis.
  ((PGraphics3D) g).projection.set(x, 0, 0, tx, 
  0, -y, 0, ty, 
  0, 0, z, tz, 
  0, 0, 0, 1);

  ((PGraphics3D) g).updateProjmodelview();
}
@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 2, 2015

Member

@yousifucv yes you are right, thanks for the note! I removed those translations in code I didn't pushed yet. I'm doing some extra testing to make sure that Processing's ortho() is consistent with gluOrtho(), hopefully will be able to close this long-standing issue soon.

Member

codeanticode commented Jun 2, 2015

@yousifucv yes you are right, thanks for the note! I removed those translations in code I didn't pushed yet. I'm doing some extra testing to make sure that Processing's ortho() is consistent with gluOrtho(), hopefully will be able to close this long-standing issue soon.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 5, 2015

Member

@REAS, @alignedleft where are the examples stored now so I can update the ones using ortho()? The reference also needs updating.

Member

codeanticode commented Jun 5, 2015

@REAS, @alignedleft where are the examples stored now so I can update the ones using ortho()? The reference also needs updating.

@alignedleft

This comment has been minimized.

Show comment
Hide comment
@alignedleft

alignedleft Jun 5, 2015

Member

@codeanticode Example are under processing-docs/content/examples (although be aware that p5 adaptations are in progress, though that may not apply to 3D examples). Reference page examples are in processing-docs/content/api_en/ XML files.

If you want to send me specific changes, I can apply them.

Member

alignedleft commented Jun 5, 2015

@codeanticode Example are under processing-docs/content/examples (although be aware that p5 adaptations are in progress, though that may not apply to 3D examples). Reference page examples are in processing-docs/content/api_en/ XML files.

If you want to send me specific changes, I can apply them.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 7, 2015

Member

@alignedleft The changes are the following:

  • In the Basics|Camera|Orthographic example, the line
ortho(0, width, 0, height, 10, far);

should be replaced with

ortho(-width/2, width/2, -height/2, height/2, 10, far);
  • In the reference page for ortho(), the the example code should have
ortho(-width/2, width/2, -height/2, height/2); // same as ortho()

instead of

ortho(0, width, 0, height); // same as ortho()
Member

codeanticode commented Jun 7, 2015

@alignedleft The changes are the following:

  • In the Basics|Camera|Orthographic example, the line
ortho(0, width, 0, height, 10, far);

should be replaced with

ortho(-width/2, width/2, -height/2, height/2, 10, far);
  • In the reference page for ortho(), the the example code should have
ortho(-width/2, width/2, -height/2, height/2); // same as ortho()

instead of

ortho(0, width, 0, height); // same as ortho()
@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 9, 2015

Member

@yousifucv if you have the chance to run some tests using the latest revisions from, let me know if you find any other issues with orthographic projection. Thanks a lot!

Member

codeanticode commented Jun 9, 2015

@yousifucv if you have the chance to run some tests using the latest revisions from, let me know if you find any other issues with orthographic projection. Thanks a lot!

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 10, 2015

Member

@alignedleft I already updated the example and reference.

I no one has any further comments, I will close this issue in the following days.

Member

codeanticode commented Jun 10, 2015

@alignedleft I already updated the example and reference.

I no one has any further comments, I will close this issue in the following days.

alignedleft added a commit to processing/processing-docs that referenced this issue Jun 11, 2015

@alignedleft

This comment has been minimized.

Show comment
Hide comment
@alignedleft

alignedleft Jun 11, 2015

Member

@codeanticode I didn't see those edits, so I went ahead and applied them. This should be all set, but I will let you close the issue.

Member

alignedleft commented Jun 11, 2015

@codeanticode I didn't see those edits, so I went ahead and applied them. This should be all set, but I will let you close the issue.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Jun 12, 2015

Member

Hi Scott, sorry I did the chances but forgot to push them :-) And then I pushed a conflicted file :-O but everything is fixed now!

Member

codeanticode commented Jun 12, 2015

Hi Scott, sorry I did the chances but forgot to push them :-) And then I pushed a conflicted file :-O but everything is fixed now!

@felzam

This comment has been minimized.

Show comment
Hide comment
@felzam

felzam Oct 2, 2015

Hi guys, while the Examples section of ortho() in the Reference has been correctly updated, the Description section still says that ortho() defaults to ortho(0, width, 0, height).

Also, the DomeProjection example in examples/Topics/Shaders doesn't work properly in v3.0 because of this change. In the drawDomeMaster() function, the line ortho(0, width, 0, height) should be changed to either ortho() or the same function with the new correct arguments.

felzam commented Oct 2, 2015

Hi guys, while the Examples section of ortho() in the Reference has been correctly updated, the Description section still says that ortho() defaults to ortho(0, width, 0, height).

Also, the DomeProjection example in examples/Topics/Shaders doesn't work properly in v3.0 because of this change. In the drawDomeMaster() function, the line ortho(0, width, 0, height) should be changed to either ortho() or the same function with the new correct arguments.

@codeanticode

This comment has been minimized.

Show comment
Hide comment
@codeanticode

codeanticode Oct 2, 2015

Member

This should be reported in the processing-docs repo:

processing/processing-docs#324
processing/processing-docs#325

Member

codeanticode commented Oct 2, 2015

This should be reported in the processing-docs repo:

processing/processing-docs#324
processing/processing-docs#325

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment