日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何绘制直线

發布時間:2023/12/15 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何绘制直线 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 一、最簡單繪制直線的方法
    • 1.1 向量
  • 二、Bresenham’s Line Drawing Algorithm
    • 2.1 屏幕是離散的
    • 2.2 直線方程的應用


前言

本系列最終是要去繪制mesh的,既然這樣我們就需要從最簡單的開始,先繪制直線。
我們都知道有個算法-Bresenham’s Line Drawing Algorithm。但是為什么要用它,這個才是我們要講的。

參考
gamma公式
本系列主要參考Dmitry V. Sokolov的軟渲染教程,詳細教程可閱讀參考鏈接

一、最簡單繪制直線的方法

說起直線,我的第一想法就是直線方程
y=kx+by = kx+by=kx+b
但是直接利用直線方程,然后直接去編寫代碼還其實挺困難的,我們先換一種方式考慮。

1.1 向量

向量可以被拆分成兩條向量的和

那么我們利用這個性質就可以寫出這么一段代碼

for (float t=0.; t<1.; t+=.000001) {int x = x0 + (x1 - x0) * t;int y = y0 + (y1 - y0) * t;image.set(x, y, color); }

這段代碼非常簡單,可以繪制任何方向上的直線,但是有個致命問題,就是非常消耗性能。t這個變量的取值決定了循環的次數,同時也影響了直線的連續性。因此我們必須改造這個方法。

二、Bresenham’s Line Drawing Algorithm

我對該算法的理解就是-只有加減法的算法

2.1 屏幕是離散的

注意以下只考慮第一象限,其他象限通過交換值即可解決

我們知道直線是連續的,但是我們的屏幕并非連續的,而是離散的,像素點之間是有1px距離的。

上面說了,直線其實是可以被拆開的,那么我們只讓某一個軸進行遞增,另外一軸跟著遞增不就行了么,那么現在我們就可以去掉循環條件中t這個變量。

for (int x = x0; x <= x1; x++) {float alpha = (x - x0) / (float)(x1 - x0);float y = y0 + (y1 - y0) * alpha;image.set(x, y, color); }

循環條件中t變量是消除了,但是我們又引入了一個除法和一個乘法,那么這個肯定是不對的,因此我們是需要去除掉的。

2.2 直線方程的應用

為了消除循環中的乘除法,我們需要引入直線方程。

y=kx+by = kx+by=kx+b
觀察直線方程,當我們每前進一個像素時,也就是x+1,那么其實y軸其實也是固定增加的。每次只增加k。
y=k(x+1)+by = k(x+1)+by=k(x+1)+b

隨著k不斷在y軸上累加,當k累加大于1時,y就可以給自身加一了。

float k = (y1 - y0) / (float)(x1 - x0); float error = 0; int y = y0; for (int x = x0; x <= x1; x++) {image.set(x, y, color);error += k;if (error > 1){y++;error--;} }

到這一步終于把循環內的乘除法給消除了。但是循環外還是存在一個除法,因此下一步就是去除循環外的除法。

推理過程就是以上。

int dy = y1 - y0; int dx = x1 - x0;int error = 0; int y = y0;for (int x = x0; x <= x1; x++) {error += dy;if (error > dx){y++;error -= dx;}}

到此終于完成這個沒有任何乘除法的算法。這個也是我們用Bresenham’s Line Drawing Algorithm的原因。

下面是完整代碼

void line(int x0, int y0, int x1, int y1, TGAImage &image, TGAColor color) {bool steep = false;if (std::abs(x0 - x1) < std::abs(y0 - y1)) {std::swap(x0, y0);std::swap(x1, y1);steep = true;}if (x0 > x1) {std::swap(x0, x1);std::swap(y0, y1);}int dy = y1 - y0;int dx = x1 - x0;int error = 0;int y = y0;int k = 1;// 處理 [-1, 0] 范圍內的斜率if (dy < 0){k = -1;dy = -dy;}for (int x = x0; x <= x1; x++){if (steep) {image.set(y, x, color);}else {image.set(x, y, color);}error += dy;if (error > dx){y += k;error -= dx;}} }

總結

以上是生活随笔為你收集整理的如何绘制直线的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。