1.02k likes | 1.17k Views
CSC 830 Computer Graphics Lecture 5 Rasterization. Course Note Credit: Some of slides are extracted from the course notes of prof. Mathieu Desburn (USC) and prof. Han-Wei Shen (Ohio State University). . Rasterization.
E N D
CSC 830 Computer GraphicsLecture 5 Rasterization Course Note Credit: Some of slides are extracted from the course notes of prof. Mathieu Desburn (USC) and prof. Han-Wei Shen (Ohio State University).
Rasterization • Okay, you have three points (vertices) at screen space. How can you fill the triangle? v2 E1 Simple Solution v2 v1 2 E1 E1 1 2 v1 1 E2 E0 E0 E2 v0 v0
My simple approach int draw_tri(render,t) GzRender *render; GzTriangle t; { sort_vert(t); /* Vertices are properly sorted, so edge1 can be composed by ver[0],ver[1] and edge2 by ver[1],[2], and so on */ init_edge(render,E0,t[0],t[1]); init_edge(render,E1,t[1],t[2]); init_edge(render,E2,t[0],t[2]); step_edges(render); return GZ_SUCCESS; }
void init_edge(GzRender *render,int i,GzVertex ver1,GzVertex ver2) { Interpolater *ip; float dy; ip = &render->interp[i]; ip->fromx = ver1.p[x]; ip->fromy = ver1.p[y]; dy = ver2.p[y]-ver1.p[y]; if(dy== 0) ip->dxdy = zmax; else ip->dxdy = (ver2.p[x]-ver1.p[x])/dy; ip->tox = ver2.p[x]; ip->toy = ver2.p[y]; ip->fromz = ver1.p[z]; if(ver2.p[y]-ver1.p[y]== 0) ip->dz = zmax; else ip->dz =(ver2.p[z]-ver1.p[z])/dy; vec_copy(ip->from_norm,ver1.n); ip->dnorm[x]=(ver2.n[x] - ver1.n[x])/dy; ip->dnorm[y]=(ver2.n[y] - ver1.n[y])/dy; ip->dnorm[z]=(ver2.n[z] - ver1.n[z])/dy; }
Interpolater x3, y3, z3 x2, y2, z2 (xn,yn,zn) xn = x1 + (yn-y1)*(x2-x1)/(y2-y1) zn = z1 + (yn-y1)*(z2-z1)/(y2-y1) x1, y1, z1
v2 v2 Step Edges v2 v1 v1 v0 v1 v0 E1 v1 v2 v0 v2 v2 E1 v1 E2 E0 E2 E1 E0 E2 v0 v0 v1 E0 v0
Better & still simple approach • Find left edge & right edge from v0 • You can not tell when y==v0.y • But you can tell by comparing x values when y == v0.1+1 • You need to treat horizontal edges carefully (divide by zero).
Back-face Culling • If a surface’s normal is pointing to the same direction as our eye direction, then this is a back face • The test is quite simple: if N * V > 0 then we reject the surface
Painters Algorithm • Sort objects in depth order • Draw all from Back-to-Front (far-to-near) • Is it so simple?
3D Cycles • How do we deal with cycles? • Deal with intersections • How do we sort objects that overlap in Z?
Z-buffer • Z-buffer is a 2D array that stores a depth value for each pixel. • Invented by Catmull in '79, it allows us to paint objects to the screen without sorting, without performing intersection calculations where objects interpenetrate. • InitScreen: for i := 0 to N dofor j := 1 to N doScreen[i][j] := BACKGROUND_COLOR; Zbuffer[i][j] := ; • DrawZpixel (x, y, z, color)if (z <= Zbuffer[x][y]) thenScreen[x][y] := color; Zbuffer[x][y] := z;
Z-buffer: Scanline I. foreach polygondoforeach pixel (x,y) in the polygon’s projectiondoz := -(D+A*x+B*y)/C; DrawZpixel(x, y, z, polygon’s color); II. foreach scan-liney doforeach “in range” polygon projectiondo for each pair (x1, x2) of X-intersections dofor x := x1 to x2doz := -(D+A*x+B*y)/C; DrawZpixel(x, y, z, polygon’s color); If we know zx,y at (x,y) than: zx+1,y = zx,y - A/C
Non Trivial Example ? Rectangle: P1(10,5,10), P2(10,25,10), P3(25,25,10), P4(25,5,10) Triangle: P5(15,15,15), P6(25,25,5), P7(30,10,5) Frame Buffer: Background 0, Rectangle 1, Triangle 2 Z-buffer: 32x32x4 bit planes
Z-Buffer Advantages • Simple and easy to implement • Amenable to scan-line algorithms • Can easily resolve visibility cycles
Z-Buffer Disadvantages • Aliasing occurs! Since not all depth questions can be resolved • Anti-aliasing solutions non-trivial • Shadows are not easy • Higher order illumination is hard in general
Rasterizing Polygons Given a set of vertices and edges, find the pixels that fill the polygon.
Scan Line Algorithms Take advantage of coherence in “insided-ness” Inside/outside can only change at edge events Current edges can only change at vertex events
Scan Line Algorithms Create a list of vertex events (bucket sorted by y)
Scan Line Algorithms Create a list of the edges intersecting the first scanline Sort this list by the edge’s x value on the first scanline Call this the active edge list
Scanline Rasterization Special Handling • Intersection is an edge end point, say: (p0, p1, p2) ?? • (p0,p1,p1,p2), so we can still fill pairwise • In fact, if we compute the intersection of the scanline with edge e1 and e2 separately, we will get the intersection point p1 twice. Keep both of the p1.
Scanline Rasterization Special Handling • But what about this case: still (p0,p1,p1,p2)
Rule • Rule: • If the intersection is the ymin of the edge’s endpoint, count it. Otherwise, don’t. • Don’t count p1 for e2
Data Structure • Edge table: • all edges sorted by their ymin coordinates. • keep a separate bucket for each scanline • within each bucket, edges are sorted by increasing x of the ymin endpoint
Active Edge Table (AET) • A list of edges active for current scanline, sorted in increasing x y = 9 y = 8
Penetrating Polygons False edges and new polygons! Compare z value & intersection when AET is calculated
Polygon Scan-conversion Algorithm Construct the Edge Table (ET); Active Edge Table (AET) = null; for y = Ymin to Ymax Merge-sort ET[y] into AET by x value Fill between pairs of x in AET for each edge in AET if edge.ymax = y remove edge from AET else edge.x = edge.x + dx/dy sort AET by x value end scan_fill
Scan Line Algorithms • For each scanline: • Maintain active edge list (using vertex events) • Increment edge’s x-intercepts, sort by x-intercepts • Output spans between left and right edges replace insert delete
Convex Polygons Convex polygons only have 1 span Insertion and deletion events happen only once
Crow’s Algorithm Find the vertex with the smallest y value to start crow(vertex vList[], int n) int imin = 0; for(int i = 0; i < n; i++) if(vList[i].y < vList[imin].y) imin = i; scanY(vList,n,imin);
Crow’s Algorithm Scan upward maintaining the active edge list scanY(vertex vList[], int n, int i) int li, ri; // left & right upper endpoint indices int ly, ry; // left & right upper endpoint y values vertex l, dl; // current left edge and delta vertex r, dr; // current right edge and delta int rem; // number of remaining vertices int y; // current scanline li = ri = i; ly = ry = y = ceil(vList[i].y); for( rem = n; rem > 0) // find appropriate left edge // find appropriate right edge // while l & r span y (the current scanline) // draw the span (1) (3) (2)
Crow’s Algorithm Draw the spans for( ; y < ly && y < ry; y++) // scan and interpolate edges scanX(&l, &r, y); increment(&l,&dl); increment(&r,&dr); increment(vertex *edge, vertex *delta) edge->x += delta->x; (2) Increment the x value
Crow’s Algorithm Draw the spans scanX(vertex *l, vertex *r, int y) int x, lx, rx; vertex s, ds; lx = ceil(l->x); rx = ceil(r->x); if(lx < rx) differenceX(l, r, &s, &ds, lx); for(x = lx, x < rx; x++) setPixel(x,y); increment(&s,&ds);
d f d f Crow’s Algorithm Calculate delta and starting values differenceX(vertex *v1, vertex *v2, vertex *e, vertex *de, int x) difference(v1, v2, e, de, (v2->x – v1->x), x – v1->x); difference(vertex *v1, vertex *v2, vertex *e, vertex *de, float d, float f) de->x = (v2->x – v1->x) / d; e->x = v1->x + f * de->x; differenceY(vertex *v1, vertex *v2, vertex *e, vertex *de, int y) difference(v1, v2, e, de, (v2->y – v1->y), y – v1->y);
Crow’s Algorithm Find the appropriate next left edge while( ly < = y && rem > 0) rem--; i = li – 1; if(i < 0) i = n-1; // go clockwise ly = ceil( v[i].y ); if( ly > y ) // replace left edge differenceY( &vList[li], &vList[i], &l, &dl, y); li = i; (3)
Crow’s Algorithm Interpolating other values difference(vertex *v1, vertex *v2, veretx *e, vertex *de, float d, float f) de->x = (v2->x – v1->x) / d; e->x = v1->x + f * de->x; de->r = (v2->r – v1->r) / d; e->r = v1->r + f * de->r; de->g = (v2->g – v1->g) / d; e->g = v1->g + f * de->g; de->b = (v2->b – v1->b) / d; e->b = v1->b + f * de->b; increment( vertex *v, vertex *dv) v->x += dv->x; v->r += dv->r; v->g += dv->g; v->b += dv->b;
Scan Line Algorithm • Low memory cost • Uses scan-line coherence • but not vertical coherence • Has several side advantages: • filling the polygons • reflections • texture mapping • Renderman (Toy Story) = scan line
Visibility • Clipping • Culling
Clipping Objects may lie partially inside and partially outside the view volume We want to “clip” away the parts outside Simple approach - checking if (x,y) is inside of screen or not What is wrong with it?
Cohen-Sutherland Clipping • Clip line against convex region • Clip against each edge • Line crosses edge • replace outside vertex with intersection • Both endpoints outside • trivial reject • Both endpoints inside • trivial accept
Cohen-Sutherland Clipping • Store inside/outside bitwise for each edge • Trivial accept outside(v1) | outside(v2) == 0 • Trivial reject outside(v1) & outside(v2) • Compute intersection (eg. x = a) (a, y1 + (a-x1) * (y2-y1)/(x2-x1))
Outcode Algorithm • Classifies each vertex of a primitive, by generating an outcode. An outcode identifies the appropriate half space location of each vertex relative to all of the clipping planes. Outcodes are usually stored as bit vectors.
if (outcode1 == '0000' and outcode2 == ‘0000’) then line segment is inside else if ((outcode1 AND outcode2) == 0000) then line segment potentially crosses clip region else line is entirely outside of clip region endif endif
The maybe case? • If neither trivial accept nor reject: • Pick an outside endpoint (with nonzero outcode) • Pick an edge that is crossed (nonzero bit of outcode) • Find line's intersection with that edge • Replace outside endpoint with intersection point • Repeat outcode test until trivial accept or reject