[comp.sys.sgi] Trouble drawing point-sampled polygons

loan@Neon.Stanford.EDU (James P. Loan) (02/09/91)

I'm trying to draw several copies of the same polygon and I'm having
a hard time getting them to look EXACTLY alike. I realize that there
is round-off error when translating within a window, but the manual
presents a way to fix that. I thought the purpose of the +/-0.5
adjustment in an ortho2() call was to "move" the coordinate system
so that integer vertices would fall exactly in the center of pixels.
Well, I wrote a test program which seems to prove exactly the opposite.
When I add in the +/-0.5 adjustment, there is [round-off] error which
makes one copy of a trapezoid smaller than the other (sometimes). When
I take out the adjustment, there is no difference between the polygons.
Since the error involves the top (flat) edge of the trapezoid, it must
mean that the top two vertices are falling on pixel edges. By the way,
the same problem arises if I draw screen-aligned rectangles instead
of trapezoids, so the problem is with VERTICES falling on pixel edges,
not points on the lines connecting the vertices.

Can anyone explain to me what is going on?

Sample program follows.

thanks for any help with this trivial but annoying problem,

pete loan
loan@neon.stanford.edu


/* Test file for problem with translating point-sampled polygons.
 * To see the problem:
 * (1) Compile this file: cc -o test test.c -lgl_s
 * (2) Get /usr/demos/bin/snoop running and turn Cmode on.
 * (3) Run the test program: test
 * (4) Use snoop to check out the HEIGHT of the two trapezoids
 * (5) Resize the test window so it is at least 700 pixels HIGH
 * (6) Use snoop again to check the HEIGHT of the trapezoids
 * (7) Edit this file so that the other ORTHO2 command is used.
 * (8) Repeat steps (1) - (6).
 */


#include <gl/gl.h>
#include <gl/device.h>

main()
{
   short val;
   long id, xs, ys;

   prefposition(100,300,100,200);
   id = winopen("");
   winconstraints();
   qdevice(ESCKEY);
   qdevice(REDRAW);
   qenter(REDRAW,id);

   while (1)
   {
      switch (qread(&val))
      {
	 case REDRAW:
	    getsize(&xs,&ys);
	    viewport(0,(Screencoord)xs-1,0,(Screencoord)ys-1);
	    ortho2(-0.5,(Coord)xs+0.5,-0.5,(Coord)ys+0.5);
/*	    ortho2(0.0,(Coord)xs+1,0.0,(Coord)ys+1); */
	    color(0);
	    clear();
	    color(5);
	    pushmatrix();
	    translate(0.0,(Coord)ys-25.0,0.0);
	    trapezoid();
	    translate(0.0,-20.0,0.0);
	    trapezoid();
	    popmatrix();
	    break;
	 case ESCKEY:
	    exit(0);
      }
   }
}

int pts[][2] = {
{40,20},
{10,20},
{13,17},
{37,17}
};

trapezoid()
{

   bgnpolygon();
   v2i(pts[0]);
   v2i(pts[1]);
   v2i(pts[2]);
   v2i(pts[3]);
   endpolygon();

}

andru@electron.lcs.mit.edu (imagician) (02/09/91)

In article <1991Feb8.200816.20381@Neon.Stanford.EDU> loan@Neon.Stanford.EDU (James P. Loan) writes:
>
>I'm trying to draw several copies of the same polygon and I'm having
>a hard time getting them to look EXACTLY alike. I realize that there
>is round-off error when translating within a window, but the manual
>presents a way to fix that. I thought the purpose of the +/-0.5
>adjustment in an ortho2() call was to "move" the coordinate system
>so that integer vertices would fall exactly in the center of pixels.
[...]
>not points on the lines connecting the vertices.
>	    viewport(0,(Screencoord)xs-1,0,(Screencoord)ys-1);
>	    ortho2(-0.5,(Coord)xs+0.5,-0.5,(Coord)ys+0.5);
>/*	    ortho2(0.0,(Coord)xs+1,0.0,(Coord)ys+1); */


    Your ortho calls are wrong. The viewport is xs pixels wide, but
    you are mapping a coordinate system which is (xs+1) wide onto it.
    What you want is

	ortho2(-0.5, (Coord)xs-0.5, -0.5, (Coord)ys-0.5);

    Any apparent discrepancy is because viewport() takes pixel
    indices as arguments, whereas ortho() calls take coordinates
    as arguments.

Andrew

bennett@sgi.com (Jim Bennett) (02/09/91)

In article <1991Feb8.200816.20381@Neon.Stanford.EDU> loan@Neon.Stanford.EDU (James P. Loan) writes:
>
>I'm trying to draw several copies of the same polygon and I'm having
>a hard time getting them to look EXACTLY alike. I realize that there
>is round-off error when translating within a window, but the manual
>presents a way to fix that. I thought the purpose of the +/-0.5
>adjustment in an ortho2() call was to "move" the coordinate system
>so that integer vertices would fall exactly in the center of pixels.
>Well, I wrote a test program which seems to prove exactly the opposite.
>When I add in the +/-0.5 adjustment, there is [round-off] error which
>makes one copy of a trapezoid smaller than the other (sometimes). When
>I take out the adjustment, there is no difference between the polygons.
>Since the error involves the top (flat) edge of the trapezoid, it must
>mean that the top two vertices are falling on pixel edges. By the way,
>the same problem arises if I draw screen-aligned rectangles instead
>of trapezoids, so the problem is with VERTICES falling on pixel edges,
>not points on the lines connecting the vertices.
>
>Can anyone explain to me what is going on?

This discussion only applies to applications who want to use pixel
coordinates.

The .5 offsets do put integer coordinates at pixel centers.  So when
you draw a line with integer vertices, it interpolates between the
pixel centers, just the way you expect.

If you draw a polygon with integer vertices, the polygon you get is
the interior of the region formed by connecting the pixel centers.

For any pixel, if its center is inside this region, then the pixel
belongs to the polygon, otherwise it doesn't.  When the edge of a
polygon passes exactly through a pixel center, then the pixel is
included in the polygon if it is on a left or lower edge, and
excluded if it is on a right or upper edge.

On a VGX or a GT, the computations are done correctly, and you should
get the same polygon regardless of where it is drawn within the window
or on the screen.

On a PI, the round off error causes different effects in different
quadrants of the viewport.  To fix this problem, you can use an offset
of 0.49 instead of 0.5, and then the PI will behave more nicely.
However, there will still be (rare) cases where a polygon will light
up different pixels, depending on its location.


Jim Bennett				(bennett@esd.sgi.com)

garyt@westcoast.esd.sgi.com (Gary Tarolli) (02/12/91)

In article <1991Feb8.200816.20381@Neon.Stanford.EDU>, loan@Neon.Stanford.EDU (James P. Loan) writes:
> 
> I'm trying to draw several copies of the same polygon and I'm having
> a hard time getting them to look EXACTLY alike. I realize that there
> is round-off error when translating within a window, but the manual
> presents a way to fix that. I thought the purpose of the +/-0.5
> adjustment in an ortho2() call was to "move" the coordinate system
> so that integer vertices would fall exactly in the center of pixels.
> Well, I wrote a test program which seems to prove exactly the opposite.
> When I add in the +/-0.5 adjustment, there is [round-off] error which
> makes one copy of a trapezoid smaller than the other (sometimes). When
> I take out the adjustment, there is no difference between the polygons.
> Since the error involves the top (flat) edge of the trapezoid, it must
> mean that the top two vertices are falling on pixel edges. By the way,
> the same problem arises if I draw screen-aligned rectangles instead
> of trapezoids, so the problem is with VERTICES falling on pixel edges,
> not points on the lines connecting the vertices.
> 
> Can anyone explain to me what is going on?
> 

When you are drawing old style polygons, you want your polygon vertices to 
land exactly on pixel centers.  But when you are drawing point-sampled
polygons you want the opposite - you should place your vertices exactly
on the pixel borders.  This is because the decision to fill a pixel or not
is based on whether the pixel center is in/outside  of the polygon. If
the polygon edge goes right thru the center of a pixel, then you are
susceptable to round off error. If you move your vertices to pixel
borders (1.5, 2.5, etc) then it takes a big roundoff error to make
things fail ( magnitude of .5).

Warning - if you attempt to do this by introducing a translate matrix,
beware if you are ddrawing lines - it may have an undesired effect on
lines.  Andrew Meyers once went thru all this and came up with a scheme
for drawing exact polygons on all our machines for doing 2-D User Interface
code.  Any comments Andrew?

--------------------
	Gary Tarolli

andru@electron.lcs.mit.edu (Andrew Myers) (02/12/91)

In article <84845@sgi.sgi.com> garyt@westcoast.esd.sgi.com (Gary Tarolli) writes:
>When you are drawing old style polygons, you want your polygon vertices to 
>land exactly on pixel centers.  But when you are drawing point-sampled
>polygons you want the opposite - you should place your vertices exactly
>on the pixel borders.  This is because the decision to fill a pixel or not
>is based on whether the pixel center is in/outside  of the polygon. If
>the polygon edge goes right thru the center of a pixel, then you are
>susceptable to round off error. If you move your vertices to pixel
>borders (1.5, 2.5, etc) then it takes a big roundoff error to make
>things fail ( magnitude of .5).

This is of course correct. Drawing lines & points is sort of antithetical
to drawing new-style point-sampled polygons. You can think of lines, points
and old-style polygons as new-style polygons which have been bloated by
0.5 pixels. This can cause problems in some programs.

In the case of the program which was presented, I believe the problem
was simply a bad ortho2() call, as I stated in an earlier article.

If you want to draw true point-sampled polygons, you should note that
it is only supported on the PI and the VGX. The GT supports new-style
polygons but does not do point-sampling.  You should set your
ortho2 call to either (0,xs,0,ys) or (-0.5, xs-0.5, -0.5, ys-0.5) depending
on whether you are in new-style polygon mode or old-style, respectively.
Old-style is the default mode, last time I checked.

If you want to use new-style polygons and have your lines work well,
then you should ensure that the line goes down the center of the pixel.
This can be done by either using coordinates with a .5 adjustment, or
by a translate(0.5,0.5,0.0) call followed by an opposing translate()
when you are finished drawing lines and points.

I recommend using new-style polygons. And if you are doing user interface
work, use the sbox() calls whenever possible.

Andrew

loan@Neon.Stanford.EDU (James P. Loan) (02/12/91)

Thanks for the replies to my problem. As Andrew Myers pointed out,
the trouble was with a bad ortho call. I outsmarted myself when
subtracting 1's and adding 0.5's between getsize(), viewport(), and
ortho2() calls.

I'm glad I brought it up, though, because I'm using new-style polygons
on a PI, but I want my code to run [the same] on all 4D machines. So
thanks for pointing out the difference between drawing lines and drawing
polygons.

-pete loan
loan@neon.stanford.edu