OpenGL绘制矢量路径的思路

102 篇文章 0 订阅
62 篇文章 0 订阅
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


  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
OpenGL可以使用glBegin和glEnd函数来绘制矢量图形。在glBegin和glEnd之间,可以使用一系列的顶点坐标来定义图形的形状。例如,可以使用glBegin(GL_TRIANGLES)和glEnd()来绘制一个三角形。在glBegin和glEnd之间,使用glVertex2f函数来指定每个顶点的坐标。例如,glVertex2f(0.0f, 0.0f)表示三角形的一个顶点在坐标原点。可以使用glColor3f函数来指定每个顶点的颜色。例如,glColor3f(1.0f, 0.0f, 0.0f)表示红色。通过在glBegin和glEnd之间多次调用glVertex2f和glColor3f函数,可以绘制出复杂的矢量图形。\[1\] 另外,OpenGL还提供了glDrawPixels函数来绘制像素图像。glDrawPixels函数的参数包括图像的宽度、高度、像素数据内容和像素数据在内存中的格式。可以从BMP文件中读取像素数据,并使用glDrawPixels函数将像素图像绘制到屏幕上。在绘制像素图像之前,可以使用glRasterPos*函数来指定绘制像素图像的起始位置。\[2\] 总结起来,使用OpenGL绘制矢量图形可以通过glBegin和glEnd函数以及glVertex2f和glColor3f函数来定义图形的形状和颜色。而绘制像素图像可以使用glDrawPixels函数,并可以通过glRasterPos*函数来指定绘制的位置。\[3\] #### 引用[.reference_title] - *1* *2* *3* [OpenGL像素操作](https://blog.csdn.net/weixin_34049948/article/details/93741898)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值