一、概述

利用自定义顶点和片元着色器渲染,并且设置图片纹理颜色为画笔颜色

二、核心代码

- (void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
//顶点缓存区
static GLfloat *vertexBuffer = NULL;
//顶点Max
static NSUInteger vertexMax = ;
//顶点个数
NSUInteger vertexCount = ,count;
CGFloat scale = self.contentScaleFactor; //点到像素转换:乘以比例因子
start.x *= scale;
start.y *= scale;
end.x *= scale;
end.y *= scale; //开辟顶点缓存区
if (vertexBuffer == NULL) {
vertexBuffer = malloc(vertexMax**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, ); for (int i = ; i < count; i++) {
if (vertexCount == vertexMax) {
//修改2倍增长
vertexMax = *vertexMax;
vertexBuffer = realloc(vertexBuffer, vertexMax**sizeof(GLfloat));
} //计算两个之间的距离有多少个点,并存储在顶点缓存区中
vertexBuffer[*vertexCount+] = start.x+(end.x-start.x)*((GLfloat)i/(GLfloat)count);
vertexBuffer[*vertexCount+] = start.y+(end.y-start.y)*((GLfloat)i/(GLfloat)count); vertexCount++;
} //绑定顶点数据
glBindBuffer(GL_ARRAY_BUFFER, vboID);
//将数据从CPU中复制到GPU中提供给OpenGL使用
glBufferData(GL_ARRAY_BUFFER, vertexCount**sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW); //启用指定属性
glEnableVertexAttribArray(ATTRIB_VERTEX);
//链接顶点属性
glVertexAttribPointer(ATTRIB_VERTEX, , GL_FLOAT, GL_FALSE, *sizeof(GLfloat), ); //使用数据总线:传递顶点数据到顶点着色器
glUseProgram(program[PROGRAME_POINT].id);
//绘制顶点:绘制模型、起始点、顶点个数
glDrawArrays(GL_POINTS, , (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*, sizeof(GLubyte)); /*创建位图上下文
参数:图片内存地址、图片宽、图片高、像素组件位数(一般设置8),每一行所占比特数、颜色空间、颜色通道
*/
brushContext = CGBitmapContextCreate(brushData, width, height, , width*, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast); //绘图
CGContextDrawImage(brushContext, CGRectMake(, , (CGFloat)width, (CGFloat)height), brushImage);
//释放上下文
CGContextRelease(brushContext); //申请纹理标志符
glGenTextures(, &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, , GL_RGBA, (int)width, (int)height, , 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 = ; 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)- encoding:NSUTF8StringEncoding];
NSString *fsrcStr = [[NSString alloc] initWithBytes:fsrc length:strlen(fsrc)- encoding:NSUTF8StringEncoding];
NSLog(@"vsrcStr------%@", vsrcStr);
NSLog(@"fsrcStr------%@", fsrcStr); GLsizei attribCt = ;
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 = ; j < NUM_ATTRIBS; j++) {
if (strstr(vsrc, attribName[j])) {
attrib[attribCt] = j;
attribUsed[attribCt++] = attribName[j];
}
} //program处理:创建、链接、生成
glueCreateProgram(vsrc, fsrc, attribCt, (const char **)&attribUsed[], attrib, NUM_UNIFORMS, &uniformName[], 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], ); //设置正射投影矩阵
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(, backingWidth, , backingHeight, -, );
//创建模型视图矩阵:单元矩阵
GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
//正射投影矩阵与模型视图矩阵相乘,结果保存在MVPMatrix矩阵中
GLKMatrix4 MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix); /*为当前程序指定Uniform变量值
参数:指明要更改的Uniform变量的位置、将要被修改的矩阵的数量、矩阵值被载入变量时是否要对举证进行变换(如转置)、将要用于更新uniform变量MVP的数组指针
*/
glUniformMatrix4fv(program[PROGRAME_POINT].uniform[UNIFORM_MVP], , 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], , brushColor); }
} glError();
}

三、效果图

GitHub

OpenGL ES画板的更多相关文章

  1. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  2. OpenGL ES 3.0: 图元重启(Primitive restart)

    [TOC] 背景概述 在OpenGL绘制图形时,可能需要绘制多个并不相连的图形.这样的情况下这几个图形没法被当做一个图形来处理.也就需要多次调用 DrawArrays 或 DrawElements. ...

  3. opengl es中不同的绘制方式

    opengl es中不同的绘制方式 转载请保留出处:http://xiaxveliang.blog.163.com/blog/static/297080342013467344263/ 1. GL_P ...

  4. OpenGL ES无法获取贴图数据原因

    最近在做一个项目,要从贴图中获取图像数据,查了很多资料,也琢磨很久,获取到的数据都是0.终于在一次偶然的机会,发现了端倪,成功了. 不得不说这"一分灵感"真的很重要 以下是在获取贴 ...

  5. OpenGL ES(一.概念)

    OpenGL ES是以手持和嵌入式设备为目标的高级3D图形应用程序编程接口,主要的支持平台是iOS,Android,Linux和Windows 1.顶点着色器 他可以用于通过矩阵变换位置,计算照明公式 ...

  6. IOS 中openGL使用教程1(openGL ES 入门篇 | 搭建openGL环境)

    OpenGL版本 iOS系统默认支持OpenGl ES1.0.ES2.0以及ES3.0 3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL项目前,需要根据业务需求选择合适 ...

  7. OpenGL ES crash notes 01 - Nice to meet you

    这篇笔记完全参照<OpenGL.ES.3.0.Programming.Guide.2nd.Edition>,摘出部分内容只为学习参考. 为什么要用英文:无论是D3D的SDK还是OES的Sp ...

  8. android opengl es代码功能

    /* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Versi ...

  9. [cocos2d-x]OPENGL ES支持的像素格式

    OPENGL ES最多支持32位颜色值. 支持的像素格式有以下几种: 客户端格式 GL格式 GL数据类型 字节数 RGBA8888 GL_RGBA GL_UNSIGNED_BYTE 4 RGB888 ...

随机推荐

  1. FineReport中如何用JavaScript解决控件值刷新不及时

    我们经常利用按钮进行一些页面值的处理工作,但是默认的逻辑造成,每次新填报的值,需要点击下空白区域或是执行某个其他操作才可以被正确读取,那么我们如何处理呢? 例:当我们用常规取值的时候,虽然B3单元格录 ...

  2. 让Oracle的 SHOW PARAMETER 命令显示隐藏参数

    转自 http://blog.csdn.net/staricqxyz/article/details/8624549 Find internal of "show parameter&quo ...

  3. npm用法及离线安装方法

    npm用法及离线安装方法 基本的用法 查看某个模块的全部信息,或者可以查看单个信息 npm info name npm info name version npm info name homepage ...

  4. ActionContext和ServletActionContext小结(转)

    ActionContext和ServletActionContext小结 1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Act ...

  5. word问题

  6. 如何在ScrollView滑动的瞬间禁用拖拽手势

    如何在ScrollView滑动的瞬间禁用拖拽手势 效果: 在UIScrollView滑动的瞬间禁用pan手势,可以防止用户按着屏幕不放后导致出现的一些莫须有的bug. // // ViewContro ...

  7. 用NSOperation写下载队列

    用NSOperation写下载队列 说明 1. 支持缓存机制 2. 图片都是在主线程中加载 3. 文件名用了md5加密 *这东西被人写烂了,但大伙如果对NSOperation不熟悉的话,可以看看本人的 ...

  8. 固定UIScrollView滑动的方向

    固定UIScrollView滑动的方向 一般而言,我们通过这两个参数CGRectMake以及contentSize就可以自动的让UIScrollView只往一个方向滚动.但我遇到过非常奇葩的情况,那就 ...

  9. 多线程应用-类(thread)

    在对class thread加锁时,锁无法正常应用,函数方式没问题. 在使用class thread方法时,并发后的查询结果不对,函数方式没问题. # -*- coding: UTF-8 -*- fr ...

  10. SpringBoot整合Redis初实践

    Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理. 有时,为了提升整个网站的性能,在开发时会将经常访问的数据进行缓存,这样在调用这个数据接口时,可以提 ...