概述
本文介绍 GLFW + GLAD 在 RayTracing in one weekend 的实现。
实验环境:Manjaro Linux 22.0.0
整体思路:
使用基于屏幕空间的光线跟踪算法,每个像素点代表一个光线。使用 GLSL 着色器语言编写顶点着色器,获取顶点在屏幕空间的坐标,经过函数计算得到 RGB 值并传输到片段着色器中。
目录
输出第一张图片
首先设置窗口尺寸
const unsigned int SCR_WIDTH = 400;
const unsigned int SCR_HEIGHT = 400;
设置参数
// 确定顶点大小
const int point_size = 1;
// 均匀等距采样
const int sample_x = SCR_WIDTH / point_size;
const int sample_y = SCR_HEIGHT / point_size;
// 确定顶点数组
const int num_of_points = sample_y * sample_x;
float vertices[num_of_points * 3];
因为 GPU 绘制顶点的时候是要通过输入的顶点数组来计算屏幕空间中的顶点,因此在 main 函数中通过 CPU 设置顶点三维坐标信息。
平常我们认为图像的空间坐标系中,坐标从 0 开始一直到边界,但是 OpenGL 中,屏幕空间是一个坐标取值为 [-1.0, 1.0] 的二维空间,因此需要进行坐标的转换。
int dy = SCR_HEIGHT / sample_y; // 顶点在虚拟屏幕空间的 y 轴步长
int dx = SCR_WIDTH / sample_x; // 顶点在虚拟屏幕空间 x 轴步长
int idx = 0;
printf("dy: %d dx: %d\n", dy, dx);
/* 遍历虚拟屏幕空间,将 [0, SCR_HEIGHT] 坐标变换到 [-1.0, 1.0] 的
* 屏幕空间坐标并记录在 vertices 数组中 */
for (int y = 0; y < SCR_HEIGHT; y += dy) {
for (int x = 0; x < SCR_WIDTH; x += dx) {
float ny = (static_cast<float>(y) / SCR_HEIGHT - 0.5) * 2.0f;
float nx = (static_cast<float>(x) / SCR_WIDTH - 0.5) * 2.0f;
vertices[idx++] = nx;
vertices[idx++] = ny;
vertices[idx++] = 0.0f; // z 轴坐标,暂时设置为 0.0f
}
}
在渲染主循环中,我们需要将顶点数据发送到 GPU,因此使用 glDrawArrays() 函数 ,参数设置为顶点个数。
glPointSize(point_size);
glDrawArrays(GL_POINTS, 0, num_of_points);
为了将顶点坐标映射成颜色值,还需要在着色器程序中进行一点小小的调整,将 [-1.0, 1.0] 的坐标轴变换到 [0.0, 1.0] 范围内。
vsOutColor.x = aPos.x / 2 + 0.5;
vsOutColor.y = aPos.y / 2 + 0.5;
vsOutColor.z = 0.25;
最终结果图如下
顶点着色器代码
// vertex shader
#version 460 core
layout (location = 0) in vec3 aPos;
out vec3 vsOutColor;
void main()
{
vsOutColor.x = aPos.x / 2 + 0.5;
vsOutColor.y = aPos.y / 2 + 0.5;
vsOutColor.z = 0.25;
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
};
片段着色器代码
// fragment shader
#version 460 core
out vec4 FragColor;
in vec3 vsOutColor;