type
status
date
slug
summary
tags
category
icon
password

Overview of OpenGL and GLSL

OpenGL is a popular, cross-platform API for rendering 2D and 3D graphics. It provides a multi-stage graphics pipeline that is partially programmable using GLSL (OpenGL Shading Language). On the hardware side, OpenGL works with the GPU, while on the software side, its API is compatible with C, C++ and many other popular programming languages. One critical task of a C++/OpenGL application is to install the programmer's GLSL code onto the GPU.
GLSL is an example of a shader language, designed to run on a GPU within the context of a graphics pipeline. Other shader languages, like HLSL, work with DirectX instead of OpenGL.

The Graphics Pipeline and Shader Stages

The graphics pipeline consists of several stages, some of which are programmable in GLSL. To use GLSL in a C++/OpenGL application, you need to load GLSL programs into these shader stages. This process involves obtaining the GLSL shader code, creating OpenGL shader objects, loading the code into the objects, and using OpenGL commands to compile, link, and install the objects on the GPU.
notion image
notion image
 

vertex shader & fragment shader

To draw something with OpenGL, you need at least a vertex shader and a fragment shader. The vertex shader's primary purpose is to send a vertex down the pipeline, while the fragment shader sets the RGB color of a pixel to be displayed. OpenGL can draw only a few simple primitives, like points, lines, and triangles, which form the basis of most 3D models.

Advanced Shader Stages: Tessellation and Geometry Shaders

Tessellation is a recent addition to OpenGL, allowing for more complex terrain generation and finer control over generated triangles. Geometry shaders, on the other hand, manipulate one primitive at a time and allow generating additional primitives, enhancing the complexity of rendered models.

Rasterization and Hidden Surface Removal

Rasterization is the process of converting 3D vertices, triangles, and colors into a 2D raster or rectangular array of pixels. Hidden surface removal ensures that objects in front block the view of objects behind them, using the color buffer and depth buffer to achieve this effect.

Drawing a Point with OpenGL

Drawing a point with OpenGL involves creating a function that initializes the shader source code, compiles the shaders, and links them to the OpenGL program object. The init function below initializes the OpenGL program and vertex array, while the display function is called every frame, loading the program containing the shaders into the pipeline and executing them.

Debugging GLSL Code

Debugging GLSL code can be challenging, as compilation happens at C++ runtime and runs on the GPU. To make debugging easier, you can write utility helper functions that check for OpenGL errors and display logs when compilation or linking fails.

Reading GLSL Source Code from File

When starting out with OpenGL, it's common to hardcode GLSL source code as strings in C++. While this approach works for small demo projects, it becomes less manageable as your program grows in complexity. Instead, consider storing the shader source code in separate files and reading them in. The following function demonstrates how to do this in C++:

Drawing a Triangle with Predefined Vertices

Once your shaders are loaded, you can draw a triangle using predefined vertices. In the C++/OpenGL application, make sure to specify GL_TRIANGLES (instead of GL_POINTS) in the glDrawArrays() call, and indicate that there are three vertices being sent through the pipeline. This will cause the vertex shader to run three times, once for each vertex provided, and will pass the points through the rasterization stage, producing a filled triangle.

Animating a Scene

To create an engaging experience, it's essential to animate your scene. Each rendering of the game scene is called a "frame," and the frequency of these renderings is the "frame rate." You can control the rate of movement within your application logic by using the elapsed time since the previous frame. This is why you should include currentTime as a parameter in your rendering function, like so: display(float currentTime).
The following code snippet demonstrates how to animate a triangle by making it bounce between the left and right boundaries:

Shared Variables in OpenGL

In OpenGL, uniform variables are special variables in shaders that are shared between the CPU and GPU. They can be used to pass data from the CPU to the GPU or control rendering behavior in the GPU. To use a uniform variable in a shader program, first, retrieve its variable ID using glGetUniformLocation(). Then, set its value using glUniform() . Note that the location of uniform variables is specific to the shader program and can change when a new shader program is bound.

Takeaway

In this blog post, we've explored some key aspects of working with OpenGL, such as loading shaders from files, drawing triangles with predefined vertices, animating scenes, and utilizing shared variables between the CPU and GPU. By understanding these concepts, you can start making some fun demo projects with OpenGL.
In the next blog, we will start to explore the mathematics behind the 3D graphics rendering.
Language Models and ChatGPTC++ noexcept Keyword
Zack Yang
Zack Yang
Just a humble bounty hunter🥷
公告
type
status
date
slug
summary
tags
category
icon
password
Hey there, welcome to my blog 👋
-- 这个博客写些什么 --
定期技术分享🤖
不定期发疯文学🤡