1 / 50

2D Graphics

2D Graphics. CIS 487/587 Bruce R. Maxim UM-Dearborn. Vector Graphics. Advantages No jagged lines  Can only draw what is on the screen Control electron gun directly (very fast) Store line end points only Disadvantages Best for wire frames

stuart
Télécharger la présentation

2D Graphics

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 2D Graphics CIS 487/587 Bruce R. Maxim UM-Dearborn

  2. Vector Graphics • Advantages • No jagged lines •  Can only draw what is on the screen • Control electron gun directly (very fast) • Store line end points only • Disadvantages • Best for wire frames • Have to draw everything as lines including circles • Can’t use TV technology

  3. Raster Graphics • Advantages • Cheaper • Can easily draw solid surfaces • Can move blocks and images around • Can control individual pixels • Disadvantages • Memory intensive • Aliasing problems

  4. Jaggies • Here’s the problem with raster graphics • A diagonal line does not always pass through the center of the pixels

  5. This won’t work • Compute the slope of the line • Plot (x0, y0) • Advance xi = xi + 1 • Advance yi = yi + 1 • Plot (xi, yi) • Repeat

  6. Bresenhem’s Algorithm • Starts at x0, y0 • Plots x0, y0 • xi = xi + 1 • When advancing yi decide between plotting (xi, yi) or (xi,yi - 1) Note: Algorithm treats separately m < 1 (<45°) and m > 1 (>45°) Quadrants II, III, IV derived from I by symmetry

  7. LaMothe Examples

  8. Draw_Line( ) int Draw_Line(int x0, int y0, // starting position int x1, int y1, // ending position UCHAR color, // color index UCHAR *vb_start, int lpitch) // video buffer & memory pitch { // function draws a line from xo,yo to x1,y1 using differential error // terms (based on Bresenahams work) int dx, // difference in x's dy, // difference in y's dx2, // dx,dy * 2 dy2, x_inc, // amount in pixel space to move during drawing y_inc, // amount in pixel space to move during drawing error, // the discriminant i.e. error i.e. decision variable index; // used for looping // pre-compute first pixel address in video buffer vb_start = vb_start + x0 + y0*lpitch;

  9. Draw_Line( ) // compute horizontal and vertical deltas dx = x1-x0; dy = y1-y0; // test which direction the line is going in i.e. slope angle if (dx>=0) { x_inc = 1; } // end if line is moving right else { x_inc = -1; dx = -dx; // need absolute value } // end else moving left

  10. DrawLine( ) // now based on which delta is greater we can draw the line if (dx > dy) { error = dy2 - dx; // initialize error term for (index=0; index <= dx; index++) // draw the line { *vb_start = color; // set the pixel // test if error has overflowed if (error >= 0) { error-=dx2; // move to next line vb_start+=y_inc; } // end if error overflowed error+=dy2; // adjust the error term vb_start+=x_inc; // move to next pixel } // end for } // end if |slope| <= 1

  11. DrawLine( ) else { error = dx2 - dy; // initialize error term for (index=0; index <= dy; index++) // draw the line { *vb_start = color; // set the pixel if (error >= 0) // test if error overflowed { error-=dy2; vb_start+=x_inc; // move to next line } // end if error overflowed error+=dx2; // adjust the error term vb_start+=y_inc; // move to next pixel } // end for } // end else |slope| > 1 return(1); // return success } // end Draw_Line

  12. DrawLine( ) // test y component of slope if (dy>=0) { y_inc = lpitch; } // end if line is moving down else { y_inc = -lpitch; dy = -dy; // need absolute value } // end else moving up // compute (dx,dy) * 2 dx2 = dx << 1; dy2 = dy << 1;

  13. Clipping • Goal is to only display the part of the image that is really viewable on the portion of the screen used for drawing • Approaches: • Border • Image space • Object space

  14. Border Clipping • Create a border that is a wide as any movable screen object • Only draw the object • Still need to detect when object will be off-screen • Requires more memory

  15. Image Space Clipping • Image space (pixel level representation of complete image) • Test each point to see if it is in the region before trying to draw it • Easy to implement • Works for all objects • Works for sub regions • Requires lots of computation for each pixel

  16. Object Space Clipping • Object space (representation of figures) • Change object to one that does not need to be clipped (e.g. chop triangle into a trapezoid) • New object passed to graphics engine • Without testing for clipping • More efficient than image space clipping • Lines are easy • Concave objects are tough

  17. Cohen Sutherland • Each region is assigned a bit code • End points P1and P2 • If y < minY or y > maxY or x < minX or x > maxX then save Sign bits of P1 and P2 P2

  18. Cohen Sutherland • Accept the point if P1 + P2 = 0 • Reject the point if P1 & P2 != 0 Note: It is best to break up the line so that line segment only occupies a single region

  19. Draw_Clip_Line( ) int Draw_Clip_Line(int x0,int y0, int x1, int y1, UCHAR color, UCHAR *dest_buffer, int lpitch) { // this helper function draws a clipped line int cxs, cys,cxe, cye; // clip and draw each line cxs = x0; cys = y0; cxe = x1; cye = y1; // clip the line if (Clip_Line(cxs,cys,cxe,cye)) // use Bresenham like before Draw_Line(cxs, cys, cxe,cye,color,dest_buffer,lpitch); return(1); // return success } // end Draw_Clip_Line

  20. Clip_Line( ) int Clip_Line(int &x1,int &y1,int &x2, int &y2) { // function clips the line using globally defined clippingregion // internal clipping codes #define CLIP_CODE_C 0x0000 #define CLIP_CODE_N 0x0008 #define CLIP_CODE_S 0x0004 #define CLIP_CODE_E 0x0002 #define CLIP_CODE_W 0x0001 #define CLIP_CODE_NE 0x000a #define CLIP_CODE_SE 0x0006 #define CLIP_CODE_NW 0x0009 #define CLIP_CODE_SW 0x0005 int xc1=x1, yc1=y1, xc2=x2, yc2=y2; int p1_code=0, p2_code=0;

  21. Clip_Line( ) // determine codes for p1 and p2 if (y1 < min_clip_y) p1_code|=CLIP_CODE_N; elseif (y1 > max_clip_y) p1_code|=CLIP_CODE_S; if (x1 < min_clip_x) p1_code|=CLIP_CODE_W; elseif (x1 > max_clip_x) p1_code|=CLIP_CODE_E;  if (y2 < min_clip_y) p2_code|=CLIP_CODE_N; elseif (y2 > max_clip_y) p2_code|=CLIP_CODE_S; if (x2 < min_clip_x) p2_code|=CLIP_CODE_W; else if (x2 > max_clip_x) p2_code|=CLIP_CODE_E;

  22. Clip_Line( ) // try and trivially reject if ((p1_code & p2_code)) return(0); // test for totally visible, if so leave points untouched if (p1_code==0 && p2_code==0) return(1); // determine end clip point for p1 … // determine end clip point for p2 …

  23. Clip_Line( ) // do bounds check if ((xc1 < min_clip_x) || (xc1 > max_clip_x) || (yc1 < min_clip_y) || (yc1 > max_clip_y) || (xc2 < min_clip_x) || (xc2 > max_clip_x) || (yc2 < min_clip_y) || (yc2 > max_clip_y) ) { return(0); } // end if // store vars back x1 = xc1; y1 = yc1; x2 = xc2; y2 = yc2; return(1); } // end Clip_Line

  24. Polygons • Defined by vertices • Closed (all line connected) • Simply draw them one line at a time • Can be convex or concave • Attributes: Number of vertices, color, position, list of vertices (x, y) form

  25. Draw_Polygon2D( ) if (poly->state) // test if the polygon is visible { // loop thru and draw a line from vertices 1 to n for (int index=0; index < poly->num_verts-1; index++) { // draw line from ith to ith+1 vertex Draw_Clip_Line(poly->vlist[index].x+poly->x0, poly->vlist[index].y+poly->y0, poly->vlist[index+1].x+poly->x0, poly->vlist[index+1].y+poly->y0, poly->color,vbuffer, lpitch); } // end for // draw line from last vertex to 0th Draw_Clip_Line(poly->vlist[0].x+poly->x0, poly->vlist[0].y+poly->y0, poly->vlist[index].x+poly->x0, poly->vlist[index].y+poly->y0, poly->color, vbuffer, lpitch); return(1); } // end if else return(0);

  26. Moving Objects • If you move an object do you need to change every vertex coordinate? • Yes, if you use world coordinates (meaning the screen coordinate system) • No, if you local coordinates (meaning local to the object itself) • Example: triangle at (4,0) might have local vertex coordinates (0,1), (-1,-1), (1,-1)

  27. Translation (Moving) • If you want to move a point (x0 , y0) to a new position (xt , yt) • The transformation would be xt = x0 + dx and yt = y0 + dy • For motion dx and dy are the components of the velocity vector dx = cos v and dy = - sin v

  28. Game_Main( ) // draw all the asteroids for (int curr_index = 0; curr_index < NUM_ASTEROIDS; curr_index++) { // glow asteroids asteroids[curr_index].color = rand()%256;  // do the graphics Draw_Polygon2D(&asteroids[curr_index], (UCHAR *)ddsd.lpSurface, ddsd.lPitch); // move the asteroid without matrix operations asteroids[curr_index].x0+=asteroids[curr_index].xv; asteroids[curr_index].y0+=asteroids[curr_index].yv;   // test for out of bounds if (asteroids[curr_index].x0 > SCREEN_WIDTH+100) asteroids[curr_index].x0 = - 100; if (asteroids[curr_index].y0 > SCREEN_HEIGHT+100) asteroids[curr_index].y0 = - 100  if (asteroids[curr_index].x0 < -100) asteroids[curr_index].x0 = SCREEN_WIDTH+100; if (asteroids[curr_index].y0 < -100) asteroids[curr_index].y0 = SCREEN_HEIGHT+100; } // end for curr_asteroid

  29. Scaling (Changing Size) • Multiply the coordinates of each vertex by the scale factor • Everything will expand from the center • The transformation would be xt = x0 * scale and yt = y0 * scale

  30. Scale_Polygon2D( ) int Scale_Polygon2D(POLYGON2D_PTR poly, float sx, float sy) { // this function scalesthe local coordinates of the polygon // test for valid pointer if (!poly) return(0); // loop and scale each point for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++) { // scale and store result back poly->vlist[curr_vert].x *= sx; poly->vlist[curr_vert].y *= sy; } // end for curr_vert // return success return(1); } // end Scale_Polygon2D

  31. Game_Main( ) // do the graphics Draw_Polygon2D(&asteroid, (UCHAR *)ddsd.lpSurface, ddsd.lPitch); // test for scale if (KEYDOWN('A')) // scale up Scale_Polygon2D(&asteroid, 1.1, 1.1); else if (KEYDOWN('S')) // scale down Scale_Polygon2D(&asteroid, 0.9, 0.9); // rotate the polygon by 5 degrees Rotate_Polygon2D(&asteroid, 5);

  32. Rotation (Turning) • Spin and object around it centered around the z-axis • Rotate each point the same angle • Positive angles are clockwise • Negative angles are counterclockwise • C++ uses radians (not degrees) • The transformation would be xt = x0 * cos() – y0 * sin() yt = y0 * cos() + x0 * sin()

  33. Rotate_Poloygon2D( ) int Rotate_Polygon2D(POLYGON2D_PTR poly, int theta) { // function rotates the local coordinates of the polygon – no matrices // test for valid pointer if (!poly) return(0); // loop and rotate each point, very crude, no lookup!!! for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++) { // perform rotation float xr = (float)poly->vlist[curr_vert].x*cos_look[theta] - (float)poly->vlist[curr_vert].y*sin_look[theta]; float yr = (float)poly->vlist[curr_vert].x*sin_look[theta] + (float)poly->vlist[curr_vert].y*cos_look[theta]; // store result back poly->vlist[curr_vert].x = xr; poly->vlist[curr_vert].y = yr; } // end for curr_vert // return success return(1); } // end Rotate_Polygon2D

  34. Summary • Drawing polygons is simply a matter of drawing lines and connecting end points • Clipping is used to remove images outside viewing area • Center polygons at (x0 , y0) and use local coordinates rather than world coordinates for the vertices

  35. World Coordinates • When using world coordinates you always need to perform the following steps • Translate to origin • Perform rotation • Translate back to new position • It’s always a good idea to put sin(x) and cos(x) values in a lookup table to avoid recomputing them

  36. Matrix Operations • Translation | 1 0 0| |x y 1| * | 0 1 0| |dx dy 1| • Scaling |sx 0 0| |x y 1| * | 0 sy 0| | 0 0 1|

  37. Matrix Operations • Rotation |cos(a) -sin(a) 0| |x y 1| * |sin(a) cos(a) 0| | 0 0 1| • (S * R) * T | sx*cos(a) –sx*sin(a) 0| |x y 1| * | sy*sin(a) sy*cos(a) 0| | dx dy 1|

  38. Mat_Init_3x2( ) inline int Mat_Init_3X2(MATRIX3X2_PTR ma, float m00, float m01, float m10, float m11, float m20, float m21) { // fills a 3x2 matrix with the sent data in row major form ma->M[0][0] = m00; ma->M[0][1] = m01; ma->M[1][0] = m10; ma->M[1][1] = m11; ma->M[2][0] = m20; ma->M[2][1] = m21; // return success return(1); } // end Mat_Init_3X2

  39. Mat_Mul1x2_3x2( ) int Mat_Mul1X2_3X2(MATRIX1X2_PTR ma, MATRIX3X2_PTR mb,MATRIX1X2_PTR mprod) { // function multiplies a 1x2 matrix against a 3x2 matrix - ma*mb and // stores result using a dummy element for the 3rd element of the 1x2 for (int col=0; col<2; col++) { // compute dot product from row of ma and column of mb float sum = 0; // used to hold result for (int index=0; index<2; index++) { sum+=(ma->M[index]*mb->M[index][col]); // add next product pair } // end for index sum += mb->M[index][col]; // add in last element * 1 mprod->M[col] = sum;  // insert resulting col element } // end for col return(1); } // end Mat_Mul_1X2_3X2

  40. Matrix Translation int Translate_Polygon2D_Mat(POLYGON2D_PTR poly, int dx, int dy) { // function translates center polygon by using a matrix multiply  if (!poly) return(0); // test for valid pointer MATRIX3X2 mt; // used to hold translation transform matrix // initialize the matrix with translation values dx dy Mat_Init_3X2(&mt,1,0, 0,1, dx, dy); // create a 1x2 matrix to do the transform MATRIX1X2 p0 = {poly->x0, poly->y0}; MATRIX1X2 p1 = {0,0}; // this will hold result // now translate via a matrix multiply Mat_Mul1X2_3X2(&p0, &mt, &p1); // now copy the result back into polygon poly->x0 = p1.M[0]; poly->y0 = p1.M[1]; // return success return(1); } // end Translate_Polygon2D_Mat

  41. Matrix Scaling int Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy) { // this function scales the local coordinates of the polygon if (!poly)return(0); // test for valid pointer MATRIX3X2 ms; // used to hold scaling transform matrix Mat_Init_3X2(&ms, sx, 0, 0, sy, 0, 0); // loop and scale each point for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++) { // scale and store result back MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y}; MATRIX1X2 p1 = {0,0}; // this will hold result Mat_Mul1X2_3X2(&p0, &ms, &p1); // now scale via a matrix multiply poly->vlist[curr_vert].x = p1.M[0]; // copy result back to vertex poly->vlist[curr_vert].y = p1.M[1]; } // end for curr_vert return(1); } // end Scale_Polygon2D_Mat

  42. Matrix Rotation int Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta) { // function rotates the local coordinates of the polygon if (!poly) return(0); // test for valid pointer // test for negative rotation angle if (theta < 0) theta += 360; MATRIX3X2 mr; // used to hold rotation transform matrix Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta], -sin_look[theta],cos_look[theta], 0, 0);

  43. Matrix Rotation // loop and rotate each point, very crude, no lookup!!! for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++) { // create a 1x2 matrix to do the transform MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y}; MATRIX1X2 p1 = {0,0}; // this will hold result // now rotate via a matrix multiply Mat_Mul1X2_3X2(&p0, &mr, &p1); // now copy the result back into vertex poly->vlist[curr_vert].x = p1.M[0]; poly->vlist[curr_vert].y = p1.M[1]; } // end for curr_vert return(1); } // end Rotate_Polygon2D_Mat

  44. Filling Polygons • Many systems draw 2D and 3D objects as collections of triangles • If we can fill a triangle, we are in pretty good shape • The general idea will be to break up figures into triangles whose base is parallel to the x-axis and the draw lots of horizontal lines

  45. Triangle Filling P0(x0 , y0) P2(x2 , y2) P1(x1 , y1)

  46. Triangle Filling • Compute dx/dy for left and right sides (basically 1/slope) call them dxy_left and dxy_right • Starting at top vertex (x0 , y0) set xs=xl= x0 and y= y0 • Add dxy_left to xs and add dxy_right to xl • Draw lines (xs,y) to (xl,y) • Increment y and go to step 3

  47. Drawing Filled Triangles void Draw_Top_TriFP(int x1,int y1,int x2, int y2, int x3,int y3, int color, UCHAR *dest_buffer, int mempitch) // function draws a triangle that has a flat top using fixed point math void Draw_Bottom_TriFP(int x1,int y1, int x2,int y2, int x3,int y3, int color, UCHAR *dest_buffer, int mempitch) // function draws triangle that has flat bottom using fixed point math void Draw_Top_Tri(int x1,int y1, int x2, int y2, int x3,int y3, int color, UCHAR *dest_buffer, int mempitch) // this function draws a triangle that has a flat top void Draw_Bottom_Tri(int x1,int y1, int x2, int y2, int x3,int y3, int color, UCHAR *dest_buffer, int mempitch) // this function draws a triangle that has a flat bottom

  48. Drawing Filled Triangles void Draw_TriangleFP_2D(int x1,int y1,int x2, int y2,int x3,int y3, int color,UCHAR *dest_buffer, int mempitch) // function draws triangle on the destination buffer using fixed point // it decomposes all triangles into a pair of flat top, flat bottom void Draw_Triangle_2D(int x1,int y1,int x2, int y2,int x3,int y3, int color, UCHAR *dest_buffer, int mempitch) // this function draws a triangle on the destination buffer // it decomposes all triangles into a pair of flat top, flat bottom

  49. Breaking Up Polygons • If number of vertices left to process is greater then 3 continue to step 2 • Take first 3 vertices and create a triangle • Split off triangle and recursively process remaining vetices

  50. Breaking Up Quadrilaterals inline void Draw_QuadFP_2D(int x0,int y0, int x1,int y1, int x2,int y2, int x3, int y3, int color, UCHAR *dest_buffer, int mempitch) { // this function draws a 2D quadrilateral // simply call the triangle function 2x, let it do all the work Draw_TriangleFP_2D(x0,y0,x1,y1,x3,y3,color,dest_buffer,mempitch); Draw_TriangleFP_2D(x1,y1,x2,y2,x3,y3,color,dest_buffer,mempitch); } // end Draw_QuadFP_2D

More Related