1、基本概念
3D图像的最小单位称为点(point)活着顶点(vertex)。它们代表三维空间中的一个点并用来建造更复杂的物体。多边形就是由点构成,而物体是由多个多边形组成。尽管通常的OpenGL支持多种多边形,但OpenGL ES 只支持三边形,所以即使我们要绘制一个正方形也要把它拆分为两个三角形绘制。坐标系问题如下说明。
默认情况下,以屏幕中心为坐标原点。原点左方为x为负值,右边为正值;y、z类似。默认情况下,从原点到屏幕边缘为1.0f,沿各轴增加或减小的数值是以任意刻度进行的----它们不代表任何真实的单位。OpenGL只是将它作为一个参照单位处理,保证它们具有相同的距离。如下图:
了解了坐标轴,我们看看怎么在坐标系中表示一个点,通常用一组浮点数来表示点。例如一个正方形的4个顶点可表示为:
float vertices[] = {
-1.0f, 1.0f, .0f, //左上
-1.0f, -1.0f, .0f, //左下
1.0f, -1.0f, .0f, //右下
1.0f, 1.0f, .0f, //右上
};
为了提高性能,通常还需要将浮点数组存入一个字节缓冲中,所以有了下面的操作:
ByteBuffer vbb = ByteBuffer.allocate(vertices.length*4);//申请内存
vbb.order(ByteOrder.nativeOrder());//设置字节顺序,其中ByteOrder.nativeOrder()是获取本机字节顺序
FloatBuffer vertexBuffer = vbb.asFloatBuffer();//转换为float型
vertexBuffer.put(vertices);//添加数据
vertexBuffer.position()//设置缓冲区起始位置
OpenGLES的很多函数功能的使用状态时关闭的。启用和关闭这些函数可以用glEnableClientState、glDisableClientState来完成。
//指定需要启用定点数组
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//说明启用数组的类型和字节缓冲,类型为GL_FLOAT
gl.glVertexPointer(3,GL10.GL_FLOAT,vertexBuffer);
//不再需要时,关闭顶点数据
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
2、多边形
多边形是由点和边构成的单闭合环。绘制多边形时需要特别注意顶点的绘制顺序,可以分为顺时针和逆时针。因为方向决定了多边形的朝向,即正面和背面。默认以逆时针次序绘制顶点的构成的面是正面。
3、渲染
有了上面基本概念的基础,说一下渲染。渲染是把物体坐标所指定的图元转化成帧缓冲区中的图像。图像和顶点坐标有着密切的关系。这个关系通过绘制模式给出。常用到的绘制模式有GL_POINTS、GL_LINE_STRIP、GL_LINE_LOOP、GL_LINES、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。下面分别介绍:
(1)、GL_POINTS:把每一个顶点作为一个点进行处理,顶点n即定义了点n,共绘制n个点。
(2)、GL_LINES:把每一个顶点最为一个独立的线段,顶点2n-1和2n之间共定义了n个线段,总共绘制N/2条线段。如果N为奇数,则忽略最后一个顶点。
(3)、GL_LINE_STRIP:绘制从每一个顶点到最后一个顶点依次相连的一组线段,第n和n+1个顶点定义了线段n,总共绘制N-1条线段。
(4)、GL_LINE_LOOP:绘制从定义第一个顶点到最后一个顶点依次相连的一组线段,然后最后一个顶点与第一个顶点相连。第n和n+1个顶点定义了线段n,然后最后一个线段是由顶点N和1之间定义,总共绘制N条线段。
(5)、GL_TRIANGLES:把每三个顶点作为一个独立的三角形。顶点3n-2,3n-1和3n定义了第n个三角形,总共绘制了N/3个三角形。
(6)、GL_TRIANGLE_STRIP:绘制一组相连的三角形。对于奇数顶点n,顶点n、n+1和n+2定义了第n个三角形;对于偶数n,顶点n+1、n和n+2定义了n个三角形,总共绘制N-2个三角形。这是最常使用的渲染方式,第一个三角形条是由三个顶点构成(索引0,1,2)。第二个三角形条是由前一个三角形的两个顶点加上数组中的下一个顶点构成,继续到整个数组结束。
(7)、GL_TRIANGLE_FAN:绘制一组相连的三角形。三角形是由第一个顶点及其后给定的顶点确定。顶点1、n+1和n+2定义了第n个三角形,总共绘制N-2个三角形。
4、绘制图形步骤
(1)、定义顶点并且转换存储在字节缓冲中;
//三角形顶点
private int[] vertices = new int[]{
0,one,0,
-one,-one,0,
one,-one,0
};
//申请内存
ByteBuffer vbb1 = ByteBuffer.allocateDirect(vertices.length * 4);
//设置字节顺序,其中ByteOrder.nativeOrder()是获取本机字节顺序
vbb1.order(ByteOrder.nativeOrder());
//转换为int类型
trangelBuffer = vbb1.asIntBuffer();
//添加数据
trangelBuffer.put(vertices);
//设置缓冲区起始位置
trangelBuffer.position(0);
(2)、我们使用顶点数组绘制图形,而opengles是默认关闭这个开关的,所以我们要启用它。
//允许顶点和颜色缓冲
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
(3)、设置绘制的颜色
(4)、设置顶点
gl.glVertexPointer(
3, //每个顶点的坐标的维数,这里为x、y、z
GL10.GL_FIXED, //顶点坐标值的类型为GL_FIXED
0, //数组中数据的偏移值
trangelBuffer//顶点坐标数据数组
);
(5)、开始绘图
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
函数原型:void glDrawArrays(int mode, int first, int count)
参数:mode----指明渲染哪一种图元。允许的符号常量有GL_POINTS 、GL_LINE_STRIP、 GL_LINE_LOOP、GL_LINES、 GL_TRIANGLE_STRIP、 GL_TRIANGLE_FAN和GL_TRIANGLES。
first-------指明在允许访问的矩阵中的起始索引
count----指明要渲染的索引数量
5、视图与透视
我们生活在一个三维的世界里,如果要观察一个物体,我们可以:
(1)、从不同的位置去观察它。(视图变换)
(2)、移动或者转移它;当然如果它是计算机里面的物体我们还可以放大或者缩小 它。(模型变换)
(3)、如果把物体画下来,我们可以选择:是否需要一种“近大远小”的透视效果。另外我们可能只希望看到物体的一部分,而不是全部。(投影变换)
(4)、我们可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部。(视口变换)
这些,都可以在OpenGL中实现。
OpenGL变换实际上是通过矩阵乘法来实现的。无论是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。
(1)、模型变换和视图变换
即设置3D模型的位移、旋转等属性。由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。设置的方法是以GL_MODEVIEW为参数调用glMatrixMode函数,如下代码所示:
gl.glMatrixMode(GL10.GL_MODELVIEW);
通常,我们需要在进行变换前把当前的矩阵设置为单位矩阵,代码如下:
gl.glLoadIdentity();
然后,就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及到三个函数:
glTranslate*,(*表示把这个函数分为float型的glTranslatef和glTranslatex)把当前矩阵和一个表示移动物体的矩阵相乘。三个参数分别表示了在三个坐标上的位移值。
glRotate*,把当前矩阵和一个表示旋转物体的矩阵相乘。物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle表示旋转的角度。
glScale*,把当前矩阵和一个表示缩放物体的矩阵相乘。x,y,z分别表示在该方向上的缩放比例。
(2)、投影变换
投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。(注意,从现在起坐标可以不再是-1.0到1.0了)
OpenGL支持两种类型的投影变换,即透视投影和正投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION为参数调用glMatrixMode函数。
gl.glMatrixMode(GL10.GL_PROJECTION);
通常需要在进行变换前把当前矩阵设置为单位矩阵。
gl.glLoadIdentity();
透视投影所产生的结果类似于照片,有近大远小的效果。比如在火车头内向前照一个铁轨的照片,两条铁轨似乎在远处相交了。
完整文章参考:http://blog.youkuaiyun.com/hmg25/article/details/6739204