My OpenGL thematic learning directory, hope to learn with you exchange progress!

  • OpenGL Learning (I) – Terminology understanding
  • OpenGL learning (2) — Xcode build OpenGL environment
  • OpenGL learning (three) – OpenGL base rendering
  • OpenGL learning (4) – front & back culling and depth testing
  • OpenGL Learning (5) – Cropping and Blending
  • OpenGL Learning (6) – Base textures
  • OpenGL Learning (7) — Summary of basic change Comprehensive Exercise practice
  • OpenGL ES Learning (8)
  • OpenGL learning (nine) — OpenGL ES preliminary exploration (next) GLKit
  • OpenGL learning (10) – GLSL syntax introduction
  • OpenGL learning (11) – using GLSL to load pictures
  • OpenGL learning (12) — OpenGL ES texture flipping strategy comparison

One, foreword

Last time I wrote an OpenGL learning (nine) — OpenGL ES preliminary (next) GLKit, using GLKit to load a stereo graphics, but we know that Apple provides GLKit function is limited, so this time we don’t use GLKit GLKBaseEffect, And the use of compiler link custom shader (shader), with a simple GLSL language to achieve vertex, slice shader, and load a picture. GLSL syntax has been introduced to the syntax of GLSL, there are grammar do not understand the place can go to see.

Second, THE complete process of GLSL loading pictures

When learning, it is best to summarize the mind map first, which can help us understand and memorize the process steps. The following is a complete mind map that I drew with GLSL loading pictures. Functions such as SetuPlayer and setupContext are packaged by myself according to the steps.

The following focuses on separating the drawing steps and drawing the mind map of the drawing part:

3. Write GLSL files

The GLSL code we write is a long string for Xcode, so it doesn’t matter what the suffix is. When we read the source code of GPUImage and ijkPlayer, we can find that their shader is stored in ordinary strings, which is not a problem. The disadvantage is that it is not easy to read and write.

So we create a file with the suffix “.vsh “and “.fsh”, where”.vsh “stands for Verterx Shader vertex shader and “.fsh” stands for Fragment Shader. Common suffixes are “. VSH “, “. FSH “and” GLSL “.

If shader files are named with the common suffix “GLSL”, how do you tell which is vertex shader and which is slice shader? The vertex shader must have an assignment to the built-in function gl_Position, and the fragment shader must have an assignment to the built-in function gl_FragColor.

Vertex shaders:

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

void main() {
    varyTextCoord = textCoordinate;
    gl_Position = position;
}
Copy the code

Slice shader:

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

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

4. Common APIS

Here are some common apis. These commonly used API we must keep in mind, because we write GLSL code, not by Xcode to help us compile, but by our developers to compile, link, generate program.

Create and compile a shader

(1)glCreateShaderCreating shaders

GLuint glCreateShader(GLenum type);
Copy the code
  • Parameter type: the type of shader created, GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
  • Return value: is a handle to the new shader object, which can be called.

(2)glDeleteShaderDelete shader

void glDeleteShader(GLuint shader);
Copy the code
  • Parameter shader: Handle to the shader object to be deleted

(3)glShaderSourceAppends the shader source code to the shader object

void glShaderSource (GLuint shader, GLsizei count, const GLchar* const *string, const GLint* length);
Copy the code
  • Parameter 1: The handle to which the shader points to the shader object.
  • Parameter 2: count The number of shader source strings. A shader can consist of multiple source strings, but each shader has only one main function.
  • Parameter 3: strings a pointer to the shader source string.
  • Parameter length: length, an array with the length of each string, or NULL, which means that the string is null-terminated.

(4)glCompileShadercompile

void glCompileShader (GLuint shader) 
Copy the code
  • Parameter shader: Handle to the shader object to compile.

2. Create and link programs

In OpenGL ES, each Program object has one and only one Vertex Shader object and one Fragment Shader object attached to it.

(1)glCreateProgramTo create the program

GLuint glCreateProgram (void)
Copy the code
  • Return value: Returns a handle to execute the new program object.

(2)glDeleteProgramDelete the program

void glDeleteProgram(GLuint program)
Copy the code
  • Parameter Program: Handle to the program object to be deleted.

(3)glAttachShaderShader attached to program

void glAttachShader (GLuint program, GLuint shader)
Copy the code
  • Parameter 1: program points to the handle of the program object.
  • Parameter 2: Shader points to a handle to the shader object to which the program is attached.

(4)glDetachShaderDisconnect the attachment

void glDetachShader(GLuint program, GLuint shader)
Copy the code
  • Parameter 1: program points to the handle of the program object.
  • Parameter 2: Shader points to a handle to the shader object to which the program is disconnected.

(5)glLinkProgramLink to the program

void glLinkProgram(GLuint program);
Copy the code
  • Parameter: program Points to a handle to the program object.

(6)glGetProgramivCheck whether the link is successful

void glGetProgramiv (GLuint program, GLenum pname, GLint* params);
Copy the code
  • Parameter 1: program Handle to the program object from which information is to be obtained.
  • Argument 2:pnameParameters for obtaining information, which can be:GL_ACTIVE_ATTRIBUTES GL_ACTIVE_ATTRIBUTES_MAX_LENGTH GL_ACTIVE_UNIFORM_BLOCK GL_ACTIVE_UNIFORM_BLOCK_MAX_LENGTH GL_ACTIVE_UNIFROMS GL_ACTIVE_UNIFORM_MAX_LENGTH GL_ATTACHED_SHADERS GL_DELETE_STATUS GL_INFO_LOG_LENGTH GL_LINK_STATUS GL_PROGRAM_BINARY_RETRIEVABLE_HINT GL_TRANSFORM_FEEDBACK_BUFFER_MODE GL_TRANSFORM_FEEDBACK_VARYINGS GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH GL_VALIDATE_STATUS
  • Parameter 3: params pointer to the location where the query result integer is stored.

(7)glUseProgramThe use of the program

void glUseProgram (GLuint program);
Copy the code
  • Parameter: program Set to a handle to the program object of the active program.

3, vertex shader and chip shader to achieve compilation, binding, connection.

(1)glGetAttribLocationPass the vertex data through myPrograme to position of the vertex shader (passattributeType)

int glGetAttribLocation (GLuint program, const GLchar* name)
Copy the code
  • Parameter 1: program specifies which program object handle is used to pass the data.
  • Parameter 2: name Specifies the name of the vertex variable. This string must be consistent with the input variable: position in shaderv.vsh.

(2)glGetUniformLocationPass the texture sampler data through myPrograme to the colorMap of the slice shader (passuniformType)

int glGetUniformLocation (GLuint program, const GLchar* name)
Copy the code
  • Parameter 1: program specifies which program object handle is used to pass the data.
  • Parameter 2: name Specifies the name of the texture sampler variable. This string must be consistent with the variable: colorMap in shaderf.vsh.

Five, source code display

The source code for the vertex shaderv.vsh and slice shaderf.fsh are given at the beginning of this article and will not be repeated here.

1. Header files and property declarations

#import <OpenGLES/ES2/gl.h>
#import "WPView.h"@interface WPView() // Draw OpenGL ES content layer on iOS and tvOS, inherit with CALayer @property(nonatomic,strong)CAEAGLLayer *myEagLayer; @property(nonatomic,strong)EAGLContext *myContext; @property(nonatomic,assign)GLuint myColorRenderBuffer; @property(nonatomic,assign)GLuint myColorFrameBuffer; @property(nonatomic,assign)GLuint myPrograme; @endCopy the code

2, entrancelayoutSubviewsfunction

- (void)layoutSubviews {//1. Set layer [self setupLayer]; //2. Set the graphics context [self setupContext]; / / 3. Empty the cache area [self deleteRenderAndFrameBuffer]; //4. Set RenderBuffer [self setupRenderBuffer]; // set FrameBuffer [self setupFrameBuffer]; //6. Start drawing [self renderLayer]; } // Override layerClass to replace CCView's layer from CALayer with CAEAGLLayer + (Class)layerClass {return [CAEAGLLayer class];
}
Copy the code

3. Set the layerssetupLayerfunction

Set layer - (void)setupLayer {//1. Create a special layer self.myeagLayer = (CAEAGLLayer *)self.layer; // set scale [selfsetContentScaleFactor:[[UIScreen mainScreen]scale]]; / / 3. Set the description attribute, set here will not maintain render content and color format for RGBA8 self. MyEagLayer. DrawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: @false,kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,nil];
}
Copy the code

4. Set the contextsetupContextfunction

Set the context - (void)setupContext {// 1. Specify the OpenGL ES rendering API version, we use 2.0 = kEAGLRenderingAPIOpenGLES2 EAGLRenderingAPI API; EAGLContext *context = [[EAGLContext alloc]initWithAPI: API]; // 3. Check whether the vm is created successfullyif(! context) { NSLog(@"Create context failed!");
        return; } // 4. Set the graphics contextif(! [EAGLContextsetCurrentContext:context]) {
        NSLog(@"setCurrentContext failed!");
        return; } //5. Change the local context to the global self.myContext = context; }Copy the code

5. Clear the cachedeleteRenderAndFrameBufferfunction

/ / 3. Empty the cache area - (void) deleteRenderAndFrameBuffer {/ * buffer into the frame buffer and render buffer2 categories. The frame buffer is the manager of the Render buffer. The Frame Buffer Object is called FBO. Render Buffers can be divided into three categories. ColorBuffer, depthBuffer, stencilBuffer. */ glDeleteBuffers(1, &_myColorRenderBuffer); self.myColorRenderBuffer = 0; glDeleteBuffers(1, &_myColorFrameBuffer); self.myColorFrameBuffer = 0; }Copy the code

6. Set RenderBuffersetupRenderBufferfunction

RenderBuffer - (void)setupRenderBuffer {//1. Define a buffer ID GLuint buffer; Buffers (1, &buffer); // buffers(1, &buffer); //3. self.myColorRenderBuffer = buffer; GlBindRenderbuffer (GL_RENDERBUFFER, self.mycolorrenderbuffer); //5. Drawable objectThe store of the CAEAGLLayer is bound to the OpenGL ES renderBuffer object [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer]; }Copy the code

7. Set the FrameBuffersetupFrameBufferfunction

Setframebuffer - (void)setupFrameBuffer {//1 Define a buffer ID GLuint buffer; Buffers(1, &buffer); // Buffers(1, &buffer); //3. self.myColorFrameBuffer = buffer; //4. glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer); / * generated after the frame buffer, you will need to will be binding, renderbuffer with framebuffer glFramebufferRenderbuffer function called for binding to the corresponding attachment points on the back of the map to work * / / / 5. Will render buffer myColorRenderBuffer by binding to the GL_COLOR_ATTACHMENT0 glFramebufferRenderbuffer function. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer); }Copy the code

8. Start drawingrenderLayerfunction

// start rendering - (void)renderLayer {glClearColor(0.3f, 0.45f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // 1. Set viewport size CGFloat scale = [[UIScreen mainScreen]scale]; glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale); NSString *vertFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
    NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"]; MyPrograme = [self loadShaders:vertFile Withfrag:fragFile]; / / 4. Link glLinkProgram (self. MyPrograme); GLint linkStatus; GlGetProgramiv (self.myprograme, GL_LINK_STATUS, &linkStatus);if (linkStatus == GL_FALSE) {
        GLchar message[512];
        glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"Program Link Error:%@",messageString);
        return;
    }
    NSLog(@"Program Link Success!"); // 5. Use program glUseProgram(self.myprograme); // The first three are vertex coordinates, and the last two are texture coordinates GLfloatAttrArr [] = {0.5 f to 0.5 f to 1.0 f to 1.0 f to 0.0 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f to 1.0 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f to 0.0 f to 0.5 f, 0.5 f to 1.0 f, f, 1.0 1.0 f to 0.5 f, 0.5 f to 1.0 f, 0.0 f, f 1.0, 0.5, f - 0.5 f to 1.0 f, f 1.0, 0.0, f}; / / 7. -- -- -- -- -- dealing with vertex data -- -- -- -- -- -- -- -- / / (1) the vertex buffer GLuint attrBuffer; Buffers(1, &attrbuffer); //(1) Buffers(1, &attrbuffer); GlBindBuffer (GL_ARRAY_BUFFER, attrBuffer); GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW); //1. GlGetAttribLocation is used to obtain vertex attribute entry. //2. Tell OpenGL ES, through glEnableVertexAttribArray, / / 3. Finally the data is passed through glVertexAttribPointer. GLuint Position = glGetAttribLocation(self.myame,"position"); / / (2). Set the appropriate format to read data from a buffer glEnableVertexAttribArray (position); GlVertexAttribPointer (position, 3, GL_FLOAT, GL_FALSE, sizeof(GL)float) * 5, NULL); //(1).glgetattribLocation, which is used to obtain the entry of the vertex attribute. GLuint textCoor = glGetAttribLocation(self.myame,"textCoordinate"); / / (2). Set the appropriate format to read data from a buffer glEnableVertexAttribArray (textCoor); GlVertexAttribPointer (textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GL)float) * 5, (float*)NULL + 3); Load the texture [self setupTexture:@]"Xia mu"]; //11. Set the sampler2D glUniform1i(glGetUniformLocation(self. myame,"colorMap"), 0); Using glDrawArrays(Say, GL_TRIANGLES, 0, 6); //13. Display from render cache to screen [self.myContext presentRenderbuffer:GL_RENDERBUFFER]; }Copy the code

8.1. Load shaderloadShadersfunction

// load shader - (GLuint)loadShaders:(NSString *)vert Withfrag:(NSString *)frag {//1. Define two zero-time shader objects, GLuint verShader, fragShader; // create program GLint program = glCreateProgram(); //2: type of compilation, GL_VERTEX_SHADER (vertex_vertex_shader), GL_FRAGMENT_SHADER(fragment_shader) // 3: File path [self compileShader:&verShadertype:GL_VERTEX_SHADER file:vert];
    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag]; GlAttachShader (program, verShader); glAttachShader(program, verShader); glAttachShader(program, fragShader); //4. Release unneeded shader glDeleteShader(verShader); glDeleteShader(fragShader);return program;
}
Copy the code

Load a texture from an imagesetupTexturefunction

SetupTexture :(NSString *)fileName {//1, convert UIImage to CGImageRef CGImageRef spriteImage = [UIImage  imageNamed:fileName].CGImage; // Check whether the image was successfully obtainedif(! spriteImage) { NSLog(@"Failed to load image %@", fileName);
        exit(1); Size_t width = CGImageGetWidth(spriteImage); size_t height = CGImageGetHeight(spriteImage); GLubyte * spriteData = (GLubyte *) calloc(width * height *4, sizeof(GLubyte)); //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. 5: bytesPerRow, the number of bits per row in bitmap, 4 for RGBA 6: ColorSpace, bitmap using the color space of the parameters of the 7: kCGImageAlphaPremultipliedLast: RGBA */ CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast); /* CGContextDrawImage uses the Core Graphics framework. The coordinate system is different from UIKit. The origin of the UIKit frame is in the upper-left corner of the screen, and the origin of the Core Graphics frame is in the lower-left corner of the screen. CGRect rect = CGRectMake(0, 0, width, height); CGContextDrawImage = CGRectMake(0, 0, width, height); //6. Draw CGContextDrawImage(spriteContext, rect, spriteImage) using the default method; CGContextRelease(spriteContext); // Bind the texture to the default texture ID (glBindTexture(GL_TEXTURE_2D, 0); /* Parameter 1: texture dimension parameter 2: linear filter, set mode parameter 3 for S, T coordinates: WrapMode, surround mode */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);floatfw = width, fh = height; Parameter 1: texture mode, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D parameter 2: loading level, generally set to 0 parameter 3: texture color value GL_RGBA parameter 4: wide parameter 5: high parameter 6: Border 7: format 8:typeGlTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, fw, FH, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); //11. Free spriteData free(spriteData);return 0;
}
Copy the code

Effect:

The renderings are displayed successfully, but they are inverted. How to solve this problem? Next articleOpenGL ES Texture Flipping Strategy ComparisonLet’s talk about some solutions and compare some of their strengths and weaknesses.

Reprint please note the original source, shall not be used for commercial communication – any more