OpenGL learning notes I

OpenGL learning notes I


Refer to the official website Hello Triangle
The purpose of this note is to refine the key content and better master the content of opengl in combination with your own understanding and translation

1, Render pipeline

The division of Graphics Pipeline (mostly translated as pipeline, which actually refers to the process that a pile of original graphics data passes through a transmission pipeline and finally appears on the screen after various changes) is roughly as follows:

The functions of each part are as follows:

  1. The main function of vertex shader is to transform 3D coordinates into another kind of 3D coordinates
    At the same time, the coordinates are transformed.

  2. Primitive assembly takes the output of vertex shader as input to assemble basic primitives (triangles, etc.).

  3. Geometry shader generates new primitives that are used in the new geometry.

  4. Rasterization stage maps primitives into pixels to generate fragments for fragment shader shading. Before fragment shader runs, invisible parts will be clipped to improve rendering efficiency.

  5. The fragment shader calculates the final color of pixels, which is also the place where all OpenGL advanced effects are produced. It will calculate the final pixel value using the data in the 3D scene (illumination, shadow, light color and so on).

  6. Alpha testing and blending. Alpha is transparency, which is used for perspective division.

A rendering pipeline should have at least two parts: vertex shader and fragment shader. Vertex shader is used to construct the most basic points, and fragment shader is used to directly output pixels. The middle part involving vertex changes can be ignored directly, and there can be no 3D scene, lighting and other information.

2, Normalized device coordinate

I don't think the official translation of normalized device coordinate here is very good. Normalized translation is much easier to understand. This coordinate refers to that the coordinate input of OpenGL must be between [- 1.0f, +1.0f], such as the following three points:

float vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
    };

3, Vectors in vertex shaders

The vector in GLSL has four dimensions rgbw, w is used for perspective division;
rgbw is data of float type. A float is 4 bytes, so a vertex in the vertex shader needs 12 bytes. There is no redundancy between vertex data, which is tightly packed, and there is no gap between values. If you use c language a lot, you will smile when you read it. This is the usual routine of void * and buffer in c language. In fact, it is true, When I read the following opengl syntax about the use of int * and buffer processing, I found that the memory processing idea of c language has played a great role in opengl data processing.

4, Draw triangle

I'll put out the codes in this part together with the codes in the exercises after class. The notes are detailed. Please see the notes for details:
Core function main function, which provides functions to draw triangles, draw rectangles (drawSquare()), draw two independent triangles (drawTwoTriangles()), and create different shader programs to draw two triangles with different colors (drawTwoTrianglesWithDifferentColor()).

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#pragma comment(lib,"glfw3.lib")

using namespace std;

float vertices[];

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
unsigned int creatShaderProc();

void drawTriangle(); 		//Basic triangle drawing
void drawSquare();			//Draw a rectangle
void drawTwoTriangles();	//Draw two triangles
unsigned int creatShaderProcOrange();	//Create an orange Shader program
void drawTwoTrianglesWithDifferentColor();	//Draw two triangles of different colors

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);  //Set glfw maximum version
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//Set glfw minimum version
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //Set to core mode
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    //create a window
    GLFWwindow* window = glfwCreateWindow(600, 600, "LearnOpenGL", NULL, NULL);

    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window); //Set as current window

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);  //The callback function of the current window to change the window size

    //Initialize glad to facilitate glfs function call
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    glViewport(0, 0, 200, 300); //Set the position and size of the display area

    //Render Loop 
    while (!glfwWindowShouldClose(window))
    {

        processInput(window);  //Detect the input and handle it accordingly

        //Rendering instructions
        //Clear screen
        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);  //Status setting function: set the screen color after emptying, which is dark blue-green at this time
        glClear(GL_COLOR_BUFFER_BIT);  //Status use function: only clear the color buffer, and other buffer bit parameters include GL_DEPTH_BUFFER_BIT and GL_STENCIL_BUFFER_BIT
        
        //drawSquare();     // Normal splicing of two triangles
        //drawTwoTriangles();   // Two separate triangles
        drawTwoTrianglesWithDifferentColor();   //Two different colors of triangles


        glfwSwapBuffers(window);  //Swap the color buffer and display it to the window
        glfwPollEvents();  //Check the trigger event, update the window status, and call the corresponding callback function
    }

    glfwTerminate();  //Release / delete allocated resources
    return 0;

}
//Callback function when changing window size
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

//Check the input and whether there is a key press
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) //If the user does not press ESC, return to GLFW_RELEASE
        glfwSetWindowShouldClose(window, true);
}

//Create shader programs, create multiple shaders and link them
unsigned int creatShaderProc()
{
    //Create vertex shader, vertex shader source code
    //GLSL language GLSL330 corresponds to opengl3 Version 3 core mode
    //Multiline string R "(...)" "Medium" and (cannot have interval)
    //layout position in: input vec3: 3D vector apos: variable name
    const char ShaderSource[] = R"(
        #version 330 core  
        layout(location = 0) in vec3 aPos; 

        void main()
        {
            gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
        }
    )";
    const GLchar* vertexShaderSource = (GLchar*)&ShaderSource;  //The glShaderSource function specifies the data of this type when specifying the shader source code
    //Compiling vertex shaders
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    //Detect compilation results
    int  success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    ///
    //Create clip shader
    const char fragSource[] = R"(
    #version 330 core
    out vec4 FragColor;

    void main()
    {
        FragColor = vec4(1.0f, 0.2f, 0.2f, 1.0f);
    } 
    )";
    const GLchar* fragShaderSource = (GLchar*)fragSource;

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragShaderSource, NULL);
    glCompileShader(fragmentShader);
    ///
    //Link shader
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); //Attach shader to program object
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    //Check whether the link is successful
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        cout << "shader link to program failed!" << infoLog << endl;
    }
    return shaderProgram;
}

///Render a triangle using a VAO vertex array object
void drawTriangle()
{
    //Vertex 3D coordinates
    float vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
    };

    unsigned int VBO;
    glGenBuffers(1, &VBO);  //1: To generate the number of buffer objects, VBO: the array used to store the buffer objects
    //1. Copy the vertex array to the buffer for opengl
    //  glBindBuffer(GL_ARRAY_BUFFER, VBO);  
    //  Multiple buffers of different types can be bound at the same time
    //  Copy the data to the memory of the current binding buffer, and specify the form of graphics card management cache, STATIC,DYNAMIC,STREAM
    //  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    /*2.Set vertex attribute pointer
        For the glVertexAttribPointer function, the parameters are: location value, vertex attribute size (dimension),
        Data type, whether it is standardized (mapped to 0 or - 1 to 1), step size (interval size between continuous vertex attribute groups),
        The offset of the position data from the buffer start position
    */
    
    //  From the currently bound GL_ ARRAY_ Get the data from VBO in buffer, and the vertex attribute 0 will now be linked to his vertex data
    //  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    //  glEnableVertexAttribArray(0); // Take the vertex attribute value as the parameter, enable the vertex attribute, and the vertex attribute is disabled by default

    //3. Use shader program
    //    glUseProgram(shaderProgram); // Activate program object

    //    glDeleteShader(vertexShader); // The shader object is no longer used. Delete it
    //    glDeleteShader(fragmentShader);
        // 3. Draw objects
        //someOpenGLFunctionThatDrawsOurTriangle();


        /*Save vertex attribute pointer configuration with VAO vertex array object
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);*/
        unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    //1. Bind VAO
    glBindVertexArray(VAO);
    //2. Bind VBO and read it into the buffer, and specify how the graphics card manages the cache
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    //3. Set vertex attribute pointer
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    //...

    //4. Draw objects
    unsigned int shaderProgram = creatShaderProc();
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);  //GL_TRIANGLE: type of entity to draw 0: starting index of vertex array, 3: number of vertices to draw
}

//Render a rectangle with EBO index buffer
void drawSquare()
{

    //Introduce index buffer
    float vertices[] = {  //vertex data 
    0.5f, 0.5f, 0.0f,   // Upper right corner
    0.5f, -0.5f, 0.0f,  // Lower right corner
    -0.5f, -0.5f, 0.0f, // lower left quarter
    -0.5f, 0.5f, 0.0f   // top left corner
    };

    unsigned int indices[] = { //Note that the index data starts from 0! 
        0, 2, 3, // First triangle
        0, 1, 2  // Second triangle
    };

    unsigned int VAO, VBO, EBO;
    //Bind VAO, VBO and EBO. VAO will store the call of VBO. Unbind VBO before unbinding VAO, otherwise the storage will be gone
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //Set vertex attribute pointer
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    unsigned int shaderProgram = creatShaderProc();

    //Render Loop 
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //Wireframe mode polygon: polygon GL_FRONT_AND_BACK: applied to the front and back of the drawing_ Line: draw with line
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    //glDrawArrays(GL_TRIANGLES, 0, 6); // set the count to 6 since we're drawing 6 vertices now (2 triangles); not 3!

    glBindVertexArray(0);
}

void drawTwoTriangles() {       //Draw a triangle with two vertices next to each other
	//Introduce index buffer
	float vertices[] = {  //vertex data 
	// first triangle
		-0.9f, -0.5f, 0.0f,  // left 
		-0.0f, -0.5f, 0.0f,  // right
		-0.45f, 0.5f, 0.0f,  // top 
		// second triangle
		 0.0f, -0.5f, 0.0f,  // left
		 0.9f, -0.5f, 0.0f,  // right
		 0.45f, 0.2f, 0.0f   // top 
	};

	unsigned int VAO, VBO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//Set vertex attribute pointer
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	unsigned int shaderProgram = creatShaderProc();

	//Render Loop 
	glUseProgram(shaderProgram);
	glBindVertexArray(VAO);
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Wireframe mode polygon: polygon GL_ FRONT_ AND_ Back: applied to the front and back of the drawing_ Line: draw with line
    //Draw using buffer instead of element
	glDrawArrays(GL_TRIANGLES, 0, 6); // set the count to 6 since we're drawing 6 vertices now (2 triangles); not 3!

	glBindVertexArray(0);
}


//Draw different colors
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShader1Source = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
const char* fragmentShader2Source = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n"
"}\n\0";

//Create shader programs, create multiple shaders and link them
unsigned int creatShaderProcOrange()
{
	//Create vertex shader, vertex shader source code
	//GLSL language GLSL330 corresponds to opengl3 Version 3 core mode
	//Multiline string R "(...)" "Medium" and (cannot have interval)
	//layout position in: input vec3: 3D vector apos: variable name
	const char ShaderSource[] = R"(
        #version 330 core  
        layout(location = 0) in vec3 aPos; 

        void main()
        {
            gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
        }
    )";
	const GLchar* vertexShaderSource = (GLchar*)&ShaderSource;  //The glShaderSource function specifies the data of this type when specifying the shader source code
	//Compiling vertex shaders
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//Detect compilation results
	int  success;
	char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
	}
	///
	//Create clip shader
	const char fragSource[] = R"(
    #version 330 core
    out vec4 FragColor;

    void main()
    {
        FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    } 
    )";
	const GLchar* fragShaderSource = (GLchar*)fragSource;

	unsigned int fragmentShader;
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragShaderSource, NULL);
	glCompileShader(fragmentShader);
	///
	//Link shader
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader); //Attach shader to program object
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	//Check whether the link is successful
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		cout << "shader link to program failed!" << infoLog << endl;
	}
	return shaderProgram;
}

void drawTwoTrianglesWithDifferentColor() {       //Draw a triangle with two vertices next to each other
	//Introduce index buffer
	float vertices0[] = {  //vertex data 
	// first triangle
		-0.9f, -0.5f, 0.0f,  // left 
		-0.0f, -0.5f, 0.0f,  // right
		-0.45f, 0.5f, 0.0f,  // top 
	};

	float vertices1[] = {  //vertex data 
	// second triangle
		 0.0f, -0.5f, 0.0f,  // left
		 0.9f, -0.5f, 0.0f,  // right
		 0.45f, 0.2f, 0.0f   // top  
	};

	unsigned int VAOs[2], VBOs[2];
    glGenVertexArrays(2, VAOs);
    glGenBuffers(2, VBOs);

    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices0), vertices0, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);	// Vertex attributes stay the same
	glEnableVertexAttribArray(0);


	glBindVertexArray(VAOs[1]);
	glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);	// Vertex attributes stay the same
	glEnableVertexAttribArray(0);

    unsigned int shaderProgram = creatShaderProc();
    unsigned int shaderProgramOrange = creatShaderProcOrange();
    glUseProgram(shaderProgram);
    glBindVertexArray(VAOs[0]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

	glUseProgram(shaderProgramOrange);
	glBindVertexArray(VAOs[1]);
	glDrawArrays(GL_TRIANGLES, 0, 3);

}

Keywords: Computer Vision Computer Graphics

Added by spudmclard on Sun, 13 Feb 2022 10:08:45 +0200