旋转时形状倾斜,使用 openGL、glm 数学、正交投影
shapes skewed when rotated, using openGL, glm math, orthographic projection
为了练习,我在 openGL 中设置了一个 2d/正交渲染管道,用于一个简单的游戏,但我遇到了与坐标系相关的问题。
简而言之,旋转会扭曲二维形状,我似乎不明白为什么。我也不完全确定我的坐标系是否正确。
首先我查找了以前的答案,但以下(最相关的 2D opengl rotation causes sprite distortion)表明问题是转换顺序不正确,但现在我只使用视图矩阵和投影矩阵,在顶点着色器中以正确的顺序相乘:
gl_Position = projection * view * model vec4(1.0); //(The model is just the identity matrix.)
总结到目前为止我的设置:
- 我成功上传了一个应该横跨整个屏幕的四边形:
GLfloat vertices[] = {
-wf, hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // top left
-wf, -hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // bottom left
wf, -hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // bottom right
wf, hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // top right
};
GLuint indices[] = {
0, 1, 2, // first Triangle
2, 3, 0, // second Triangle
};
wf 和 hf 为 1,我正在尝试使用 -1 到 1 坐标系,因此我不需要按着色器中的分辨率进行缩放(尽管我不确定这样做是否正确。 )
我的视口和正交矩阵:
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
...
glm::mat4 mat_ident(1.0f);
glm::mat4 mat_projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
...虽然这显然不考虑屏幕宽度和高度。我看到其他人使用 width 和 height 而不是 1s,但这似乎破坏了系统或什么都不显示。
我使用静态方法旋转,该方法修改包含 glm::quaternion
(时间/1000)的结构以获取秒数:
main_cam.rotate((GLfloat)curr_time / TIME_UNIT_TO_SECONDS, 0.0f, 0.0f, 1.0f);
// which does: glm::angleAxis(angle, glm::vec3(x, y, z) * orientation)
最后,我将矩阵作为统一传递:
glUniformMatrix4fv(MAT_LOC, 1, GL_FALSE, glm::value_ptr(mat_projection * FreeCamera_calc_view_matrix(&main_cam) * mat_ident));
...并在顶点着色器中相乘
gl_Position = u_matrix * vec4(a_position, 1.0);
v_position = a_position.xyz;
全屏四边形以其中心为中心旋转(0、0,如我所愿),但它的长度和宽度扭曲了,这意味着我没有设置正确。
我最好的猜测是我没有创建正确的正交矩阵,但不可否认,我很难在堆栈溢出或其他地方找到任何可能有助于调试的东西。大多数答案都表明矩阵乘法顺序是错误的,但这里不是这种情况。
第二个问题是——我不应该在 2d 游戏的上下文中将我的坐标设置为 1/-1 吗?我这样做是为了使编写着色器更容易。我还担心添加模型矩阵后 character/object 移动。
可能是什么导致了这个问题?如果我需要将 gl::ortho 的参数乘以宽度和高度,那么我该如何转换坐标 v_position (我的 "in"/"varying" 位置属性的插值版本)在着色器中应该在 -1 到 1 范围内工作?在放置实体时选择特定坐标系有什么意义?游戏将使用 sprite 和纹理,所以我正在考虑像素坐标系,但很快就很难在着色器方面进行推理。我宁愿让这个工作。
感谢您的帮助。
编辑:是否可以将我的 varying/interpolated v_position 设置为计算的 gl_Position 值而不是属性位置?
尝试在 glm::ortho 的前两个参数中考虑要显示的 window 的纵横比,以反映显示器的纵横比。
GLfloat aspectRatio = SCREEN_WIDTH / SCREEN_HEIGHT;
glm::mat4 mat_projection = glm::ortho(-aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);
为了练习,我在 openGL 中设置了一个 2d/正交渲染管道,用于一个简单的游戏,但我遇到了与坐标系相关的问题。
简而言之,旋转会扭曲二维形状,我似乎不明白为什么。我也不完全确定我的坐标系是否正确。
首先我查找了以前的答案,但以下(最相关的 2D opengl rotation causes sprite distortion)表明问题是转换顺序不正确,但现在我只使用视图矩阵和投影矩阵,在顶点着色器中以正确的顺序相乘:
gl_Position = projection * view * model vec4(1.0); //(The model is just the identity matrix.)
总结到目前为止我的设置: - 我成功上传了一个应该横跨整个屏幕的四边形:
GLfloat vertices[] = {
-wf, hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // top left
-wf, -hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // bottom left
wf, -hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // bottom right
wf, hf, 0.0f, 0.0, 0.0, 1.0, 1.0, // top right
};
GLuint indices[] = {
0, 1, 2, // first Triangle
2, 3, 0, // second Triangle
};
wf 和 hf 为 1,我正在尝试使用 -1 到 1 坐标系,因此我不需要按着色器中的分辨率进行缩放(尽管我不确定这样做是否正确。 )
我的视口和正交矩阵:
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
...
glm::mat4 mat_ident(1.0f);
glm::mat4 mat_projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
...虽然这显然不考虑屏幕宽度和高度。我看到其他人使用 width 和 height 而不是 1s,但这似乎破坏了系统或什么都不显示。
我使用静态方法旋转,该方法修改包含 glm::quaternion
(时间/1000)的结构以获取秒数:
main_cam.rotate((GLfloat)curr_time / TIME_UNIT_TO_SECONDS, 0.0f, 0.0f, 1.0f);
// which does: glm::angleAxis(angle, glm::vec3(x, y, z) * orientation)
最后,我将矩阵作为统一传递:
glUniformMatrix4fv(MAT_LOC, 1, GL_FALSE, glm::value_ptr(mat_projection * FreeCamera_calc_view_matrix(&main_cam) * mat_ident));
...并在顶点着色器中相乘
gl_Position = u_matrix * vec4(a_position, 1.0);
v_position = a_position.xyz;
全屏四边形以其中心为中心旋转(0、0,如我所愿),但它的长度和宽度扭曲了,这意味着我没有设置正确。
我最好的猜测是我没有创建正确的正交矩阵,但不可否认,我很难在堆栈溢出或其他地方找到任何可能有助于调试的东西。大多数答案都表明矩阵乘法顺序是错误的,但这里不是这种情况。
第二个问题是——我不应该在 2d 游戏的上下文中将我的坐标设置为 1/-1 吗?我这样做是为了使编写着色器更容易。我还担心添加模型矩阵后 character/object 移动。
可能是什么导致了这个问题?如果我需要将 gl::ortho 的参数乘以宽度和高度,那么我该如何转换坐标 v_position (我的 "in"/"varying" 位置属性的插值版本)在着色器中应该在 -1 到 1 范围内工作?在放置实体时选择特定坐标系有什么意义?游戏将使用 sprite 和纹理,所以我正在考虑像素坐标系,但很快就很难在着色器方面进行推理。我宁愿让这个工作。
感谢您的帮助。
编辑:是否可以将我的 varying/interpolated v_position 设置为计算的 gl_Position 值而不是属性位置?
尝试在 glm::ortho 的前两个参数中考虑要显示的 window 的纵横比,以反映显示器的纵横比。
GLfloat aspectRatio = SCREEN_WIDTH / SCREEN_HEIGHT;
glm::mat4 mat_projection = glm::ortho(-aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);