OpenGL ES rendering pipeline and shader, opengles rendering pipeline

Source: Internet
Author: User

OpenGL ES rendering pipeline and shader, opengles rendering pipeline

1. rendering pipeline

In OpenGL ES 1.0, fixed pipelines are supported, while OpenGL ES 2.0 does not support fixed pipelines and only supports programmable pipelines. What is a pipeline? What are fixed and programmable pipelines? Pipelines, also known as rendering pipelines, are called OpenGL ES rendering pipelines Because OpenGL ES performs a series of operations sequentially during rendering. Pipeline is derived from the assembly line operation in the Ford automobile production workshop. It is the same in the OpenGL ES rendering process. One operation is followed by one operation, just like the assembly line operation, this greatly improves the rendering efficiency. Shows the entire rendering pipeline:

Vertex Shader and Fragment Shader in the shadow section in the figure are programmable pipelines. The programmable pipeline means that this operation can be implemented dynamically without having to be written to the code. Dynamic Programming is generally provided by scripts. in OpenGL ES, the ability to write such scripts is also provided by the Shader Language. What are the benefits of programmable pipelines? It is convenient for us to dynamically modify the rendering process without rewriting the compilation code. Of course, it is not convenient to debug like many scripting languages.

Then, this figure is the "Architecture diagram" of OpenGL ES. Learning OpenGL ES is to learn every part of this image. Here we will give a rough introduction.

Vertex Array/Buffer objects: the Vertex data source. In this case, the Vertex input of the rendering pipeline is usually used in Buffer objects for better efficiency. In today's example, Vertex Array is used for simplicity;

Vertex Shader:Vertex shaderOperations on vertices are implemented in a programmable manner, such as coordinate space conversion, and calculation of per-vertex color and texture coordinates;

Primitive Assembly:MetaassemblyThe vertex processed by the coloring tool is assembled as a basic element in the image Assembly stage. OpenGL ES supports three basic elements: points, lines, and triangles that can be rendered by OpenGL ES. Then, the assembled elements areCrop(Clip): Keep the elements completely in the cone, discard the elements completely out of the cone, and crop the elements half out of the cone. Then, crop the elements in the cone.RemoveProcessing(Cull):This process can be encoded to determine whether to remove the front, back or all.

Rasterization: grating. In the grating phase, the basic elements are converted into two-dimensional fragment. fragment indicates the pixels that can be rendered to the screen. It contains location, color, texture coordinates, and other information, these values are calculated by interpolation of vertex information of the element. These parts are then sent to the part coloring tool for processing. This is a qualitative process from vertex data to pixels that can be rendered on the display device.

Fragment Shader: The Fragment Shader can operate the Fragment in a programmable manner. In this phase, it receives fragment, color, depth value, and template value after raster processing as the input.

Per-Fragment Operation: this stage tests and processes each piece of element output by the Cell Coloring tool to determine the final pixel used for rendering. The processing process is as follows:

Pixel ownership test: This test determines whether the position of the Pixel in framebuffer is owned by the current OpenGL ES. That is to say, to test whether a pixel is visible to the user or blocked by overlapping windows;

Scissor Test: A cropping Test that determines whether a pixel is in a cut rectangle defined by glScissor. pixels not in the cut area are cropped;

Stencel Test: Template Test. Compare the value in the template cache with a reference value for corresponding processing;

Depth Test: the Depth Test compares the Depth of the fragment in the next fragment and the frame buffer to determine which pixel is in front and which pixel is blocked;

Blending: mixing the color of the clip and the existing color values in the frame buffer, and writing the new values obtained from the mixing into the frame buffer;

Dithering: Jitter. jitter means that you can see more colors than the actual image by using limited colors, to alleviate the problem of changing colors due to the limited precision of the color value.

Framebuffer: This is the last stage of the pipeline. Stored in Framebuffer can be used to render the pixel values in the screen or texture, or read back the pixel values from Framebuffer, however, other values (such as depth values and template values) cannot be read ).

Ii. vertex shader

Next let's take a closer look at the vertex shader:

Input received by the vertex shader:

Attributes: the vertex data provided by vertext array, such as spatial location, normal vector, texture coordinate, and vertex color. It is used for data of each vertex.Attributes are available only in the vertex coloring tool, but not in the Cell Coloring tool.Attribute can be understood as the input data for each vertex. OpenGL ES 2.0 specifies that the maximum number of attributes supported by all implementations cannot be less than 8.

Uniforms: uniforms stores the read-only constant data that is passed by the application to the shader. In the vertex coloring tool, the data is usually a transformation matrix, illumination parameter, color, and so on. The variable modified by the uniform modifier is a global variable, which can be seen in both the vertex shader and the fragment shader. That is to say, if these two pointers are connected to the same application, they share the same uniform global variable set. Therefore, if the uniform variables with the same name are declared in the two colorers, make sure that the variables with the same name are identical: the same name + the same type, because they are actually the same variable. In addition, the uniform variable is stored in the constant storage area, which limits the number of uniform variables, openGL ES 2.0 also specifies that the maximum number of uniform variables to be supported by all implementations must be no less than 128, and the maximum number of uniform variables of the chip colorator cannot be less than 16.

Samplers: a special uniform used to render textures. Sampler can be used for vertex pasters and fragment pasters.

Shader program: the source code of a program stated by main, which describes the operations performed on the vertex, such as coordinate transformation. Calculate the illumination formula to generate the per-vertex color or calculate the texture coordinate.

Output of vertex coloring Er:

Varying: the varying variable is used to store the output data of the vertex coloring tool. Of course, it also stores the input data of the chip coloring tool. The varying variable will be linearly interpolated in the raster processing phase. If the vertex coloring er declares the varying variable, it must be passed to the bitwise coloring machine before it can be further passed to the next stage, therefore, the varying variables declared in the vertex coloring tool should be re-declared in the Cell Coloring tool with the same name and the same type of varying variables. OpenGL ES 2.0 also specifies that the maximum number of varying variables to be supported by all implementations cannot be less than 8.

At least the position information-built-in variable gl_Position should be output in the vertex coloring tool stage. The other two optional variables are gl_FrontFacing and gl_PointSize.

3. Cell Coloring Tool

Next, let's take a closer look at the part element coloring tool:

The metamanager accepts the following input:

Varyings, that is, gl_FragCoord, gl_FrontFacing, and gl_PointCoord. OpenGL ES 2.0 also specifies that the maximum number of varying variables to be supported by all implementations cannot be less than 8.

Uniforms: As mentioned earlier, this is a constant used for the film element coloring device, such as atomization parameters and texture parameters; openGL ES 2.0 also specifies that the maximum number of uniform variables supported by all implementations cannot be less than 16.

Samples: a special uniform used to render a texture.

Shader program: the source code of a program stated by main, which describes the operations performed on the chip.

Only the unique varying output variable-the built-in variable gl_FragColor In the vertex coloring tool stage.

4. Differences in programming between vertex coloring and fragment coloring

1. Difference in accuracy

The coloring language has three levels of precision: lowp, mediump, and highp. We can define the default precision at the beginning of the glsl script file. The following code defines that the float type uses the highp-level precision by default.

precision highp float;

In the vertex coloring phase, if the default precision is not customized by the user, both int and float are at the highp level by default. In the fragment coloring phase, if the default precision is not defined by the user, so there is really no default precision. We must place the precision descriptor before each variable. In addition, the OpenGL ES 2.0 standard does not require that all implementations support highp accuracy in the fragment phase. We can determine whether to define GL_FRAGMENT_PRECISION_HIGH to determine whether the implementation supports the highp precision in the fragment coloring tool phase, and then compile the portable code. Of course, we usually do not need to use the highp-level precision in the Cell Coloring tool phase. We recommend that you first use the mediump-level precision, the highp precision should be considered only when the effect is not good enough.

2. attribute modifiers can only be used for vertex coloring. I have already said this before.

3. Due to different precision or compilation optimization, the same calculation may have different results in the vertex coloring and fragment coloring phases, which may cause some problems. Therefore, glsl introduces the invariant modifier to modify the same variable in two coloring stages, so that the same value is obtained for the same calculation.

5. Use the vertex coloring tool and the chip coloring tool.

Well, there is enough theoretical knowledge. Let's take a look at how to add vertex pasters and fragment pasters to the code. Code. As mentioned above, the programmable pipeline is implemented by writing script files in the shader Language. These script files are equivalent to the C source code. The source code requires compilation links. Therefore, the corresponding compiler and the linker are required, the shader object and the program object are equivalent to the compiler and the linker. The shader object is loaded into the source code and then compiled into the object form (just as the C source code is compiled into the. obj file ). The compiled shader can be assembled into the program object. Each program object must be assembled with two shader objects: one vertex shader and one chip shader, then, the program object is connected to an executable file, so that the executable file can be used in render.

1. Create, load, and compile shader

First, we add a new class GLESUtils to the project so that it inherits from NSObject. Modify GLESUtils. h:

#import 
Include

@ Interface GLESUtils: NSObject

// Create a shader object, load the shader source string, and compile the shader.
//
+ (GLuint) loadShader :( GLenum) type withString :( NSString *) shaderString;

+ (GLuint) loadShader :( GLenum) type withFilepath :( NSString *) shaderFilepath;

@ End

Modify GLESUtils. m:

#import "GLESUtils.h"

@ Implementation GLESUtils

+ (GLuint) loadShader :( GLenum) type withFilepath :( NSString *) shaderFilepath
{
NSError * error;
NSString * shaderString = [NSString stringWithContentsOfFile: shaderFilepath
Encoding: NSUTF8StringEncoding
Error: & error];
If (! ShaderString ){
NSLog (@ "Error: loading shader file: % @", shaderFilepath, error. localizedDescription );
Return 0;
}

return [self loadShader:type withString:shaderString];

}

+(GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString
{
// Create the shader object
GLuint shader = glCreateShader(type);
if (shader == 0) {
NSLog(@”Error: failed to create shader.”);
return 0;
}

// Load the shader sourceconst char * shaderStringUTF8 = [shaderString UTF8String];glShaderSource(shader, 1, &shaderStringUTF8, NULL);// Compile the shader

glCompileShader(shader);

// Check the compile statusGLint 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 = malloc(sizeof(char) * infoLen); glGetShaderInfoLog (shader, infoLen, NULL, infoLog); NSLog(@"Error compiling shader:\n%s\n", infoLog ); free(infoLog); } glDeleteShader(shader); return 0;}return shader;

}

@end

The auxiliary class GLESUtils has two class methods used to follow the shader script string or shader script file to create a shader, then load it, compile it. The following describes each step in detail.

1), create/delete a shader

The glCreateShader function is used to create a shader. The GLenum type parameter indicates the shader type to be processed. It can be GL_VERTEX_SHADER or GL_FRAGMENT_SHADER, indicating the vertex shader or the shader. It returns a handle pointing to the created shader object.

The glDeleteShader function is used to destroy the shader. The parameter is the shader object handle returned by glCreateShader.

2) load the shader

The glShaderSource function is used to provide the shader source code for the specified shader. The first parameter is the shader object handle, the second parameter indicates the number of shader source code strings, the third parameter is the shader source code string array, and the fourth parameter is an int array, indicates the length that each source code string should use. If this parameter is NULL, it indicates that the source code string ends with \ 0 and the source code is specified as \ 0 when the content of the string is read, if this parameter is not NULL, the first length (the length corresponding to each string) in each source code string is read as the source code.

3) Compile shader

The glCompileShader function is used to compile the specified shader object. This will compile the source code stored in the shader object. We can use the glGetShaderiv function to query the shader object information. In this example, we can query the compilation information. In addition, we can also query GL_DELETE_STATUS, GL_INFO_LOG_STATUS, GL_SHADER_SOURCE_LENGTH, and GL_SHADER_TYPE. Here we query the compilation status. If 0 is returned, the compilation error is returned, and the error information is written to the info log. We can query the info log to obtain the error information.

2. Write a coloring script.

The interfaces provided by GLESUtils allow us to use two methods: script string or script file to provide the shader source code. Generally, the script file method provides more flexibility. (Cocos2D Source Code provides many script strings to deal with some common situations. If you are interested, you can check them ). Here, we use the script file method.

1) Add a vertex coloring script.

Right-click the Supporting Files directory, choose New File> Other> Empty, and enter VertexShader. glsl to remove the check box in target Tutorial02. The suffix glsl indicates GL Shader Language.

Edit the content as follows:

attribute vec4 vPosition; 

void main(void)
{
gl_Position = vPosition;
}

Select Tutorial02 and add VertexShader. glsl to Build Phases-> Copy Bundle Sources.

The source code of the vertex coloring script is very simple. If you have carefully read the previous introduction, you can see it at a glance. Attribute vPosition indicates the position information of vec4 input from the application, and the built-in vary variable vPosition is output. Note: The default precision is used here.

2), add a script for the part meta coloring

Add a file named FragmentShader. glsl in the same way as the vertex coloring script. edit the file as follows:

precision mediump float;

void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Do not forget to add FragmentShader. glsl to Build Phases-> Copy Bundle Sources.

The source code of the object meta-coloring script is also very simple. As mentioned earlier, the object meta-coloring either defines the default precision or adds the precision descriptor before each variable. Here, the custom float precision is mediump. Then, specify the built-in output variable gl_FragColor as red.

3. Create a program, assemble the shader, link the program, and use the program

1), create a program

Add two members to the OpenGLView class declaration of OpenGLView. h:

 GLuint _programHandle; GLuint _positionSlot;

Then add the member Method to the anonymous category in OpenGLView. m:

- (void)setupProgram;

Before-(void) render method, add its implementation:

- (void)setupProgram { // Load shaders // NSString * vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader" ofType:@"glsl"]; NSString * fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader" ofType:@"glsl"]; GLuint vertexShader = [GLESUtils loadShader:GL_VERTEX_SHADER withFilepath:vertexShaderPath]; GLuint fragmentShader = [GLESUtils loadShader:GL_FRAGMENT_SHADER withFilepath:fragmentShaderPath];
// Create program, attach shaders. _programHandle = glCreateProgram(); if (!_programHandle) { NSLog(@"Failed to create program."); return; } glAttachShader(_programHandle, vertexShader); glAttachShader(_programHandle, fragmentShader); // Link program // 

glLinkProgram(_programHandle);

// Check the link status

GLint linked;
glGetProgramiv(_programHandle, GL_LINK_STATUS, &linked );
if (!linked)
{
GLint infoLen = 0;
glGetProgramiv (_programHandle, GL_INFO_LOG_LENGTH, &infoLen );

 if (infoLen > 1) { char * infoLog = malloc(sizeof(char) * infoLen); glGetProgramInfoLog (_programHandle, infoLen, NULL, infoLog ); NSLog(@"Error linking program:\n%s\n", infoLog ); free (infoLog ); } glDeleteProgram(_programHandle); _programHandle = 0; return;}glUseProgram(_programHandle);// Get attribute slot from program//

_positionSlot = glGetAttribLocation(_programHandle, “vPosition”);
}

With the previous introduction, the above Code is easy to understand. First, we created a secondary method provided by GLESUtils from the script we created earlier to load and compile vertex shader and segment element shader. Then we created a program, assemble vertex shader and segment shader into the program object, and then use glLinkProgram to link the assembled shader so that the two shader can work together. Note: The shader can be connected during the connection process, that is, the same name and the number of variables must not exceed the range. How do we check the shader compilation and program links. If everything is correct, we can call glUseProgram to activate the program object and use it in render. Call glGetAttribLocation to obtain the slot of the variable vPosition defined in the shader in the program. With this slot, we can operate on the vPosition.

4. Example

Before calling the render method in-(void) layoutSubviews, insert a call to setupProgram:

 [self setupProgram];
[self render];

Then rewrite the render method:

- (void)render

{
glClearColor(0, 1.0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);

// Setup viewport//

glViewport(0, 0, self.frame.size.width, self.frame.size.height);

GLfloat vertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f };// Load the vertex data//

glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot);

// Draw triangle//

glDrawArrays(GL_TRIANGLES, 0, 3);

[_context presentRenderbuffer:GL_RENDERBUFFER];

}

In the newly added code, the first glViewport indicates the area on the screen where the surface will be rendered. Then, we create an array of triangle vertices, use glVertexAttribPointer to load the triangle vertex data to OpenGL ES and associate it with vPositon. Finally, use glDrawArrays to render the triangle element.

5. Compile and run

Compile and run. A red triangle is displayed in the center of the screen. Do you know why it is red? That's because the program also links to the Cell Coloring tool. In the Cell Coloring script file, we specify the gl_FragColor value as red vec4 (1.0, 0.0, 0.0, 1.0 ).

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.