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