0

我目前正在使用 OpenGL(高兴,GLFW,GLM)。我刚开始学习,找不到正确的方法来翻译并实际渲染它。例如,我想每帧旋转 1 度。我已经看过有关如何使用 GLM 进行这些翻译的教程,但我似乎无法弄清楚如何采用这样的方法:glm::mat4 translate = glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, 0.f));并将其应用于像这样呈现的对象:

glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES,3, GL_UNSIGNED_INT, 0);

我真的不确定我不理解什么,任何帮助将不胜感激。

编辑:我知道您可以更改顶点并重新绑定数组,但这似乎会很慢。那行得通吗?

4

1 回答 1

1

我假设您对不同坐标系和变换(如投影、视图和模型矩阵)的概念有些熟悉。如果没有,您应该在此处阅读它们https://learnopengl.com/Getting-started/Coordinate-Systems

简而言之,模型矩阵将世界中的对象作为一个整体进行变换。在大多数情况下,它包含平移、旋转和缩放。需要注意的是,矩阵乘法的阶数一般定义为

glm::mat4 model = translate * rotate * scale;

需要使用视图矩阵来获得相机的视图,而投影矩阵添加透视并用于确定屏幕上的内容以及将被渲染的内容。

要将变换应​​用于要使用着色器绘制的对象,您需要先将矩阵加载到着色器中。

glm::mat4 model = glm::translate(glm::mat4(1.f), glm::vec3(2.f, 0.f, 0.f));

unsigned int modelMatrixLoc = glGetUniformLocation(ourShader.ID, "model");
glUniformMatrix4fv(modelMatrixLoc , 1, GL_FALSE, glm::value_ptr(model));

在这里,模型矩阵将以“模型”的名称加载到着色器中。然后,您可以在着色器中使用此矩阵来转换 GPU 上的顶点。

一个简单的着色器看起来像这样

#version 460 core
layout (location = 0) in vec3 position_in;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position_in, 1.0);
}

为确保您的法线向量不会倾斜,您可以计算另一个矩阵

glm::mat3 model_normal = glm::transpose(glm::inverse(model));

如果你要将它添加到着色器中,它看起来像这样

#version 460 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec3 normal_in;

uniform mat4 model;
uniform mat3 model_normal;
uniform mat4 view;
uniform mat4 projection;

out vec3 normal;

void main()
{
    gl_Position = projection * view * model * vec4(position_in, 1.0);
    normal = model_normal * normal_in;
}

请注意我们现在如何使用 mat3 而不是 mat4?这是因为我们不想平移法线向量,而矩阵的平移部分位于第四列,我们在这里将其切除。这也意味着将 4d 向量的最后一个分量设置为1是否要平移和0不平移非常重要。


编辑:我知道您可以更改顶点并重新绑定数组,但这似乎会很慢。那行得通吗?

如果你想改变它的外观,你可以随时编辑你的模型。但是,转换在 CPU 上会慢很多。请记住,GPU 已针对此类任务进行了高度优化。所以我建议在 GPU 上进行大多数转换。

如果您只需要更改对象的部分顶点,则在大多数情况下更新顶点会更好。


我将如何随着时间不断地旋转?

作为时间的函数旋转,有多种方法。澄清一下,应用于着色器中对象的变换不是永久性的,将在下一次绘制调用时重置。如果使用同一轴执行旋转,最好在某处指定角度,然后为该角度计算单个旋转(矩阵)。要使用 GLFW 执行此操作,您可以使用

const double radians_per_second = ... ;
const glm::vec3 axis = ... ;

// rendering loop start

double time_seconds = glfwGetTime();
float angle = radians_per_second * time_seconds;
glm::mat4 rotation = glm::rotate(glm::mat4(1.f), angle, axis);

另一方面,如果旋转不在同一轴上执行,则必须将两个旋转矩阵相乘。

rotation = rotation * additional_rotation;

在这两种情况下,您都需要像我上面解释的那样为模型矩阵设置旋转。


另外,如果我想让一个正方形跟随鼠标,每次鼠标移动时我都必须重建顶点吗?

不,您不需要这样做。如果只想将方块移动到鼠标的位置,可以使用平移。要获得鼠标在世界空间中的位置,您似乎可以使用glm::unProject( ... );. 我还没有尝试过,但看起来它可以解决你的问题。你可以看看这里

https://glm.g-truc.net/0.9.2/api/a00245.html#gac38d611231b15799a0c06c54ff1ede43

如果您需要有关此主题的更多信息,可以查看已回答的此线程

使用 GLM 的 UnProject


改变相机位置和旋转的 GLFW/GLAD 功能是什么?

那只是视图矩阵。再看这里


我基本上是在尝试创建 FPS 相机。我想出了运动,但我不知道旋转。

你可以在这里看看 learnopengl.com/Getting-started/Camera。只需向下滚动,直到看到“环顾四周”部分。我认为那里的解释非常好。


我已经看过了,但对一件事感到困惑。如果每个渲染的立方体都有视图、透视和模型,我将如何更改相机的视图、透视和模型?

好的,我想我理解这里的误解。并非所有 3 个矩阵都是每个对象。模型矩阵是每个对象,每个相机的视图矩阵和每个查看模式的投影矩阵(例如,具有 90° 或正交视野的透视图),因此通常只有一次。

于 2020-07-23T23:24:37.680 回答