Chapter 2:Hello Triangle: An OpenGL ES2.0 example
This chapter goes over the basics of the required steps how to drawn a triangle to commonly demonstrate the necessary steps.
Hello Triangle Example
Remember though, OpenGL ES 2.0 is fully shader based, which means you can’t draw any geometry without having the appropriate shaders loaded and bound.
Below shows the main steps about how to drawn a triangle.
declare an ESContext and initialize it.
ESContext esContext;
UserData userData;
esInitialize(&esContext);
esContext.userData = &userData;
The ESContext is passed into all of the ES framework utility functions and contains all of the necessary information about the program that the ES framework needs.
The reason for passing around a context is that the sample programs and the ES code framework do not need to use any global data.
The ESContext has a member variable named userData that is a void*. Each of the sample programs will store any of the data that are needed for the application in userData.
The other elements in the ESContext structure are intended only to be read by the user application. Other data in the ESContext structure include information such as the window width and height, EGL context, and callback function pointers.
create the window
esCreateWindow(&esContext, "Hello Triangle", 320, 240, ES_WINDOW_RGB);
esCreateWindow funciton use EGL to create an on-screen render surface that is attached to a window.
initialize everything needed to run the program.
if(!Init(&esContext)) {
return 0;
}
Init function do the following works:
- load and compile vertex & fragment shader
GLbyte vShaderStr[] =
"attribute vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"}; \n";
GLbyte fShaderStr[] =
"precision mediump float; \n"
"void main() \n"
"{ \n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
"} \n";
...
GLuint shader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
...
// Load the shader source
glShaderSource(shader, 1, &vShaderStr, NULL);
glShaderSource(fragment, 1, &fShaderStr, NULL);
// Compile the shader
glCompileShader(shader);
glCompileShader(fragment);
The gl_FragColor is a special built-in variable that contains the final output color for the fragment shader.
从代码可知:vPosition为attribute 0, fragment shader只是将颜色设置为 (1.0, 0.0, 0.0, 1.0)。
- create program
GLuint programObject = glCreateProgram();
- attach shader to program
glAttachShader(programObject, shader);
glAttachShader(programObject, fragment);
- bind vPosition to attribute 0
glBindAttribLocation binds the vPosition attribute declared in the vertex shader to location 0
// Bind vPosition to attribute 0
glBindAttribLocation(programObject, 0, "vPosition");
- link the program
// Link the program
glLinkProgram(programObject);
- clear color buffer(与glClear的区别)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
register a callback function that will be called to render the frame.
esRegisterDrawFunc(&esContext, Draw);
After setting above, we can set drawing parameters.
- set viewport
glViewport informs OpenGL ES of the origin, width, and height of the 2D rendering surface that will be drawn to.
UserData *userData = esContext->userData;
GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f};
// Set the viewport: left-top x, left-top y, width, height
glViewport(0, 0, esContext->width, esContext->height);
- clear color buffer
In OpenGL ES, there are multiple types of buffers that are involved in drawing: color, depth, and stencil.
In the Hello Triangle example, only the color buffer is drawn to. At the beginning of each frame, we clear the color buffer using the glClear function.
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
- use the program object
// Use the program object
glUseProgram(programObject);
- load the vertex data and draw
The vertex positions need to be loaded to the GL and connected to the vPosition attribute declared in the vertex shader.
As you will remember, earlier we bound the vPosition variable to attribute location 0.
// Load the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices); glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
- swap buffer to smoothly draw primitives.
Double buffering is adopted to avoid seeing artifacts as partial updates to the framebuffer where displayed.
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
This function informs EGL to swap the front buffer and back buffer. The parameters sent to eglSwapBuffers are the EGL display and surface. These two parameters represent the physical display and the rendering surface, respectively.
enter into the main message processing loop until the window is closed
esMainLoop(&esContext);
难点
- 理解attribute值设置的问题(vPosition的值如何设置),及attribute与location对应关系。
- 理解glClear与glClearColor区别