使用 OpenGL 4 的旋转矩阵
Posted
技术标签:
【中文标题】使用 OpenGL 4 的旋转矩阵【英文标题】:Rotation matrix with OpenGL 4 【发布时间】:2014-05-27 21:32:39 【问题描述】:我正在尝试使用矩阵使用 OpenGL 4 旋转三角形,但在中途时三角形似乎反转了方向。它显然不是旋转方向,所以我必须在某处弄错深度缓冲区。我已经尝试解决这个问题,但我没有找到任何使用 OpenGL 4 进行旋转的示例,只有那些使用折旧函数的示例。这是我的代码:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include "maths_funcs.h"
#include "maths_funcs.cpp"
const char* vertex_shader =
"#version 400\n"
"layout(location = 0) in vec3 vertex_position;"
"layout(location = 1) in vec3 vertex_colour;"
"uniform mat4 pmatrix;"
"uniform mat4 rmatrix;"
"uniform mat4 smatrix;"
"out vec3 colour;"
"void main () "
" colour = vertex_colour;"
" gl_Position = smatrix * rmatrix * vec4 (vertex_position, 1.0);"
"";
const char* fragment_shader =
"#version 400\n"
"in vec3 colour;"
"out vec4 frag_colour;"
"void main () "
" frag_colour = vec4 (colour, 1.0);"
"";
float angle = 0.0f;
int main ()
// start GL context and O/S window using the GLFW helper library
if (!glfwInit ())
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
GLFWwindow* window = glfwCreateWindow (640, 480, "Triangle Rotation test", NULL, NULL);
if (!window)
fprintf (stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
glfwMakeContextCurrent (window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit ();
// get version info
const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
const GLubyte* version = glGetString (GL_VERSION); // version as a string
printf ("Renderer: %s\n", renderer);
printf ("OpenGL version supported %s\n", version);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable (GL_DEPTH_TEST); // enable depth-testing
glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
float points[] =
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
;
float colours[] =
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
;
float pmatrix[] =
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
;
float rmatrix[] =
cos(10), 0.0f, sin(10), 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-sin(10), 0.0f, cos(10), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
;
float smatrix[] =
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, cos(10), sin(10), 0.0f,
0.0f, -sin(10), cos(10), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
;
GLuint vbo = 0;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);
unsigned int colours_vbo = 0;
glGenBuffers (1, &colours_vbo);
glBindBuffer (GL_ARRAY_BUFFER, colours_vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), colours, GL_STATIC_DRAW);
GLuint vao = 0;
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
glEnableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer (GL_ARRAY_BUFFER, colours_vbo);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
GLuint vs = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertex_shader, NULL);
glCompileShader (vs);
GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragment_shader, NULL);
glCompileShader (fs);
GLuint shader_programme = glCreateProgram ();
glAttachShader (shader_programme, fs);
glAttachShader (shader_programme, vs);
glLinkProgram (shader_programme);
int pmatrix_location = glGetUniformLocation (shader_programme, "pmatrix");
int rmatrix_location = glGetUniformLocation (shader_programme, "rmatrix");
int smatrix_location = glGetUniformLocation (shader_programme, "smatrix");
while (!glfwWindowShouldClose (window))
// wipe the drawing surface clear
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram (shader_programme);
rmatrix[0] = cos(angle);
rmatrix[2] = sin(angle);
rmatrix[8] = -sin(angle);
rmatrix[10] = cos(angle);
smatrix[5] = cos(angle);
smatrix[6] = sin(angle);
smatrix[9] = -sin(angle);
smatrix[10] = cos(angle);
glUniformMatrix4fv (pmatrix_location, 1, GL_FALSE, pmatrix);
glUniformMatrix4fv (rmatrix_location, 1, GL_FALSE, rmatrix);
glUniformMatrix4fv (smatrix_location, 1, GL_FALSE, smatrix);
glBindVertexArray (vao);
// draw points 0-3 from the currently bound VAO with current in-use shader
glDrawArrays (GL_TRIANGLES, 0, 3);
// update other events like input handling
glfwPollEvents ();
// put the stuff we've been drawing onto the display
glfwSwapBuffers (window);
angle+=0.01f;
if (angle >= 3.14f)
angle = -3.14f;
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
【问题讨论】:
这听起来与您的深度缓冲区没有任何关系......但是,您似乎在顶点着色器中以错误的顺序应用缩放和旋转。 假设 s 和 r 应该代表什么? 嗯,r 是旋转,s 是另一个旋转矩阵。如果我只使用其中一个,三角形仍然会在中途切换方向。 是的,我很快就知道了,只是通过查看矩阵包含的内容。这些名字让我很烦;)我认为 s 是比例的超级简写,r 是旋转,p 是投影。 【参考方案1】:由于您没有使用投影矩阵,因此您必须在顶点着色器中反转 z 坐标。更改此行:
gl_Position = smatrix * rmatrix * vec4 (vertex_position, 1.0);
这样的:
vec4 eyePos = smatrix * rmatrix * vec4 (vertex_position, 1.0);
gl_Position = vec4(eyePos.xy, -eyePos.z, eyePos.w);
gl_Position
值在剪辑坐标中,除以w
后得到 NDC(标准化设备坐标)。虽然世界坐标通常在右手坐标系中指定,z 轴指向屏幕外,但 NDC 是左手坐标系,z 轴指向 进入屏幕。
典型的投影变换负责将 z 坐标从屏幕外翻转到屏幕内。但如果不使用投影变换,则必须自己翻转 z 坐标。
另外,您可能需要仔细检查您是否真的有深度缓冲区。也许在glfwCreateWindow()
之前添加这个:
glfwWindowHint(GLFW_DEPTH_BITS, 24);
根据我在 GLFW 文档中可以找到的内容,这可能是默认设置。但是明确指定它并没有什么坏处。
【讨论】:
以上是关于使用 OpenGL 4 的旋转矩阵的主要内容,如果未能解决你的问题,请参考以下文章