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

I. Introduction to GLKit framework

The GLKit framework is designed to simplify application development based on OpenGL/OpenGL ES. Its appearance speeds up OpenGL ES or OpenGL application development. Use math libraries, background texture loading, pre-created shader effects, and standard views and view controllers to implement the render loop.

  • No need to write your own shaders: The GLKit framework provides functionality and classes that reduce the amount of work required to create new shader-based applications, or to support existing applications that rely on fixed function vertex or fragment handling provided by earlier versions of OpenGL ES.
  • Function:
  • 1. Load the texture
  • 2, to provide high-performance mathematical operations
  • 3. Provide common shaders
  • 4. Provide views and view controllers

To put it simply, GLKit is designed to make it easier and easier for iOS developers to use OpenGL ES or OpenGL. It encapsulates a bunch of libraries so we can just write the core code.

While Apple has dropped OpenGL ES, iOS developers can continue to use it.

Second, use GLKit for view rendering

1, GLKView

GLKView inherits UIView and provides the View for drawing. Let’s look at the default implementation of GLKView using OpenGL ES to draw content:

  • 1, initialize view – (instancetype)initWithFrame:(CGRect)frame context:(EAGLContext *)context; Initialize the new view.

  • 2. Set the view’s proxy

  • DrawableDepthFormat: drawableStencilFormat: drawableStencilFormat: drawableStencilFormat: drawableStencilFormat DrawableMultisample Specifies the format of the multisample buffer

  • DrawableHeight Specifies the height (in pixels) of the underlying cache object.

  • Context stores the state of the OpenGL ES context used to draw the contents of a view. – (void)bindDrawable; Binds the underlying FrameBuffer object to an OpenGL ES enableSetNeedsDisplay Boolean value that specifies whether the view responds to messages that invalidate the view’s contents. – (void)display; Redraw the view content immediately. Snapshot UIImage type that draws the view content and returns it as a new image object.

  • Void FrameBuffer – (void)deleteDrawable; Deletes a drawable object associated with a view.

  • – (void)glkView:(glkView *)view drawInRect:(CGRect)rect; Draw view content (proxy must be implemented)

2, GLKViewController

GLKViewController inherits FROM UIViewController (extends to standard UIKit design mode for managing and rendering the contents of a drawing view)

  • 1. Set the frame rate

    PreferredFramesPerSecond Rate at which the view controller calls the view and updates the view content, default is 30.

    FramesPerSecond The actual rate at which the view controller calls the view and updates the view contents.

  • 2. Configure the GLKViewController agent

  • 3, control frame update: paused Boolean value, rendering loop has been paused. PauseOnWillResignActive Specifies whether the view controller automatically pauses the rendering loop when the current program reactivates the active state. ResumeOnDidBecomeActive Boolean for view control to automatically resume the rendering loop when the current application becomes active.

  • 4. Get updates about the View: the number of frames that framesPerSecond has sent since its creation. TimeSinceFirstResume The amount of time that has elapsed since the view controller first resumed sending the update event. TimeSinceLastResume The amount of time since the last time the view controller resumed sending the update event. TimeSinceLastUpdate and the amount of time that has elapsed since the last view controller called the delegate method. TimeSinceLastDraw The amount of time that has elapsed since the last time the view controller called the view display method.

  • 5, implement proxy method:

    - (void)glkViewControllerUpdate:(GLKViewController *)controller;Handling update events

    - (void)glkViewController:(GLKViewController *)controller willPause:(BOOL)pause;Pause/resume notification

3, GLKBaseEffect

GLKBaseEffect is a simple lighting/shading system provided by GLKit for OpenGL based rendering.

  • 1, name Effect:

    Label names an Effect.

  • 2. Configure model view transformation:

    Transform binding effects are applied to vertex data model views, projections, and texture transformations.

  • 3. Configure lighting effect:

    LightingType is used to calculate the lighting strategy for each fragment, GLKLightingType.

typedef NS_ENUM(GLint, GLKLightingType)
{
    GLKLightingTypePerVertex,
    GLKLightingTypePerPixel
} NS_ENUM_AVAILABLE(10_8, 5_0);
Copy the code

GLKLightingTypePerVertex means performing lighting calculations on each vertex in the triangle and then interpolating within the triangle. GLKLightingTypePerPixel means that the input for the lighting calculation is inserted into the triangle and the lighting calculation is performed on each fragment.

  • 4. Configure lighting:

    LightModelTwoSided Boolean value representing computed illumination on both sides of the primitive. Material Calculates the material properties used to render the pixel lighting. LightModelAmbientColor The color of the environment in which the effect is applied to all the pixels rendered. Light0, light1, light2 are the first, second, and third lighting attributes in the scene respectively. Note: GLKit supports up to 3 lights.

  • 5. Configuration texture:

    Texture2d0 is readonly’s first texture property. Texture2d1 is readonly, the second texture property. The order in which textureOrder textures are applied to render primitives. ** Note: ** supports a maximum of two textures and three lights, so GLKit has limitations. If you want to support multiple textures, you can’t use GLKit, you have to write your own.

  • 6. Configuration atomization:

    Fog Applies to the fog property of the scene.

  • 7. Configure color information:

    ColorMaterialEnabled A Boolean value that calculates whether the color vertex property is used when lighting interacts with the material. UseConstantColor A Boolean value indicating whether constant colors are used. ConstantColor does not provide the constantColor used for each vertex color data.

  • 8. Prepare the drawing effect:

    – (void) prepareToDraw; Prepare the render effect (synchronize all effect changes to maintain a consistent state when drawing). Note: Must be written before drawing.

GLKit test

The mind map is as follows:

First I’m going to create a project with a default storyboard, and for convenience, I’m going to change the Class type of the built-in View to GLKView, or we can create it with alloc.

Then we import the header GLKit in the.h file and change the parent class of the ViewController to GLKViewController.

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>

@interface ViewController : GLKViewController
Copy the code

Next import the header file in the.m file.

#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
Copy the code

Define two global variables EAGLContext and GLKBaseEffect

@interface ViewController(a)
{
    EAGLContext *context;
    GLKBaseEffect *cEffect;
}
@end
Copy the code

1. OpenGL ES related initialization

Let’s create a method called setUpConfig to initialize OpenGL ES

1) initialize context & set the current context

  • Initialization context:
context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
Copy the code

EAGLContext is the Apple iOS platform implementation of OpenGL ES rendering layer. The parameter represents which OpenGL ES API is used for initialization. OpenGL ES 1 uses a fixed pipeline. There is little difference between 2 and 3.

KEAGLRenderingAPIOpenGLES1 = 1, kEAGLRenderingAPIOpenGLES2 = 2, kEAGLRenderingAPIOpenGLES3 = 3.

  • Set the current context:
[EAGLContext setCurrentContext:context];
Copy the code

2) get GLKView & set context

GLKView *view = (GLKView *) self.view;
view.context = context;
Copy the code

3) Configure the render cache for view creation

(1). drawableColorFormat: Color cache format

Summary: OpenGL ES has a cache that stores the colors that will be displayed on the screen. You can use its properties to set the color format of each pixel in the buffer.

view.drawableColorFormat = >GLKViewDrawableColorFormatRGBA8888;
Copy the code

GLKViewDrawableColorFormatRGBA8888 = 0, the default cache the smallest part of each pixel (RGBA) using 8 bit, (so 4 bytes per pixel, 4 * 8 bit). GLKViewDrawableColorFormatRGB565, if your APP allows a smaller range of color, can set this. Makes your APP consume less resources (memory and processing time)

(2). drawableDepthFormat: Deep cache format

view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
Copy the code

GLKViewDrawableDepthFormatNone = 0 means no depth buffer GLKViewDrawableDepthFormat16, GLKViewDrawableDepthFormat24, If you want to use this property (usually used in 3 d games), you should choose GLKViewDrawableDepthFormat16 or GLKViewDrawableDepthFormat24. The difference here is using GLKViewDrawableDepthFormat16 will consume fewer resources.

Here is the complete code for the setUpConfig method:

- (void)setUpConfig {
    // 1. Initialize context & set current context
    context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
    // Check whether the context was successfully created
    if(! context) {NSLog(@"Create ES context Failed");
    }
    // Sets the current context
    [EAGLContext setCurrentContext:context];
    
    //2. Get GLKView & set context
    GLKView *view =(GLKView *) self.view;
    view.context = context;
        
    //3. Configure the render cache created by the view.
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    
    //4. Set the background color
    glClearColor(1.0.0.1.0);
}
Copy the code

2. Load vertex/texture coordinate data

Create another method called setUpVertexData to load vertex/texture coordinate data.

1) Set vertex array (vertex coordinates and texture coordinates) :

I’m putting the vertex coordinates and the texture coordinates in one array, and you can put them in two arrays, but I think it’s easier to do it in one array, and if you have two arrays, you have to create two buffers.

   GLfloat vertexData[] = {
       0.5.0.5.0.0f,    1.0f, 0.0f, / / right
      0.5.0.5.0.0f,    1.0f, 1.0f, / / right
      0.5.0.5.0.0f,    0.0f, 1.0f, / / left
       
      0.5.0.5.0.0f,    1.0f, 0.0f, / / right
       0.5.0.5.0.0f,    0.0f, 1.0f, / / left
      0.5.0.5.0.0f,   0.0f, 0.0f, / / lower left
   };
Copy the code

We have two triangles here, so we have six vertices. The first three elements make up vertex coordinates, the fourth and fifth elements make up two-dimensional texture coordinates, and so on. The value range of texture coordinate system [0,1]; The origin is the lower left corner (0,0); So (0,0) is the lower left corner of the texture image, and the point (1,1) is the upper right corner.

2) Open up vertex cache:

  • Vertex arrays: The developer has the option to set the function pointer to pass the vertex data directly from memory when calling the draw method, that is, the data was previously stored in memory, called vertex arrays
  • Vertex cache: Better performance is to pre-allocate a block of video memory to which vertex data is pre-passed. This part of video memory is called the vertex buffer.

(1) Create vertex buffer identifier ID

GLuint bufferID;
glGenBuffers(1, &bufferID);
Copy the code

The first parameter to glGenBuffers(GLsizei n, GLuint *buffers) is to indicate that there is a buffer. Vertex Buffer Objects (VBO)

(2) Bind vertex buffer (clear function)

glBindBuffer(GL_ARRAY_BUFFER, bufferID);
Copy the code

The first parameter of glBindBuffer(GLenum target, GLuint buffer) represents what it is used for, and GL_ARRAY_BUFFER represents the array buffer.

(3) Copy vertex array data to vertex cache (memory — >GPU memory)

glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
Copy the code

glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)

The target parameter: specifies the type of data, as in glBindBuffer above.

Size parameter: How big the data is.

Data: Address of data. This is an array, so the name of the array is the first address.

Usage parameter: drawing mode, static drawing or dynamic drawing.

3) Open the read channel:

(1) It is off by default

In iOS, all vertex shader Attribute variables are turned off by default for performance reasons. Meaning that vertex data is not available on the shader side (server side). Even if you already use the glBufferData method, copy the vertex data from memory to the vertex cache (GPU memory). So, must open the channel by glEnableVertexAttribArray method, specify the access attributes, can let the vertex shaders to be able to access to the data from CPU to GPU.

Note: data on the GPU is visible, the shader can read data, is determined by whether to enable the corresponding attribute, that’s the function of glEnableVertexAttribArray, allowed to read the vertex shader GPU (server) data.

(2) the method introduction A, glEnableVertexAttribArray method:

glEnableVertexAttribArray(GLuint index)
Copy the code

Function: Enable the attribute channel function.

The index parameters: GLKVertexAttribPosition, normal GLKVertexAttribNormal, color GLKVertexAttribColor, texture 1 GLKVertexAttribTexCoord, Texture 2 GLKVertexAttribTexCoord1

B, glVertexAttribPointer;

glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
Copy the code

Function: Upload vertex data to video memory (set the appropriate way to read data from buffer)

  • Parameter list:

Indx parameter: specifies the index value of the vertex attribute to be modified

2, size parameter: read the number (step) each time. (Position is composed of 3 (x,y,z), color is 4 (R, G, B, A), and texture is 2)

The type parameter specifies the data type of each component in the array. Available symbolic constants are GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, and GL_FLOAT, starting with GL_FLOAT.

Normalized parameter: Specifies whether data values are normalized (GL_TRUE) or converted to a normalized value (GL_FALSE) when accessed.

5, Stride parameter: specify the offset between continuous vertex attributes. If 0, the vertex attributes are understood to mean that they are tightly packed together. The initial value is 0

PTR: Specifies a pointer to the first component of the first vertex property in the array. The initial value is 0

Here is the complete code for the setUpVertexData method:

- (void)setUpVertexData {
    // 1. Set the vertex array (vertex coordinates, texture coordinates)
    GLfloat vertexData[] = {
        0.5.0.5.0.0f,    1.0f, 0.0f, / / right
        0.5.0.5.0.0f,    1.0f, 1.0f, / / right
        0.5.0.5.0.0f,    0.0f, 1.0f, / / left
        
        0.5.0.5.0.0f,    1.0f, 0.0f, / / right
        0.5.0.5.0.0f,    0.0f, 1.0f, / / left
        0.5.0.5.0.0f,   0.0f, 0.0f, / / lower left
    };
    //2. Create a vertex buffer
    //(1). Create a vertex cache identifier ID
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    //(2). Bind vertex buffer.
    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
    //(3). Copy vertex array data to vertex cache (GPU memory)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
    
    //3. Open read channel.
    // Vertex coordinate data
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
    
    // Texture coordinate data
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
}
Copy the code

3. Load texture data (GLBaseEffect)

Create another method called setUpTexture to load the texture data (using GLBaseEffect).

Note: because the texture origin is: lower left (0,0); View origin is: upper left corner (0,0); Therefore, when set the options parameters of texture, need to preach GLKTextureLoaderOriginBottomLeft flip, or texture is upside down. That’s the solution in GLKit, not so convenient in OpenGL ES.

- (void)setUpTexture {
    //1. Get the texture image path
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@" How much more" ofType:@"jpg"];
    
    //2. Set texture parameters
    // The origin of the texture coordinates is the lower left corner, but the image shows that the origin should be the upper left corner.
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
    
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
    
    //3. Use Apple GLKit to provide GLKBaseEffect to complete shader work (vertex/chip)
    cEffect = [[GLKBaseEffect alloc]init];
    cEffect.texture2d0.enabled = GL_TRUE;
    cEffect.texture2d0.name = textureInfo.name;
}
Copy the code

4, implement the proxy method GLKViewDelegate

The GLKView object makes its OpenGL ES context the current context and binds its framebuffer to the target of the OpenGL ES rendering command. The delegate method should then draw the contents of the view.

// Draw the contents of the view
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    / / 1.
    glClear(GL_COLOR_BUFFER_BIT);
    
    //2. Prepare to draw
    [cEffect prepareToDraw];
    
    //3. Start drawing, using a triangle, starting from the 0th vertex, draw a total of 6
    glDrawArrays(GL_TRIANGLES, 0.6);
}
Copy the code

5. Final call

- (void)viewDidLoad {
    [super viewDidLoad];
    //1.OpenGL ES related initialization
    [self setUpConfig];
    
    //2. Load vertex/texture coordinate data
    [self setUpVertexData];
    
    //3. Load texture data (using GLBaseEffect)
    [self setUpTexture];  
}
Copy the code

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