計算機圖形學課程總結

longshilin.com發表於2017-01-03

計算機圖形學是我大三上學期開設的課程。現在寫個部落格,做點總結,也算是沒白學這麼課程吧~

一、 解釋圖形學中名詞的含義

  • 圖形要素:幾何要素和非幾何要素。
  • 多邊形掃描轉換:從多邊形頂點表示到點陣表示的轉換。
  • 消隱:在繪製圖形時,消除被遮擋的不可見的線或面。
  • 扭失:曲面片四個頂點的二階導。
  • 引力場技術:物體延伸到空間中對另一個物體產生吸引效應的技術。
  • 滅點:指立體圖形的各邊延伸至同一相交點。
  • 正則形體:由幾何形體內部的點集和緊緊包裹這些點集的表皮所構成。
  • 反走樣:減少或消除圖形因鋸鋸齒齒而失真的技術。
  • 顯示解析度:顯示器在顯示影象時的解析度。
  • C1連線:兩條相鄰曲線段在相交點處,具有相同的一階導。
  • C2連線:兩條相鄰曲線段在相交點處,具有相同的一階導和二階導。
  • 簡單光照模型:由環境光放射、漫反射及鏡面光反射構成。
  • 深度緩衝儲存:三維圖形中處理影象深度座標的過程。
  • 捕捉技術:利用外部裝置捕捉計算機能直接理解的資料,如物體尺寸測量、物體空間定位等。
  • 儲存解析度:幀緩衝區的大小
  • 法向量插值法:保留雙向性插值,並對頂點採用法向量插值,其中頂點的法向向量值由該點相鄰的多邊形面片的法向向量值取平均值取得。
  • CRT:陰極射線管
  • DPU:分散處理單元
  • 象素:基本原色素及其灰度的基本編碼。
  • 4連通:同一畫素在上、下、左、右四個方向上連通。
  • 實體:同時具有幾何要素和視覺要素的物件。
  • 型值點:位於最終得到的自由曲線上的點。
  • 控制點:不位於最終得到的自由曲線上的點。
  • 顏色位面法:每一個位面控制一種顏色或灰度,每一個象素點在每一個位面中佔一位,通過幾個位面中德同一位組合成一個象素。

二、概念簡述

  • 影象和圖形的區別:圖形是無中生有,由計算機軟體繪製出來的,它是物件導向的,同時具有幾何屬性和視覺屬性。而影象是由計算機外部裝置捕捉得到的,並面向計算機內傳輸的資訊。
  • 字元的兩種表示方式:點陣字元和向量字元。
  • 實體的表示方法:邊界表示、分解表示、構造實體幾何表示、掃描表示和元球表示。

三、基本圖形生成演算法

  • 畫任意斜率的直線(基於 DDA 演算法)
#include <graphics.h>
#include <conio.h>

// 四捨五入
int Round(float x)
{
    return (int)(x < 0 ? x - 0.5 : x + 0.5);
}

// 使用 DDA 演算法畫任意斜率的直線(包括起始點,不包括終止點)
void Line_DDA(int x1, int y1, int x2, int y2, int color)
{
    float x, y;     // 當前座標點
    float cx, cy;   // x、y 方向上的增量

    int steps = abs(x2 - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1);

    x = (float)x1;
    y = (float)y1;
    cx = (float)(x2 - x1) / steps;
    cy = (float)(y2 - y1) / steps;

    for(int i = 0; i < steps; i++)
    {
        putpixel(Round(x), Round(y), color);    // 在座標 (x, y) 處畫一個 color 顏色的點
        x += cx;
        y += cy;
    }
}

// 主函式
void main()
{
    initgraph(640, 480);

    // 測試畫線
    Line_DDA(100, 1, 1, 478, GREEN);
    Line_DDA(1, 478, 638, 1, GREEN);

    // 按任意鍵退出
    getch();
    closegraph();
}
  • 畫任意斜率的直線(基於直線的中點演算法)
#include <graphics.h>
#include <conio.h>

// 使用中點演算法畫任意斜率的直線(包括起始點,不包括終止點)
void Line_Midpoint(int x1, int y1, int x2, int y2, int color)
{
    int x = x1, y = y1;
    int a = y1 - y2, b = x2 - x1;
    int cx = (b >= 0 ? 1 : (b = -b, -1));
    int cy = (a <= 0 ? 1 : (a = -a, -1));

    putpixel(x, y, color);

    int d, d1, d2;
    if (-a <= b)        // 斜率絕對值 <= 1
    {
        d = 2 * a + b;
        d1 = 2 * a;
        d2 = 2 * (a + b);
        while(x != x2)
        {
            if (d < 0)
                y += cy, d += d2;
            else
                d += d1;
            x += cx;
            putpixel(x, y, color);
        }
    }
    else                // 斜率絕對值 > 1
    {
        d = 2 * b + a; 
        d1 = 2 * b;
        d2 = 2 * (a + b);
        while(y != y2) 
        { 
            if(d < 0)
                d += d1; 
            else 
                x += cx, d += d2; 
            y += cy; 
            putpixel(x, y, color);
        } 
    }
}

// 主函式
void main()
{
    initgraph(640, 480);

    // 測試畫線
    Line_Midpoint(100, 1, 1, 478, GREEN);
    Line_Midpoint(1, 478, 638, 1, GREEN);

    // 按任意鍵退出
    getch();
    closegraph();
}
  • 畫任意斜率的直線(基於 Bresenham 演算法)
#include <graphics.h>
#include <conio.h>

// 使用 Bresenham 演算法畫任意斜率的直線(包括起始點,不包括終止點)
void Line_Bresenham(int x1, int y1, int x2, int y2, int color)
{
    int x = x1;
    int y = y1;
    int dx = abs(x2 - x1);
    int dy = abs(y2 - y1);
    int s1 = x2 > x1 ? 1 : -1;
    int s2 = y2 > y1 ? 1 : -1;

    bool interchange = false;   // 預設不互換 dx、dy
    if (dy > dx)                // 當斜率大於 1 時,dx、dy 互換
    {
        int temp = dx;
        dx = dy;
        dy = temp;
        interchange = true;
    }

    int p = 2 * dy - dx;
    for(int i = 0; i < dx; i++)
    {
        putpixel(x, y, color);
        if (p >= 0)
        {
            if (!interchange)       // 當斜率 < 1 時,選取上下象素點
                y += s2;
            else                    // 當斜率 > 1 時,選取左右象素點
                x += s1;
            p -= 2 * dx;
        }
        if (!interchange)
            x += s1;                // 當斜率 < 1 時,選取 x 為步長
        else
            y += s2;                // 當斜率 > 1 時,選取 y 為步長
        p += 2 * dy;
    }
}

// 主函式
void main()
{
    initgraph(640, 480);

    // 測試畫線
    Line_Bresenham(100, 1, 1, 478, GREEN);
    Line_Bresenham(1, 478, 638, 1, GREEN);

    // 按任意鍵退出
    getch();
    closegraph();
}
  • 畫圓(基於中點演算法)
#include <graphics.h>
#include <conio.h>

// 中點畫圓法
void Circle_Midpoint(int x, int y, int r, int color)
{
    int tx = 0, ty = r, d = 1 - r;

    while(tx <= ty)
    {
        // 利用圓的八分對稱性畫點
        putpixel(x + tx, y + ty, color);
        putpixel(x + tx, y - ty, color);
        putpixel(x - tx, y + ty, color);
        putpixel(x - tx, y - ty, color);
        putpixel(x + ty, y + tx, color);
        putpixel(x + ty, y - tx, color);
        putpixel(x - ty, y + tx, color);
        putpixel(x - ty, y - tx, color);

        if(d < 0)
            d += 2 * tx + 3;
        else
            d += 2 * (tx - ty) + 5, ty--;

        tx++;
    }
}

// 主函式
void main()
{
    initgraph(640, 480);

    // 測試畫圓
    Circle_Midpoint(320, 240, 200, RED);
    Circle_Midpoint(320, 240, 101, RED);

    // 按任意鍵退出
    getch();
    closegraph();
}
  • 畫圓(基於正負演算法)
#include <graphics.h>
#include <conio.h>

// 正負畫圓法
void Circle_PN(int x, int y, int r, int color)
{
    int tx = 0, ty = r, f = 0;

    while(tx <= ty)
    {
        // 利用圓的八分對稱性畫點
        putpixel(x + tx, y + ty, color);
        putpixel(x + tx, y - ty, color);
        putpixel(x - tx, y + ty, color);
        putpixel(x - tx, y - ty, color);
        putpixel(x + ty, y + tx, color);
        putpixel(x + ty, y - tx, color);
        putpixel(x - ty, y + tx, color);
        putpixel(x - ty, y - tx, color);

        if(f <= 0)
            f = f + 2 * tx + 1, tx++;
        else
            f = f - 2 * ty + 1, ty--;
    }
}

// 主函式
void main()
{
    initgraph(640, 480);

    // 測試畫圓
    Circle_PN(320, 240, 200, RED);
    Circle_PN(320, 240, 101, RED);

    // 按任意鍵退出
    getch();
    closegraph();
}
  • 畫圓(基於 Bresenham 演算法)
#include <graphics.h>
#include <conio.h>

// 使用 Bresenham 畫圓法
void Circle_Bresenham(int x, int y, int r, int color)
{
    int tx = 0, ty = r, d = 3 - 2 * r;

    while( tx <= ty)
    {
        // 利用圓的八分對稱性畫點
        putpixel(x + tx, y + ty, color);
        putpixel(x + tx, y - ty, color);
        putpixel(x - tx, y + ty, color);
        putpixel(x - tx, y - ty, color);
        putpixel(x + ty, y + tx, color);
        putpixel(x + ty, y - tx, color);
        putpixel(x - ty, y + tx, color);
        putpixel(x - ty, y - tx, color);

        if (d < 0)      // 取上面的點
            d += 4 * tx + 6;
        else            // 取下面的點
            d += 4 * (tx - ty) + 10, ty--;

        tx++;
    }
}

// 主函式
void main()
{
    initgraph(640, 480);

    // 測試畫圓
    Circle_Bresenham(320, 240, 200, RED);
    Circle_Bresenham(320, 240, 101, RED);

    // 按任意鍵退出
    getch();
    closegraph();
}
  • 畫填充圓(基於 Bresenham 演算法)
#include <graphics.h>
#include <conio.h>

// 基於 Bresenham 演算法畫填充圓
void FillCircle_Bresenham(int x, int y, int r, COLORREF color)
{
    int tx = 0, ty = r, d = 3 - 2 * r, i;

    while( tx < ty)
    {
        // 畫水平兩點連線(<45度)
        for (i = x - ty; i <= x + ty; i++)
        {
            putpixel(i, y - tx, color);
            if (tx != 0)    // 防止水平線重複繪製
                putpixel(i, y + tx, color);
        }

        if (d < 0)          // 取上面的點
            d += 4 * tx + 6;
        else                // 取下面的點
        {
            // 畫水平兩點連線(>45度)
            for (i = x - tx; i <= x + tx; i++)
            {
                putpixel(i, y - ty, color);
                putpixel(i, y + ty, color);
            }

            d += 4 * (tx - ty) + 10, ty--;
        }

        tx++;
    }

    if (tx == ty)           // 畫水平兩點連線(=45度)
        for (i = x - ty; i <= x + ty; i++)
        {
            putpixel(i, y - tx, color);
            putpixel(i, y + tx, color);
        }
}

// 主函式
void main()
{
    // 建立繪圖視窗
    initgraph(640, 480);

    // 測試畫填充圓
    FillCircle_Bresenham(320, 240, 100, GREEN);

    // 按任意鍵退出
    getch();
    closegraph();
}

相關文章