485-代码 Flashcards

1
Q

include <GLFW/glfw3.h>

#include <GL/glew.h>
int main(){
if (!glfwInit()) {
fprintf(stderr, “Failed to initialize GLFW\n”);
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

window = glfwCreateWindow(1280, 720, “CMPT 485”, NULL, NULL);
if (window == NULL) {
fprintf(stderr, “Failed to open GLFW window.\n”);
glfwTerminate();
return -1;
}

// glfwSetWindowPos(window, 0, 0);
glfwMakeContextCurrent(window);

glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, “Failed to initialize GLEW\n”);
return -1;
}

glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
}

A

GLFW 是一个开源的库,主要用于 OpenGL 和 Vulkan 应用程序的开发。它的全称是 “Graphics Library Framework”。
GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入
glfwInit() 用于初始化 GLFW。如果返回值为 false,说明初始化失败,程序打印错误信息并退出。
设置多重采样(MSAA)为 4x,提升渲染的抗锯齿效果。
指定 OpenGL 的主版本号和次版本号为 3.3。
设置 OpenGL 的配置为核心模式(Core Profile),禁用了旧的固定功能管线。
使程序在未来的 OpenGL 版本中也能向前兼容(通常在 macOS 中是必须的)。

glfwCreateWindow(1280, 720, “CMPT 485”, NULL, NULL):
创建一个大小为 1280x720 的窗口,标题为 “CMPT 485”。
如果创建失败,glfwCreateWindow 返回 NULL,然后程序终止并释放 GLFW。

// glfwSetWindowPos(window, 0, 0):
将窗口位置设置在屏幕的左上角 (0, 0)。
glfwMakeContextCurrent(window):
绑定当前创建的窗口为 OpenGL 上下文,这样后续的 OpenGL 指令会作用在这个窗口上。

GLEW(全称:OpenGL Extension Wrangler Library)是一个开源的工具库,用于简化 OpenGL 扩展的加载和管理。由于 OpenGL 的功能扩展依赖于不同的显卡和驱动,GLEW 通过标准化的方式帮助开发者轻松访问这些扩展。GLEW 的作用
加载 OpenGL 扩展函数:
OpenGL 的很多功能(特别是现代 OpenGL 的功能)是通过扩展提供的,而这些扩展需要手动加载函数指针。GLEW 自动完成这部分工作。例如,glGenBuffers 等现代 OpenGL 函数在一些系统中需要通过扩展来访问,GLEW 负责让这些函数直接可用。
跨平台支持:它屏蔽了操作系统和显卡驱动之间的差异,让开发者在不同的平台(如 Windows、macOS、Linux)上使用统一的接口。简化开发:开发者不需要手动管理 OpenGL 扩展,只需通过 GLEW 提供的 API 来查询和使用扩展功能。

设置输入模式为 Sticky Keys,可以让按键事件被记录下来,即使按键松开后仍然可以被检测到。确保我们一定能按ESC键。

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

int main(){
std::vector<Model> models;
loadModels("bunny.models", models);
Model model = models[0]; // for now just take the first model in the file</Model>

float angle = 3.1416 * model.ra / 180.0; // 将旋转角度从度数转换为弧度
glm::mat4 I = glm::mat4(1.0f); // 单位矩阵
glm::mat4 Ms = glm::scale(I, glm::vec3(model.sx, model.sy, model.sz));
glm::mat4 Mr = glm::rotate(I, angle, glm::vec3(model.rx, model.ry, model.rz));
glm::mat4 Mt = glm::translate(I, glm::vec3(model.tx, model.ty, model.tz));
glm::mat4 Mminust = glm::translate(I, glm::vec3(-model.tx, -model.ty, -model.tz));
glm::mat4 ModelMatrix = Mt * Mr * Ms;
}

A

先旋转再放大,列行式,所以M[3][0]表示4列0行。

  1. 加载模型信息
    std::vector<Model> models:定义一个 Model 类型的向量,用来存储加载的多个模型数据。
    loadModels("bunny.models", models):从文件 "bunny.models" 加载 3D 模型信息,结果存储到 models 中。
    Model model = models[0]:当前只取第一个模型,后续基于这个模型进行操作。</Model>

float angle = 3.1416 * model.ra / 180.0; // 将旋转角度从度数转换为弧度
模型的旋转角度(单位:度)。radians=degrees× Π/180°
glm::mat4(1.0f):生成一个 4x4 的单位矩阵,作为矩阵操作的起点。
glm::scale:生成缩放矩阵。
参数解释:
I:单位矩阵。
glm::vec3(model.sx, model.sy, model.sz):缩放因子(x, y, z 轴)。
glm::rotate:生成旋转矩阵。
参数解释:
I:单位矩阵。
angle:旋转的弧度。
glm::vec3(model.rx, model.ry, model.rz):旋转轴向量(x, y, z 轴)。
glm::mat4 Mt = glm::translate(I, glm::vec3(model.tx, model.ty, model.tz));
生成一个与 Mt 相反方向的平移矩阵,用于某些情况下的反向操作。
将平移矩阵 (Mt)、旋转矩阵 (Mr)、缩放矩阵 (Ms) 按顺序相乘,生成最终的模型矩阵。

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

int main(){
glClearColor(0.7f, 0.8f, 0.8f, 0.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

GLuint programID = LoadShaders(“TransformVertexShader.vertexshader”,
“ColorFragmentShader.fragmentshader”);
glUseProgram(programID);

}

A
  1. 设置背景颜色
    glClearColor(0.7f, 0.8f, 0.8f, 0.0f);
    设置清屏时的背景颜色。
    参数 (0.7f, 0.8f, 0.8f, 0.0f) 分别是 红、绿、蓝、透明度(RGBA 格式)。
    在 glClear(GL_COLOR_BUFFER_BIT) 被调用时,屏幕将填充为这种深蓝色(或浅蓝色)。
  2. 启用深度测试
    开启深度测试(Depth Test)。
    深度测试的作用: 确保场景中更靠近相机的物体遮挡更远的物体。
  3. 设置深度比较函数
    glDepthFunc(GL_LESS);
    设置深度测试的规则:
    GL_LESS:只有当前像素比之前的像素更靠近相机时才会被绘制。
    用途: 让 OpenGL 自动处理像素的遮挡关系,实现正确的 3D 渲染效果。
  4. 加载和使用着色器程序
    (a) LoadShaders 函数
    用于加载和编译 GLSL(OpenGL 着色语言)着色器:
    TransformVertexShader.vertexshader: 顶点着色器,负责处理顶点的位置和变换。
    ColorFragmentShader.fragmentshader: 片段着色器,负责处理像素的颜色。
    返回值 programID 是生成的着色器程序的 ID。
    (b) 使用着色器程序
    告诉 OpenGL 使用刚刚加载的着色器程序 programID。
    作用: 之后的绘图命令都会使用这个着色器程序进行渲染。
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

GLsizei numVertices = positions.size();
velocities.resize(numVertices);
for (int i = 0; i < numVertices; ++i) {

}

A
  1. 获取顶点数量
    GLsizei numVertices = positions.size(); // should be same as numNormals
    positions.size():获取顶点位置数组的大小(通常表示顶点的数量)。
    numVertices:保存顶点的数量,用于后续绘制或粒子初始化。
    GLsizei 类型: OpenGL 中专门用于表示尺寸的整数类型。
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

以下为create Vertex buffer objects:
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(glm::vec3), &positions[0], GL_STREAM_DRAW);

GLuint normalsbuffer;
glGenBuffers(1, &normalsbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalsbuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);

GLuint velocitybuffer;
glGenBuffers(1, &velocitybuffer);
glBindBuffer(GL_ARRAY_BUFFER, velocitybuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(glm::vec3), &velocities[0], GL_DYNAMIC_DRAW);

以下为创建和绑定一个 顶点数组对象:
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID); (这个很重要)

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute: 对应顶点着色器的 layout(location = 0)
3, // size: 每个顶点有 3 个分量(如 x, y, z 坐标)
GL_FLOAT, // type: 每个分量的数据类型是 float
GL_FALSE, // normalized: 数据是否需要归一化(这里不需要)
0, // stride: 每个顶点数据的间隔(0 表示紧密排列)
(void*)0 // pointer: 数据在缓冲区中的偏移量(这里从头开始)
);

glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normalsbuffer);
glVertexAttribPointer(
1, // attribute: 对应 layout(location = 1)
3, // size: 每个法线向量有 3 个分量(x, y, z)
GL_FLOAT, // type: 浮点数
GL_FALSE, // 不需要归一化
0, // 紧密排列
(void*)0 // 数据从缓冲区的头部开始
);

glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, velocitybuffer);
glVertexAttribPointer(
2, // attribute: 对应 layout(location = 2)
3, // size: 每个速度向量有 3 个分量(x, y, z)
GL_FLOAT, // type: 浮点数
GL_FALSE, // 不需要归一化
0, // 紧密排列
(void*)0 // 数据从缓冲区的头部开始
);

glBindVertexArray(0);
glPointSize(4)

A

创建和初始化 顶点缓冲对象(Vertex Buffer Object,VBO),用于存储顶点、法线和速度等数据,并将它们传递给 GPU。
为顶点数据(位置、法线、速度)创建独立的缓冲对象。
将数据从 CPU(主内存)传递到 GPU(显存)。
准备 GPU 使用这些数据进行顶点处理,例如绘制 3D 模型或粒子系统。

创建 VBO
绑定 VBO
填充数据到 VBO
法线和速度缓冲区的初始化

glGenBuffers(1, &vertexbuffer):
生成一个缓冲对象,并返回其 ID 存储到 vertexbuffer。
参数 1 表示创建一个缓冲对象。

lBindBuffer:
将生成的缓冲对象绑定到 GL_ARRAY_BUFFER,表示当前操作的是顶点数据缓冲区。

GL_ARRAY_BUFFER: 数据的目标缓冲类型,这里是顶点数组。
numVertices * sizeof(glm::vec3): 缓冲区数据的总大小(顶点数量 × 每个顶点的大小)。
&positions[0]: 顶点数据的起始地址,positions 是一个存储顶点位置的 std::vector<glm::vec3>。
GL_STREAM_DRAW: 提示 GPU,这些数据会被频繁更新但很少使用。
功能: 将 positions 中的顶点位置数据传递到 GPU。

GL_STREAM_DRAW: 提示 GPU,这些数据会被频繁更新但很少使用。

法线缓冲区:
使用 GL_STATIC_DRAW,表示法线数据不会频繁改变。
速度缓冲区:
使用 GL_DYNAMIC_DRAW,表示速度数据可能会频繁更新。

  1. 定义 VAO 标识符
    GLuint VertexArrayID;
    定义一个无符号整数变量 VertexArrayID,用于存储 VAO 的标识符。
  2. 生成 VAO
    glGenVertexArrays(1, &VertexArrayID);
    使用 glGenVertexArrays 函数生成一个 VAO。
    参数:
    1 的意思是要生成的 顶点数组对象(VAO) 的数量。
    &VertexArrayID 是用于存储生成的 VAO ID 的指针。
  3. 绑定 VAO
    glBindVertexArray(VertexArrayID);
    使用 glBindVertexArray 函数将生成的 VAO 绑定为当前活动的 VAO。
    从这一刻开始,所有与顶点属性相关的配置(如绑定顶点缓冲区、设置顶点属性指针)都会保存到这个 VAO 中。

VAO 的作用
记录顶点属性状态:
VAO 是一个容器,用于保存与顶点数据相关的状态。
例如:顶点缓冲区(VBO)的绑定、顶点属性指针的设置等。

这段代码的作用是创建一个 VAO,并将其绑定为当前活动状态,接下来可以在 VAO 上配置顶点属性。VAO 是管理和优化顶点数据配置的关键工具,在 OpenGL 开发中非常重要。

如果你的应用只需要渲染一种类型的顶点数据(例如单个模型或场景),一个 VAO 就足够。

第三部分:
glEnableVertexAttribArray(0);
启用属性索引为 0 的顶点属性。
索引 0 是顶点着色器中对应的 layout(location = 0) 的输入变量。

glBindBuffer:绑定 vertexbuffer,表示顶点位置数据所在的缓冲区。
glVertexAttribPointer:配置顶点属性:
属性索引 0(与顶点着色器的 layout(location = 0) 对应)。
每个顶点包含 3 个浮点数(如位置的 x, y, z)。

代码的整体流程
启用属性数组:
启用顶点属性对应的索引(如 0、1、2)。
绑定缓冲区:
分别绑定顶点位置、法线、速度的缓冲区。
配置属性指针:
使用 glVertexAttribPointer 告诉 OpenGL 每个顶点属性的数据布局(如每个顶点有几个分量、类型、间隔等)。
关联到着色器:
这些属性的索引(0、1、2)必须与顶点着色器的 layout(location = x) 对应。

第四部分:
glBindVertexArray(0):将当前绑定的 VAO 解除绑定。
参数 0 表示不绑定任何 VAO。
在解绑之后,任何顶点属性配置都不会生效,直到绑定新的 VAO。
glPointSize(4):设置点的大小为 4 像素。
这会影响绘制 GL_POINTS 模式时的点的渲染大小。

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

在使用 glBufferData 或 glNamedBufferData 时,选择 DRAW、READ 或 COPY的场景。

A

如果数据由 CPU 上传到 GPU 使用:
选择 DRAW(这是最常见的情况)。

如果数据由 GPU 生成,供 CPU 读取:
选择 READ。

如果数据在 GPU 内部操作(GPU 生成 → GPU 使用):
选择 COPY。

配合使用 STATIC、DYNAMIC 和 STREAM
每个场景都需要结合访问频率进行选择:

STATIC: 数据只上传一次,之后多次使用(如静态顶点缓冲区)。
DYNAMIC: 数据会频繁修改并多次使用(如动态顶点缓冲区)。
STREAM: 数据只使用几次就被覆盖(如实时流数据)。

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

GLsizei

A

GLsizei 是 OpenGL 中的一个数据类型,全称是 “OpenGL Size Integer”。它是一个专门为表示大小或计数(如数组大小、对象数量)而定义的数据类型。
// 定义一个包含三个顶点的数组
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};

// 使用 GLsizei 指定顶点数量
GLsizei vertexCount = 3;

// 绘制顶点
glDrawArrays(GL_TRIANGLES, 0, vertexCount);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q
A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

cos(a+b)=
sin(a-b)=
除了绕y轴的旋转矩阵

A

cosacosb - sinasinb
sinacosb - cosasinb
[cosx, -sinx]
[sinx, cosx]
y轴sin符号变一下

How well did you know this?
1
Not at all
2
3
4
5
Perfectly