More trouble in trapezoid land
Keith Packard <[email protected]>
| Newsgroups | gmane.comp.xfree86.render |
|---|---|
| Message-ID | <E1798gp-0004WS-00@localhost> |
Just when you thought it was safe to draw trapezoids... I've been experimenting with 'sharp' polygons, those with aliased edges. This is effected by generating a 1-bit mask instead of an 8-bit mask. It shows off-by-one errors quite easily. Here's one: +--/--------+ |A/ | |/ B | / | /| | ------------------ 0.5 \| | \ C | |\ | |D\ | +--\--------+ Ok, so let's enumerate the "primitive" alphas, those computed directly from the area: A, AB, D, ABCD And composite alphas: B = AB - A CD = ABCD - AB C = CD - D Now, try a few rounding modes: Round Ceil Floor A 0 1 0 <- AB 1 1 0 D 0 1 0 <- ABCD 1 1 1 B 1 0 0 CD 0 0 1 C 0 -1 1 A+B+C+D 1 2 1 This example has a problem when using 'Ceil' rounding; the pixel will be drawn by both trapezoid 'A' and 'D'. Here's another one: L +---------\---+------------+ | \ | | | A \B| C | | \| | | \ | ---------------\------------- N | D |E\ F | +-------------+--\---------+ B and C belong to trap Q A D E belong to trap R F belongs to trap S Trap R is rendered without knowledge of boundary N When drawing trap Q: Aq: primitive ABq: primitive ADq: primitive Bq = ABq - Aq When drawing trap R: ADr: primitive Trap S doesn't intersect the left pixel at all, it's alpha is not evaluated. Now, try a few rounding modes: Round Ceil Floor Aq: 1 1 0 ABq: 1 1 0 ADq: 1 1 0 ADr: 1 1 0 <- Bq: 0 0 0 <- This example has a problem when using 'Floor' rounding; the pixel is never drawn. Curiously, if you blindly evaluate the alpha for trap S, it turns out to be one. Pretend there is a zero-sized trapezoid 'G' between the line 'L' and the right edge of the left pixel As: primitive ADs: primitive ABs: primitive ABDGs: primitive Ds = ADs - As DGs = ABDGs - ABs Gs = DGs - Ds Round Ceil Floor As 1 1 0 ADs 1 1 0 ABs 1 1 0 ABDGs 1 1 1 Ds 0 0 0 DGs 0 0 1 Gs 0 0 1 We've just approximated an empty pixel with an alpha of 1. Move left and perform the same hat trick and you get another 'full' pixel. Now we've eliminated 'floor' and 'ceil' as accurate rounding modes, here's my final example: +----------/ | /| | / | | / | | A / | | / | | / B | | / | -----/---------- N |C/ | |/ D | +----------+ Trap R: AC (no knowledge of N) Trap S: B Trap T: D ACr/ACt: primitive ABs/ABt: primitive At/As: primitive ABCD: primitive Bs: ABs - As CDt: ABCD - ABt Ct: ACt - At Dt: CDt - Ct Round Ceil Floor At/As: 0 1 0 ACr/ACt: 1 1 0 <- ABs/ABt: 1 1 0 ABCD: 1 1 1 Bs: 1 0 0 <- CDt: 0 0 1 Ct: 1 0 0 Dt: -1 0 1 <- Our old negative alpha friend has reappeared, resulting in a pixel getting rendered twice. I have two suggestions here -- it's clear that the 'Round' mode generates the most "reasonable" results, except for negative alpha. Given that these computations reflect sub-pixel accumulated error in coverage involving deeper alpha values, it seems that 'Round' is our mode of choice; it limits the error to cases where some portion of the pixel is smaller than 1/max_alpha, and then errors occur only in the upper left corner of the trapezoid. However, when depth is 1, we obviously need a different spec -- it's rather hard to generate trapezoids whose pixel coverage is always >= 1/max_alpha when max_alpha is 1. For this case, I suggest that we ignore area and look only at whether the desired region contains a particular point within the pixel -- to match our AA trapezoids, that should probably be the center. I think all this requires is a change in how the primitive alpha values are computed; alpha is '1' if the primitive area contains the line from the center of the pixel to the origin, else '0'. I'll give this a try and see what happens. Keith Packard XFree86 Core Team HP Cambridge Research Lab