EGL
The OpenGL ES command requires a rendering context and a rendering surface to complete a graph. Rendering context: Stores the relevant OpenGL ES states. Rendering surface: a surface used to draw primitives, which specifies the type of cache required for rendering. Examples are color cache, depth cache, template cache. The OpenGL ES API does not provide information on how to create a render context or how the context is connected to the acoustic window system. EGL is the interface between Khronos rendering apis [such as OpenGL ES] and native window systems. The only platform that supports OpenGL ES but does not support EGL is iOS.
EGL’s main functions are as follows:
- Communicate with the local window system
- Querying Available Configurations
- Create a drawing surface available to OpenGL ES
- Synchronize rendering between different classes of apis, such as between OpenGL ES and OpenVG, or between OpenGL and local window drawing commands
- Manage rendering resources, such as texture mapping
IOS provides QuartzCore/CAEAGLLayer as the drawing surface
Shaders and programs
Two basic objects need to be created to be rendered by shaders: a shader object and a program object
The general process of obtaining a linked post-shader object consists of six steps:
- Create a vertex shader object and a fragment shader object
- Link the source code to each shader object
- Compile the shader object
- Create a program object
- Link the compiled shader object to the program object
- Linker object
The API is introduced
Shader API
GLuint glCreateShader(GLenum type)
GL_VERTEX_SHADER or GL_FRAGMENT_SHADER RETURN: The return value is a handle to the new shader object and can be called
void glDeleteShader(GLuint shader)
Shader: Handle to the shader object to delete
void glShaderSource(GLuint shader, GLsizei count, const GLchar* const *string, const GLint* length)
Shader: a handle to a shader object count: The number of shader source strings. A shader can consist of multiple source strings, but each shader has only one main function. String: a pointer to an array that holds a shader source string of count: Pointer to an array of integers holding the size of each shader string and the number of elements count
void glCompileShader(GLuint shader)
Shader: Handle to the shader object to compile
void glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
Shader: shader object handle to be compiled pname: name of the obtained parameter params: pointer to the integer storage location of the query result
Pname Optional name | |
---|---|
GL_COMPILE_STATUS | |
GL_DELETE_STATUS | |
GL_INFO_LOG_LENGTH | |
GL_SHADER_SOURCE_LENGTH | |
GL_SHADER_TYPE |
void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
Bufsize: the size of the cache where information logs are stored. Length: the length of the log where information is written (minus the null terminator). If you do not need to know the length, you can pass Null infolog: a pointer to the string cache where the information log is stored
Application API
GLuint glCreateProgram(void)
Return: Returns a handle to a new program object
void glDeleteProgram(GLuint program)
Delete program: handle to program object
void glAttachShader(GLuint program, GLuint shader)
Shader: Handle to a shader object pointing to a program link
void glDetachShader(GLuint program, GLuint shader)
Shader: Handle to a shader object pointing to a program link
void glLinkProgram(GLuint program)
Link program: Handle to a program object
void glGetProgramiv(GLuint program, GLenum pname, GLint* params)
Program: handle to the program object. Pname: parameter name to obtain information. Params: pointer to the location where the query result integer is stored
Pname Optional name | |
---|---|
GL_ACTIVE_ATTRIBUTES | |
GL_ACTIVE_ATTRIBUTE_MAX_LENGTH | |
GL_ACTIVE_UNIFORM_BLOCKS | |
GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH | |
GL_ACTIVE_UNIFORMS | |
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 |
void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
Bufsize: the size of the cache where information logs are stored. Length: the length of the log to which information is written (minus the null terminator). If you do not need to know the length, you can pass Null infolog: a pointer to the string cache where the information log is stored
void glUseProgram(GLuint program)
Set to active program: handle to program object
Relationship between FrmeBuffer and RenderBuffer
Reference documentation
FrameBuffer FrameBuffer
The RenderBuffer is one of the attachments to the frame buffer
The RenderBuffer stores the results of the render operation. The shader can easily manipulate the contents of the RenderBuffer and pass them to the frame buffer for display quickly.
Image to load
Set the shader file
1. Vertex shaders
shaderv.vsh
// Set the image vertex
attribute vec4 position;
// Set texture coordinates
attribute vec2 textCoordinate;
// Pass variables from vertex shader to slice shader (pass texture coordinates)
varying lowp vec2 varyTextCoord;
void main() {
varyTextCoord = textCoordinate;
gl_Position = position;
}
Copy the code
2. Chip shader
shaderf.fsh
// Set the float type to high precision
precision highp float;
// Texture coordinates passed from the vertex shader
varying lowp vec2 varyTextCoord;
/ / texture
uniform sampler2D colorMap;
void main() {
// Pass in the texture and coordinates, return the 4-dimensional vector information of the striene (RGBA)
gl_FragColor = texture2D(colorMap, varyTextCoord);
}
Copy the code
Texture loading complete code
#import "CustomView.h"
#import <OpenGLES/ES2/gl.h>
/** Create layer 2. Create context 3. 4. Set RenderBuffer 5. Set FrameBuffer 6. Start drawing */
@interface CustomView(a)
// Draw the carrier
@property (nonatomic.strong) CAEAGLLayer *myEAGLLayer;
/ / context
@property (nonatomic.strong) EAGLContext *myContext;
// Render buffer
@property (nonatomic.assign) GLuint myColorRenderBuffer;
// Frame buffer: depth/color/template
@property (nonatomic.assign) GLuint myColorFrameBuffer;
/ / application
@property (nonatomic.assign) GLuint myPrograme;
@end
@implementation CustomView
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (void)layoutSubviews {
[self setupLayer];
[self setupContext];
[self deleteBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self renderLayer];
}
/// Draw layers
- (void)setupLayer {
// 1. Create layers
self.myEAGLLayer = (CAEAGLLayer *)self.layer;
// set the scale
[self setContentScaleFactor:[UIScreen mainScreen].scale];
// 3. Set the buffer
/ / kEAGLDrawablePropertyRetainedBacking draw over whether or not to retain
/ / kEAGLDrawablePropertyColorFormat color format
self.myEAGLLayer.drawableProperties = @{
kEAGLDrawablePropertyRetainedBacking: @(NO),
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
};
}
/// Set the context
- (void)setupContext {
/ / 1. To create
self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
/ / 2. The judgment
if (!self.myContext) {
NSLog(@"create context failure");
return;
}
// 3. Set the context
if(! [EAGLContext setCurrentContext:self.myContext]) {
NSLog(@"set current context failure");
return; }}/// delete the buffer
- (void)deleteBuffer {
glDeleteBuffers(1, &_myColorRenderBuffer);
self.myColorRenderBuffer = 0;
glDeleteBuffers(1, &_myColorFrameBuffer);
self.myColorFrameBuffer = 0;
}
/ / / set the RenderBuffer
- (void)setupRenderBuffer {
/ / 1. Definitions
GLuint buffer;
glGenRenderbuffers(1, &buffer);
self.myColorRenderBuffer = buffer;
/ / 2. Binding
// glBindBuffer(GL_RENDERBUFFER, buffer);
glBindRenderbuffer(GL_RENDERBUFFER, buffer);
// 3. Set the render context
[self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEAGLLayer];
}
/ / / set the FrameBuffer
- (void)setupFrameBuffer {
/ / 1. Definitions
GLuint buffer;
glGenFramebuffers(1, &buffer);
self.myColorFrameBuffer = buffer;
/ / 2. Binding
// glBindBuffer(GL_FRAMEBUFFER, buffer);
glBindFramebuffer(GL_FRAMEBUFFER, buffer);
// 3. Bind render buffer and frame buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
}
/// start drawing
- (void)renderLayer {
// 1. Clear the buffer
glClearColor(0.3.0.45.0.5.1);
glClear(GL_COLOR_BUFFER_BIT);
// 2. Set the viewport
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);
// 3. Read the shader file address
NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"vsh"];
NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"fsh"];
// 4. Get program (bind vertex shader and slice shader data)
self.myPrograme = [self loaderShaders:vertFile withFrag:fragFile];
// 5
glLinkProgram(self.myPrograme);
GLint linkState;
// Get the link status
glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkState);
if (linkState == GL_FALSE) {
/ / link failure
GLchar message[512];
glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
NSString *messageString = [NSString stringWithUTF8String:message];
NSLog(@"Programe link failure: %@", messageString);
return;
}
// 6
glUseProgram(self.myPrograme);
// 7. Vertex data, two triangles
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,
};
Vertex data -> vertex buffer
GLuint attrBuffer;
glGenBuffers(1, &attrBuffer);
glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
// 9. Open channel
// a. Get and open the vertex data channel and set the data
GLuint position = glGetAttribLocation(self.myPrograme, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5.NULL);
// b. Get and open the texture data channel and set the data
GLuint textCoordinate = glGetAttribLocation(self.myPrograme, "textCoordinate");
glEnableVertexAttribArray(textCoordinate);
glVertexAttribPointer(textCoordinate, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
// load the texture
[self setupTexture:@"Image"];
// 11. Set the texture sampler
glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
/ / 12. Draw
glDrawArrays(GL_TRIANGLES, 0.6);
// 13. Display from render buffer to screen
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
}
// Get the texture
- (GLuint)setupTexture:(NSString *)fileName {
// 1
CGImageRef spriteImage = [UIImage imageNamed:@"Image"].CGImage;
if(! spriteImage) {NSLog(@"load image failure");
exit(1);
}
/ / 2. Wide high
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
// 3. Get image bytes width * height *4(RGBA)
GLubyte *spriteData = (GLubyte *) calloc(width * height * 4.sizeof(GLubyte));
// 4. Set context
/* Parameter 1: data, pointing to the memory address of the drawn image to be rendered. Parameter 2: width, the bitmap width, in pixels. Parameter 3: height, the bitmap height, in pixels. BitPerComponent, the number of bits per component of pixels in memory, such as 32-bit RGBA, is set to 8. The colorSpace, bitmap using the color space kCGImageAlphaPremultipliedLast: RGBA * /
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4.CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// 5. On CGContextRef, draw the picture
CGRect rect = CGRectMake(0.0, width, height);
CGContextDrawImage(spriteContext, rect, spriteImage);
// 6. Finish drawing and release the context
CGContextRelease(spriteContext);
// 7. Bind texture to default texture ID. If there is only one texture, the second parameter texture can be set to 0, and texture 0 is activated by default
glBindTexture(GL_TEXTURE_2D, 0);
// 8. Set the texture properties
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);
// 9. Load the texture
float fw = width, fh = height;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
/ / 10. Release
free(spriteData);
return 0;
}
#pragma mark - shader
// create a shader
/// @param vertFilePath Vertex shader string file path
/// @param fragFilePath The string file path of the fragment shader
- (GLuint)loaderShaders:(NSString *)vertFilePath withFrag:(NSString *)fragFilePath {
// 1. Define vertex shaders and slice shaders
GLuint verShader, fragShader;
// 2. Create program
GLuint program = glCreateProgram();
// 3. Create and compile shaders
[self compileShader:&verShader type:GL_VERTEX_SHADER filePath:vertFilePath];
[self compileShader:&fragShader type:GL_FRAGMENT_SHADER filePath:fragFilePath];
// 4. Link shaders and programs
glAttachShader(program, verShader);
glAttachShader(program, fragShader);
// 5. Clean up useless objects
glDeleteShader(verShader);
glDeleteShader(fragShader);
return program;
}
// create and compile shaders
/// @param shader pointer
/// @param type: vertex/slice
/// @param filePath shader string filePath
- (void)compileShader:(GLuint *)shader type:(GLenum)type filePath:(NSString *)filePath {
// 1. Read files
NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
const GLchar *source = (GLchar *)[content UTF8String];
// 2. Create a shader of the corresponding type
*shader = glCreateShader(type);
// 3. Attach shader source code to shader
glShaderSource(*shader, 1, &source, NULL);
/ / 4. Compilation
glCompileShader(*shader);
}
@end
Copy the code
Texture flip
1. Rotate matrix without flipping texture
GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");
float radians = 180 * 3.14159f / 180.0f;
float s = sin(radians);
float c = cos(radians);
GLfloat zRotation[16] = {
c, -s, 0.0,
s, c, 0.0.0.0.1.0.0.0.0.0.0.1.0
};
glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);
Copy the code
2. When decompressing the image, flip the source file (most commonly used ✨✨✨)
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width * height * 4.sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4.CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGRect rect = CGRectMake(0.0, width, height);
CGContextDrawImage(spriteContext, CGRectMake(0.0, width, height), spriteImage);
CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
CGContextScaleCTM(spriteContext, 1.0.1.0);
CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
CGContextDrawImage(spriteContext, rect, spriteImage);
CGContextRelease(spriteContext);
glBindTexture(GL_TEXTURE_2D, 0);
Copy the code
3. Modify the slice shader file and texture coordinates
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x,1.0-varyTextCoord.y));
}
Copy the code
4. Modify the vertex shader less than the third method
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;
void main()
{
varyTextCoord = vec2(textCoordinate.x,1.0-textCoordinate.y);
gl_Position = position;
}
Copy the code
5. Modify texture coordinate data mapping
GLfloat attrArr[] =
{
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, / / right
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, / / left
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, / / lower left
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, / / right
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, / / left
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, / / right}; * /Copy the code
See OpenGL 2D Texture Unit & Texture Flip Solutions