Introduction to the

This article records my first Opengl drawing color rectangle process, may I describe the content is not accurate, but also please correct

implementation

Configuration layer

+(Class)layerClass{
    return [CAEAGLLayer class];
}
Copy the code

Replace the Layer of the current View with the CAEAGLLayer class, where OpengL’s drawing content is displayed.

Self.layer.opaque = YES; self.layer.opaque = YES; self.layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];Copy the code

CAEAGLLayer can be configured with additional attributes:

KEAGLDrawablePropertyRetainedBacking incoming Boolean value, said whether keep drawing, if set to NO, the next time will be redrawn. KEAGLDrawablePropertyColorFormat Set the layer color buffer format, which is used by the EAGLContext object to create the storage of the render buffer. 32 – bit RGBA format

Configuring context

        _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
        if(! _context) {return; } // Set the current context to the one we createdif(! [EAGLContextsetCurrentContext:_context]) {
            return; }}Copy the code

Set buffer (render buffer and frame buffer)

// Return n render buffer object handles in the buffer. These handles are not guaranteed to be consecutive integers, but are definitely not used. GLuint renderbuffer[1]; glGenRenderbuffers(ARRAY_SIZE(renderbuffer), renderbuffer); GlBindRenderbuffer (GL_RENDERBUFFER, renderbuffer[0]); // Verify that the binding was created successfullyif (glIsRenderbuffer(renderbuffer[0]) == GL_TRUE) {
        NSLog(@"Successfully generated render cache"); } // Allocate storage space for buffer objects. // Set the Frame Buffer, which is roughly the same as the render Buffer. glGenFramebuffers(ARRAY_SIZE(framebuffer), framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer[0]);if (glIsFramebuffer(framebuffer[0]) == GL_TRUE) {
        NSLog(@"Frame cache bound successfully"); } / / the relevant buffer attached to the frame buffer glFramebufferRenderbuffer (GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[0]); GlDeleteRenderbuffers (ARRAY_SIZE(renderbuffer), renderbuffer); GlDeleteFramebuffers (ARRAY_SIZE(framebuffer), framebuffer);Copy the code

Render cache: it is a highly efficient memory area managed by OpenGL ES. The data in render cache is meaningful only when it is associated with a frame cache object, and the image cache format must be consistent with the rendering format required by OpenGL ES.

Frame cache: It is a direct image of the picture displayed on the screen, also called a Bit Map or raster. Each storage unit of the frame cache corresponds to a pixel on the screen, and the entire frame cache corresponds to a frame of image.

Function to explain

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[0]); Parameters:

target: The specified frame buffer target must be GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, or GL_FRAMEBUFFER. (GL_FRAMEBUFFER = GL_DRAW_FRAMEBUFFER); attachment: GL_COLOR_ATTACHMENT(0~ I) –> GL_DEPTH_ATTACHMENT –> GL_DEPTH_ATTACHMENT –> GL_DEPTH_ATTACHMENT –> GL_DEPTH_ATTACHMENT –> GL_DEPTH_ATTACHMENT GL_STENCIL_ATTACHMENT –> renderbuffertarget: must be GL_RENDERBUFFER, the specified renderbuffertarget renderbuffer: renderbuffer object handle.

Prepare shader source code

In OpenGL, everything is in 3D space, whereas screens and Windows are 2D arrays of pixels, so much of OpenGL’s work is about converting 3D coordinates into 2D pixels that fit your screen. The process of converting 3D coordinates into 2D coordinates is handled by the graphics rendering pipeline of OpenGL. In OpenGL, everything is in 3D space, whereas screens and Windows are 2D arrays of pixels, so much of OpenGL’s work is about converting 3D coordinates into 2D pixels that fit your screen. The process of converting 3D coordinates into 2D coordinates is handled by the graphics rendering pipeline of OpenGL

** Shaders ** are small programs that run on a GPU. These small programs run for a specific part of the graphics rendering pipeline. At its most basic, a shader is simply a program that converts input to output. Shaders are also very independent programs because they cannot communicate with each other; The only communication between them is through inputs and outputs.

Shaders are written in a C-like language called GLSL. GLSL is tailored for graphical computing and contains some useful features for vector and matrix operations.

Vertex shader

OpenGL ES 3.0// Accept the input variable layout(location = 0)in vec3 position;
layout(location = 1) invec3 color; // Out vec3 outColor; // this is equivalent to the C main function voidmainGl_Position = vec4(position[0],position[1],position[2], 1.0); outColor = color; }Copy the code

The first part of the graphics rendering pipeline is the Vertex Shader, which takes a single Vertex as input. A Vertex is a collection of data in 3D coordinates. Vertex data is represented by Vertex attributes, which can contain any data we want to use.

Fragment shader

#version 300 es

precision mediump float; // Indicates the accuracy of the datainvec3 outColor; out vec4 FragColor; // The output color voidmain() {FragColor = vec4 (outColor. X, outColor. J y, outColor. J z, 1.0); the; }Copy the code

The main purpose of the fragment shader is to calculate the final color of a pixel, and this is where all of OpenGL’s advanced effects are generated. Typically, fragment shaders contain data about the 3D scene (such as lighting, shadows, light colors, and so on) that can be used to calculate the color of the final pixels.

After all the corresponding color values are determined, the final objects are sent to the final stage, which we call the Alpha test and Blending stage. This phase checks the corresponding depth (and Stencil) value of the fragment to determine whether the pixel is in front of or behind other objects and whether it should be discarded. This phase also checks the alpha value (which defines an object’s transparency) and blends the objects. So, even if the output color of one pixel is calculated in the fragment shader, the final pixel color may be completely different when rendering multiple triangles.

Create a shader object

Static GLuint createGLShader(const char *shaderText, GLenum shaderType) {// Create a shader based on the incomingtypeParameter creates a new vertex or fragment shader and returns the new shader object handle //GL_VERTEX_SHADER GL_FRAGMENT_SHADER GLuint shader = glCreateShader(shaderType); // Provide the shader source code for the shader object. Shader --> shader object handle // count --> number of shader source strings // string --> array pointer to string // length --> pointer to an integer array that holds the size of the art shader string and the number of elements count. GlShaderSource (shader, 1, &shaderText, NULL); // The shader is the shader handle glCompileShader(shader); // Call this method to get the shader source code compiled successfully and other related information // The second parameter, pname, tells you what to query for /* GL_COMPILE_STATUS --> Is compile_successful returns GL_TRUE GL_INFO_LOG_LENGTH --> query source code compiled length GL_SHADER_SOURCE_LENGTH --> query source code length GL_SHADER_TYPE --> query shader type () GL_DELETE_STATUS --> Whether the shader is marked for deletion */ int compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);if(! compiled) { GLint infoLen = 0; glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLen);if (infoLen > 1) {
            char *infoLog = (char *)malloc(sizeof(char) * infoLen);
            if(infoLog) {// Retrieve information log // parameters: Shader shader object handle // maxLength Specifies the size of the buffer for storing information logs. // length Specifies the length of the log for writing information, which does not need to be known. // infoLog Specifies the pointer for storing log information (shader, infoLen, NULL, infoLog); GLlog("Error compiling shader: %s\n", infoLog); free(infoLog); }} // Delete the shader object, // If a shader is linked to a program object, this method does not delete the shader immediately. Instead, it marks the shader as deleted, and when the shader is no longer connected to any program object, its memory is freed.return 0;
    }
    
    return shader;
}
Copy the code

Creating program objects

GLuint Program = glCreateProgram(); GLuint Program = glCreateProgram(); GLuint vertShader = createGLShader(vertext, GL_VERTEX_SHADER); GLuint fragShader = createGLShader(frag, GL_FRAGMENT_SHADER); // Chip shaderif (vertShader == 0 || fragShader == 0) {
        return0; In ES 3.0, each program object must be attached to a vertex shader and a fragment shader. GlAttachShader (program, vertShader); glAttachShader(program, fragShader); GlLinkProgram (program); glLinkProgram(program); glLinkProgram(program); glLinkProgram(program); // Check whether the link is successful. glGetProgramiv(program, GL_LINK_STATUS, &success);if(! success) { GLint infoLen; GlGetProgramiv (program, GL_INFO_LOG_LENGTH, &infoLen);if (infoLen > 1) {
            GLchar *infoText = (GLchar *)malloc(sizeof(GLchar)*infoLen + 1);
            if(infoText) { memset(infoText, 0x00, sizeof(GLchar)*infoLen + 1); GlGetProgramInfoLog (program, infoLen, NULL, infoText); GLlog("%s", infoText); free(infoText); GlValidateProgram (program); glValidateProgram(program); glValidateProgram(program) } } glDeleteShader(vertShader); glDeleteShader(fragShader); // Delete program object glDeleteProgram(program);return0; } /* * After linking shaders, generate executable programs. */ / disconnect the specified program object and fragment shader glDetachShader(program, vertShader); glDetachShader(program, fragShader); // mark the shader to delete glDeleteShader(vertShader); glDeleteShader(fragShader);Copy the code

A program object is a container object to which shaders are linked, which in turn produces the final executable.

Input vertex data

// Triangle + color coordinates static GLfloatAre [] = {/ / point coordinates / / color 0.5 f, 0.5 f to 0.0 f to 1.0 f to 0.0 f to 0.0 f to 0.5 f to 0.5 f to 0.0 f to 0.0 f to 1.0 f to 0.0 f to 0.5 f to 0.5 f to 0.0 f, 0.0 f, f 0.0, 1.0 f to 0.5 f, f 0.5, 0.0, f 1.0 f, f 0.0, 1.0} f; Static unsigned int indices[] = {0, 1,2,3}; unsigned int VAO,VBO,EBO; // Create VAO objects,VBO objects,EBO objects glGenVertexArrays(1, &vao); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); // bind VAO VBO EBO glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); GlBufferData (GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); GlVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0); / / activate 0 variables, for the sake of performance, if do not activate the shader can not accept the data glEnableVertexAttribArray (0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
        glEnableVertexAttribArray(1);
Copy the code

VAO VBO EBO

Draw code without using VAO VBO:

    static GLfloatAre [] = {0.0 f, f, 0.5 0.0 f to 0.5 f to 0.5 f to 0.0 f to 0.5 f to 0.5 f to 0.0 f}; GLint posSlot = glGetAttribLocation(_program,"position");
    glVertexAttribPointer(posSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(posSlot);
    
    static GLfloatColors [] = {0.0 f, f, 1.0 1.0 f, f 1.0, 0.0 f, f 1.0, 1.0 f, f 1.0, 0.0} f; GLint colorSlot = glGetAttribLocation(_program,"color");
    glVertexAttribPointer(colorSlot, 3, GL_FLOAT, GL_FALSE, 0, colors);
    glEnableVertexAttribArray(colorSlot);
Copy the code

VBO

As shown in the example above, the transfer of a normal vertex array requires frequent transfer of vertex data from CPU to GPU during drawing, which is inefficient. To speed up the display, the graphics card added an extended VBO (Vertex Buffer Object), or Vertex cache. It directly creates a cache area in GPU to store vertex data, because it is used to cache vertex data, so it is called vertex cache. Using vertex cache can greatly reduce the overhead of data copy between CPU and GPU, thus significantly improving the efficiency of program running.

function

Void glGenBuffers (GLsizei n, GLuint* buffers);

Parameter n: Specifies the number of vertex cache objects to be created. Parameter buffers: Stores the created vertex cache object handle

Void glBindBuffer (GLenum target, GLuint Buffer);

Target: specifies the target of the binding. The value can be GL_ARRAY_BUFFER (for vertex data) or GL_ELEMENT_ARRAY_BUFFER (for index data) buffer: handle to the vertex cache object

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

Target: specifies the binding target. The value can be GL_ARRAY_BUFFER (for vertex data) or GL_ELEMENT_ARRAY_BUFFER (for index data). Size: specifies the size of the vertex buffer, in bytes. Data: used to initialize data in the vertex cache. The value can be NULL, indicating that only space is allocated, and then initialized by glBufferSubData. Usage: Indicates how the cache area will be used. Its main purpose is to optimize the cache area. For example, frequently modified data may be placed in the GPU cache for fast operation.

usage:

GL_STATIC_DRAW indicates that the cache will not be modified. GL_DYNAMIC_DRAW indicates that the cache will be changed periodically. GL_STREAM_DRAW indicates that the cache will be changed frequentlyCopy the code

Void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);

Offset: indicates the start offset of the data to be updated. Size: indicates the number of data to be updated, also in bytes. Data: data used for updating;

Void glDeleteBuffers (GLsizei n, const GLuint* buffers)

N: specifies the number of vertex cache objects. Buffers: Specifies the handle of the vertex cache object

VAO

The full name of VAO is Vertex Array Object. It is not used to store data, but it is related to vertex drawing. It is positioned as a state object, which records and stores state information. VAO records the information needed to do a drawing, including where the data is, what the format of the data is, and so on. A VAO can be thought of as a container that can contain multiple VBos. Because it further accommodates VBO, the rendering efficiency will be further improved. Vertex array objects are currently supported in OpenGL ES3.0 and above.

function

GlGenVertexArrays (GLsizei n, GLuint* Arrays);

N: number of vertices array objects: handles to vertices array objects

2, set the vertex array object to the current vertex array object glBindVertexArray (GLuint Array);

Arrays: Handles to vertices array objects

GlDeleteVertexArrays (GLsizei n, const GLuint* Arrays);

N: number of vertices array objects: handles to vertices array objects

use

As written in the code, after the VAO is bound, subsequent VBO operations are stored in the currently bound VAO. This records the current drawing state. The next time you want to draw the current graph, you only need to bind the current VAO again for subsequent drawing operations. Using VAO with OpenGL ES2.0 requires a separate API.

GLvoid glGenVertexArraysOES(GLsizei n, GLuint *arrays)
GLvoid glBindVertexArrayOES(GLuint array);
GLvoid glDeleteVertexArraysOES(GLsizei n, const GLuint *arrays);; 
GLboolean glIsVertexArrayOES(GLuint array);
Copy the code

EBO

EBO (Element Buffer Object, also known as Index Buffer Object, IBO) can be used when existing graphics are drawn and vertex data is reused.

function

1. Create EBO(similar to VBO)

unsigned int EBO;
glGenBuffers(1, &EBO);
Copy the code

Bind EBO and copy the index to the buffer

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
Copy the code

3. Use glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0). Alternative glDrawArrays

Added the function

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

This function is used to pass vertex attributes to the vertex shader argument:

Index: location size of the variable corresponding to the vertex shader: indicates the number of components corresponding to the vertex property. In other words, the receiver is a vector of several bits. If 3 is written, it is represented as VEC3. The receiver is a three-dimensional vector. Must be 1 to 4. Type: indicates the type of each component. The available symbolic constants are GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, and GL_FLOAT, The initial value is GL_FLOAT; Normalized: specifies whether to normalize each component, i.e., float, stride: specifies the offset between contiguous vertex attributes

This function is used differently with or without VBO, but PTR is indeed a pointer to vertex data when VBO is not applied. When using VBO, the vertex data is already copied to video memory, where PTR is represented as a cheap amount of buffer data.

None EBO: glVertexAttribPointer(colorSlot, 3, GL_FLOAT, GL_FALSE, 0, colors);

Have the EBO:

static GLfloatAre [] = {/ / point coordinates / / color 0.5 f, 0.5 f to 0.0 f to 1.0 f to 0.0 f to 0.0 f to 0.5 f to 0.5 f to 0.0 f to 0.0 f to 1.0 f to 0.0 f to 0.5 f to 0.5 f to 0.0 f, 0.0 f, f 0.0, 1.0 f to 0.5 f, f 0.5, 0.0, f 1.0 f, f 0.0, 1.0} f; . (VBO and other code)....... glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
Copy the code

Here, attribute 0 is closely related to attribute 1, and the components of both attribute 0 and attribute 1 are 3, starting with attribute 0. Stride = 6*sizeof(float).stride = 6*sizeof(float).stride = 6*sizeof(float).stride = 6*sizeof(float).stride = 6*sizeof(float).stride = 6*sizeof(float).stride = 6*sizeof(float)

draw

EBO of use:

glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0); Parameter: model: Specifies which primitives to render (what shapes to draw the points into). Optional:

GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_FAN, GL_TRIANGLES, count: GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_unsigned_int. indices: A pointer to an indexed array is represented as an offset when VBO is used and 0 is passed if it is closely connected.

Do not use the EBO

glDrawArrays(GL_TRIANGLES, 0, 3); Parameter: model has the same meaning as above: first indicates the starting index of vertex data, and 0 if starting from scratch. Count indicates the number of vertex data to be passed in.

The last show

[_context presentRenderbuffer:GL_RENDERBUFFER];