OpenGL中控制纹理绘制区域

来源:互联网 发布:java中size是什么意思 编辑:程序博客网 时间:2024/04/30 09:07

OpenGL上绘制图像时,有时候需要控制图像形状,比如圆形,方形,裁处各种形状。

如下效果


         


最简单的方法就是在上面加个遮罩


其实遮罩也很麻烦,需要对View进行重绘。于是打算从根源出发,控制OpenGL的绘制区域。


矩形剪裁就很简单了,这里不多说了。主要说说圆形,圆形是通过无限细分来逐渐逼近圆形。细分等分越大,线条看起来越光滑。下面是10等分,51等分和100等分的效果图。


      


OpenGL中,纹理和顶点坐标是对应的。只改变定点坐标的话,得到剪裁后的结果会偏移。所以需要同时改变定点坐标和纹理坐标,来控制绘制区域。

其中,定点坐标的坐标系是以屏幕中心为原点的普通坐标系,最大长度为单位长度1。而纹理坐标有点不同,其原点在屏幕左下角,最大长度为单位长度1

所以,顶点对应的纹理坐标只需要做相应的坐标转换。


基本关系是:

 for(GLuint i = 0; i < num_vertex ; i++)          {              texcoord[0] = (cos(delta_angle * i) + 1.0) * 0.5;              texcoord[1] = (sin(delta_angle * i) + 1.0) * 0.5;              glTexCoord2fv(texcoord);                vertex[0] = cos(delta_angle * i) * radius;              vertex[1] = sin(delta_angle * i) * radius;              vertex[2] = 0.0;              vertex[3] = 1.0;              glVertex4fv(vertex);          } 


矩形和圆形的处理如下:

AGLKVertexAttribArrayBuffer *temvertexBuffer;    if (mask == ovglview_mask_none) {        numOfVertext = 4;        drawModel = GL_TRIANGLE_STRIP;                temvertexBuffer = [[AGLKVertexAttribArrayBuffer alloc]                                                        initWithAttribStride:sizeof(SceneVertex)                                                        numberOfVertices:sizeof(vertices) / sizeof(SceneVertex)                                                        bytes:vertices                                                        usage:GL_STATIC_DRAW];    }    else if (mask == ovglview_mask_rectangle){        numOfVertext = 4;        drawModel = GL_TRIANGLE_STRIP;        SceneVertex temVertex[4];        for (int i = 0; i < 4; i++) {            temVertex[i].textureCoords.s = vertices[i].textureCoords.s/scale_1 + (1.0f - 1.0f/scale_1)/2.0;            temVertex[i].textureCoords.t = vertices[i].textureCoords.t/scale_1 + (1.0f - 1.0f/scale_1)/2.0;            temVertex[i].positionCoords.x = vertices[i].positionCoords.x/scale_1;            temVertex[i].positionCoords.y = vertices[i].positionCoords.y/scale_1;            temVertex[i].positionCoords.z = vertices[i].positionCoords.z/scale_1;        }        temvertexBuffer = [[AGLKVertexAttribArrayBuffer alloc]                                                       initWithAttribStride:sizeof(SceneVertex)                                                       numberOfVertices:sizeof(temVertex) / sizeof(SceneVertex)                                                       bytes:temVertex                                                       usage:GL_STATIC_DRAW];    }    else if (mask == ovglview_mask_circle){        SceneVertex circleVertex[100];        GLsizei num = 100;        GLfloat angle = 2*PI/num;        GLfloat r = 1.0/scale_1;        for (GLint i = 0; i < num; i++) {            circleVertex[i].textureCoords.s = 1.0 - (GLfloat)((r * cos(angle * i)) +1.0)*0.5;            circleVertex[i].textureCoords.t = (GLfloat)((r * sin(angle * i)) +1.0)*0.5;            circleVertex[i].positionCoords.x = (GLfloat)(r * cos(angle * i));            circleVertex[i].positionCoords.y = (GLfloat)(r * sin(angle * i));            circleVertex[i].positionCoords.z = 0;        }        temvertexBuffer = [[AGLKVertexAttribArrayBuffer alloc]                                                        initWithAttribStride:sizeof(SceneVertex)                                                        numberOfVertices:sizeof(circleVertex) / sizeof(SceneVertex)                                                        bytes:circleVertex                                                        usage:GL_STATIC_DRAW];        numOfVertext = num;        drawModel = GL_TRIANGLE_FAN;    }

还需要强调的是,顶点的绘制模式也需要随之改变


常见的模式有三种:

#define GL_TRIANGLES                     0x0004
#define GL_TRIANGLE_STRIP                0x0005
#define GL_TRIANGLE_FAN                  0x0006


OpenGL中绘制的是三角面片(基本单位)图像是由若干三角面片组成的


三种绘制模式如图所示:


GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);


图片来自OpenGL】理解GL_TRIANGLE_STRIP等绘制三角形序列的三种方式

GL_TRIANGLES

是以每三个顶点绘制一个三角形。第一个三角形使用顶点v0,v1,v2,第二个使用v3,v4,v5,以此类推。如果顶点的个数n不是3的倍数,那么最后的1个或者2个顶点会被忽略。

这是最基本的绘制方式,单纯以三个顶点来绘制三角形,但是比较浪费资源,其顶点不能重用。

GL_TRIANGLE_STRIP

是可以进行顶点重用的,规则有点拗口:

构建当前三角形的顶点的连接顺序依赖于要和前面已经出现过的2个顶点组成三角形的当前顶点的序号的奇偶性(如果从0开始):

如果当前顶点是奇数:

组成三角形的顶点排列顺序:T = [n-1 n-2 n].

如果当前顶点是偶数:

组成三角形的顶点排列顺序:T = [n-2 n-21 n].

以上图为例,第一个三角形,顶点v2序号是2,是偶数,则顶点排列顺序是v0,v1,v2。第二个三角形,顶点v3序号是3,是奇数,则顶点排列顺序是v2,v1,v3,第三个三角形,顶点v4序号是4,是偶数,则顶点排列顺序是v2,v3,v4,以此类推。

这个顺序是为了保证所有的三角形都是按照相同的方向绘制的,使这个三角形串能够正确形成表面的一部分。对于某些操作,维持方向是很重要的,比如剔除。

注意:顶点个数n至少要大于3,否则不能绘制任何三角形。

例如:一个矩形由两个三角形组成,按照GL_TRIANGLES模式需要6个顶点,而按照GL_TRIANGLE_STRIP只需要4个顶点,但是需要注意顶点的顺序

GL_TRIANGLE_FAN

顾名思义,有个fan,是和扇形相关的,方便绘制扇形。可以以某一点为圆心进行绘制

它的三角形的顶点排列顺序是T = [n-1 n-2 n].各三角形形成一个扇形序列。

所以,在改变顶点坐标和纹理坐标的同时,还需要改变绘制模式


个人见解,有误之处还请指正