There is only Miku

Result of work on FSGL library with OpenGL ES and code:

Next I will describe how all this was programmed, and how various interesting problems were solved.

First we initialize the OpenGL ES context, as I wrote in the previous note. Further we will consider only rendering, a brief description of the code.

The Matrix is ​​watching you

This Miku figure in the video is made up of triangles. To draw a triangle in OpenGL, you need to specify three points with x, y, z coordinates in the 2D coordinates of the OpenGL context.
Since we need to draw a figure containing 3D coordinates, we need to use the projection matrix. We also need to rotate, zoom, or do anything with the model – for this, the model matrix is used. There is no concept of a camera in OpenGL, in fact, objects rotate around a static camera. For this, the view matrix is used.

To simplify the implementation of OpenGL ES – it does not have matrix data. You can use libraries that add missing functionality, such as GLM.

Shaders

In order to allow the developer to draw whatever and however he wants, it is necessary to implement vertex and fragment shaders in OpenGL ES. A vertex shader must receive rendering coordinates as input, perform transformations using matrices, and pass the coordinates to gl_Position. A fragment or pixel shader – already draws the color/texture, applies overlay, etc.

I wrote the shaders in GLSL. In my current implementation, the shaders are embedded directly into the main application code as C strings.

Buffers

The vertex buffer contains the coordinates of the vertices (vertices), this buffer also receives coordinates for texturing and other data necessary for shaders. After generating the vertex buffer, you need to bind a pointer to the data for the vertex shader. This is done with the glVertexAttribPointer command, where you need to specify the number of elements, a pointer to the beginning of the data and the step size that will be used to walk through the buffer. In my implementation, the binding of vertex coordinates and texture coordinates for the pixel shader is done. However, it is worth mentioning that the transfer of data (texture coordinates) to the fragment shader is carried out through the vertex shader. For this, the coordinates are declared using varying.

In order for OpenGL to know in what order to draw the points for triangles – you need an index buffer (index). The index buffer contains the number of the vertex in the array, with three such indices you get a triangle.

Textures

First, you need to load/generate a texture for OpenGL. For this, I used SDL_LoadBMP, the texture is loaded from a bmp file. However, it is worth noting that only 24-bit BMPs are suitable, and the colors in them are not stored in the usual RGB order, but in BGR. That is, after loading, you need to replace the red channel with blue.
Texture coordinates are specified in the UV format, i.e. it is necessary to transmit only two coordinates. The texture is output in the fragment shader. To do this, it is necessary to bind the texture to the fragment shader.

Nothing extra

Since, according to our instructions, OpenGL draws 3D via 2D – then to implement depth and sampling of invisible triangles – we need to use sampling (culling) and a depth buffer (Z-Buffer). In my implementation, I managed to avoid manual generation of the depth buffer using two commands glEnable(GL_DEPTH_TEST); and sampling glEnable(GL_CULL_FACE);
Also, be sure to check that the near plane for the projection matrix is ​​greater than zero, since depth checking with a zero near plane will not work.

Rendering

To fill the vertex buffer, index buffer with something conscious, for example the Miku model, you need to load this model. For this, I used the assimp library. Miku was placed in a Wavefront OBJ file, loaded using assimp, and data conversion from assimp to vertex, index buffers was implemented.

Rendering takes place in several stages:

  1. Rotate Miku using the model matrix rotation
  2. Clearing the screen and depth buffer
  3. Drawing triangles using the glDrawElements command.

The next step is to implement WebGL rendering using Emscripten.

Source code:
https://github.com/demensdeum/OpenGLES3-Experiments/tree/master/8-sdl-gles-obj-textured-assimp-miku
Model:
https://sketchfab.com/models/7310aaeb8370428e966bdcff414273e7