複雜多邊形光柵化演算法

2021-09-20 08:42:50 字數 2817 閱讀 3388

雖然已經一年多沒有維護gbox這個圖形庫專案了,最近確實時間不夠用。。。

今年的重點是把xmake徹底正好,至少在架構和大功能(包依賴管理)上,要完全落實下來,後期就是零散的維護和外掛程式功能擴充套件了。。

tbox我會陸陸續續一直進行一些小規模更新,明年上半年稍微重構一些模組後,就開始重點重新搞gbox了,這才是我一直最想做,也是最喜歡做的專案了

所以我寧願開發的慢點,也要把它做精,做到最好。。

好了,回歸正題,雖然現在gbox還處於早期開發中,並不能用到實際的專案中去,但是裡面的一些演算法,還是很有參考學習價值的。。

我這兩天沒事就拿出來分享下,如果有感興趣的同學,可以直接閱讀原始碼:monotone.c

畢竟這個演算法我陸陸續續花了整整一年的時間,才把它徹底搞透,並且實現出來。。

為什麼會花這麼久呢,也許是我太笨了哈。。嘿嘿。。當然也有工作原因哈。。

我先簡單講講研究和實現這個複雜多邊形光柵化演算法的背景:

我的gbox目前有兩套渲染裝置,一套是直接純演算法渲染,其核心演算法就是掃瞄多邊形填充演算法,這個演算法已經算是很普遍了,也很成熟,效率也很高

但是在我的另外一套基於opengl es渲染裝置中(為了能夠利用gpu進行加速渲染),在渲染複雜多邊形時,就遇到了問題:opengl不支援複雜多邊形的填充

後來我想了很多辦法,也去google了下,發現可以通過opengl的模板來實現,然後我就開寫了。。

寫到一半,整體效果也出來了,自以為搞定了,卻又遇到乙個很難跨過的瓶頸,效率太低了,用這種方式渲染乙個老虎頭,幀率只有:15 fps

比我用純演算法的實現還慢,後來就思考為什麼這麼慢呢,乙個原因就是模板確實很慢。。。

第二個原因就是:我要實現通用的渲染介面,要支援各種填充規則,裁剪規則,這些複雜性,也使得基於模板的方式整體不太好優化。。

就這樣折騰了半年,最後決定,還是整體重構gbox吧,徹底不用模板實現了,採用另外一種方式:

先在上層對複雜多邊形根據各種填充規則和裁剪,進行預處理,核心演算法呢就是:對複雜多邊形進行三角化分割,並且合併成凸多邊形

再送到opengl中進行快速渲染。。。

那問題來了,如果才能高效分割多邊形呢,而且還要支援各種填充規則?

繼續google,最後發現libtess2的光柵化**裡面的演算法是可以完全做到的,但是我不可能直接用它的**,乙個原因是維護不方便

另外乙個原因是,它裡面的實現,很多地方效率不是很高,而我要實現的比他更高效,更穩定。。。

那就必須要先看透它的實現邏輯,然後再去改進和優化裡面的演算法實現。。。

雖然裡面**不多,但是我光看透,就又花了半年時間,最後陸陸續續寫了半年,終於才完全搞定。。

最後效果嗎,還是不錯的,至少在我的mac pro上用opengl渲染老虎頭,幀率可以達到:60 fps

當然,裡面肯定還是有很多問題在裡面的,不做最近確實沒時間整了,只能先擱置下來了,等以後在優化優化。。。

先曬曬,三角化後的效果:

然後再曬張老虎頭效果:

接著我再對分割演算法做些簡要描述:

gbox中實現演算法跟libtess2演算法中的一些不同和改進的地方:

整個演算法總共有四個階段:

從原始複雜多邊形構建dcel mesh網(dcel雙連通邊緣鍊錶, 跟quad-edge類似,相當於是個簡化版).

如果多邊形是凹多邊形或者複雜多邊形,那麼先把它分割成單調多邊形區域(mesh結構維護)

對基於mesh的單調多邊形進行快速三角化處理

合併三角化後的區域到凸多邊形

其中光柵化演算法實現上分有七個階段:

簡化mesh網,並且預先處理一些退化的情況(例如:子區域退化成點、線等)

構建頂點事件列表並且排序它 (基於最小堆的優先順序排序).

構建活動邊緣區域列表並且排序它(使用區域性區域的插入排序,大部分情況下都是o(n),而且量不多).

使用bentley-ottman掃瞄演算法,從事件佇列中掃瞄所有頂點事件,並且計算交點和winding值(用於填充規則計算)

如果產生交點改變了mesh網的拓撲結構或者活動邊緣列表發生改變,需要對mesh的一致性進行修復

當我們處理過程中,發生了一些mesh face的退化情況,那麼也需要進行處理

將單調區域的left face標記為」inside」,也就是最後需要獲取的輸出區域

光柵化介面的使用例子,來自原始碼:gbox/gl/render.c:

更詳細的演算法實現細節,請參考我的實現: monotone.c

static tb_void_t gb_gl_render_fill_convex(gb_point_ref_t points, tb_uint16_t count, tb_cpointer_t priv)

static tb_void_t gb_gl_render_fill_polygon(gb_gl_device_ref_t device, gb_polygon_ref_t polygon, gb_rect_ref_t bounds, tb_size_t rule)

個人主頁:tboox開源工程

原文出處:

光柵渲染器(四)多邊形繪製

暫時找不到合適繪製多邊形的演算法,就自己豐衣足食,不當之處希望大家指出。首先繪製凸四邊形,畢竟這個渲染器我最低的要求就是能畫個正方體 演算法設計 多邊形是由多個三角形組合而成。希望通過輸入四個頂點繪製多邊形,但不能隨意指定頂點繪製多邊形,否則就是這樣 所以我們需要找到不相鄰的2個點,通過這2個點,分...

多邊形填充演算法實現

功能 填充多邊形 引數 lppoints 指向頂點座標陣列的指標,陣列型別為point,多邊形由它們順次封閉連線得到 ncount 頂點的個數 ncolor 填充的顏色 預設為黑色 pdc 裝置控制代碼指標 返回 無返回值 說明 可以是邊相交的多邊形 void fillpolygon lppoint...

掃瞄多邊形填充演算法

掃瞄多邊形填充演算法 在做手機地圖的過程中,由於j2me沒提供多邊形填充的api,只能自己實現了,以下是實現的思路,請批評指正 多邊形填充,就是把多邊形所佔據的柵格象素賦予指定的顏色值。要完成這個任務,乙個首要的問題就是求出多邊形所佔據的柵格象素,判斷乙個網格在多邊形內還是多邊形外,在多邊形內的象素...