iOS视频渲染gles_02

glsl 渲染

参考:

https://www.cnblogs.com/zhoug2020/p/7842808.html

https://www.jianshu.com/p/ee597b2bd399

https://www.jianshu.com/p/02ebf6084ec7

渲染流程如图:

 

 

代码如下:

#import <UIKit/UIKit.h>

@interface showView : UIView

 @end

  1 //
  2 //  showView.m
  3 //  gltest2
  4 //
2020/5/19.
  7 //
  8 
  9 #import <Foundation/Foundation.h>
 10 #import "showView.h"
 11 #import <OpenGLES/ES2/gl.h>
 12 @interface showView()
 13 
 14 @property(nonatomic ,strong)CAEAGLLayer *myEglayer;
 15 @property(nonatomic ,strong)EAGLContext *myContext;
 16 @property(nonatomic ,assign)GLuint  myColorRenderBuff;
 17 @property(nonatomic ,assign)GLuint  myColorFrameBuff;
 18 @property(nonatomic,assign)GLuint myProgram;
 19 
 20 - (void)setupLayer;
 21 @end
 22 
 23 //集成UIview,作为函数入口
 24 @implementation showView
 25 
 26 //重写layerClass,将View返回的图层从CALayer替换成CAEAGLLayer
 27 //如果我们继承了UIView,那我们就可以重写+layerClass方法使得在创建的时候能返回一个不同的图层子类
 28 + (Class)layerClass {
 29 return [CAEAGLLayer class];
 30 }
 31  
 32 - (void)layoutSubviews {
 33     
 34     [self setupLayer];
 35     [self setupContext];
 36     [self SETRenderAndFrameBuffer];
 37     [self Render];
 38 }
 39 
 40 
 41 -(void)setupLayer{
 42     
 43     self.myEglayer = (CAEAGLLayer*) self.layer;
 44            //设置放大倍数
 45            [self setContentScaleFactor:[[UIScreen mainScreen] scale]];
 46            
 47            // CALayer 默认是透明的,必须将它设为不透明才能让其可见
 48     self.myEglayer.opaque = YES;
 49            
 50            // 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8
 51     self.myEglayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
 52                                             [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
 53     }
 54 
 55 -(void)setupContext{
 56     
 57     EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
 58     if (!context) {
 59         NSLog(@"Create context failed!");
 60         return;
 61     }
 62     if(![EAGLContext setCurrentContext:context])
 63     {
 64         NSLog(@"setCurrentContext failed!");
 65         return;
 66     }
 67     self.myContext = context;
 68 }
 69 
 70 -(void)SETRenderAndFrameBuffer
 71 {
 72     /*
 73         buffer分为frame buffer 和 render buffer2个大类。
 74         其中frame buffer 相当于render buffer的管理者。
 75         frame buffer object即称FBO。
 76         render buffer则又可分为3类。colorBuffer、depthBuffer、stencilBuffer。
 77         */
 78     //先清空后设置
 79     glDeleteBuffers(1, &_myColorRenderBuff);
 80     self.myColorRenderBuff = 0;
 81     glDeleteBuffers(1, &_myColorFrameBuff);
 82     self.myColorFrameBuff =0;
 83     
 84     //再设置---先设置渲染缓冲,在设置帧缓冲
 85     GLuint buffer1;
 86     glGenRenderbuffers(1, &buffer1);//申请一个缓冲区标识符 **render
 87     self.myColorRenderBuff =buffer1;
 88     glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuff);//将标识符绑定到GL_RENDERBUFFER
 89     //将可绘制对象drawable object的  CAEAGLLayer的存储绑定到OpenGL ES renderBuffer对象
 90     [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEglayer];
 91     
 92     //设置帧缓冲
 93   
 94     glGenFramebuffers(1, &buffer1);//申请一个缓冲区标识符 ** frame 这里申请标志注意是frame 而不是glgenbuffer
 95     self.myColorFrameBuff =buffer1;
 96     glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuff);
 97     /*生成帧缓存区之后,则需要将renderbuffer跟framebuffer进行绑定,
 98         调用glFramebufferRenderbuffer函数进行绑定到对应的附着点上,后面的绘制才能起作用
 99         将渲染缓存区myColorRenderBuffer 通过glFramebufferRenderbuffer函数绑定到 GL_COLOR_ATTACHMENT0上。*/
100     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self .myColorRenderBuff);
101     
102     
103 }
104 
105 -(void)Render{
106     
107     glClearColor(0, 1.0, 0, 1.0);
108     glClear(GL_COLOR_BUFFER_BIT);
109     
110     //1设置视图窗口大小
111     CGFloat scale =[[UIScreen mainScreen] scale];
112     glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, 
113 self.frame.size.height * scale);
114     
115     //着色器 program的设置
116     NSString* vFIle= [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
117     NSString* fFIle= [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];
118 //顶点,片元的编译流程:读取文件路径,创建着色器shader对象,将着色器源码附着到s对象上,把着色器源代码编译成目标代码
119 //programe:创建程序,附着着色器,链接程序,使用程序
120     self.myProgram = [self loadShader:vFIle frag:fFIle];
121     glLinkProgram(self.myProgram);
122     //判断是否连上
123     GLint statusLink;
124     glGetProgramiv(self.myProgram, GL_LINK_STATUS, &statusLink);
125     if(statusLink == GL_FALSE)
126     {
127         GLchar message[512];
128         glGetProgramInfoLog(self.myProgram, sizeof(message), 0, &message[0]);
129         NSString *messageString = [NSString stringWithUTF8String:message];
130         NSLog(@"Program Link Error:%@",messageString);
131         return;
132     }
133      NSLog(@"Program Link Success!");
134     glUseProgram(self.myProgram);
135     
136     //加载纹理和VERTEX,进行绘制
137     //设置顶点矩阵
138     GLfloat attrArr[] = {
139           0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
140            -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
141            -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,
142            0.5f, 0.5f, -1.0f,      1.0f, 1.0f,
143            -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
144            0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
145        };
146     
147     
148     //顶点数据拷贝到显存
149     GLuint vrtID;
150     glGenBuffers(1, &vrtID);
151     glBindBuffer(GL_ARRAY_BUFFER, vrtID);
152     glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
153     
154     //0.将顶点数据通过myProgram传递到顶点着色程序的position
155     //1.glGetAttribLocation,用来获取vertex attribute的入口的.
156     //2.告诉OpenGL ES,通过glEnableVertexAttribArray,
157     //3.最后数据是通过glVertexAttribPointer传递过去的。
158     
159     //:第二参数字符串必须和shaderv.vsh中的输入变量:position保持一致
160     GLuint Position = glGetAttribLocation(self.myProgram, "position");
161     //设置合适的格式从buffer里面读取数据
162     glEnableVertexAttribArray(Position);
163     glVertexAttribPointer(Position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);
164     
165     
166     //处理纹理数据
167     //glGetAttribLocation,用来获取vertex attribute的入口的.
168     //注意:第二参数字符串必须和"shaderv.vsh"中的输入变量:textCoordinate保持一致
169     
170     GLuint textcoor = glGetAttribLocation(self.myProgram, "textCoordinate");
171     glEnableVertexAttribArray(textcoor);
172     glVertexAttribPointer(textcoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5,(float *)NULL + 3);
173     //加载纹理
174    
175     [self setupTexture];
176 //-----------------------------------------------------------------------不旋转这块可以不调用,对应的着色器中的
177 //vPos = vPos * rotateMatrix;这句话就可以不调用了,否则,着色器自动✖️一个未知旋转矩阵,课程会导致纹理超出屏幕范围而无法渲染
178     //获取shader里面的变量,这里记得要在glLinkProgram后面,后面,后面!
179        GLuint rotate = glGetUniformLocation(self.myProgram, "rotateMatrix");
180 
181        float radians = 180 * 3.14159f / 180.0f;
182        float s = sin(radians);
183        float c = cos(radians);
184 
185        //z轴旋转矩阵
186        GLfloat zRotation[16] = { //
187            1, 0, 0, 0, //
188            0, c, -s , 0,//
189            0, s , c, 0,//
190            0.0, 0, 0, 1.0//
191        };
192 
193        //设置旋转矩阵
194        glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);
195 //-----------------------------------------------------------------------
196        glDrawArrays(GL_TRIANGLES, 0, 6);
197 
198  
199 
200        [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
201 
202     
203 
204 }
205 
206  
207 
208 -(GLuint)loadShader:(NSString*)vert frag:(NSString*)fert{
209 
210     //临时着色对象
211 
212     GLuint verShader,fragShader;
213 
214     [self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];
215 
216      [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fert];
217 
218     
219 
220     GLuint programs = glCreateProgram();
221 
222     
223 
224     glAttachShader(programs, verShader);
225 
226     glAttachShader(programs, fragShader);
227 
228     
229 
230     //附着上之后可以删掉了
231 
232     glDeleteShader(verShader);
233 
234     glDeleteShader(fragShader);
235 
236     
237 
238     return programs;
239 
240 }
241 
242 //编译着色器
243 
244 -(void)compileShader:(GLuint*)shader type:(GLenum)type file:(NSString*)file{
245 
246   
247 
248     NSString* Content= [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
249 
250     const GLchar* source = (GLchar*)[Content UTF8String];
251 
252     //创建着色器对象,加载源码,编译着色器对象
253 
254     *shader  =glCreateShader(type);
255 
256     glShaderSource(*shader, 1, &source, NULL);
257 
258     glCompileShader(*shader);
259 
260  
261 
262     
263 
264 }
265 
266  
267 
268 - (GLuint)setupTexture{
269 
270     // 1获取图片的CGImageRef
271 
272     CGImageRef spriteImage = [UIImage imageNamed:@"for_test"].CGImage;
273 
274     if (!spriteImage) {
275 
276         NSLog(@"Failed to load image");
277 
278         exit(1);
279 
280     }
281 
282     
283 
284     // 2 读取图片的大小
285 
286     size_t width = CGImageGetWidth(spriteImage);
287 
288     size_t height = CGImageGetHeight(spriteImage);
289 
290     
291 
292     GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte)); //rgba共4个byte
293 
294     
295 
296     CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
297 
298                                                        CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
299 
300     
301 
302     // 3在CGContextRef上绘图
303 
304     CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
305 
306     
307 
308     CGContextRelease(spriteContext);
309     //上边的操作相当于对图片进行解压缩
310     
311 
312     // 4绑定纹理到默认的纹理ID(这里只有一张图片,故而相当于默认于片元着色器里面的colorMap,如果有多张图不可以这么做)
313 
314     glBindTexture(GL_TEXTURE_2D, 0);
315 
316     
317   //纹理维度,线性过滤,环绕模式
318     
319 
320     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
321 
322     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
323 
324     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
325 
326     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
327 
328     
329 
330     float fw = width, fh = height;
331 
332     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
333 
334     
335 
336     glBindTexture(GL_TEXTURE_2D, 0);
337 
338     
339 
340     free(spriteData);
341 
342     return 0;
343 
344 }
345 
346  
347 
348 @end
349 
350  

 

 

#import "ViewController.h"
#import"showView.h"

@interface ViewController ()

@property(nonatomic ,strong)showView* showV;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.showV = (showView *)self.view;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

 注意修改view的class,否则黑屏崩溃

 

glsl着色器:

片元着色:fsh


varying lowp vec2 varyTextCoord;

uniform sampler2D colorMap;


void main()
{
    gl_FragColor = texture2D(colorMap, varyTextCoord);
}

-------------------------------------------------------------------
顶点着色:vsh


attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;

varying lowp vec2 varyTextCoord;

void main()
{
    varyTextCoord = textCoordinate;
    
    vec4 vPos = position;

    vPos = vPos * rotateMatrix;

    gl_Position = vPos;
}

 

 这里图片旋转的时候的旋转矩阵计算方式如下:

 

 

 

 

上边代码显示的图片是倒着的,愿意是gl中的坐标和iOS坐标是相反的。解决方式:

1修改纹理坐标和顶点坐标的对应关系:

    //6.设置顶点、纹理坐标
    //前3个是顶点坐标,后2个是纹理坐标
//    GLfloat attrArr[] =
//    {
//        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
//        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
//        -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,
//
//        0.5f, 0.5f, -1.0f,      1.0f, 1.0f,
//        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
//        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
//    };
    
    GLfloat attrArr[] =
    {
        0.5f, -0.5f, -1.0f,     1.0f, 1.0f,
        -0.5f, 0.5f, -1.0f,     0.0f, 0.0f,
        -0.5f, -0.5f, -1.0f,    0.0f, 1.0f,
        
        0.5f, 0.5f, -1.0f,      1.0f, 0.0f,
        -0.5f, 0.5f, -1.0f,     0.0f, 0.0f,
        0.5f, -0.5f, -1.0f,     1.0f, 1.0f,
    };

2旋转矩阵翻转图形,不翻转纹理

  • 在顶点着色器 shaderv.vsh 中,我们传进一个旋转矩阵 rotateMatrix,因为矩阵传进来就不会再修改了,所以我们用 uniform 来修饰,4行4列的矩阵 mat4。然后用顶点坐标 vPos 乘以这个 rotateMatrix 旋转矩阵,让每一个顶点都应用旋转变化。
链接:参考https://www.jianshu.com/p/038a160f6cdc 可以绕X轴翻转镜像;绕z轴是旋转,180度

 

3 在解压图片时,将图片源文件翻转

使用下面三行代码,对图片进行了平移缩放操作以后,再重新绘制。

CGContextTranslateCTM(spriteContext, 0, rect.size.height);

 CGContextScaleCTM(spriteContext, 1.0, -1.0);

CGContextDrawImage(spriteContext, rect, spriteImage);

 

4、修改片元着色器中的纹理坐标

这里是修改了片元着色器的代码,x 坐标不动,将 y 坐标改为 1-y,这样就达到了翻转的效果。其他地方代码不用动

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main() {
    //gl_FragColor = texture2D(colorMap, varyTextCoord);
    gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x,1.0-varyTextCoord.y));
}

5、修改顶点着色器中的纹理坐标

在顶点着色器传入的时候,就翻转。相比上面的片元着色器,执行次数要少很多,有几个顶点执行几次。

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main() {
    varyTextCoord = vec2(textCoordinate.x,1.0-textCoordinate.y);
    gl_Position = position;
}


 

posted on 2020-05-19 20:52  邗影  阅读(133)  评论(0)    收藏  举报

导航