Python+Opengl 圆柱的实现
不知道有多少人像我一样,在刚接触OpenGL时,要画一个圆柱却不知从何下手。
本人Python和OpenGL纯新手,因研究需要,没有系统学习,就直接上手了,如果你也是这种情况,欢迎来交流。
关于OpenGL实现圆柱网上的方法很多,但都是标准的直圆柱,我的目标是可以产生沿任意曲线的圆柱,也是可以说是管道,其实就是三维加粗的曲线。因为我实在想不出更好的表述方法,就是用圆柱来代替了。
给我参考最多的是这篇文章,实现的是螺旋弹簧,这篇文章给我的启发很大,下面是链接,可以直接参考这篇文章。使用OpenGL绘制弹簧。
下面说下我的实现方法,就当是一个学习笔记了。先上个效果图。光照参考的这篇文章,这篇文章实现的也是个圆柱,他是要一个螺杆,也可以参考他的圆柱画法。

不管是那种圆柱,本质上是有两部分组成,侧面和顶、底两个面。而在OpenGL中表达面最普遍的方法是用确定顶点,用三角形或四边形方法表示。这里的话,侧面可以采用GL_TRIANGLE_STRIP或者GL_QUAD_STRIP。顶、底面的话用GL_TRIANGLE_FAN比较方便。
难点的话就是求出所有顶点,按照顺序将他们连接起来。
可以先从画一个圆开始
圆当然是用多边形近似了,至于用多少条边近似,就看具体需求了。需要用到的数学知识就一个,圆的参数方程,r是半径,t是角度(0-2π)。
那么看一下具体代码吧。在圆上取了36个点,用36边形近似一个圆。
Vertexs = [0 for i in range(nNumVertexs)] # 顶点数组
nNumVertexs = 36 # 圆顶点个数
STEP = 360 / nNumVertexs # 圆每一段的角度
radius = 0.5
for i in range(0, nNumVertexs):
p = STEP * i * 3.14 / 180 # 转为弧度
Vertexs[i] = vector3(radius * math.cos(p), radius * math.sin(p), 0.0)
vector3是我自定义的三维空间点的类,具体如下。(这其实是个三维向量的类,这里用作表示三维点)这个类用作向量的话,可以做很多向量的运算,具体内容可以参考这个文章。
class vector3:
def __init__(self, x_=0, y_=0, z_=0): # 构造函数
self.x = x_
self.y = y_
self.z = z_
得到了圆的坐标,用GL_TRIANGLE_FAN画出圆。为方便理解,圆心取(0,0,0)此处用线框画出。
glBegin(GL_TRIANGLE_FAN)
glVertex3f(0,0,0)
for j in range(0, nNumVertexs):
glVertex3d(Vertexs[j].x, Vertexs[j].y, Vertexs[j].z)

画第二个圆
有个画第一个圆的基础,那么画第二圆就不难了。在这里,在z轴的负方向取一个点作为圆心,画出第二个圆。下图是一个斜45度的视角。第二个圆的代码就不贴了。
画侧面
此时,已经有两个圆,每个圆36个顶点,生成点的时候已经定义好顶点的顺序了,已经是说我们可以按照这个顺序连接两个圆的顶点形成圆柱的侧面。下面是代码。
nNumcenters = 2 # 圆心数
nNumVertexs = 36 # 圆顶点个数
Vertexs = [[0 for i in range(nNumVertexs)]0 for i in range(nNumcenters)] # 顶点数组
Centers= [0 for i in range(nNumcenters )] # 顶点数组
Centers[0] = vector3(0.1, 0, 0) # 1圆中心
Centers[1] = vector3(-0.1, 0, 0) # 2圆中心
STEP = 360 / nNumVertexs # 圆每一段的角度
radius = 0.5
for i in range(0, nNumcenters):
for j in range(0, nNumVertexs):
p = STEP * i * 3.14 / 180 # 转为弧度
Vertexs[i][j] = vector3(radius * math.cos(p), radius * math.sin(p), 0.0)
glBegin(GL_TRIANGLE_LINE)
for i in range(0, nNumcenters):
glVertex3d(Centers[i].x, Centers[i].y, Centers[i].z)
for j in range(0, nNumVertexs):
glVertex3d(Vertexs[j].x, Vertexs[j].y, Vertexs[j].z)
for i in range(0, nNumcenters-1):
for j in range(0, nNumVertexs):
glVertex3d(Vertexs[i][j].x, Vertexs[i][j].y, Vertexs[i][j].z)
glVertex3d(Vertexs[i + 1][j].x, Vertexs[i + 1][j].y, Vertexs[i + 1][j].z)
glVertex3d(Vertexs[i][0].x, Vertexs[i][0].y, Vertexs[k][i][0].z)
glVertex3d(Vertexs[i + 1][0].x, Vertexs[i + 1][0].y, Vertexs[i + 1][0].z)

将上面代码中glBegin(GL_TRIANGLE_LINE)改为glBegin(GL_TRIANGLE_FILL)就是填充状态了。
To be continued…