画圆环的想法与画球体的想法大致相同,不同的是,圆环中间为空,而环体的直径又相同,所以通过设置两个半径,用两个半径和角度就可以确定每个点的x,y,z坐标。
首先,还是先把环体切成几个部分,每个部分打开之后都是一个矩形,把每个矩形都用画三角形带的方式绘制出来的话,那么圆环就可以实现。
接下来就是坐标的计算:
假定以圆环中心为坐标圆心,想要确定每个点的坐标,就需要设置两个半径,一个内圈半径r1,一个环体半径r2,再设置一个alpha角和alpha角的步长(alphaStep),用来取到环体上的每个圆,还要设置一个beta角和beta角的步长(betaStep),用来取到每一个圆上的点。
那么假定两点(x0,y0,z0)(x1,y1,z1),可以得出x0 = [(r1+r2)+r2 * cos(beta)] * cos(alpha),
y0 = [(r1+r2)+r2 * cos(beta)] * sin(alpha),z0 = -r2 * sin(beta).
而x1,y1,z1与x0,y0,z0不同的地方只有alpha的角度,给alpha加一个步长,就得到x1,y1,z1.
x1 = [(r1+r2)+r2 * cos(beta)] * cos(alpha+alphaStep),
y1 = [(r1+r2)+r2 * cos(beta)] * sin(alpha+alphaStep),
因为圆环环体的直径处处相等,所以圆环向Z轴负方向的延伸值不变。
所以,z1 = z0 = -r2 * sin(beta).
需要注意的是,z轴坐标需要取反,因为是向z轴负方向延伸。
取到了两点坐标之后,接下来就可以用两层循环取到圆环上的各个点。
for( int i = 0;i < count;i ++ ){ alpha = i * alphaStep; for( int j = 0;j <= count0;j ++ ){ beta = j * betaStep; x0 = (float) (Math.cos(alpha) * (Rring + Rinner + Rinner * Math.cos(beta))); y0 = (float) (Math.sin(alpha) * (Rring + Rinner + Rinner * Math.cos(beta))); z0 = (float) -(Rring * Math.sin(beta)); x1 = (float) (Math.cos(alpha + alphaStep) * (Rring + Rinner + Rinner * Math.cos(beta))); y1 = (float) (Math.sin(alpha + alphaStep) * (Rring + Rinner + Rinner * Math.cos(beta))); z1 = (float) (-Rring * Math.sin(beta)); }取到了圆环上的各个点的坐标后,剩下的就简单了,设置清屏色,设置绘图颜色,然后指定模型视图矩阵,加载单位矩阵,放置眼球位置,设置旋转角度。最后再指定顶点指针,绘制三角形带。
运行效果图:(为观察方便起见,效果图还是以画线带的方式绘制)
附代码:
public class MyRingRenderer extends AbstractRenderer{ @Override public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//设置清屏色 gl.glColor4f(1f, 1f, 1f, 1f);//设置绘图颜色 gl.glMatrixMode(GL10.GL_MODELVIEW);//模型视图矩阵 gl.glLoadIdentity();//加载单位矩阵 GLU.gluLookAt(gl, 0, 0, 5, 0, 0, 0, 0, 1, 0);//放置眼球位置 gl.glRotatef(xRotate, 1, 0, 0);//x轴旋转角度 gl.glRotatef(yRotate,0,1,0);//y轴旋转角度 List<Float> coords = new ArrayList<Float>(); float Rinner = 0.2f;//内圆半径 float Rring = 0.3f;//环半径 int count = 20;//循环次数 float alpha = 0;//外圆角度 float x0,x1,y0,y1,z0,z1; float alphaStep = (float) (2 * Math.PI / count);//alpha角的步长(外部圆环) float betaStep = (float) (2 * Math.PI / count);//beta角的步长(每个切片) float beta = 0;//切片循环角度 int count0 = 20;//循环次数 /***************************外层循环主要负责把圆环切成几个部分*******************************/ for( int i = 0;i < count;i ++ ){ alpha = i *alphaStep; /***************************内层循环主要负责把每个部分画出来*******************************/ for( int j = 0;j <= count0;j ++ ){ beta = j * betaStep; x0 = (float) (Math.cos(alpha) * (Rring + Rinner + Rinner * Math.cos(beta))); y0 = (float) (Math.sin(alpha) * (Rring + Rinner + Rinner * Math.cos(beta))); z0 = (float) -(Rring * Math.sin(beta)); x1 = (float) (Math.cos(alpha + alphaStep) * (Rring + Rinner + Rinner * Math.cos(beta))); y1 = (float) (Math.sin(alpha + alphaStep) * (Rring + Rinner + Rinner * Math.cos(beta))); z1 = (float) (-Rring * Math.sin(beta)); coords.add(x0); coords.add(y0); coords.add(z0); coords.add(x1); coords.add(y1); coords.add(z1); } gl.glVertexPointer(3,GL10.GL_FLOAT,0, BufferUtils.list2FloatBuffer(coords));//顶点指针 gl.glDrawArrays(GL10.GL_LINE_STRIP,0,coords.size() / 3) ;//画线带 } } }