OpenGL rotation behaves weird between 90 and 270 degrees
I am new with OpenGL and I'm trying to learn it by writing my own simple engine. I have implemented texture mapping, world, view and perspective matrices so far. However I have noticed a strange behaviour of rotations. I have a mesh class which has a rotation attributes (around x, y and z axes). When I change these attributes, the object's rotation matrix is recomputed and later it is applied in the vertex shader to transform the vertices. When I rotate the mesh this way between 0 - 90 and 270 - 360 degrees, everything looks fine, but if the rotation is in the 90 - 270 degrees, the triangles that are further away from the camera start to get bigger, instead of getting smaller, than the ones that are closer. The triangles that are closer, however, are drawn in front of the triangles that are further away, so the z coordination should be fine. When the rotation continues, everything gets seamlessly back to OK as soon as 270 degrees are reached. Also, when I apply the rotation matrix with a function in my code (not in the shader), everything works fine, the problem only occurs when I apply the rotation matrix in the shader.
I provide a picture and a video:
https://www.youtube.com/watch?v=jJLT4DTEYyQ&feature=youtu.be
My vertex shader is:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texture_coordination;
layout (location = 2) in vec3 normal;
uniform mat4 perspective_matrix;
uniform mat4 world_matrix;
uniform mat4 view_matrix;
out vec2 uv_coordination;
void main()
{
gl_Position = perspective_matrix * view_matrix * world_matrix * vec4(position, 1.0);
uv_coordination = texture_coordination;
}
I make my matrices like this:
void make_rotation_matrix(float degrees_x, float degrees_y, float degrees_z, float matrix[4][4])
{
degrees_x *= PI_DIVIDED_180; // convert to radians
degrees_y *= PI_DIVIDED_180;
degrees_z *= PI_DIVIDED_180;
float sin_x = sin(degrees_x);
float cos_x = cos(degrees_x);
float sin_y = sin(degrees_y);
float cos_y = cos(degrees_y);
float sin_z = sin(degrees_z);
float cos_z = cos(degrees_z);
matrix[0][0] = cos_z * cos_y;
matrix[1][0] = cos_z * sin_y * sin_x - sin_z * cos_x;
matrix[2][0] = cos_z * sin_y * cos_x + sin_z * sin_x;
matrix[3][0] = 0;
matrix[0][1] = sin_z * cos_y;
matrix[1][1] = sin_z * sin_y * sin_x + cos_z * cos_x;
matrix[2][1] = sin_z * sin_y * cos_x - cos_z * sin_x;
matrix[3][1] = 0;
matrix[0][2] = -1 * sin_y;
matrix[1][2] = cos_y * sin_x;
matrix[2][2] = cos_y * cos_y;
matrix[3][2] = 0;
matrix[0][3] = 0;
matrix[1][3] = 0;
matrix[2][3] = 0;
matrix[3][3] = 1;
}
void make_perspective_matrix(float fov_degrees, float near_plane, float far_plane, float matrix[4][4])
{
float aspect_ratio = global_window_width / ((float) global_window_height);
float range = near_plane - far_plane;
float tan_half_fov = tanf(fov_degrees / 2.0 * PI_DIVIDED_180);
matrix[0][0] = 1.0f / (tan_half_fov * aspect_ratio) ; matrix[1][0] = 0.0f; matrix[2][0] = 0.0f; matrix[3][0] = 0.0f;
matrix[0][1] = 0.0f; matrix[1][1] = 1.0f / tan_half_fov; matrix[2][1] = 0.0f; matrix[3][1] = 0.0f;
matrix[0][2] = 0.0f; matrix[1][2] = 0.0f; matrix[2][2] = (-1 * near_plane - far_plane) / (float) range; matrix[3][2] = 1.0;
matrix[0][3] = 0.0f; matrix[1][3] = 0.0f; matrix[2][3] = 2.0f * far_plane * near_plane / (float) range; matrix[3][3] = 0.0f;
}
void multiply_matrices(float matrix_a[4][4], float matrix_b[4][4], float matrix_result[4][4])
{
unsigned int i,j;
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
matrix_result[i][j] =
matrix_b[0][j] * matrix_a[i][0] +
matrix_b[1][j] * matrix_a[i][1] +
matrix_b[2][j] * matrix_a[i][2] +
matrix_b[3][j] * matrix_a[i][3];
}
void mesh_3d::update_transformation_matrix()
{
float helper_matrix[4][4];
multiply_matrices(this->translation_matrix,this->rotation_matrix,helper_matrix);
multiply_matrices(helper_matrix,this->scale_matrix,this->transformation_matrix);
}
And I draw the mesh like this:
void mesh_3d::draw()
{
glUniformMatrix4fv(world_matrix_location,1,GL_TRUE,(const GLfloat *)this->transformation_matrix); // load this model's transformation matrix
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
if (this->texture != NULL)
{
glActiveTexture(GL_TEXTURE0); // set the active texture unit to 0
glBindTexture(GL_TEXTURE_2D,this->texture->get_texture_object());
}
glBindBuffer(GL_ARRAY_BUFFER,this->vbo);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(vertex_3d),0); // position
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,sizeof(vertex_3d),(const GLvoid*) 12); // texture coordination
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,sizeof(vertex_3d),(const GLvoid*) 20); // normal
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,this->ibo);
glDrawElements(GL_TRIANGLES,this->triangles.size() * 3,GL_UNSIGNED_INT,0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
}
The mesh has it's cale and translation matrix set to identity by default of course.
I've been stuck with this for a few days now and I don't know how to move on, I'd be glad if someone could at least point out what might be wrong.
I have printed out the matrix values for 0 and 122 degrees:
0 degrees:
model (world):
1 0 0 0
0 1 0 0
0 0 1 0
0 0 3 1
view:
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
projection (perspective):
0.75 0 0 0
0 1 0 0
0 0 1.06186 1
0 0 -0.618557 0
122 degrees:
model (world):
-0.529919 0 -0.848048 0
0 1 0 0
0.848048 0 0.280814 0
0 0 3 1
view: same as before
projection (perspective): same as before
Some of your matrix calculations don't match what I get when I try to replicate them. With your notation, I get the following for the rotation matrix:
matrix[0][0] = cos_z * cos_y;
matrix[1][0] = cos_z * sin_y * sin_x + sin_z * cos_x;
matrix[2][0] = -cos_z * sin_y * cos_x + sin_z * sin_x;
matrix[3][0] = 0.0f;
matrix[0][1] = -sin_z * cos_y;
matrix[1][1] = -sin_z * sin_y * sin_x + cos_z * cos_x;
matrix[2][1] = sin_z * sin_y * cos_x + cos_z * sin_x;
matrix[3][1] = 0.0f;
matrix[0][2] = sin_y;
matrix[1][2] = -cos_y * sin_x;
matrix[2][2] = cos_y * cos_x;
matrix[3][2] = 0.0f;
If you compare to your result, it's mostly just sign differences. Looks like you used left-handed rotations, while I used right-handed, which changes the sign of all sin_[xyz]
values. matrix[2][2]
is very different, though, looks like you have a typo there.
Your projection matrix also looks non-standard. In the OpenGL projection matrices that are normally used (eg matching the Red Book), these matrix elements are different:
matrix[2][2] = (near_plane + far_plane) / range;
matrix[3][2] = -1.0f;
链接地址: http://www.djcxy.com/p/81750.html
上一篇: 表格单元格中旋转文字的边距/填充