0
votes

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:

enter image description herehttps://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

1
It looks like the back face of the cube isn't being rendered.PandaConda
use glm glm.g-truc.net/0.9.4/index.html to check your matrices. It's painful to check this line by line. Btw - constrained on [0-90] "+" [270-360) sin() is bijective.Solkar

1 Answers

2
votes

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 (e.g. matching the Red Book), these matrix elements are different:

matrix[2][2] = (near_plane + far_plane) / range;
matrix[3][2] = -1.0f;