OpenGL繪製矢量路徑的思路

1. 引言

軟件方法繪製,如QT、Android(skia)都自帶2D繪圖引擎,支持矢量路徑填充並且抗鋸齒!如果使用OpenGL繪製矢量,對建模算法以及紋理都有要求,不同的建模算法決定了最終的視覺效果。OpenGL繪製路徑,抗鋸齒效果由紋理來實現。下面介紹兩種不同效果的路徑實現和繪製:

2. 純色圓角路徑

通過紋理方式實現抗鋸齒單色路徑繪製。

建模算法非常簡單:將一個polyline分解成一些列兩點的線段,單獨對每個線段建模,如下圖0132和4576處貼兩個半圓,2354用寬度爲1的像素條放樣生成。線段的末端是半圓,所以線段與線段之間能很好地銜接。



思路來源:http://chimera.labs.oreilly.com/books/1234000001814/ch06.html#AaLinesWithTextures

注意:如果貼圖是半透明的,拐角處紋理會增強,效果不理想,如下圖,所以該建模算法只適合單色不透明路徑。


3. 立體路徑

現在各家手機地圖中路線都是立體紋理繪製,紋理效果如下圖:


實現立體路徑繪製,建模算法的難點在拐角處處理,尤其銳角,角度很小的時候如何處理。經過一段時間的研究,實現了一種簡單而且足夠魯邦的算法,思路非常簡單:銳角的時候進行插值(使用的是三次樣條插值),將銳角轉化成鈍角,鈍角的時候建模算法如下圖:


如上圖,一個建模處理單元由三個點組成,P0,P1,P2組成且夾角爲鈍角,路徑寬度爲2*radius,建模思路如下:

T1 = normalize( P1-P0 );	// P0P1 單位向量
N1 = Vec2f( -T1.y, T1.x);	// 法線向量可以直接寫出
v0 = P0 + radius * N1;		// 右手法則,v0方向爲正
v1 = p0 - radius * N1;
v2 = P1 + radius * N1;
v3 = P1 - radius * N1;

T2 = normalize( P2-P1 );	// P0P1 單位向量
N2 = Vec2f( -T2.y, T2.x);	// 法線向量可以直接寫出
v4 = P1 + radius * N2;
v5 = p1 - radius * N2;
v6 = P2 + radius * N2;
v7 = P2 - radius * N2;

verticesList: v0, v1, v2, v3, v4, v5, v6, v7
triangleIndexList: 0,1,2,  2,1,3,  2,4,5, 2,5,4, 2,3,4, 2,4,3,	4,5,6	6,5,7
拐角處可能會出現翻轉情況,所以245和234三角形分別被CW和CCW各一個。


插值算法

如下圖:


原始頂點爲P0,P1,P2,插值結果成五個頂點:P0, P1', P2', P3', P2。P1'和P3‘分別是P0P1線段和P1P2線段的中點;P2’爲P0,P1,P2的加權平均值,權重分別爲 1/8, 6/8, 1/8,代碼如下:

    /**
     * 細分:3個頂點變換成5個頂點,起始頂點不變
     */
    private void cubicInterpolation(PointF p0, PointF p1, PointF p2, ArrayList<PointF> oPntList) {
        oPntList.add(p0);
        oPntList.add(new PointF((p0.x + p1.x) / 2, (p0.y + p1.y) / 2));
        oPntList.add(new PointF((p0.x + 6 * p1.x + p2.x) / 8, (p0.y + 6 * p1.y + p2.y) / 8));
        oPntList.add(new PointF((p1.x + p2.x) / 2, (p1.y + p2.y) / 2));
        oPntList.add(p2);
    }
最終立體路徑效果如下圖:藍線上面爲直接建模的效果圖,可以看出拐角處有明顯的填補瑕疵,藍線下面爲拐角處增加插值處理,拐角處過度要柔和很多


4. 零碎點

Qt Examples and Demos中Demonstrations中的 Path Stroking 例子支持OpenGL渲染器,前段時間研究了下QT的OpenGL路徑建模類也不太理想,只能實現單色的路徑繪製如果使用立體紋理貼圖拐角處效果不太好。


圖中三行分別爲MiterJoin, RoundJoin, BevelJoin的填充圖和線框圖,線框模式下可以看出JOIN_ROUND下拐角處有明顯的擠壓現象。

源碼見:https://map-render.googlecode.com/svn/trunk/map-render目錄下,road render目錄中:

qtriangulatingstroker.h
qtriangulatingstroker.cpp
qhelper.h
qbase.h
qbase.cpp
road_render_app.cpp


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章