Rasterization,

Hidden Surface Removal

and

OpenGL Buffers

 

Speaker  : 羅右鈞

Date        : 2015.8.4

Location : 交通大學

Rasterization

- Or called Scan conversion

- Convert primitives to fragments (potential pixels)

- We will focus on how to do line drawing and polygon filling

Rasterization

Line drawing

    - DDA

    - Bresenham's Algorithm

 

Polygon filling

    - Flood Fill

DDA (Digital Differential Analyzer)

- Simplest line drawing algorithm

- Basic idea : 

using precalculated slope m by two given endpoints, and

when m >= 1 : increment x by 1, find the best y in each iteration

when m < 1   : increment y by 1, find the best x in each iteration

(we ignore negative slope)

DDA (Digital Differential Analyzer)

Assume write_pixel (int x, int y, int color) .

given two endpoints (x1, y1) , (x2, y2) ,

we can get the slope :

m = (y2 - y1) / (x2 - x1)

=> m = △y / △x

=> △y = m△x 

DDA (Digital Differential Analyzer)

Assume 0 <= m <= 1,

we increment x by 1, find the best y in each iteration :

for ( x = x1 ; x <= x2 ; x++ ) {
    y += m;
    write_pixel ( x, round(y), color ); // 由於 m 可能是浮點數,需對y做四捨五入找出最適當的pixel位置
}

then we get the result :

DDA (Digital Differential Analyzer)

The result is not good enough when m > 1,

so when m > 1, we need to change our method to 

increment y by 1, find the best x in each iteration.

(not optimized)

(optimized)

Bresenham's Algorithm

Optimized DDA algorithm (avoid floating-point operation) .

Given two endpoints (x0, y0) , (x1, y1) , assume :

- x1 > x0

- line equation : y = mx + b

- 0 <= m <= 1, where m is slope

Bresenham's Algorithm

In this case, we increment x by 1 and find the best y, just same as DDA .

Assume we currently finish processing the pixel (xi, yi) .

We want to find the next position of pixel (xi+1, yi+1) .

xi+1 = xi + 1, since we increment x by 1.

we need to determine y = yi or yi + 1 (remain y or increment y by 1) .

Bresenham's Algorithm

Define :

d1 = y - yi

- d2 = (y+ 1) - y

Since y = m(xi + 1) + b when x = xi + 1 (by y = mx + b) ,

we get :

- d1 = m(xi + 1) + b - yi

- d2 = (yi + 1) - m(xi + 1) - b

d1 - d2m(xi + 1) + b - yi - yi - 1 + m(xi + 1) + b

= 2m(xi + 1) - 2yi + 2b - 1

Bresenham's Algorithm

How to determine yi+1 ?

When d1 - d2 < 0 , yi+1 = yi (remain y)

When d1 - d2 > 0 , yi+1 = yi + 1 (increment y by 1)

Bresenham's Algorithm

How to avoid floating-point operation ?

We simply multiply △x to m = △y /△x​ to eliminate denominator.

We apply this to d1 - d2 = 2m(xi + 1) - 2yi + 2b - 1 :

Assume pi△x (d1 - d2)

= △x [ 2m( xi + 1 ) - 2yi + 2b - 1 ]

= △x [ 2・(△y / △x)・( xi + 1 ) - 2yi + 2b - 1 ] ( by m = △y / △x )

= 2△y ( xi + 1 ) - 2△x・yi + 2△x・b - △x ( by multiplying △x )

= 2△y・xi + 2△y - 2△x・yi + 2△x・b - △x

= 2△y・xi - 2△x・yi2△y + 2△x・b - △x

 

The blue part is constant in every iteration, we can simplify as 

pi = 2△y・xi - 2△x・yi + c

 

Bresenham's Algorithm

Since determine d1 - d2 is positive or negative to pick the best y

= determine pi is positive or negative

pi = 2△y・xi - 2△x・yi + c

pi+1 = 2△y・xi+1 - 2△x・yi+1 + c

 

pi+1 - pi

2△y・xi+1 - 2△x・yi+1 + c - (2△y・xi - 2△x・yi + c)

= 2△y・(xi+1 - xi) - 2△x・(yi+1 - yi)  ( xi+1 - xi = 1, since we increment x by 1)

= 2△y - 2△x・(yi+1 - yi

 

Finally we get pi+1 p+ 2△y - 2△x・(yi+1 - yi) 

The blue part is either 0 (pi < 0) or 1(pi > 0)

Bresenham's Algorithm

In conclusion :

- when pi < 0 , pi+1 = pi + 2△y , since yi+1 - y= 0

- when pi > 0 , pi+1 = pi + 2△y - 2△x , since yi+1 - y= 1

So we only need to calculate the initial p ,

then in every iteration , we calculate next p by the below formula to

determine the next pixel position ( find the best y ) .

 

we know that pi2△y・xi - 2△x・yi + 2△y + 2△x・b - △x

p0 (initial p)

= 2△y・x0 - 2△x・y0 + 2△y + 2△x・b - △x

2△y・x0 - 2△x・y0 + 2△y + 2△x・[ y0 - (△y / △x)・x0 ] - △x

( by  y0 = m・x0 + b => b = y0 - (△y / △x)・x0 )

2△y - 2△x

Bresenham's Algorithm

So, this is how it works :

1. given two endpoints (x0, y0) , (x1, y1)

2. calculate constants :

    - △x = x1 - x0 and △y = y1 - y0

    - 2△x and 2△y

    - p0 = 2△y - 2△x

3. draw pixel ( round(x0), round(y0) )

4. for x = x0 to x1, i = 0 {
        if ( pi < 0 ) , write_pixel (xi + 1, yi, color) , pi+1 =  pi + 2△y

        else           , write_pixel (xi + 1, yi + 1, color) , pi+1 pi + 2△y - 2△x

        increment i

    }

Polygon Rasterization

Hollow polygon : 

use Bresenham's algorithm or another line drawing algorithm to draw polygon's edges.

 

Solid polygon :

use Flood Fill algorithm

Flood Fill Algorithm

First find the initial point (x,y) (or called seed point) ,

then recursively find the neighbors of the seed point and draw them.

 

Assume we have a function read_pixel (x, y) to get the pixel color at the position (x, y)

void flood_fill(int x, int y) {
    if ( read_pixel(x,y) == replacement_color ) { 
        write_pixel(x,y,target_color);
        flood_fill(x-1,y);
        flood_fill(x+1,y);
        flood_fill(x,y-1);
        flood_fill(x,y+1);
    }
}

Hidden Surface Removal

- or called visible-surface determination

- determine which fragments are visible

- two approachs :

    - Object space approach , such as Painter algorithm.

    - Image space approach , such as Z-buffer algorithm.

Painter Algorithm

- Or called Priority Fill

- Sort objects depending on their distance to viewer, then draw them from far to near. But whenever object or camera moves, we need to sort again.

- Not work in this case :

Z-buffer Algorithm

OpenGL Buffers

Frame buffer consists of :

- Color buffer

- Depth buffer

- Stencil buffer

- Accumulation buffer

Color Buffer

- Color buffer consists of :

    - Front buffer

    - Back buffer

- Save pixel's RGB or RGBA values 

( need to set glutInitDisplayMode( GLUT_RGBA ) )

Single buffering

- Set glutInitDisplayMode(GLUT_SINGLE)

- Only use front buffer for display and rendering

- Problem : monitor refreshing and GPU drawing are asynchronized.

Could cause flickering when doing animation.

Double buffering

- Set glutInitDisplayMode(GLUT_DOUBLE)

- Use front buffer for display and back buffer for rendering

- Need to call glutSwapBuffers() in the end of display function

- Also remember to call glClear(GL_COLOR_BUFFER_BIT) to clear the previous drawing

Depth buffer (Z-buffer) 

- Save pixel's depth value

- Need to do in OpenGL :

    - glutInitDisplayMode(GLUT_DEPTH)

​    - glEnable(GL_DEPTH_TEST)

- Use glDepthFunc(GLenum func) to determine how to test depth value.

- Also remember to call glClear(GL_DEPTH_BUFFER_BIT) in the end of display function to clear the previous depth value

 

Depth buffer (Z-buffer) 

(Cont.) Use glDepthFunc(GLenum func) to determine how to test depth value.

 

GL_NEVER:never pass

GL_LESS:if target pixel's z value < current pixel's z value,then pass (default)

GL_EQUAL:if target pixel's z value = current pixel's z value,then pass

GL_LEQUAL:if target pixel's z value <= current pixel's z value,then pass

GL_GREATER :if target pixel's z value > current pixel's z value,then pass

GL_NOTEQUAL:if target pixel's z value != current pixel's z value,then pass

GL_GEQUAL:if target pixel's z value = current pixel's z value,then pass

GL_ALWAYS:always pass

Stencil buffer

- Provide programmer to save extra value in each pixel for customizing.

- Typicall applications : masking and inverted image

 

Accumulation buffer

- Save RGBA color components

- How many bits need to save each color component depend on hardware implementation. You can check it by calling glGetIntegerv

- Use glAccum( GLenum op, GLfloat value ) to manipulate accumulation buffer

 

Accumulation buffer

- (Cont.) Use glAccum( GLenum op, GLfloat value ) to manipulate accumulation buffer

 

op can be one of the following values:

GL_ACCUM:從目前選定的color buffer(front 或 back)中讀取值(用glReadBuffer(GL_FRONT 或 GL_BACK) 進行讀取而選定目前的color buffer)用給定的value乘上R、G、B、A值,然後將結果加到accumulation buffer 中。

GL_LOAD:跟GL_ACCUM操作類似,但它是用結果值替換掉accumulation buffer中的值,而不是與之相加。

GL_RETURN:從accumulation buffer中取值,以value乘以該值,然後將該結果放入目前選定的color buffer中。

GL_ADD:將value與accumulation中的每個pixel的R、G、B、A分量相加。

GL_MULT:將value與accumulation中的每個pixel的R、G、B、A分量相乘。

Accumulation buffer

- Typical applications : Motion blur and Anti-aliasing

Without motion blur

With motion blur

Without anti-aliasing

With anti-aliasing

Rasterization, Hidden Surface Removal and OpenGL Buffers

By Howard Lo

Rasterization, Hidden Surface Removal and OpenGL Buffers

  • 782