Introduction to Modern OpenGL

OpenGL (like Direct3D, Metal, etc.) is a graphics API, which provides the interface for specialized hardware on the GPU.

These APIs need a lot of code to optimize hardware utilization and often becomes a performance bottleneck. Need to download updates for drivers often. Also heavily rely on single core performance.

Low-level graphics APIs such as Vulkan shrinks the size of drivers, moving API closer to hardware again

Core Profile OpenGL

Removes:

Shaders handle all rendering: to draw anything you have to write your own shaders.

Shader: a user program loaded and executed in a stage of the rendering pipeline.

OpenGL 4.5 pipeline

Evolution Trend of OpenGL

Rending application can easily become CPU limited: analyse triangles/sec

CPU bottleneck:

Modern way: Put all the data to pass to the GPU in memory, and a few function calls to pass the data to the GPU.

Pipeline

Shaders replace fixed-function pipeline parts that had hard-coded functionality.

Vertex Fetch

Gets all info of the vertices of primitives to be drawn by GPU.

Vertex shader

Per-vertex execution. Produces vertices in clip space.

Replaces in the fixed-function stage:

Tessellation

[Not covered] Breaking primitives into smaller triangles. e.g. Bezier patch -> triangles.

Tessellation Control Shader (TCS)

Per-patch vertex (control points) execution. Produces tessellation output patch vertices, i.e. tessellation level factors (level of subdivision), outer and inner.

Tessellation Primitive Generator (TPG)

Per-tessellation level factors execution. Performs tessellation and generates tessellation coordinates.

Tessellation Evaluation Shader (TES)

Per-tessellation coordinate execution. Produces vertex position from tessellation coordinate

Tessellation engine

Geometry Shading

[Assume vertex shader -> geometry shader. Another optional stage.]

Per-primitive execution.

Produces either:

Can transform a primitive (e.g. one point $\rightarrow$ triangle(s))

Primitive assembly etc.

Special hardware to handle these.

Rasterization

If not clipped out, produces a set of fragments (window space pixel location, color, depth attributes)

Can interpolate any type of vertex attributes over primitives.

Fragment Shader

Per-fragment execution, hence the busiest stage. Produces color of corresponding pixels in framebuffer.

Replaces in the fixed-function stage:

Per-Fragment Operations

Special hardware operations. Includes:

Frame Buffer

Pipeline from Wright et al.

OpenGL programs

Old OpenGL

GLUT: glutMainLoop initiates an infinite event loop. In each loop, GLUT will:

New OpenGL

GLEW: Extension loading library

GLM: OpenGL Mathematics library

GLFW: Alternative to GLUT as a library for

Components

(Note: all “Objects” are identifiers of type GLuint)

Main Display function

Make Shader Program From Files

For each shader (vertex and fragment):

After creating both:

Shader programs in GLSL

Vertex Shader

#version 330 core // openGL version and profile

// input attributes from buffers (per vertex)
layout (location = 0) in vec4 vPos; 
layout (location = 1) in vec4 vColor;

// uniform variables from initialization of UniLocs (global)
uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;

// output variable to the fragment shader
out vec4 v2fColor;

void main()
{
    v2fColor = vColor;
    // mandatory: clip space position of the vertex.
    gl_Position = ProjectionMatrix * ModelViewMatrix * vPos;
}

Fragment Shader

#version 330 core

// output attributes from buffers (per fragment)
// location = 0: default color buffer
layout (location = 0) out vec4 fColor;

// input variable from the vertex shader
// must match output name from vertex shader
in vec4 v2fColor;

void main()
{
    fColor = v2fColor;
}

Alternate implementation

Use one VBO to represent multiple attributes per VAO

GLfloat vertPosColor[numVerts*2][3] = { /* alternate pos and color */ }

// for vPos
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
// for vColor
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 		(void*)(3 * sizeof(GLfloat))); 

Repeating vertices with Indexed array

// define vertPos[count][3], vertColor[count][3]
GLushort vertIndex[] = 
	{ 0, 1, 2,  3, 4, 5,  0, 5, 4,  1, 3, 5,  2, 4, 3 };

// create buffer objects for each of vertPos, vertColor, vertIndex

// Index buffer is bound to GL_ELEMENT_ARRAY_BUFFER target binding point.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertIndexBufferObj);

void MyDisplay(void) {
    // ...
    
    glBindVertexArray(VAO);
	glDrawElements(GL_TRIANGLES, sizeof(vertIndex)/sizeof(GLushort),
		GL_UNSIGNED_SHORT, 0);
    glutSwapBuffers();
}