
Graphics Programming Principles and Algorithms Zongli Shi May 27, 2017 Abstract This paper is an introduction to graphics programming. This is a computer science field trying to answer questions such as how we can model 2D and 3D objects and have them displayed on screen. Researchers in this field are constantly trying to find more efficient algorithms for these tasks. We are going to look at basic algorithms for modeling and drawing line segments, 2D and 3D polygons. We are also going to explore ways to transform and clip 2D and 3D polygons. For illustration purpose, the algorithms presented in this paper are implemented in C++ and hosted at GitHub. Link to the GitHub repository can be found in the introduction paragraph. 1 Introduction Computer graphics has been playing a vital role in communicating computer-generated information to human users as well as providing a more intuitive way for users to interact with computers. Al- though nowadays, devices such as touch screens are everywhere, the effort of developing graphics system in the first place and beauty of efficient graphics rendering algorithms should not be underes- timated. Future development in graphics hardware will also bring new challenges, which will require us to have a thorough understanding of the fundamentals. This paper will mostly investigate the various problems in graphics programming and the algorithms to solve them. All of the algorithms are also presented in the book Computer Graphics by Steven Harrington [Har87]. This paper will also serve as a tutorial, instructing the readers to build a complete graphics system from scratch. At the end we shall have a program manipulating basic bits and bytes but capable of generating 3-D animation all by itself. To better assist the reader in implementing the algorithms presented in this paper, the writer's implementation in C++ can be found in the following GitHub link: https://github.com/shizongli94/graphics_programming. 2 Basic Problems in Graphics The basic problems in graphics programming are similar to those in any task of approximation. The notion of shapes such as polygons and lines are abstract, and by their definitions, continuous in their nature. A line can extend to both directions forever. A polygon can be made as large as we want. However, most display devices are represented as a rectangle holding finitely many individual displaying units called pixels. The size of the screen limits the size of our shapes and the amount of pixels limit how much detail we can put on screen. Therefore, we are trying to map something continuous and infinite in nature such as lines and polygons to something discrete and finite. In this process, some information has to be lost but we should also try to approximate the best we can. We will first look at how to draw a line on screen to illustrate the process of building a discrete representation and how to recover as much lost information as we can. 1 3 Drawing a Line Segment Since a line is infinite in its nature, we have to restrict ourselves to drawing line segments, which will a be reasonable representation of infinite line when going from one side of a screen to another. The simplest way to represent a line segment is to have the coordinates of its two end points. One way of drawing a line segment will be simply starting with one end point and on the way of approaching the other, turning on pixels. This approach resembles our experience of drawing a line segment on paper, but it poses two questions. First, on what criterion should we select a pixel? And second, if the criterion is set, how do we efficiently select the required pixels? For the first question, let us define X as the pixel on row r and column c, and the lines y = r and x = c running through X and intersecting at its center. We also denote L as the line segment with end points (x1; y1) and (x2; y2) where x1 ≤ x2. We then will have a criterion when jmj < 1=2 (m is the slope) as follows: Pixel X will be turned on if y1 < r < y2, x1 < c < x2 and if the intersecting point of x = c and L is within the boundaries of X. We shall not be concerned with when the line crosses x = c at one of the boundaries of pixel X, because choosing either pixel adjacent to this boundary has no effect on our line representation. Notice that we are using the typical mathematical coordinate system with origin at the lower left corner despite most device manufacturers putting the origin at the upper left corner of a screen. Also we are going to use indices starting from 0 instead of 1. This is the typical approach in computer programming. This is for the case jmj < 1=2. For future reference, we call it the gentle case. For the steeper case when jmj > 1=2, we simply re-label the x-axis as the y-axis and y-axis as the x-axis. When labels are interchanged, those two cases are basically the same. They both have the absolute value of slope smaller than 1=2. But why do we bother to divide into two cases? We will see in a moment that this division into cases dramatically simplifies our problem of selecting pixels. When looking at Figure1, we see that pixel at (1; 1) is selected and turned as well as the pixel at (2; 2). The pixel at (0; 0) is not selected even though the line segment starts within its boundaries. The pixel at (2; 1) is not selected either even though there is a portion of the line segment running through it. 4 The First Algorithm: DDA The first algorithm we are going to introduce is DDA. It stands for Digital Differential Analyzer. Before we start to see how the algorithm works, let's first answer why we need to divide line drawing into two cases and restrict ourselves only to the gentle case. Referring to Figure1 and only considering positive slope, notice that when the line segment starts from the pixel at (0; 0), it faces two choices. If it is gentle enough, it will enter the pixel at (1; 0) and crosses x = 1 before leaving it. Otherwise, it will go into pixel (1; 1) and cross its line x = 1 before leaving it. However, it will never be able to reach the pixel (1; 2), because its slope is no larger than 1=2. Therefore we only need to choose one out of the two possible pixels. Furthermore, we already know where the two pixels are located. If the pixel where the line segment starts is at row y0 and column x0, the two pixels we need to choose from will both be in the next column x0 +1. One of them will be in row x0, same as the original pixel. The other will be in row x0 + 1, only one level above the original pixel. Then our algorithm can be described as starting with one pixel, and scanning each column of pixels from left to right. Every time when we are entering the next column, we either choose the pixel in the same row as the pixel in the previous column, or we choose the pixel in the row one level above the pixel in the previous column. When the slope is negative, we still only have two pixels to choose from. If the pixel we start from is at (x0y0), then the pixels we choose from are (x0 + 1; y0) and (x0 + 1; y0 − 1). For future explanations, we are going to use the grid in Figure2 as representation of a screen. Notice the origin in the grid is the lower left corner of a rectangular screen. The pixels below x-axis and the pixels to the left of y-axis are not shown on screen. For simplicity, the upper and right boundaries of the screen are not shown. 2 y = 2 y = 1 y = 0 x = 0 x = 1 x = 2 Figure 1: Criterion on how to select a pixel y x Figure 2: A Screen of Pixels 3 y P0 B0 x Figure 3: An Example of DDA Algorithm y P1 B1 x Figure 4: The state of the program right after coloring a pixel in the second column To understand an algorithm, it is always helpful to have a sense of the idea behind it. For DDA, when we are scanning the columns one by one, the movement from one column to another is essentially the same as adding 1 each time to the x-coordinate. Since a straight line has a constant rate of change, we can exploit this property by adding m, the value of slope, to the y-coordinate each time we move to a new column. This is the idea behind DDA. To describe the implementation details, we define a crossing point to be the point where the line segment of interest crosses the center line of a column. We obtain the coordinates of first crossing point P0 as (x0; y0) and distance h between P0 and B0, which is the central point of the row boundary right below P0. We use h to determine if we want to color subsequent pixels. When we move to the column x0 + 1, we add m to h. If h < 1, we color the pixel (x0 + 1; y0). If h > 1, we color the pixel (x0 + 1; y0 + 1) and we subtract 1 from h. However, we can not use h to determine the first pixel we want to color because there is not a pixel in the previous color we can refer to.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages37 Page
-
File Size-