OpenGL ES画板
程序员文章站
2022-03-09 22:18:45
一、概述 利用自定义顶点和片元着色器渲染,并且设置图片纹理颜色为画笔颜色 二、核心代码 三、效果图 GitHub ......
一、概述
利用自定义顶点和片元着色器渲染,并且设置图片纹理颜色为画笔颜色
二、核心代码
- (void)renderlinefrompoint:(cgpoint)start topoint:(cgpoint)end { //顶点缓存区 static glfloat *vertexbuffer = null; //顶点max static nsuinteger vertexmax = 64; //顶点个数 nsuinteger vertexcount = 0,count; cgfloat scale = self.contentscalefactor; //点到像素转换:乘以比例因子 start.x *= scale; start.y *= scale; end.x *= scale; end.y *= scale; //开辟顶点缓存区 if (vertexbuffer == null) { vertexbuffer = malloc(vertexmax*2*sizeof(glfloat)); } //求得两点之间的距离 float seq = sqrtf((end.x-start.x)*(end.x-start.x)+(end.y-start.y)*(end.y-start.y)); /*向上取整:求得距离要产生多少个点 kbrushpixelstep值越大,笔触越细;值越小,笔触越粗 */ nsinteger pointcount = ceil(seq/kbrushpixelstep); count = max(pointcount, 1); for (int i = 0; i < count; i++) { if (vertexcount == vertexmax) { //修改2倍增长 vertexmax = 2*vertexmax; vertexbuffer = realloc(vertexbuffer, vertexmax*2*sizeof(glfloat)); } //计算两个之间的距离有多少个点,并存储在顶点缓存区中 vertexbuffer[2*vertexcount+0] = start.x+(end.x-start.x)*((glfloat)i/(glfloat)count); vertexbuffer[2*vertexcount+1] = start.y+(end.y-start.y)*((glfloat)i/(glfloat)count); vertexcount++; } //绑定顶点数据 glbindbuffer(gl_array_buffer, vboid); //将数据从cpu中复制到gpu中提供给opengl使用 glbufferdata(gl_array_buffer, vertexcount*2*sizeof(glfloat), vertexbuffer, gl_dynamic_draw); //启用指定属性 glenablevertexattribarray(attrib_vertex); //链接顶点属性 glvertexattribpointer(attrib_vertex, 2, gl_float, gl_false, 2*sizeof(glfloat), 0); //使用数据总线:传递顶点数据到顶点着色器 gluseprogram(program[programe_point].id); //绘制顶点:绘制模型、起始点、顶点个数 gldrawarrays(gl_points, 0, (int)vertexcount); //绑定渲染缓存区到特定标志符上 glbindrenderbuffer(gl_renderbuffer, viewrenderbuffer); //开始渲染 [context presentrenderbuffer:gl_renderbuffer]; }
- (textureinfo_t)texturefromname:(nsstring *)name { cgimageref brushimage; cgcontextref brushcontext; glubyte *brushdata; size_t width, height; gluint texid; textureinfo_t texture; brushimage = [uiimage imagenamed:name].cgimage; width = cgimagegetwidth(brushimage); height = cgimagegetheight(brushimage); //开辟纹理图片内存 brushdata = (glubyte *)calloc(width*height*4, sizeof(glubyte)); /*创建位图上下文 参数:图片内存地址、图片宽、图片高、像素组件位数(一般设置8),每一行所占比特数、颜色空间、颜色通道 */ brushcontext = cgbitmapcontextcreate(brushdata, width, height, 8, width*4, cgimagegetcolorspace(brushimage), kcgimagealphapremultipliedlast); //绘图 cgcontextdrawimage(brushcontext, cgrectmake(0, 0, (cgfloat)width, (cgfloat)height), brushimage); //释放上下文 cgcontextrelease(brushcontext); //申请纹理标志符 glgentextures(1, &texid); //绑定纹理 glbindtexture(gl_texture_2d, texid); //设置纹理属性:缩小滤波器、线性滤波器 gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear); /*生成2d纹理图片 参数:纹理目标、图像级别(0为基本级别)、颜色组件(gl_rgba、gl_alpha)、图像宽、图像高、边框宽度(一般为0)、像素数据颜色格式、像素数据类型、内存中指向图像数据指针 */ glteximage2d(gl_texture_2d, 0, gl_rgba, (int)width, (int)height, 0, gl_rgba, gl_unsigned_byte, brushdata); free(brushdata); //配置纹理属性 texture.id = texid; texture.width = (int)width; texture.height = (int)height; return texture; }
- (void)setupshaders { for (int i = 0; i < num_programs; i++) { //读取顶点着色器程序 char *vsrc = readfile(pathforresource(program[i].vert)); //读取片元着色器程序 char *fsrc = readfile(pathforresource(program[i].frag)); nsstring *vsrcstr = [[nsstring alloc] initwithbytes:vsrc length:strlen(vsrc)-1 encoding:nsutf8stringencoding]; nsstring *fsrcstr = [[nsstring alloc] initwithbytes:fsrc length:strlen(fsrc)-1 encoding:nsutf8stringencoding]; nslog(@"vsrcstr------%@", vsrcstr); nslog(@"fsrcstr------%@", fsrcstr); glsizei attribct = 0; glchar *attribused[num_attribs]; glint attrib[num_attribs]; glchar *attribname[num_attribs] = { "invertex" }; const char *uniformname[num_uniforms] = { "mvp","pointsize","vertexcolor", "texture" }; for (int j = 0; j < num_attribs; j++) { if (strstr(vsrc, attribname[j])) { attrib[attribct] = j; attribused[attribct++] = attribname[j]; } } //program处理:创建、链接、生成 gluecreateprogram(vsrc, fsrc, attribct, (const char **)&attribused[0], attrib, num_uniforms, &uniformname[0], program[i].uniform, &program[i].id); free(vsrc); free(fsrc); if (i == programe_point) { gluseprogram(program[programe_point].id); //为当前程序指定uniform变量 gluniform1i(program[programe_point].uniform[uniform_texture], 0); //设置正射投影矩阵 glkmatrix4 projectionmatrix = glkmatrix4makeortho(0, backingwidth, 0, backingheight, -1, 1); //创建模型视图矩阵:单元矩阵 glkmatrix4 modelviewmatrix = glkmatrix4identity; //正射投影矩阵与模型视图矩阵相乘,结果保存在mvpmatrix矩阵中 glkmatrix4 mvpmatrix = glkmatrix4multiply(projectionmatrix, modelviewmatrix); /*为当前程序指定uniform变量值 参数:指明要更改的uniform变量的位置、将要被修改的矩阵的数量、矩阵值被载入变量时是否要对举证进行变换(如转置)、将要用于更新uniform变量mvp的数组指针 */ gluniformmatrix4fv(program[programe_point].uniform[uniform_mvp], 1, gl_false, mvpmatrix.m); //为当前程序对象uniform变量的pointsize赋值 gluniform1f(program[programe_point].uniform[uniform_point_size], brushtexture.width/kbrushscale); //为当前程序对象uniform变量顶点颜色赋值 gluniform4fv(program[programe_point].uniform[uniform_vertex_color], 1, brushcolor); } } glerror(); }
三、效果图