Bug 100 : ortho() behaving differently with P3D and OPENGL
Last modified: 2009-09-02 07:31




Status:
ASSIGNED
Resolution:
-
Priority:
P5
Severity:
normal

 

Reporter:
fry
Assigned To:
fry

Attachment Type Created Size Actions
This example does the expected, displaying a centered rectangle. application/octet-stream 2009-03-29 07:50 273 bytes

Description:   Opened: 2005-07-27 20:00
from watz:

The following code produces different results with OPENGL and P3D (version
0089). The P3D looks as expected, but OPENGL will just show a blank canvas.

Additional oddity: In P3D it works correctly, but ortho() automagically
centers the world coords around the top left corner of the window. Maybe
that's supposed to happen, what do I know.

Code:
import processing.opengl.*;

void setup() {
size(1066,200, P3D);
framerate(5);
}

void draw() {
background(200);
lights();
ortho(0,width, 0,height, -10,20);

translate(width/2,height/2);
for(int i=0; i<10; i++) {
pushMatrix();
translate(random(width),random(height));
rotateX(PI/4);
rotateY(PI/4);
box(50);
popMatrix();
}
}

http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115919744

fry:

the oddity is how it's supposed to behave (if i'm understanding correctly.
if you ask for ortho from (0, 0) to (width, height), you're gonna get all
your coordinates mapped into that range, no?

watz:

That's what I thought too, but it maps values in the range
(-width/2,-height/2) to (width/2,height/2), hence the translate in the code
to bring it back on the screen.

I was just testing ortho() to see if it was an alternative to perspective
rendering since the aspect ratio of my canvas is so extreme that
perspective yields correct but weird effects. So it's not a big priority,
I'm sure there are more important bugs to fix.
Additional Comment #1 From quintopia 2007-04-18 16:53
Additional info about this bug: When ortho is used with OPENGL, the first iteration of draw will behave perfectly. I can render things in ortho mode, I just can't animate them; all succeeding executions of draw (in looping programs) result in drawn shapes not appearing. It occurs whether the objects are drawn using processing methods (beginShape, vertex) or gl methods (gl.glBegin, gl.glVertex3d). Thus, if the drawn objects are preceded by background(0), you'll get a permanent black screen, and if you use background(255) you'll get a permanent white screen, etc. This results in ortho being utterly unusable in OPENGL with looping programs.

Workaround: use P3D
Additional Comment #2 From fry 2007-04-20 17:29
ahhhh.. that's very helpful, thanks. that may in fact be something really
easy to fix.
Additional Comment #3 From ewjordan 2007-06-20 12:41
I've checked into this one a little bit, here's a minimal demonstration:

[quote]

[color=#CC6600]import[/color] processing.opengl.*;

[color=#996600]float[/color] far = 416;

[color=#CC6600]void[/color] [color=#993300][b]setup[/b][/color]() {
[color=#996600]size[/color](640,480, [color=#CC0000]OPENGL[/color]);
[color=#777755]//size(640,480,P3D); [/color]
}

[color=#CC6600]void[/color] [color=#993300][b]draw[/b][/color]() {
[color=#996600]background[/color](200);
[color=#CC6600]if[/color] ([color=#CC0000]mousePressed[/color])
[color=#996600]ortho[/color](0,[color=#CC0000]width[/color],
0,[color=#CC0000]height[/color], -10,far);
[color=#CC6600]else[/color] [color=#996600]perspective[/color]();
[color=#996600]rect[/color]([color=#CC0000]mouseX[/color],
[color=#CC0000]mouseY[/color], 300,300);
}

[/quote]

If you change the 'far' variable to much less than 416, the rect no longer
shows up when you click the mouse to put it into ortho() mode. Also, try
switching to P3D - you'll see that the translation happens in the opposite
y-direction compared to OpenGL.

I looked around the code, I can't find anything in PGraphicsOpenGL that's
messing up any transformation stuff - ortho is merely inherited, as are all
the camera/projection settings. Besides, some debugging showed that the
triangles were showing up in render_triangles with the exact same values as
they do in P3D, so something must be happening once we send the triangles
out to the graphics card. Some stray transformations are slipping into the
hardware pipeline, perhaps? [I suspect beginDraw() on this end, though I
don't exactly know what's going on here. But it's the only time in that
file that the projection matrix is used at all, so...is it possible that
OpenGL needs a different sign convention than we use or something? I've
noticed a few -1s attached to y coordinates, though that doesn't fix the
weird clipping against the far plane thing.]
Additional Comment #4 From ewjordan 2007-06-20 12:42
D'oh, I forgot that Format For Discourse doesn't work in the bugs
db...here's the code, this time readable:

import processing.opengl.*;

float far = 416;

void setup() {
size(640,480, OPENGL);
//size(640,480,P3D);
}

void draw() {
background(200);
if (mousePressed) ortho(0,width, 0,height, -10,far);
else perspective();
rect(mouseX, mouseY, 300,300);
}
Additional Comment #5 From fry 2007-06-23 15:59
hm, actually we flip the y coordinate when using OpenGL, so i wonder if
that's not happening with the ortho() camera is used (perspective has been
debugged more, since it's the default).
Additional Comment #6 From suzuki 2008-02-21 17:19
boolean orthoOn = true;

void setup() {
size(800, 400, P3D);
ortho();
noStroke();
}

void draw() {
background(100, 200, 100);
directionalLight(255, 255, 255, -1, 0, -0.5);

pushMatrix();
if (orthoOn) {
translate(width/1.5, height);
}
else {
translate(width/4, height/2);
}
sphere(100);

translate(width/2, 0);
rotateY(PI/4);
box(100);
popMatrix();
}

void keyPressed() {
if (orthoOn) {
perspective();
orthoOn = false;
}
else {
ortho();
orthoOn = true;
}
}

I'm also having to translate everything over by screen dimensions to center
them...but I'm having a much harder time with directionalLight() and
ortho(). It seems like certain surface normals are getting
scrambled--anyway, I see lighting artifacts not present with perspective().
(Seems to be better at odd angles, and when directional light z < 0.)

FWIW!
Additional Comment #7 From esperanc 2009-03-29 07:50
edit]
This example does the expected, displaying a centered rectangle.
Additional Comment #8 From esperanc 2009-03-29 08:26
In my opinion, OPENGL does the right thing, while P3D works weirdly. In the
OPENGL example attached above, the rectangle is displayed as expected,
i.e., centered on the screen. Moreover, screenX and screenY agree that
0,0,0 is mapped onto the center of the screen. Notice, however, that in
order to understand what is going on, we must realize that with an identity
modelview matrix, the world is restricted to the space
-1,-1,-1<=x,y,z<=1,1,1. Also, Processing tries to simplify things by not
revealing that there is a final Viewport transformation that maps the
normalized device coordinates to the screen.

If we simply change OPENGL with P3D, nothing is displayed, although screenX
and screenY still print as 100,100 (the center of the screen). In fact, I
cannot understand what P3D does in this case at all. The problem seems to
be the initial modelview transformation that is loaded at the beginning of
each frame.

Incidentally, I cannot understand even the simple example given in the
ortho reference page:

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

Why does the translation of (100,100,0) map 0 to the center of the screen?
Additional Comment #9 From esperanc 2009-09-02 07:31
Here's another (simple) example that illustrates the oddness how ortho()
behaves. It is a minor modification of the standard test example in the
Processing reference page:

void setup(){
size(100, 100, P3D);
}
void draw(){
noFill();
background(200);
if (mousePressed) {
camera(0,0,0,0,0,-1,0,1,0);
ortho(0,width,0,height,-height,height);
}
else {
camera();
perspective();
}
translate(50, 50, 0);
rotateX(-PI/6);
rotateY(PI/3);
box(45);
}

Notice that when using orthogonal projection, the standard camera is not
very appropriate, and thus the code above establishes an identity modelview
projection by calling camera(0,0,0,0,0,-1,0,1,0).

I went as far as implementing this in pure OpenGL (using python), and this
should work as expected, i.e., display a centered cube in either
perspective or orthogonal projection. In Processing, however, it does not
work correctly. Using P3D, as in the code above, the cube will have some of
its edges clipped. If OPENGL is used, the orthogonal projection is not
shown at all. Both work as expected when displaying the perspective projection.

A few observations:
(1) The reference page for ortho() uses an example that is misleading. The
"default" ortho call should have clipped the cube, and using -10,10 as
near/far planes is not reasonable, but rather, the default should take into
account the overall size of the window in much the same way as perspective
does.
(2) A word of caution should be included in the documentation for ortho()
drawing attention to the fact that the default camera is set up with the
default perspective projection in mind. This is the reason why a
translation of 100,100 is needed in the example rather than the more
reasonable 50,50 as used in the code above.
(3) The implementation for ortho() is WRONG in P3D with respect to the
near/far planes.
(4) The implementation for ortho() is WRONG in OPENGL (in processing).