OpenGL Advanced | Draw a triangle

1. Prepare drawing data

  • VBO(Vertex Buffer Object)

        In opengl, all data must be stored in video memory , and CPU data can be transmitted to GPU through VBO (Vertex Buffer Object).

        VBO (Vertex Buffer Object) is a mechanism in OpenGL for storing vertex data in video memory so that the GPU can quickly access and process it. VBO is a buffer object, similar to an array or list in the CPU, which can be used to store attributes such as vertex positions, colors, and texture coordinates. Using VBO can avoid the process of copying vertex data from CPU to GPU every time rendering, thus improving rendering efficiency.

GLuint vbo;
void Init()
{
    float data[] = {
        -0.2f,-0.2f,-0.6f,1.0f,
        0.2f,-0.2f,-0.6f,1.0f,
        -0.2f,0.2f,-0.6f,1.0f
    };
    glGenBuffers(1, &vbo);                                                   //需要1个VBO,把vbo写入到显卡进去,供后续操作
    glBindBuffer(GL_ARRAY_BUFFER, vbo);                                      //把vbo设置到卡槽上
    //glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12, nullptr,GL_STATIC_DRAW);//只在GPU上开辟内存不传数据
    glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12,data,GL_STATIC_DRAW);      //将数据从cpu传到Gpu,此后data数据可删除。
    glBindBuffer(GL_ARRAY_BUFFER, 0);                                        //卡槽重新绑定,防止误操作
}

Two, write Shader

1. Vertex shader

        The vertex shader, test.vs file is as follows:

attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
void main()
{
	gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}
  •  uniform和attribute

In OpenGL, uniforms and attributes are two different types used to pass data in shader programs.

  1. Uniform variables: Uniform variables are global variables used to pass data between different shader stages. They are accessible anywhere in the shader program, independent of vertices or fragments. Uniform variables are usually used to pass global data, such as transformation matrices, lighting parameters, textures, etc. In a program, you can use the glGetUniformLocation function to get the location (or slot) of a Uniform variable, and then use the glUniform function to pass the value to the Uniform variable.

  2. Attribute variable: Attribute variable is a vertex attribute used to receive input data for each vertex in the vertex shader. They are usually used to represent the position, color, normal and other attributes of vertices. Attribute variables can only be used in the vertex shader, and each vertex will have a corresponding attribute value. In the program, you can use the glGetAttribLocation function to get the location (or slot) of the Attribute variable, and then use the glVertexAttribPointer function to set the format and location of the attribute data.

        Regarding the allocation of slots (location), both Uniform variables and Attribute variables are allocated from 0. Their position (or slot) value within the shader program can be obtained using the glGetUniformLocation and glGetAttribLocation functions. For Uniform variables, you can use the glUniform function to pass the value to the Uniform variable at the specified location. For the Attribute variable, you can use the glVertexAttribPointer function to bind attribute data to the Attribute variable at the specified location.

        It should be noted that the way and usage of Uniform variables and Attribute variables to transfer data between different shader stages are different. Uniform variables are used to pass global data throughout the shader program, while Attribute variables are used to receive attribute data for each vertex in the vertex shader.

2. Fragment shader

        Fragment shader, test.fs file is as follows:

#ifdef GL_ES
precision mediump float;
#endif
void main()
{
	gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}

3. Compile Shader

1. Related functions

  • glCreateShader

GLuint glCreateShader(GLenum shaderType);

        shaderType indicates the type of shader to create, two types of shaders are supported:

  1.  A shader of type GL_VERTEX_SHADER is a shader designed to run on a programmable vertex processor.
  2.  A shader of type GL_FRAGMENT_SHADER is a shader designed to run on a programmable fragment processor.

        glCreateShader creates an empty shader object and returns a non-zero value (Shader ID) that can be referenced. Shader objects are used to maintain source code strings that define shaders.

  • glShaderSource

        glShaderSource is the function used to set the shader source code in OpenGL. Its function is to load the shader source code in string form into the specified shader object for subsequent compilation and linking. Specifically, the glShaderSource function has four parameters:

void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
  1. shader: The ID of the shader object whose source code is to be set.
  2. count: The number of source code strings to set.
  3. string: Pointer to an array of source code strings.
  4. length: the length of each string in the source code string array, if it is NULL, the length of the string is used by default.
  • glCompileShader

        glCompileShader is the function used to compile shader objects in OpenGL. Its function is to compile the shader source code loaded by the glShaderSource function into an executable shader program for OpenGL rendering.

Specifically, the glCompileShader function has one parameter:

void glCompileShader(GLuint shader);
  1. shader: The ID of the shader object to compile.
  • glGetShaderiv

            glGetShaderiv is one of the functions for obtaining shader object parameters in OpenGL. Its function is to obtain specific parameter information of a specified shader object, such as compilation status, number of parameters, parameter types, and so on. Specifically, the glGetShaderiv function has three parameters:

void glGetShaderiv(GLuint shader, GLenum pname, GLint *params);
  1. shader: The ID of the shader object to query.

  2. pname: the name of the parameter to be queried, optional values ​​include:

    • GL_SHADER_TYPE: shader type, the value is GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
    • GL_DELETE_STATUS: Whether the shader has been marked for deletion.
    • GL_COMPILE_STATUS: shader compilation status, the value is GL_TRUE or GL_FALSE.
    • GL_INFO_LOG_LENGTH: The length of the shader information log, in characters.
    • GL_SHADER_SOURCE_LENGTH: The length of the shader source code in characters.
    • GL_NUM_SHADER_BINARY_FORMATS: Number of supported shader binary formats.
    • GL_SHADER_BINARY_FORMATS: List of supported shader binary formats.
    • Other parameters, such as GL_SHADER_IDENTITY_MATRIX and so on.
  3. params: Pointer to variables storing return parameter values.

  • glDeleteShader

        glDeleteShader is one of the functions for deleting shader objects in OpenGL. Its function is to delete the shader object that has been created and release the resources in the video memory. Specifically, the glDeleteShader function has one parameter:

void glDeleteShader(GLuint shader);
  1. shader: The ID of the shader object to delete.

        It should be noted that if the shader object has been attached to the program object, the shader object cannot be deleted until the program object is linked. Therefore, it is usually recommended to delete the shader object immediately after using it, so as not to take up too much video memory resources.

2. Give an example

GLuint CompileShader(GLenum shaderType, const char* shaderCode)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &shaderCode, nullptr);
    glCompileShader(shader);
    GLint compileResult = GL_TRUE;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
    if (compileResult == GL_FALSE) {
        char szLog[1024] = { 0 };
        GLsizei logLen = 0;
        glGetShaderInfoLog(shader, 1024, &logLen, szLog);
        printf("Compile Shader fail error log : %s \nshader code :\n%s\n", szLog, shaderCode);
        glDeleteShader(shader);
        shader = 0;
    }
    return shader;
}

Fourth, link into a program

1. Related functions

  • glCreateProgram

        glCreateProgram is one of the functions in OpenGL to create shader program objects. Its role is to create a shader program object and return its ID, which is used to manage the linking process of multiple shader objects. Specifically, the glCreateProgram function has no parameters and only returns a shader program object ID of type GLuint:

GLuint glCreateProgram(void);
  • glAttachShader

        glAttachShader is one of the functions in OpenGL to attach a shader object to a program object. Its role is to attach one or more shader objects to a program object in preparation for subsequent link operations. Specifically, the glAttachShader function has two parameters:

void glAttachShader(GLuint program, GLuint shader);
  1. program: The ID of the program object to attach to.
  2. shader: The ID of the shader object to attach.
  • glLinkProgram

        glLinkProgram is one of the functions for linking shader programs in OpenGL, which is used to link all attached shader objects in a program object into an executable program. During the linking process, OpenGL will match and connect the variable names and types between different shaders, and finally generate a shader program that can be executed by the GPU. Specifically, the glLinkProgram function has one parameter:

void glLinkProgram(GLuint program);
  1. program: The ID of the program object to link.

        It should be noted that the glLinkProgram function will store the link log in the program object after the link is completed. We can query the link status by calling the glGetProgramiv function, or get the link log by calling the glGetProgramInfoLog function. Additionally, if the link fails, the status of the program object will be marked as link failed, and the program object cannot be used.

  • glDetachShader

        glDetachShader is one of the functions in OpenGL that detach shader objects from program objects. Its role is to separate a shader object from a program object, so that the shader object can be used in other program objects. Specifically, the glDetachShader function has two parameters:

void glDetachShader(GLuint program, GLuint shader);
  1. program: The ID of the program object from which the shader object is to be detached.
  2. shader: The ID of the shader object to detach.
  • glGetProgramiv

        glGetProgramiv is one of the functions in OpenGL to get the parameters of the shader program object. Its function is to obtain specific parameter information of the specified shader program object, such as link status, number of parameters, parameter types, and so on. Specifically, the glGetProgramiv function has three parameters:

void glGetProgramiv(GLuint program, GLenum pname, GLint *params);
  1. program: The ID of the shader program object to query.

  2. pname: the name of the parameter to be queried, optional values ​​include:

    1. GL_DELETE_STATUS: Whether the program has been marked for deletion.
    2. GL_LINK_STATUS: Program link status, the value is GL_TRUE or GL_FALSE.
    3. GL_VALIDATE_STATUS: Program verification status, the value is GL_TRUE or GL_FALSE.
    4. GL_INFO_LOG_LENGTH: The length of the link or verification log, in characters.
    5. GL_ATTACHED_SHADERS: Number of shader objects attached.
    6. GL_ACTIVE_ATTRIBUTES: The number of active vertex attributes.
    7. GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: The maximum length of the active vertex attribute name.
    8. GL_ACTIVE_UNIFORMS: The number of active Uniform variables.
    9. GL_ACTIVE_UNIFORM_MAX_LENGTH: The maximum length of the active Uniform variable name.
    10. Other parameters, such as GL_PROGRAM_BINARY_RETRIEVABLE_HINT and so on.
  3. params: Pointer to variables storing return parameter values.

  • glDeleteProgram

        glDeleteProgram is one of the functions for deleting shader program objects in OpenGL. Its function is to delete the created shader program object and release the resources in the video memory. Specifically, the glDeleteProgram function has one parameter:

void glDeleteProgram(GLuint program);
  1. program: The ID of the shader program object to delete.

2. Give an example

GLuint CreateProgram(GLuint vsShader, GLuint fsShader) {
    GLuint program = glCreateProgram();
    glAttachShader(program, vsShader);
    glAttachShader(program, fsShader);
    glLinkProgram(program);
    glDetachShader(program, vsShader);
    glDetachShader(program, fsShader);
    GLint nResult;
    glGetProgramiv(program, GL_LINK_STATUS, &nResult);
    if (nResult == GL_FALSE) {
        char log[1024] = { 0 };
        GLsizei writed = 0;
        glGetProgramInfoLog(program, 1024, &writed, log);
        printf("create gpu program fail,link error : %s\n", log);
        glDeleteProgram(program);
        program = 0;
    }
    return program;
}

5. Read shader source code to GPU program

GLuint program;
void Init()
{
    //...
    //准备绘图数据
    //...
    
    int fileSize = 0;
    unsigned char * shaderCode = LoadFileContent("Res/test.vs", fileSize);
    GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);
    delete shaderCode;
    shaderCode = LoadFileContent("Res/test.fs", fileSize);
    GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);
    delete shaderCode;
    program = CreateProgram(vsShader, fsShader);
    glDeleteShader(vsShader);
    glDeleteShader(fsShader);
}

6. Read the variables in the shader

1. Related functions

  • glGetUniformLocation

        glGetUniformLocation is one of the functions in OpenGL used to get the location (or slot) of a Uniform variable. It is used to query the location of the Uniform variable in the specified shader program object, so that it can be assigned later. Specifically, the glGetUniformLocation function has two parameters:

GLint glGetUniformLocation(GLuint program, const GLchar *name);
  1. program: The ID of the shader program object to query for the Uniform variable.
  2. name: The name of the Uniform variable. ( The name of the Uniform variable must exactly match the name of the Uniform variable defined in the shader program.)
  • glGetAttribLocation

        glGetAttribLocation is one of the functions used to get the location (or slot) of Attribute variables in OpenGL. It is used to query the location of the Attribute variable in the specified shader program object for subsequent binding of vertex data. Specifically, the glGetAttribLocation function has two parameters:

GLint glGetAttribLocation(GLuint program, const GLchar *name);
  1. program: The ID of the shader program object to query the Attribute variable.
  2. name: The name of the Attribute variable. (The name of the Attribute variable must exactly match the name of the Attribute variable defined in the shader program.)

2. Give an example

GLint positionLocation,modelMatrixLocation,viewMatrixLocation,projectionMatrixLocation;
void Init()
{
    //...
    //准备绘图数据
    //...

    //...
    //读取shader源码到GPU程序
    //...

    positionLocation = glGetAttribLocation(program, "position");
    modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");
    viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");
    projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
}

Seven, set the MVP matrix

1. MVP Matrix

        Setting the MVP (Model-View-Projection) matrix in OpenGL is one of the important steps for transforming and projecting objects. Usually, the Model matrix represents the model transformation of the object, the View matrix represents the observation transformation of the camera, and the Projection matrix represents the projection transformation.

        For the Model matrix and View matrix, the default is the identity matrix, so there is no need to explicitly set them, and the identity matrix can be created by using the default constructor of glm::mat4 in the glm library.

        For the Projection matrix, you can use the glm::perspective function in the glm library to set it.

glm::mat4 glm::perspective(float fov, float aspect, float near, float far);
  1. fov: Field of View, in radians.
  2. aspect: The aspect ratio of the viewport (width divided by height).
  3. near: The distance from the near plane to the camera.
  4. far: the distance from the far plane to the camera.

        This function will return a perspective projection matrix where all vertices in the near and far planes and within the frustum will be rendered. It can be applied to the Projection matrix.

2. Set the MVP matrix

glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
void SetViewPortSize(float width, float height)
{
    projectionMatrix = glm::perspective(glm::radians(45.0f), width / height, 0.1f, 1000.0f);
}

8. Set the Uniform variable

1.glUniformMatrix4fv

        glUniformMatrix4fv is one of the functions in OpenGL for passing 4x4 matrix data to Uniform variables. It is used to pass one or more 4x4 matrix values ​​to a Uniform variable of type Matrix4 defined in the shader program.

void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
  1. location: The location (or slot) of the Uniform variable to pass data to.
  2. count: The number of matrices to pass. If you pass only one matrix, count is 1.
  3. transpose: Specifies whether the matrix should be transposed before passing it. Normally, you can set it to GL_FALSE.
  4. value: Pointer to the GLfloat array containing the data to be passed. Matrix data is stored in arrays in column-major order.

2. Code example

void Draw()
{
    glUseProgram(program);//启用着色器程序
    glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));   //将模型矩阵传递给着色器程序中的模型矩阵Uniform变量modelMatrixLocation
    glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));    //将视图矩阵传递给着色器程序中的视图矩阵Uniform变量viewMatrixLocation
    glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));  //将投影矩阵传递给着色器程序中的投影矩阵Uniform变量projectionMatrixLocation
    glUseProgram(0);      //停用着色器程序
}

9. Read vbo data and draw a triangle

1. Related functions

  • glVertexAttribPointer

        The glVertexAttribPointer function is used to specify the pointer of the vertex attribute and set related parameters.

void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);

The parameters are explained as follows:

  1. index: The index of the vertex attribute, corresponding to the vertex attribute variable in the shader program.
  2. size: The number of components of the vertex attribute, for example, 3 means that the vertex attribute is composed of three components (such as the position attribute is x, y, z).
  3. type: The data type of the vertex attribute, for example, GL_FLOAT means floating-point data.
  4. normalized: Specifies whether to normalize non-floating point data, usually set to GL_FALSE.
  5. stride: The byte offset between the vertex attributes, used to locate the data of different attributes in the vertex data.
  6. pointer: The pointer of the vertex attribute data, pointing to the starting position in the vertex data buffer.
  • glEnableVertexAttribArray

        The glEnableVertexAttribArray function is used to enable the vertex attribute array of the specified index.

void glEnableVertexAttribArray(GLuint index);

The parameters are explained as follows:

  1. index: The index of the vertex attribute, corresponding to the vertex attribute variable in the shader program.
  • glDrawArrays

        The glDrawArrays function is used to perform primitive drawing operations based on vertex arrays.

void glDrawArrays(GLenum mode, GLint first, GLsizei count);

The parameters are explained as follows:

  1. mode: Specifies the primitive type to be drawn, for example, GL_POINTS means to draw points, GL_TRIANGLES means to draw triangles, etc.
  2. first: Specify the starting index in the vertex array, indicating which vertex to start drawing from.
  3. count: Specifies the number of vertices to draw.

2. Code example

void Draw()
{
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //...
    //设置Uniform变量
    //...

    glBindBuffer(GL_ARRAY_BUFFER, vbo);  //将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER)
    glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0);   //定义位置属性
    glEnableVertexAttribArray(positionLocation);  //启用位置属性索引为positionLocation的顶点属性数组
    glDrawArrays(GL_TRIANGLES, 0, 3);    //执行绘制操作。该函数指定了绘制的模式、起始顶点索引和顶点数量。
    glBindBuffer(GL_ARRAY_BUFFER, 0);    //解绑顶点缓冲对象
}

10. Supplementary Notes

        The shader is usually called a shader, and its function is to render the points on the CPU. The shader is executed in parallel on the GPU. For example, the data of three vertices will be processed in parallel on the three cores.

        For example, if we draw a triangle, we need three vertex data. The vertex shader will be executed three times, each time with different vertex data as input. ( There is no need to create a separate vertex shader file for each vertex, we can use the same vertex shader file for all three vertices, just provide each vertex with a different position attribute as input), and use the uniform variable mvpMatrix Perform a model-view-projection transformation. ( That is: the position is different, the m, v, and p matrices are the same )

  • Vertex matrix of 3*4 data, three vertices:
    float data[] = {
        -0.2f,-0.2f,-0.6f,1.0f,
        0.2f,-0.2f,-0.6f,1.0f,
        0.0f,0.2f,-0.6f,1.0f
    };
  • Vertex shader file: 
attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

Guess you like

Origin blog.csdn.net/weixin_39766005/article/details/130586491