rendering
Process logic
Program execution flow
ViewDidLoad function (set background + create toggle filter effect toolbar) –> filterInit function (initialize context, prepare vertex and texture loading) –> shader load/compile, program use –> startFilerAnimation
When toggling the bottom FilterBar –> toggle the split screen option, use the corresponding shader to load/compile, and use –> startFilerAnimation for program
Built-in properties
- Define vertex coordinates and texture coordinates structure SenceVertex
typedef struct {
GLKVector3 positionCoord; // (X, Y, Z)
GLKVector2 textureCoord; // (U, V)
} SenceVertex;
Copy the code
- Context EAGLContext –>EAGLContext
- The timer refreshed CADisplayLink and the start time NSTimeInterval
- Shader program handle program– >GLuint
- VertexBuffer –>GLuint
- Texture ID textureID – > GLuint
SetupFilterBar Bottom filter scroll bar
Create the bottom part of the screen options toolbar, using the FilterBarDelegate callback to change the toolbar options action
@protocol FilterBarDelegate <NSObject>
- (void)filterBar:(FilterBar *)filterBar didScrollToIndex:(NSUInteger)index;
@end
Copy the code
The filterInit filter handles initialization
- Initialize the context and set it to the current context
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.context];
Copy the code
- Initialize vertex coordinates (0,1,2,3) and texture coordinates
self.vertices = malloc(sizeof(SenceVertex) * 4);
self.vertices[0] = (SenceVertex){{-1, 1, 0}, {0, 1}};
self.vertices[1] = (SenceVertex){{-1, -1, 0}, {0, 0}};
self.vertices[2] = (SenceVertex){{1, 1, 0}, {1, 1}};
self.vertices[3] = (SenceVertex){{1, -1, 0}, {1, 0}};
Copy the code
- Bind the render cache bindRenderLayer
- Create render cache, frame cache object
GLuint renderBuffer;
GLuint frameBuffer;
Copy the code
- Gets the frame render cache name, binds the render cache and connects the render cache to the layer
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
Copy the code
- Gets the frame cache name, binds the frame cache, and attaches the render cache to the frame cache
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
renderBuffer);
Copy the code
- Get texture image path, read image UIImage
NSString *imagePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"kunkun.jpg"]; / / read pictures UIImage * image = [UIImage imageWithContentsOfFile: imagePath];Copy the code
-
To load a texture from an image, return the texture ID: texttureID
-
Convert UIImage to CGImageRef
-
Read the size, width and height of the picture, rect
-
Gets the color space of the picture
-
Get image bytes width height 4 (RGBA) open up image data storage space
-
Create context
-
Flip the image upside down (the image is inverted by default)
-
The image is redrawn to get a new decompressed bitmap
-
Get texture ID
-
Load texture 2D data
-
Set texture properties (Filter and Wrap)
-
Binding texture
-
Release the context, imageData
-
GLuint createTextureWithImage:(UIImage *)image {//1, convert UIImage to CGImageRef CGImageRef CGImageRef = [image CGImage]; If (! cgImageRef) { NSLog(@"Failed to load image"); exit(1); } GLuint width = (GLuint)CGImageGetWidth(cgImageRef); GLuint height = (GLuint)CGImageGetHeight(cgImageRef); Rect = CGRectMake(0, 0, width, height); / / get photo color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB (); (gba) void *imageData = malloc(width * height *4); //4. Create context /* Parameter 1: data, pointing to the memory address of the drawn image to be rendered 2: width,bitmap width, in pixels 3: height,bitmap height, in pixels 4: BitPerComponent, the number of bits per component of pixels in memory, such as 32-bit RGBA, is set to 8. KCGImageAlphaPremultipliedLast colorSpace, bitmap using the color space: RGBA */ CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGContextTranslateCTM(context, 0, height); CGContextScaleCTM (context, 1.0 f, 1.0 f); CGColorSpaceRelease(colorSpace); CGContextClearRect(context, rect); CGContextDrawImage(context, recT, cgImageRef); CGContextDrawImage(context, recT, cgImageRef); GLuint textureID; GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D parameters 1: texture mode, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D parameters 2: loading level, generally set to 0 parameter 3: texture color value GL_RGBA parameter 4: wide parameter 5: high parameter 6: 7: format 8: type 9: GlTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); //7. Set the texture property glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //8. Bind texture /* Parameter 1: texture dimension parameter 2: texture ID, since there is only one texture, give 0. */ glBindTexture(GL_TEXTURE_2D, 0); //9. Release context,imageData CGContextRelease(context); free(imageData); //10. Return textureID; }Copy the code
- Set texture ID
self.textureID = textureID
Copy the code
- Set the viewport
glViewport(0, 0, self.drawableWidth, self.drawableHeight); - (GLint)drawableWidth {GLint backingWidth; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); return backingWidth; } // Get the render cache height - (GLint)drawableHeight {GLint backingHeight; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); return backingHeight; }Copy the code
- Set the vertex cache
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
GLsizeiptr bufferSizeBytes = sizeof(SenceVertex) * 4;
glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self.vertices, GL_STATIC_DRAW);
Copy the code
- Set the default shader setupNormalShaderProgram
[self setupShaderProgramWithName:@"Normal"];
Copy the code
StartFilerAnimation Filter animation
- Pause the CADisplayLink timer
- Method to set displayLink
- Add displayLink to runloop running loop;
// Start a filter animation - (void)startFilerAnimation {//1. //CADisplayLink timer if (self.displayLink) {[self.displayLink invalidate]; self.displayLink = nil; } //2. Set the displayLink method self.startTimeInterval = 0; self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeAction)]; / / 3. Add displayLink to the runloop running cycle [self. DisplayLink addToRunLoop: [NSRunLoop mainRunLoop] forMode: NSRunLoopCommonModes]; }Copy the code
-
Timing of the animation
-
The use of the program
-
Binding buffer
-
The incoming time
-
Remove the canvas
-
redraw
-
Render to the screen
-
Animation - (void)timeAction {//DisplayLink's current time if (self.starttimeInterval == 0) {self.starttimeInterval = self.displayLink.timestamp; } // Use program glUseProgram(self.program); // bind buffer glBindBuffer(GL_ARRAY_BUFFER, self.vertexbuffer); / / incoming time CGFloat currentTime = self. DisplayLink. Timestamp - self. StartTimeInterval; GLuint time = glGetUniformLocation(self.program, "Time"); glUniform1f(time, currentTime); // Clear the canvas glClear(GL_COLOR_BUFFER_BIT); glClearColor(1, 1, 1, 1); // Redraw glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Render to screen [self.context presentRenderbuffer:GL_RENDERBUFFER]; }Copy the code
FilterBarDelegate
Select a grayscale shader based on index and restart the filter animation
-(void)filterBar:(FilterBar *)filterBar didScrollToIndex:(NSUInteger)index;
-
Index = 0 sets the default shader
[self setupShaderProgramWithName:@”Normal”];
-
Index = 1 sets the binary screen shader
[self setupShaderProgramWithName:@”SplitScreen_2″];
-
Index = 2 sets the 3 split screen shader
[self setupShaderProgramWithName:@”SplitScreen_3″];
-
Index = 3 sets 4 split-screen shaders
[self setupShaderProgramWithName:@”SplitScreen_4″];
-
Index = 4 Sets 6 split-screen shaders
[self setupShaderProgramWithName:@”SplitScreen_6″];
-
Index = 5 sets 9 split-screen shaders
[self setupShaderProgramWithName:@”SplitScreen_9″];
Split-screen filter: Chip shader Shaders implement different algorithms
Switch split screen – setupShaderProgramWithName loading different vertex shader program and the fragment shader
Binary screen
The x value of the texture coordinate is unchanged, and the y value is changed:
When y is in the range [0, 0.5], the screen’s (0, 0) coordinates need the corresponding image’s (0, 0.25), so y = y+0.25
When y is in the range of [0.5, 1], the screen’s (0,0.5) coordinates need the corresponding image’s (0,0.25), so y = y-0.25
- Chip shader program
precision highp float; uniform sampler2D Texture; varying highp vec2 TextureCoordsVarying; void main() { vec2 uv = TextureCoordsVarying.xy; float y; If (uv) > = 0.0 && y uv) < = 0.5) {y y = uv. Y + 0.25; } else {y = uv. y-0.25; } gl_FragColor = texture2D(Texture, vec2(uv.x, y)); }Copy the code
Three split screen
The x value of texture coordinates remains unchanged, and the y value changes:
When y is in the [0, 1/3] range, the screen’s (0, 0) coordinates need to correspond to the image’s (0, 1/3), so y = y+1/3
When y is in the [1/3, 2/3] range, the screen’s (0, 1/3) coordinates need the corresponding image’s (0, 1/3), so y stays the same
When y is in the [2/3, 1] range, the screen’s (0, 2/3) coordinates need to correspond to the image’s (0, 1/3), so y = y-1/3
- Chip shader program
precision highp float; uniform sampler2D Texture; varying highp vec2 TextureCoordsVarying; void main() { vec2 uv = TextureCoordsVarying.xy; If (uv.y < 1.0/3.0) {uv.y = uv.y + 1.0/3.0; } else if (uv) y > 2.0/3.0) {uv. Y = uv. Y - 1.0/3.0. } gl_FragColor = texture2D(Texture, uv); }Copy the code
Four split screen
The screen is divided into four equal sections to display a reduced texture image:
When x is in the range [0, 0.5], x = x*2
When x is in the range of [0.5, 1], x = (x-0.5)*2
When y is in the range [0, 0.5], y = y*2
When y is in the range of [0.5, 1], y = (y-0.5)*2
- Chip shader program
precision highp float; uniform sampler2D Texture; varying highp vec2 TextureCoordsVarying; void main() { vec2 uv = TextureCoordsVarying.xy; If (uv.x <= 0.5){uv.x = uv.x * 2.0; }else{uv.x = (uv.x -0.5) * 2.0; } if (uv.y<= 0.5) {uv.y = uv.y * 2.0; }else{uv.y = (uV. y-0.5) * 2.0; } gl_FragColor = texture2D(Texture, uv); }Copy the code
Six split screen
Texture coordinates x and Y change rules:
When x is in the range [0, 1/3], x is equal to x plus 1/3
When x is in the range 1/3, 2/3, x doesn’t change
When x is in the [2/3, 1] range, x is equal to x minus 1/3
When y is in the range [0, 0.5], y = y+0.25
When y is in the range of [0.5, 1], y = y-0.24
- Chip shader program
precision highp float; uniform sampler2D Texture; varying highp vec2 TextureCoordsVarying; void main() { vec2 uv = TextureCoordsVarying.xy; If (uv.x <= 1.0/3.0){uv.x = uv.x + 1.0/3.0; } else if (uv) x > = 2.0/3.0) {uv. X = uv. X - 1.0/3.0. } if(uv.y <= 0.5){uv.y = uv.y + 0.25; }else {uv.y = uv.y -0.25; } gl_FragColor = texture2D(Texture, uv); }Copy the code
Nine points screen
Texture coordinates x, y change rule: when x is in [0, 1/3] range, x = x*3
When x is in the range 1/3, 2/3, x is equal to x minus 1/3 times 3
When x is in the [2/3, 1] range, x is equal to x minus 2/3 times 3
When y is in the range 0, 1/3, y is equal to y times 3
When y is in the 1/3, 2/3 range, y is equal to y minus 1/3 times 3
When y is in the [2/3, 1] range, y is equal to y minus 2/3 times 3
- Chip shader program
precision highp float; uniform sampler2D Texture; varying highp vec2 TextureCoordsVarying; void main() { vec2 uv = TextureCoordsVarying.xy; If (uv.x < 1.0/3.0) {uv.x = uv.x * 3.0; } else if (uv) x < 2.0/3.0) {uv. X = (uv) x - 1.0/3.0) * 3.0; } else {uv.x = (uv.x-2.0/3.0) * 3.0; } if (uv.y <= 1.0/3.0) {uv.y = uv.y * 3.0; } else if (uv) y < 2.0/3.0) {uv. Y = (uv) y - 1.0/3.0) * 3.0; } else {uv.y = (uv.y-2.0/3.0) * 3.0; } gl_FragColor = texture2D(Texture, uv); }Copy the code