Catalogue of series articles
Easy to understand OpenGL ES 3.0 (I) essential knowledge for entry!!
Easy to understand OpenGL ES 3.0 (II) rendering triangle
Easy to understand OpenGL ES 3.0 (III) NDK integrated opengl
preface
Next, in the previous article, we will talk about vbo, vao, and the default vertex storage. So explain why you use these things by drawing simple coordinate lines and triangles= v=!!!
design sketch

Draw coordinate lines and triangles
Well, it's like hello world, an entry-level program. So draw two more coordinate lines.
It's similar to the background drawing process in the previous article. In general, it's better to do appropriate things in the rendering callback with the help of the environment provided by GLSurfaceView. It's not so detailed. See the previous article for details.
The header file omits the implementation of triangledemo H (omitted)
TriangleDemo.cpp
// // Created by Lai on 2020/11/7. // #include "TriangleDemo.h" #include "../util/logUtil.h" #include "../util/GLUtil.h" #include <GLES3/gl3.h> void TriangleDemo::draw(int screenW, int screenH) { //LOGCATE("TriangleSample::Draw"); GLfloat triangleVertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, }; GLfloat lineVertices[] = { -1.0f, 0.0f, 0.0f, 1.0, -0, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, }; if(m_ProgramObj == 0) return; glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(1.0, 1.0, 1.0, 1.0); // Use the program object glUseProgram (m_ProgramObj); // Load the vertex data glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, lineVertices ); glDrawArrays (GL_LINES , 0, 4); glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices ); glEnableVertexAttribArray (0); glDrawArrays (GL_TRIANGLES , 0, 3); glUseProgram (GL_NONE); } void TriangleDemo::Init() { if (m_ProgramObj != 0) return; if(m_ProgramObj != 0) return; char vShaderStr[] = "#version 300 es \n" "layout(location = 0) in vec4 vPosition; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" "gl_PointSize = 50.0; \n" "} \n"; char fShaderStr[] = "#version 300 es \n" "precision mediump float; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n" "} \n"; LOGCATE("init TriangleDemo"); m_ProgramObj = GLUtil::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader); } void TriangleDemo::OnSurfaceChanged(int width, int height) { LOGCATE("MyGLRenderContext::OnSurfaceChanged [w, h] = [%d, %d]", width, height); glViewport(0, 0, width, height); }
Compile the shader, fill the vertex coordinate data with glVertexAttribPointer, and then draw with glDrawArrays
void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
Take the vertex coordinates of a line as an example
GLfloat lineVertices[] = { -1.0f, 0.0f, 0.0f, 1.0, -0, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, }; // Draw line / start from 0 / 4 vertices in total glDrawArrays (GL_LINES , 0, 4);
GLenum mode: draw the model. Have the following shapes
GL_APIENTRY glEnableVertexAttribArray (GLuint index);
Turn on vertex position to allow the shader to read GPU data.
The parameter corresponds to the location of the vertex shader, so it is glEnableVertexAttribArray(0);
char vShaderStr[] = "#version 300 es \n" "layout(location = 0) in vec4 vPosition; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" "gl_PointSize = 50.0; \n" "}
The calling sequence can only be called before the drawing is called.
Then finish the renderings
Usual vertex assignment
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, lineVertices );
The first parameter 0: corresponds to the position of the vertex shader. For example, the index using the layout(location = 0) Attribute in the vertex shader
The second parameter 3: size, attribute variable data is composed of several elements, x,y,z,w; There are four at most. The vertex data used in this example is three.
Third parameter GL_FLOAT: the type of vertex data. The example here is composed of floating-point values
The fourth parameter, normalized, is usually set to GL_FALSE
The fifth parameter is 0: step size. Write 0 and let opengl decide
The last parameter: without vbo, directly fill in the vertex data
You can see more detailed explanations
In learnopongl Hello, triangle
The api is like this. Let's talk about vertex storage. Now this way is to get data from memory, that is, there are few vertices, so it doesn't matter if you just draw four vertices and make filters. However, if there are more vertex data, you need to consider optimization. Therefore, in order to shorten the distance between cpu and gpu and improve efficiency, this VBO appears.
Vertex buffer objects (VBO)
In general, a large number of vertices are stored in GPU memory (commonly known as video memory) without running around from CPU - > GPU.
The general steps are: generate - > bind - > fill in data
Take the vertex of the triangle to illustrate
Generate VBO cache
//1: the number of vbos to be created, //&Trianglevbo: store buffer objects glGenBuffers(1, &triangleVBO);
Binding data
//GL_ARRAY_BUFFER: the type of buffer object. Here is a vertex buffer type //Triangle VBO: the buffer object that needs to be bound, that is, what is generated above glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
Fill in data
//GL_ARRAY_BUFFER: plug point data for the current VBO of the specified type //sizeof(lineVertices): data size. sizeof calculation //lineVertices: vertex data //GL_STATIC_DRAW: GL_ STATIC_ Draw indicates that the data will not or will hardly change. glBufferData(GL_ARRAY_BUFFER, sizeof(lineVertices), lineVertices, GL_STATIC_DRAW);
Assign values to vertex attributes
//0: layout corresponding to vertex shader (location = 0) //3: Vertex attributes are more or less a group. For example, mine is x,y,z, so it's 3. The color may be 4 because there are r,g,b,a //GL_FLOAT: data type //0: step size //0: it's 0 directly here. You don't need to fill in vertex data. Go back to the currently bound buffer to find it. Offset of buffer start position glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
Then draw
glDrawArrays(GL_TRIANGLES, 0, 3);
Specific code, in order to facilitate understanding, do not get any polymorphic encapsulation. Directly copy and change from the previous one, and directly add the code
Header file omission
TriangleDemoVBO.cpp
// // Created by Lai on 2020/11/15. // #include "TriangleDemoVBO.h" #include "../util/logUtil.h" #include "../util/GLUtil.h" #include <GLES3/gl3.h> void TriangleDemoVBO::draw(int screenW, int screenH) { //LOGCATE("TriangleSample::Draw"); GLfloat triangleVertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, };; GLfloat lineVertices[]= { -1.0f, 0.0f, 0.0f, 1.0, -0, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, }; if(m_ProgramObj == 0) return; glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(1.0, 1.0, 1.0, 1.0); // Use the program object glUseProgram (m_ProgramObj); //Bind object GL_ARRAY_BUFFER: it can be used to save the vertex array data set by glVertexAttribPointer() glBindBuffer(GL_ARRAY_BUFFER, lineVBO); //GL for the current VBO plug point data_ STATIC_ Draw indicates that the data will not or will hardly change. glBufferData(GL_ARRAY_BUFFER, sizeof(lineVertices), lineVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_LINES, 0, 4); //Bind object GL_ARRAY_BUFFER: it can be used to save the vertex array data set by glVertexAttribPointer() glBindBuffer(GL_ARRAY_BUFFER, triangleVBO); //GL for the current VBO plug point data_ STATIC_ Draw indicates that the data will not or will hardly change. glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLES, 0, 3); glEnableVertexAttribArray(0); glUseProgram (GL_NONE); } void TriangleDemoVBO::Init() { if (m_ProgramObj != 0) return; if(m_ProgramObj != 0) return; char vShaderStr[] = "#version 300 es \n" "layout(location = 0) in vec4 vPosition; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" "gl_PointSize = 50.0; \n" "} \n"; char fShaderStr[] = "#version 300 es \n" "precision mediump float; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " fragColor = vec4 ( 0.0, 0.0, 0.0, 1); \n" "} \n"; LOGCATE("init TriangleDemoVBO"); m_ProgramObj = GLUtil::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader); //create object glGenBuffers(1, &triangleVBO); glGenBuffers(1, &lineVBO); } void TriangleDemoVBO::OnSurfaceChanged(int width, int height) { LOGCATE("MyGLRenderContext::OnSurfaceChanged [w, h] = [%d, %d]", width, height); glViewport(0, 0, width, height); }
I wonder if you have found that glbindbuffer - > glbufferdata - > draw is required for each drawing All need to be bound and filled. It's OK for me to switch between the two models. If there are more vertex data, it's not easy to manage. It will be troublesome to bind to the corresponding VBO, so a thing called VAO comes out to represent whose VBO it is. It's like a class needs a head teacher. It's easy to find it then.
Vertex array object (VAO)
The creation of VAO is similar to that of VBO
//Create VAO glGenVertexArrays(1, &triangleVAO);
binding
glBindVertexArray(triangleVAO);
Then, like writing VBO at ordinary times, follow the process
//Bind object GL_ARRAY_BUFFER: it can be used to save the vertex array data set by glVertexAttribPointer() glBindBuffer(GL_ARRAY_BUFFER, triangleVBO); //GL for the current VBO plug point data_ STATIC_ Draw indicates that the data will not or will hardly change. glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0);
In this way, this triangleVBO belongs to this triangleVAO.
So when drawing
glBindVertexArray(triangleVAO); glDrawArrays(GL_TRIANGLES, 0, 3);
It's that simple.
The specific code is omitted from the header file
// // Created by Lai on 2020/11/20. // #include <logUtil.h> #include <GLUtil.h> #include "TriangleDemoVAO.h" void TriangleDemoVAO::draw(int screenW, int screenH) { //LOGCATE("TriangleSample::Draw"); if(m_ProgramObj == 0) return; glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(1.0, 1.0, 1.0, 1.0); // Use the program object glUseProgram (m_ProgramObj); glBindVertexArray(triangleVAO); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(lineVAO); glDrawArrays(GL_LINES, 0, 4); glUseProgram (GL_NONE); } void TriangleDemoVAO::Init() { glClearColor(0.5f, 0.5f, 0.5f, 1.0f); if (m_ProgramObj != 0) return; if(m_ProgramObj != 0) return; char vShaderStr[] = "#version 300 es \n" "layout(location = 0) in vec4 vPosition; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" "gl_PointSize = 50.0; \n" "} \n"; char fShaderStr[] = "#version 300 es \n" "precision mediump float; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " fragColor = vec4 ( 1.0, 0.5, 0.0, 1); \n" "} \n"; LOGCATE("init TriangleDemoVAO"); m_ProgramObj = GLUtil::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader); GLfloat triangleVertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, }; glGenVertexArrays(1, &triangleVAO); //create object glGenBuffers(1, &triangleVBO); glBindVertexArray(triangleVAO); //Bind object GL_ARRAY_BUFFER: it can be used to save the vertex array data set by glVertexAttribPointer() glBindBuffer(GL_ARRAY_BUFFER, triangleVBO); //GL for the current VBO plug point data_ STATIC_ Draw indicates that the data will not or will hardly change. glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); GLfloat lineVertices[]= { -1.0f, 0.0f, 0.0f, 1.0, -0, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, }; glGenVertexArrays(1, &lineVAO); glGenBuffers(1, &lineVBO); glBindVertexArray(lineVAO); //Bind object GL_ARRAY_BUFFER: it can be used to save the vertex array data set by glVertexAttribPointer() glBindBuffer(GL_ARRAY_BUFFER, lineVBO); //GL for the current VBO plug point data_ STATIC_ Draw indicates that the data will not or will hardly change. glBufferData(GL_ARRAY_BUFFER, sizeof(lineVertices), lineVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); } void TriangleDemoVAO::OnSurfaceChanged(int width, int height) { LOGCATE("MyGLRenderContext::OnSurfaceChanged [w, h] = [%d, %d]", width, height); glViewport(0, 0, width, height); }
The generated VAO and VBO are similar, and can be encapsulated into tool classes in the future.
summary
As for whether to use VAO or not, VBO Look at yourself. Many vertex data can be considered. If it's helpful to you, please give me a compliment = v =!!!.