How Opengl-Day2 Begins Two Weeks draws a triangle

First remember a few nouns
  • Vertex Array Object, VAO
  • Vertex Buffer Object, VBO
  • Index Buffer Objects: Element Buffer Object, EBO or Index Buffer Object, IBO
Some conceptual points
  • Everything in OpenGL is in 3D space. Screens and windows are arrays of 2D pixels. Most of OpenGL's work is to change 3D coordinates into 2D pixels that fit on the screen.
  • The 3D to 2D processing is managed by the graphics rendering pipeline.
    Pipeline: A process in which a stack of raw graphical data passes through a pipeline and changes are processed to make it appear on the screen.
    Change handling: 3D coordinates to 2D coordinates, 2D coordinates to colored pixels
    Coordinates: Accurately represents the position of a point in 2D space
    Pixel: Approximate value of this point (should be understood as approximate location, pixel fills coordinates)
Graphic Rendering Pipeline (Pipeline)
  • Function: 3D Coordinates - > Colored 2D Pixels
  • Shader: Quick data processing ()
  • Phase: Vertex Data->Vertex Shader->Shape (Primitive) Assembly->Geometry Shader->Rasterization->Fragment Shader->Testing and Mixing

Vertex data: vertex data is entered into the vertex shader
Vertex shader: 3D coordinates - > another 3D coordinate
Shape assembly: vertex shader vertex - > assembly to specified meta shape
Is the data rendered as a series of points, a triangle, or a long line? GL_POINTS, GL_TRIANGLES, GL_LINE_STRIP
Geometric Shader: A series of points in the form of primitives - > Generate new vertices to construct new primitives
Rasterization: Primitives are mapped to pixels on the final screen to generate segments for use by the segment shader
Fragment Shader: Calculate Final Color
It is also where all OpenGL advanced effects come into being. Data that usually contains 3D scenes (light, shadow, color of light) will be used to calculate the color of the final pixel
Test and Blend: Blend fragments, transparency, order of coverage, etc.

Preliminary usage process
  • Define at least one vertex shader
  • You can use the default geometry shader
  • Define at least one segment shader
Coding this process:
  1. Enter some vertex data for OpenGL. (3D coordinates)
    About coordinates
float vertices[] = {
/* X Axis, Y-Axis, Z-Axis (plane graphics do not require Z-Axis) */
	-0.5f, -0.5f, 0.0f,
	0.5f, -0.5f, 0.0f,
	0.0f, 0.5f, 0.0f
};
  1. Vertex data passed to vertex shader
    Through the vertex buffer object, a large amount of data is sent to the graphics card at one time. After the data is sent to the memory on the graphics card, the vertex shader can immediately access the vertices.
//Generate a VBO object using the glGenBuffers function and a buffer ID
unsigned int VBO;
glGenBuffers(1, &VBO);

//Binding Buffer Object Type GL_ARRAY_BUFFER is vertex buffer type
glBindBuffer(GL_ARRAY_BUFFER, VBO);

//Assign vertex data to buffer memory
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

/* 
glBufferData Is a function designed to copy user-defined data to the current binding buffer
 Parameter 1: Target buffer type GL_ARRAY_BUFFER is vertex buffer type
 Parameter 2: Specify the size of the transmitted data in bytes
 Parameter 3: The actual data you want to send
 Parameter 4: Specifies how we want the graphics card to manage the given data
    GL_STATIC_DRAW : The data will not or will hardly change.
    GL_DYNAMIC_DRAW: The data will change a lot.
    GL_STREAM_DRAW : The data changes every time it is drawn.
*/
  1. Write vertex shader (vertex shader language)
  • Version declaration
  • In keyword, declares all input vertex properties in the vertex shader, the location value of the location variable
  • Place inside a function
  • Location data is assigned to a predefined gl_Position variable
#version 330 core
layout (location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
  1. Compile Vertex Shader
    • Temporarily hard-code the above code into a code file C-style string
    • Create a shader object, referenced by ID, so the type is unsigned int
    • Provide the type of shader you need to create to glCreateShader, vertex shader GL_VERTEX_SHADER
    • Attach shader source to shader object
    • Compile
    • Check compilation success
//*Temporarily hard-code the above code in the code file**C-style string**
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";
    
//Create a shader object, referenced by ID, so the type is unsigned int
unsigned int vertexShader;

//Provide the type of shader you need to create to glCreateShader, vertex shader GL_VERTEX_SHADER
vertexShader = glCreateShader(GL_VERTEX_SHADER);

//Attach shader source to shader object
//glShaderSource function
//The first parameter is the shader object to be compiled as.
//The second parameter specifies the number of source strings passed, where there is only one.
//The third parameter is the vertex shader's true source code
//The fourth parameter is set to NULL first.
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);

//Compile
glCompileShader(vertexShader);

//Check compilation success
int  success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
//Print information if unsuccessful
if(!success)
{
    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
    std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
  1. Write fragment shaders, compile shaders
#version 330 core
out vec4 FragColor;

void main()
{
		//						R G B Transparency
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
} 

const char *fragmentShaderSource = "#version 330 core\n"
	"out vec4 FragColor;\n"
	"void main()\n"
	"{\n"
	"FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
	"}\0";

unsigned int fragmentShader;
//GL_FRAGMENT_SHADER Fragment Shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
  1. Final Link to Shader Program Object
//Create Program Object
unsigned int shaderProgram;
shaderProgram = glCreateProgram();

//Link Shader
//Additional vertex shader
glAttachShader(shaderProgram, vertexShader);
//Additional Fragment Shader
glAttachShader(shaderProgram, fragmentShader);
//link
glLinkProgram(shaderProgram);

//Determine whether a link is successful or not
int  success;
char infoLog[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success) {
    glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog);
    std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}


//Activator Object
glUseProgram(shaderProgram);
//After the glUseProgram function call, this program object is used in every shader call and rendering call
//Delete shader object after program call
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

  1. Link Vertex Properties (specify how OpenGL interprets vertex data before rendering)
    *Use the glVertexAttribPointer function to tell OpenGL how to parse vertex data (applied to vertex-by-vertex attributes)
/*
    The first parameter specifies the vertex properties that we want to configure. Remember that we used layout(location = 0) in the vertex shader to define the location value of the position vertex attribute? It can set the position value of the vertex property to zero. Because we want to pass data to this vertex attribute, here we pass in 0.
    The second parameter specifies the size of the vertex attribute. The vertex attribute is a vec3, which consists of three values, so the size is 3.
    The third parameter specifies the type of data, here is GL_ FLOAT (vec* in GLSL is composed of floating point values).
    The next parameter defines whether we want the data to be standardized (Normalize). If we set it to GL_TRUE, all data is mapped between 0 (for signed data, -1) and 1. We set it to GL_FALSE.
    The fifth parameter, called Stride, tells us the interval between consecutive sets of vertex attributes. Since the next set of location data is after three floats, we set the step size to 3 * sizeof(float). Note that because we know this array is tightly aligned (there is no gap between the two vertex attributes), we can also set it to 0 to allow OpenGL to determine the exact step size (only available if the values are tightly aligned). Once we have more vertex attributes, we have to define the interval between each vertex attribute more carefully, and we will see more examples later (Note: This parameter simply means how many bytes are between the second occurrence of this attribute and the entire array 0).
    The last parameter is of type void*, so we need to do this strange cast. It represents the Offset of the starting position of the location data in the buffer. Since the location data is at the beginning of the array, this is 0. We will explain this parameter in more detail later.
*/
//Set resolution
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//Start Vertex Properties
glEnableVertexAttribArray(0);
  1. Comprehensive Coding
    We used a vertex buffer object to initialize the vertex data into the buffer, established a vertex and a segment shader, and showed OpenGL how to link the vertex data to the vertex properties of the vertex shader. Draw an object in OpenGL, and the code looks like this:
// 0. Copy the vertex array to the buffer for OpenGL use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 1. Set vertex property pointer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 2. Use the shader program when rendering an object
glUseProgram(shaderProgram);
// 3. Draw objects
someOpenGLFunctionThatDrawsOurTriangle();
Index Buffer Object (EBO)

Increase indexing while keeping VAO and VBO unchanged

float vertices[] = {
    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 starts at 0! 
    0, 1, 3, // First triangle
    1, 2, 3  // Second triangle
};

unsigned int EBO;
glGenBuffers(1, &EBO);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

.

Keywords: C++ OpenGL

Added by xiosen on Wed, 27 Oct 2021 20:19:44 +0300